1- import { Payload , Permission , SessionSignature , Utils } from '@0xsequence/wallet-primitives'
1+ import { Payload , Permission , SessionSignature , Constants } from '@0xsequence/wallet-primitives'
22import { AbiFunction , AbiParameters , Address , Bytes , Hash , Hex , Provider } from 'ox'
33import { MemoryPkStore , PkStore } from '../pk/index.js'
44import { ExplicitSessionSigner , UsageLimit } from './session.js'
5- import { GET_LIMIT_USAGE , INCREMENT_USAGE_LIMIT } from '../../../../primitives/dist/constants.js'
65
76export type ExplicitParams = Omit < Permission . SessionPermissions , 'signer' >
87
8+ const VALUE_TRACKING_ADDRESS : Address . Address = '0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE'
9+
910export class Explicit implements ExplicitSessionSigner {
1011 private readonly _privateKey : PkStore
1112
@@ -28,6 +29,27 @@ export class Explicit implements ExplicitSessionSigner {
2829 sessionManagerAddress : Address . Address ,
2930 provider ?: Provider . Provider ,
3031 ) : Promise < Permission . Permission | undefined > {
32+ if ( call . value !== 0n ) {
33+ // Validate the value
34+ if ( ! provider ) {
35+ throw new Error ( 'Value transaction validation requires a provider' )
36+ }
37+ const usageHash = Hash . keccak256 (
38+ AbiParameters . encode (
39+ [
40+ { type : 'address' , name : 'signer' } ,
41+ { type : 'address' , name : 'valueTrackingAddress' } ,
42+ ] ,
43+ [ this . address , VALUE_TRACKING_ADDRESS ] ,
44+ ) ,
45+ )
46+ const { usageAmount } = await this . readCurrentUsageLimit ( wallet , sessionManagerAddress , usageHash , provider )
47+ const value = Bytes . fromNumber ( usageAmount + call . value , { size : 32 } )
48+ if ( Bytes . toBigInt ( value ) > this . sessionPermissions . valueLimit ) {
49+ return undefined
50+ }
51+ }
52+
3153 for ( const permission of this . sessionPermissions . permissions ) {
3254 // Validate the permission
3355 if ( await this . validatePermission ( permission , call , wallet , sessionManagerAddress , provider ) ) {
@@ -37,12 +59,12 @@ export class Explicit implements ExplicitSessionSigner {
3759 return undefined
3860 }
3961
40- async getCurrentUsageLimit (
62+ private async getCurrentPermissionUsageLimit (
4163 wallet : Address . Address ,
4264 sessionManagerAddress : Address . Address ,
4365 permission : Permission . Permission ,
4466 ruleIndex : number | bigint ,
45- provider ? : Provider . Provider ,
67+ provider : Provider . Provider ,
4668 ) : Promise < UsageLimit > {
4769 const encodedPermission = {
4870 target : permission . target ,
@@ -54,15 +76,40 @@ export class Explicit implements ExplicitSessionSigner {
5476 mask : Bytes . toHex ( rule . mask ) ,
5577 } ) ) ,
5678 }
57-
5879 const usageHash = Hash . keccak256 (
5980 AbiParameters . encode (
6081 [ { type : 'address' , name : 'signer' } , Permission . permissionStructAbi , { type : 'uint256' , name : 'ruleIndex' } ] ,
6182 [ this . address , encodedPermission , BigInt ( ruleIndex ) ] ,
6283 ) ,
6384 )
64- const readData = AbiFunction . encodeData ( GET_LIMIT_USAGE , [ wallet , usageHash ] )
65- const getUsageLimitResult = await provider ! . request ( {
85+ return this . readCurrentUsageLimit ( wallet , sessionManagerAddress , usageHash , provider )
86+ }
87+
88+ private async getCurrentValueUsageLimit (
89+ wallet : Address . Address ,
90+ sessionManagerAddress : Address . Address ,
91+ provider : Provider . Provider ,
92+ ) : Promise < UsageLimit > {
93+ const usageHash = Hash . keccak256 (
94+ AbiParameters . encode (
95+ [
96+ { type : 'address' , name : 'signer' } ,
97+ { type : 'address' , name : 'valueTrackingAddress' } ,
98+ ] ,
99+ [ this . address , VALUE_TRACKING_ADDRESS ] ,
100+ ) ,
101+ )
102+ return this . readCurrentUsageLimit ( wallet , sessionManagerAddress , usageHash , provider )
103+ }
104+
105+ private async readCurrentUsageLimit (
106+ wallet : Address . Address ,
107+ sessionManagerAddress : Address . Address ,
108+ usageHash : Hex . Hex ,
109+ provider : Provider . Provider ,
110+ ) : Promise < UsageLimit > {
111+ const readData = AbiFunction . encodeData ( Constants . GET_LIMIT_USAGE , [ wallet , usageHash ] )
112+ const getUsageLimitResult = await provider . request ( {
66113 method : 'eth_call' ,
67114 params : [
68115 {
@@ -71,7 +118,7 @@ export class Explicit implements ExplicitSessionSigner {
71118 } ,
72119 ] ,
73120 } )
74- const usageAmount = AbiFunction . decodeResult ( GET_LIMIT_USAGE , getUsageLimitResult )
121+ const usageAmount = AbiFunction . decodeResult ( Constants . GET_LIMIT_USAGE , getUsageLimitResult )
75122 return {
76123 usageHash,
77124 usageAmount,
@@ -99,7 +146,7 @@ export class Explicit implements ExplicitSessionSigner {
99146 let value : Bytes . Bytes = callDataValue . map ( ( b , i ) => b & rule . mask [ i ] ! )
100147 if ( rule . cumulative ) {
101148 if ( provider ) {
102- const { usageAmount } = await this . getCurrentUsageLimit (
149+ const { usageAmount } = await this . getCurrentPermissionUsageLimit (
103150 wallet ,
104151 sessionManagerAddress ,
105152 permission ,
@@ -109,7 +156,7 @@ export class Explicit implements ExplicitSessionSigner {
109156 // Increment the value
110157 value = Bytes . fromNumber ( usageAmount + Bytes . toBigInt ( value ) , { size : 32 } )
111158 } else {
112- throw new Error ( 'Cumulative rules require a provider and usage hash ' )
159+ throw new Error ( 'Cumulative rules require a provider' )
113160 }
114161 }
115162
@@ -147,8 +194,8 @@ export class Explicit implements ExplicitSessionSigner {
147194 provider ?: Provider . Provider ,
148195 ) : Promise < boolean > {
149196 if (
150- call . data . length > 4 &&
151- Hex . isEqual ( Hex . slice ( call . data , 0 , 4 ) , AbiFunction . getSelector ( INCREMENT_USAGE_LIMIT ) )
197+ Hex . size ( call . data ) > 4 &&
198+ Hex . isEqual ( Hex . slice ( call . data , 0 , 4 ) , AbiFunction . getSelector ( Constants . INCREMENT_USAGE_LIMIT ) )
152199 ) {
153200 // Can sign increment usage calls
154201 return true
@@ -174,8 +221,8 @@ export class Explicit implements ExplicitSessionSigner {
174221 ) : Promise < SessionSignature . SessionCallSignature > {
175222 let permissionIndex : number
176223 if (
177- call . data . length > 4 &&
178- Hex . isEqual ( Hex . slice ( call . data , 0 , 4 ) , AbiFunction . getSelector ( INCREMENT_USAGE_LIMIT ) )
224+ Hex . size ( call . data ) > 4 &&
225+ Hex . isEqual ( Hex . slice ( call . data , 0 , 4 ) , AbiFunction . getSelector ( Constants . INCREMENT_USAGE_LIMIT ) )
179226 ) {
180227 // Permission check not required. Use the first permission
181228 permissionIndex = 0
@@ -231,12 +278,35 @@ export class Explicit implements ExplicitSessionSigner {
231278 if ( Bytes . toBigInt ( value ) === 0n ) continue
232279
233280 // read on-chain "used so far"
234- const currentUsage = await this . getCurrentUsageLimit ( wallet , sessionManagerAddress , perm , ruleIndex , provider )
281+ const currentUsage = await this . getCurrentPermissionUsageLimit (
282+ wallet ,
283+ sessionManagerAddress ,
284+ perm ,
285+ ruleIndex ,
286+ provider ! ,
287+ )
235288 increments . push ( {
236289 usageHash : currentUsage . usageHash ,
237290 usageAmount : Bytes . toBigInt ( Bytes . fromNumber ( currentUsage . usageAmount + Bytes . toBigInt ( value ) , { size : 32 } ) ) ,
238291 } )
239292 }
293+
294+ // Check the value
295+ if ( call . value !== 0n ) {
296+ if ( ! provider ) {
297+ throw new Error ( 'Value transaction validation requires a provider' )
298+ }
299+ const currentUsage = await this . getCurrentValueUsageLimit ( wallet , sessionManagerAddress , provider )
300+ const value = Bytes . fromNumber ( currentUsage . usageAmount + call . value , { size : 32 } )
301+ if ( Bytes . toBigInt ( value ) > this . sessionPermissions . valueLimit ) {
302+ throw new Error ( 'Value transaction validation failed' )
303+ }
304+ increments . push ( {
305+ usageHash : currentUsage . usageHash ,
306+ usageAmount : Bytes . toBigInt ( value ) ,
307+ } )
308+ }
309+
240310 return increments
241311 }
242312}
0 commit comments