Skip to content
2 changes: 1 addition & 1 deletion packages/wallet/core/src/signers/session-manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -193,7 +193,7 @@ export class SessionManager implements SapientSigner {
throw new Error('Repeated usage hashes')
}

const data = AbiFunction.encodeData(Constants.INCREMENT_USAGE_LIMIT, [uniqueIncrements])
const data = AbiFunction.encodeData(Constants.INCREMENT_USAGE_LIMIT, [increments])

return {
to: this.address,
Expand Down
22 changes: 10 additions & 12 deletions packages/wallet/core/src/signers/session/explicit.ts
Original file line number Diff line number Diff line change
Expand Up @@ -250,6 +250,7 @@ export class Explicit implements ExplicitSessionSigner {
): Promise<UsageLimit[]> {
const increments: { usageHash: Hex.Hex; increment: bigint }[] = []
const usageValueHash = this.getValueUsageHash()
let valueUsed = 0n

for (const call of calls) {
// Find matching permission
Expand Down Expand Up @@ -281,18 +282,15 @@ export class Explicit implements ExplicitSessionSigner {
}
}

// Check the value
if (call.value !== 0n) {
const existingIncrement = increments.find((i) => Hex.isEqual(i.usageHash, usageValueHash))
if (existingIncrement) {
existingIncrement.increment += call.value
} else {
increments.push({
usageHash: usageValueHash,
increment: call.value,
})
}
}
valueUsed += call.value
}

// Check the value
if (valueUsed > 0n) {
increments.push({
usageHash: usageValueHash,
increment: valueUsed,
})
}

// If no increments, return early
Expand Down
48 changes: 35 additions & 13 deletions packages/wallet/dapp-client/src/ChainSessionManager.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Envelope, Relayer, Signers, State, Wallet } from '@0xsequence/wallet-core'
import { Attestation, Extensions, Payload, SessionConfig } from '@0xsequence/wallet-primitives'
import { Attestation, Constants, Extensions, Payload, SessionConfig } from '@0xsequence/wallet-primitives'
import { AbiFunction, Address, Hex, Provider, RpcTransport, Secp256k1 } from 'ox'

import { DappTransport } from './DappTransport.js'
Expand Down Expand Up @@ -36,7 +36,7 @@ import {
Transaction,
TransportMode,
} from './types/index.js'
import { CACHE_DB_NAME } from './utils/constants.js'
import { CACHE_DB_NAME, VALUE_FORWARDER_ADDRESS } from './utils/constants.js'
import { TypedData } from 'ox/TypedData'

interface ChainSessionManagerEventMap {
Expand Down Expand Up @@ -398,6 +398,11 @@ export class ChainSessionManager {
try {
if (!this.transport) throw new InitializationError('Transport failed to initialize.')

const session = this.sessions.find((s) => Address.isEqual(s.address, sessionAddress))
if (!session) {
throw new ModifyExplicitSessionError('Session not found.')
}

const payload: ModifySessionPayload = {
walletAddress: this.walletAddress,
sessionAddress: sessionAddress,
Expand Down Expand Up @@ -427,6 +432,8 @@ export class ChainSessionManager {
throw new ModifyExplicitSessionError('Wallet or session address mismatch.')
}

session.permissions = newPermissions

if (this.transport?.mode === TransportMode.POPUP) {
this.transport?.closeWallet()
}
Expand Down Expand Up @@ -614,6 +621,8 @@ export class ChainSessionManager {
this.sessions.push({
address: explicitSigner.address,
isImplicit: false,
chainId: this.chainId,
permissions,
})
return
} catch (err) {
Expand Down Expand Up @@ -660,7 +669,7 @@ export class ChainSessionManager {
* @throws {InitializationError} If the session is not initialized.
* @throws {TransactionError} If the transaction fails at any stage.
*/
async buildSignAndSendTransactions(transactions: Transaction[], feeOption?: Relayer.FeeOption): Promise<string> {
async buildSignAndSendTransactions(transactions: Transaction[], feeOption?: Relayer.FeeOption): Promise<Hex.Hex> {
if (!this.wallet || !this.sessionManager || !this.provider || !this.isInitialized)
throw new InitializationError('Session is not initialized.')
try {
Expand All @@ -676,17 +685,30 @@ export class ChainSessionManager {

const callsToSend = calls
if (feeOption) {
const transfer = AbiFunction.from(['function transfer(address to, uint256 value)'])
const transferCall: Payload.Call = {
to: feeOption.token.contractAddress as `0x${string}`,
value: BigInt(0),
data: AbiFunction.encodeData(transfer, [feeOption.to as Address.Address, BigInt(feeOption.value)]),
gasLimit: BigInt(feeOption.gasLimit),
delegateCall: false,
onlyFallback: false,
behaviorOnError: 'revert' as const,
if (feeOption.token.contractAddress === Constants.ZeroAddress) {
const forwardValue = AbiFunction.from(['function forwardValue(address to, uint256 value)'])
callsToSend.unshift({
to: VALUE_FORWARDER_ADDRESS,
value: BigInt(feeOption.value),
data: AbiFunction.encodeData(forwardValue, [feeOption.to as Address.Address, BigInt(feeOption.value)]),
gasLimit: BigInt(feeOption.gasLimit),
delegateCall: false,
onlyFallback: false,
behaviorOnError: 'revert' as const,
})
} else {
const transfer = AbiFunction.from(['function transfer(address to, uint256 value)'])
const transferCall: Payload.Call = {
to: feeOption.token.contractAddress as `0x${string}`,
value: BigInt(0),
data: AbiFunction.encodeData(transfer, [feeOption.to as Address.Address, BigInt(feeOption.value)]),
gasLimit: BigInt(feeOption.gasLimit),
delegateCall: false,
onlyFallback: false,
behaviorOnError: 'revert' as const,
}
callsToSend.unshift(transferCall)
}
callsToSend.unshift(transferCall)
}
const signedCalls = await this._buildAndSignCalls(callsToSend)
const hash = await this.relayer.relay(signedCalls.to, signedCalls.data, BigInt(this.chainId))
Expand Down
8 changes: 6 additions & 2 deletions packages/wallet/dapp-client/src/DappClient.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
import { ChainId } from '@0xsequence/network'
import { Relayer, Signers } from '@0xsequence/wallet-core'
import { Address } from 'ox'
import { Address, Hex } from 'ox'

import { ChainSessionManager } from './ChainSessionManager.js'
import { DappTransport } from './DappTransport.js'
Expand Down Expand Up @@ -534,7 +534,11 @@ export class DappClient {
*
* const txHash = await dappClient.sendTransaction(1, [transaction]);
*/
async sendTransaction(chainId: ChainId, transactions: Transaction[], feeOption?: Relayer.FeeOption): Promise<string> {
async sendTransaction(
chainId: ChainId,
transactions: Transaction[],
feeOption?: Relayer.FeeOption,
): Promise<Hex.Hex> {
if (!this.isInitialized) throw new InitializationError('Not initialized')
const chainSessionManager = this.getChainSessionManager(chainId)
if (!chainSessionManager.isInitialized)
Expand Down
2 changes: 2 additions & 0 deletions packages/wallet/dapp-client/src/types/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,8 @@ export type Transaction =
export type Session = {
address: Address.Address
isImplicit: boolean
permissions?: Signers.Session.ExplicitParams
chainId?: ChainId
}

// --- Event Types ---
Expand Down
1 change: 1 addition & 0 deletions packages/wallet/dapp-client/src/utils/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@ export const CACHE_DB_NAME = 'sequence-cache'
export const NODES_URL = 'https://nodes.sequence.app/{network}'
export const RELAYER_URL = 'https://dev-{network}-relayer.sequence.app'
export const DEFAULT_KEYMACHINE_URL = 'https://v3-keymachine.sequence-dev.app'
export const VALUE_FORWARDER_ADDRESS = '0xABAAd93EeE2a569cF0632f39B10A9f5D734777ca'