Skip to content

Comments

feat: new session keys with viem#618

Draft
hugomrdias wants to merge 2 commits intomasterfrom
hugomrdias/session-keys
Draft

feat: new session keys with viem#618
hugomrdias wants to merge 2 commits intomasterfrom
hugomrdias/session-keys

Conversation

@hugomrdias
Copy link
Member

@hugomrdias hugomrdias commented Feb 19, 2026

  • still needs wiring in react and sdk
  • proper e2e testing

Example usage:

import * as SessionKey from '@filoz/synapse-core/session-key'
import { privateKeyToAccount } from 'viem/accounts'
import { type Hex } from 'viem'
import { mainnet } from '@filoz/synapse-core/chains'

const rootAccount = privateKeyToAccount('0xaa14e25eaea762df1533e72394b85e56dd0c7aa61cf6df3b1f13a842ca0361e5' as Hex)

const sessionKey = SessionKey.fromSecp256k1({
  privateKey: '0xaa14e25eaea762df1533e72394b85e56dd0c7aa61cf6df3b1f13a842ca0361e5' as Hex,
  root: rootAccount,
  chain: mainnet,
})
sessionKey.on('expirationsUpdated', (e) => {console.log(e.detail)})
sessionKey.on('connected', (e) => {console.log(e.detail)})
sessionKey.on('disconnected', () => {console.log('disconnected')})
sessionKey.on('error', (e) => {console.log(e.detail)})


const { event: loginEvent } = await SessionKey.loginSync(client, {
  address: sessionKey.address,
  onHash(hash) {
    console.log(`Waiting for tx ${hash} to be mined...`)
  },
})

console.log('event login:', loginEvent.args)

await sessionKey.connect()

if(sessionKey.hasPermission('CreateDataSet')) {
  const hash = await createDataSet(sessionKey.client, {
    payee: '0x1234567890123456789012345678901234567890',
    payer: sessionKey.rootAddress,
    serviceURL: 'https://example.com',
  })
  console.log('event created dataset:', hash)
}

const { event: revokeEvent } = await SessionKey.revokeSync(client, {
  address: sessionKey.address,
  onHash(hash) {
    console.log(`Waiting for tx ${hash} to be mined...`)
  },
})
console.log('event revoked:', revokeEvent.args)
sessionKey.disconnect()

@github-project-automation github-project-automation bot moved this to 📌 Triage in FOC Feb 19, 2026
@hugomrdias hugomrdias changed the title Hugomrdias/session-keys feat: new session keys with viem Feb 19, 2026
@hugomrdias hugomrdias self-assigned this Feb 19, 2026
@cloudflare-workers-and-pages
Copy link

Deploying with  Cloudflare Workers  Cloudflare Workers

The latest updates on your project. Learn more about integrating Git with Workers.

Status Name Latest Commit Preview URL Updated (UTC)
✅ Deployment successful!
View logs
synapse-dev aa80d34 Commit Preview URL

Branch Preview URL
Feb 19 2026, 06:18 PM

* console.log(expirations)
*/
export async function getExpirations(client: Client<Transport, Chain>, options: getExpirations.OptionsType) {
const expirations: Record<SessionKeyPermissions, bigint> = EMPTY_EXPIRATIONS
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
const expirations: Record<SessionKeyPermissions, bigint> = EMPTY_EXPIRATIONS
const expirations: Record<SessionKeyPermissions, bigint> = { ...EMPTY_EXPIRATIONS }

readonly expirations: Record<SessionKeyPermissions, bigint>
hasPermission: (permission: SessionKeyPermissions) => boolean
syncExpirations: () => Promise<void>
connect: () => void
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
connect: () => void
async connect: () => void

?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
connect: () => void
async connect: () => Promise<void>

const permission = getPermissionFromTypeHash(hash)
this.expirations[permission] = event.args.expiry
}
this.emit('expirationsUpdated', this.#expirations)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

and if it fails and doesn't even get here?

* @param logs - The transaction logs.
* @returns The AuthorizationsUpdated event.
*/
export function extractRevokeEvent(logs: Log[]) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

could just reuse the login one to do the same job?

error: CustomEvent<Error>
}

export type SessionKeyType = 'Secp256k1' | 'P-256'
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oh really ...?

@rvagg
Copy link
Collaborator

rvagg commented Feb 20, 2026

This might be a good opportunity to deal with type SessionKeyPermissions being a closed union and ALL_PERMISSIONS being a bit misleading in its name. This came up this week in filecoin-project/curio#1028, noting that (a) SessionKeyRegistry doesn't care what these strings are, it's not exclusive, and (b) DeleteDataSet isn't even standard anymore, it's gone, so our existing set isn't even accurate (but as per that issue we're talking about repurposing it to do Client<>Curio auth, not touching FWSS).

Perhaps:

  • ALL_PERMISSIONS -> FWSS_PERMISSIONS
  • EMPTY_PERMISSIONS has the same problem
  • Make SessionKeyPermissions open, or rename it to FWSSPermissions and do a type SessionKeyPermission = FWSSPermissions | Hex.
  • login(), revoke() should expand their permissions? as per above.
  • getExpirations() and hasPermission() is harder, but we could clearly document that they are dealing specifically with FWSS only

Not a blocker, but the current session key code gives the impression this is all canonical and a closed set of permissions. But developers should be able to use the registry to do non-FWSS things and having an SDK that makes that easy would be nice.

@rvagg
Copy link
Collaborator

rvagg commented Feb 20, 2026

Will I be able to pass sessionKey.client to the SDK in the end of this? For the signing operations, will we need to update them to differentiate between a SessionKeyAccount client and a standard one so we can pick out rootAddress when it exists?

@hugomrdias
Copy link
Member Author

Will I be able to pass sessionKey.client to the SDK in the end of this? For the signing operations, will we need to update them to differentiate between a SessionKeyAccount client and a standard one so we can pick out rootAddress when it exists?

Yeah not sure yet, because session keys only works for those 4 mutations (maybe just 3 if delete dataset is gone), some of the other services do other mutations that need the root client.

I think for now I'm just adding a new constructor option to pass a session keys and internally use if available and has permission.

There's one subtle thing in this design, that I want your opinion.

The connect/disconnect are actually optional, they are there if you want realtime tracking of the permissions, if you don't you can just pass whatever expirations you got from login and YOLO the mutations.

I will be cleaning up with your comments and finish testing hopefully sps work today.

@rvagg
Copy link
Collaborator

rvagg commented Feb 23, 2026

you can just pass whatever expirations you got from login and YOLO the mutations

Pass to where? I don't think we care in any of the places we use it, so this isn't an internal concern. I think the answer here is to just document how expirations work and for long-lived session key instances advise that the developer should be sure to refresh expiries occasionally to be sure to perform login() as needed. Otherwise, not our problem (except for the fact that errors arising from expired permissions will be opaque about the cause!).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: ⌨️ In Progress

Development

Successfully merging this pull request may close these issues.

hook in session key properly, rethink session key client and inherit transport properly

3 participants