From 17daeb5e561a61cd1b48fecca2f0802e31d856b8 Mon Sep 17 00:00:00 2001 From: Lyova Potyomkin Date: Fri, 1 Nov 2024 12:05:46 +0200 Subject: [PATCH 01/42] feat: store sessions offchain to reduce gas --- .../src/validators/SessionKeyValidator.sol | 285 ++++++------------ packages/contracts/test/SessionKeyTest.ts | 47 ++- 2 files changed, 112 insertions(+), 220 deletions(-) diff --git a/packages/contracts/src/validators/SessionKeyValidator.sol b/packages/contracts/src/validators/SessionKeyValidator.sol index 05f1f52b..8926d5de 100644 --- a/packages/contracts/src/validators/SessionKeyValidator.sol +++ b/packages/contracts/src/validators/SessionKeyValidator.sol @@ -20,6 +20,7 @@ library SessionLib { using SessionLib for SessionLib.Constraint; using SessionLib for SessionLib.UsageLimit; + // TODO: we don't need to store constraints, so we can remove this restriction uint256 constant MAX_CONSTRAINTS = 16; // We do not permit session keys to be reused to open multiple sessions @@ -34,8 +35,11 @@ library SessionLib { // This struct is used to track usage information for each session. // Along with `status`, this is considered the session state. - // While everything else is considered the session spec. - struct UsageTrackers { + // While everything else is considered the session spec, and is stored offchain. + // Storage layout of this struct is weird to conform to ERC-7562 storage access restrictions during validation. + // Each innermost mapping is always mapping(address account => ...). + struct SessionStorage { + mapping(address => Status) status; UsageTracker fee; // (target) => transfer value tracker mapping(address => UsageTracker) transferValue; @@ -46,44 +50,6 @@ library SessionLib { mapping(address => mapping(bytes4 => mapping(uint256 => UsageTracker))) params; } - // This is the main struct that holds information about all sessions and their state. - // This struct has weird layout because of the AA storage access restrictions for validation. - // Innermost mappings are all mapping(address account => ...) because of this. - struct SessionStorage { - // (target, selector) => call policy - mapping(address => mapping(bytes4 => mapping(address => CallPolicy))) callPolicy; - // (target) => transfer policy. Used for calls with calldata.length < 4. - mapping(address => mapping(address => TransferPolicy)) transferPolicy; - mapping(address => Status) status; - // Timestamp after which session is considered expired - mapping(address => uint256) expiry; - // Tracks gasLimit * maxFeePerGas of each transaction - mapping(address => UsageLimit) feeLimit; - UsageTrackers trackers; - // These 2 mappings are only used in getters / view functions, not used during validation. - mapping(address => CallTarget[]) callTargets; - mapping(address => address[]) transferTargets; - } - - struct CallPolicy { - // this flag is needed, as otherwise, an empty CallPolicy (default mapping entry) - // would mean no constraints - bool isAllowed; - uint256 maxValuePerUse; - UsageLimit valueLimit; - // We restrain from using a dynamic array here, as it would mean further - // complications for the storage layout due to the AA storage access restrictions. - uint256 totalConstraints; - Constraint[MAX_CONSTRAINTS] constraints; - } - - // For transfers, i.e. calls without a selector - struct TransferPolicy { - bool isAllowed; - uint256 maxValuePerUse; - UsageLimit valueLimit; - } - struct Constraint { Condition condition; uint64 index; @@ -121,11 +87,6 @@ library SessionLib { NotEqual } - struct CallTarget { - address target; - bytes4 selector; - } - struct SessionSpec { address signer; uint256 expiry; @@ -170,7 +131,7 @@ library SessionLib { LimitState[] callParams; } - function checkAndUpdate(UsageLimit storage limit, UsageTracker storage tracker, uint256 value) internal { + function checkAndUpdate(UsageLimit memory limit, UsageTracker storage tracker, uint256 value) internal { if (limit.limitType == LimitType.Lifetime) { require(tracker.lifetimeUsage[msg.sender] + value <= limit.limit, "Lifetime limit exceeded"); tracker.lifetimeUsage[msg.sender] += value; @@ -183,7 +144,7 @@ library SessionLib { // } } - function checkAndUpdate(Constraint storage constraint, UsageTracker storage tracker, bytes calldata data) internal { + function checkAndUpdate(Constraint memory constraint, UsageTracker storage tracker, bytes calldata data) internal { uint256 index = 4 + constraint.index * 32; bytes32 param = bytes32(data[index:index + 32]); Condition condition = constraint.condition; @@ -206,101 +167,54 @@ library SessionLib { constraint.limit.checkAndUpdate(tracker, uint256(param)); } - function validate(SessionStorage storage session, Transaction calldata transaction) internal { - require(session.status[msg.sender] == Status.Active, "Session is not active"); + function validate(SessionStorage storage state, Transaction calldata transaction, SessionSpec memory spec) internal { + require(state.status[msg.sender] == Status.Active, "Session is not active"); // TODO uncomment when it's possible to check timestamps during validation - // require(block.timestamp <= session.expiry); + // require(block.timestamp <= state.expiry); // TODO: update fee allowance with the gasleft/refund at the end of execution uint256 fee = transaction.maxFeePerGas * transaction.gasLimit; - session.feeLimit[msg.sender].checkAndUpdate(session.trackers.fee, fee); + spec.feeLimit.checkAndUpdate(state.fee, fee); address target = address(uint160(transaction.to)); if (transaction.data.length >= 4) { bytes4 selector = bytes4(transaction.data[:4]); - CallPolicy storage callPolicy = session.callPolicy[target][selector][msg.sender]; + CallSpec memory callPolicy; + bool found = false; + + for (uint256 i = 0; i < spec.callPolicies.length; i++) { + if (spec.callPolicies[i].target == target && spec.callPolicies[i].selector == selector) { + callPolicy = spec.callPolicies[i]; + found = true; + break; + } + } - require(callPolicy.isAllowed, "Call not allowed"); + require(found, "Call not allowed"); require(transaction.value <= callPolicy.maxValuePerUse, "Value exceeds limit"); - callPolicy.valueLimit.checkAndUpdate(session.trackers.callValue[target][selector], transaction.value); + callPolicy.valueLimit.checkAndUpdate(state.callValue[target][selector], transaction.value); - for (uint256 i = 0; i < callPolicy.totalConstraints; i++) { - callPolicy.constraints[i].checkAndUpdate(session.trackers.params[target][selector][i], transaction.data); + for (uint256 i = 0; i < callPolicy.constraints.length; i++) { + callPolicy.constraints[i].checkAndUpdate(state.params[target][selector][i], transaction.data); } } else { - TransferPolicy storage transferPolicy = session.transferPolicy[target][msg.sender]; - require(transferPolicy.isAllowed, "Transfer not allowed"); - require(transaction.value <= transferPolicy.maxValuePerUse, "Value exceeds limit"); - transferPolicy.valueLimit.checkAndUpdate(session.trackers.transferValue[target], transaction.value); - } - } - - function fill(SessionStorage storage session, SessionSpec memory newSession, address account) internal { - session.status[account] = Status.Active; - session.expiry[account] = newSession.expiry; - session.feeLimit[account] = newSession.feeLimit; - for (uint256 i = 0; i < newSession.callPolicies.length; i++) { - CallSpec memory newPolicy = newSession.callPolicies[i]; - session.callTargets[account].push(CallTarget({ target: newPolicy.target, selector: newPolicy.selector })); - CallPolicy storage callPolicy = session.callPolicy[newPolicy.target][newPolicy.selector][account]; - callPolicy.isAllowed = true; - callPolicy.maxValuePerUse = newPolicy.maxValuePerUse; - callPolicy.valueLimit = newPolicy.valueLimit; - require(newPolicy.constraints.length <= MAX_CONSTRAINTS, "Too many constraints"); - callPolicy.totalConstraints = newPolicy.constraints.length; - for (uint256 j = 0; j < newPolicy.constraints.length; j++) { - callPolicy.constraints[j] = newPolicy.constraints[j]; + TransferSpec memory transferPolicy; + bool found = false; + + for (uint256 i = 0; i < spec.transferPolicies.length; i++) { + if (spec.transferPolicies[i].target == target) { + transferPolicy = spec.transferPolicies[i]; + found = true; + break; + } } - } - for (uint256 i = 0; i < newSession.transferPolicies.length; i++) { - TransferSpec memory newPolicy = newSession.transferPolicies[i]; - session.transferTargets[account].push(newPolicy.target); - TransferPolicy storage transferPolicy = session.transferPolicy[newPolicy.target][account]; - transferPolicy.isAllowed = true; - transferPolicy.maxValuePerUse = newPolicy.maxValuePerUse; - transferPolicy.valueLimit = newPolicy.valueLimit; - } - } - function getSpec(SessionStorage storage session, address account) internal view returns (SessionSpec memory) { - CallSpec[] memory callPolicies = new CallSpec[](session.callTargets[account].length); - TransferSpec[] memory transferPolicies = new TransferSpec[](session.transferTargets[account].length); - for (uint256 i = 0; i < session.callTargets[account].length; i++) { - CallTarget memory target = session.callTargets[account][i]; - CallPolicy storage callPolicy = session.callPolicy[target.target][target.selector][account]; - Constraint[] memory constraints = new Constraint[](callPolicy.totalConstraints); - for (uint256 j = 0; j < callPolicy.totalConstraints; j++) { - constraints[j] = callPolicy.constraints[j]; - } - callPolicies[i] = CallSpec({ - target: target.target, - selector: target.selector, - maxValuePerUse: callPolicy.maxValuePerUse, - valueLimit: callPolicy.valueLimit, - constraints: constraints - }); - } - for (uint256 i = 0; i < session.transferTargets[account].length; i++) { - address target = session.transferTargets[account][i]; - TransferPolicy storage transferPolicy = session.transferPolicy[target][account]; - transferPolicies[i] = TransferSpec({ - target: target, - maxValuePerUse: transferPolicy.maxValuePerUse, - valueLimit: transferPolicy.valueLimit - }); + require(found, "Transfer not allowed"); + require(transaction.value <= transferPolicy.maxValuePerUse, "Value exceeds limit"); + transferPolicy.valueLimit.checkAndUpdate(state.transferValue[target], transaction.value); } - return - SessionSpec({ - // Signer addresses are not stored in SessionStorage, - // and are filled in later in the `sessionSpec()` getter. - signer: address(0), - expiry: session.expiry[account], - feeLimit: session.feeLimit[account], - callPolicies: callPolicies, - transferPolicies: transferPolicies - }); } function remainingLimit( @@ -321,9 +235,11 @@ library SessionLib { } } - function getState(SessionStorage storage session, address account) internal view returns (SessionState memory) { - SessionSpec memory spec = getSpec(session, account); - + function getState( + SessionStorage storage session, + address account, + SessionSpec calldata spec + ) internal view returns (SessionState memory) { LimitState[] memory transferValue = new LimitState[](spec.transferPolicies.length); LimitState[] memory callValue = new LimitState[](spec.callPolicies.length); LimitState[] memory callParams = new LimitState[](MAX_CONSTRAINTS * spec.callPolicies.length); // there will be empty ones at the end @@ -332,11 +248,7 @@ library SessionLib { for (uint256 i = 0; i < transferValue.length; i++) { TransferSpec memory transferSpec = spec.transferPolicies[i]; transferValue[i] = LimitState({ - remaining: remainingLimit( - transferSpec.valueLimit, - session.trackers.transferValue[transferSpec.target], - account - ), + remaining: remainingLimit(transferSpec.valueLimit, session.transferValue[transferSpec.target], account), target: spec.transferPolicies[i].target, selector: bytes4(0), index: 0 @@ -346,11 +258,7 @@ library SessionLib { for (uint256 i = 0; i < callValue.length; i++) { CallSpec memory callSpec = spec.callPolicies[i]; callValue[i] = LimitState({ - remaining: remainingLimit( - callSpec.valueLimit, - session.trackers.callValue[callSpec.target][callSpec.selector], - account - ), + remaining: remainingLimit(callSpec.valueLimit, session.callValue[callSpec.target][callSpec.selector], account), target: callSpec.target, selector: callSpec.selector, index: 0 @@ -361,7 +269,7 @@ library SessionLib { callParams[paramLimitIndex++] = LimitState({ remaining: remainingLimit( callSpec.constraints[j].limit, - session.trackers.params[callSpec.target][callSpec.selector][j], + session.params[callSpec.target][callSpec.selector][j], account ), target: callSpec.target, @@ -380,7 +288,7 @@ library SessionLib { return SessionState({ status: session.status[account], - fee: remainingLimit(spec.feeLimit, session.trackers.fee, account), + fee: remainingLimit(spec.feeLimit, session.fee, account), transferValue: transferValue, callValue: callValue, callParams: callParams @@ -390,39 +298,26 @@ library SessionLib { contract SessionKeyValidator is IHook, IValidationHook, IModuleValidator, IModule { using SessionLib for SessionLib.SessionStorage; - using EnumerableSet for EnumerableSet.AddressSet; + using EnumerableSet for EnumerableSet.Bytes32Set; - bytes4 constant EIP1271_SUCCESS_RETURN_VALUE = 0x1626ba7e; - - // session owner => session storage - mapping(address => SessionLib.SessionStorage) private sessions; - // account => owners - mapping(address => EnumerableSet.AddressSet) sessionOwners; + // TODO: add more events for session state changes + event SessionCreated(address indexed account, bytes32 indexed sessionHash, SessionLib.SessionSpec sessionSpec); - function sessionSpec(address account, address signer) public view returns (SessionLib.SessionSpec memory spec) { - spec = sessions[signer].getSpec(account); - spec.signer = signer; - } + bytes4 constant EIP1271_SUCCESS_RETURN_VALUE = 0x1626ba7e; - function sessionState(address account, address signer) public view returns (SessionLib.SessionState memory) { - return sessions[signer].getState(account); - } + // account => hashes of session specs + // Can be used to trustlessly revoke all session keys. + // TODO: Is emitting an event sufficient? + // mapping(address => EnumerableSet.Bytes32Set) private sessionHashes; + mapping(address => uint256) private sessionCounter; + // session hash => session state + mapping(bytes32 => SessionLib.SessionStorage) private sessionStates; - function activeSigners(address account) external view returns (address[] memory) { - return sessionOwners[account].values(); - } - - function sessionList( - address account - ) external view returns (SessionLib.SessionState[] memory states, SessionLib.SessionSpec[] memory specs) { - uint256 length = sessionOwners[account].length(); - states = new SessionLib.SessionState[](length); - specs = new SessionLib.SessionSpec[](length); - for (uint256 i = 0; i < length; i++) { - address signer = sessionOwners[account].at(i); - specs[i] = sessionSpec(account, signer); - states[i] = sessionState(account, signer); - } + function sessionState( + address account, + SessionLib.SessionSpec calldata spec + ) external view returns (SessionLib.SessionState memory) { + return sessionStates[keccak256(abi.encode(spec))].getState(account, spec); } function handleValidation(bytes32 signedHash, bytes memory signature) external view returns (bool) { @@ -434,21 +329,24 @@ contract SessionKeyValidator is IHook, IValidationHook, IModuleValidator, IModul if (sessionData.length == 0) { return false; } - SessionLib.SessionSpec memory newSession = abi.decode(sessionData, (SessionLib.SessionSpec)); - createSession(newSession); + SessionLib.SessionSpec memory sessionSpec = abi.decode(sessionData, (SessionLib.SessionSpec)); + createSession(sessionSpec); return true; } - function createSession(SessionLib.SessionSpec memory newSession) public { + function createSession(SessionLib.SessionSpec memory sessionSpec) public { + bytes32 sessionHash = keccak256(abi.encode(sessionSpec)); require(_isInitialized(msg.sender), "Account not initialized"); - require(newSession.signer != address(0), "Invalid signer"); + require(sessionSpec.signer != address(0), "Invalid signer"); require( - sessions[newSession.signer].status[msg.sender] == SessionLib.Status.NotInitialized, + sessionStates[sessionHash].status[msg.sender] == SessionLib.Status.NotInitialized, "Session already exists" ); - require(newSession.feeLimit.limitType != SessionLib.LimitType.Unlimited, "Unlimited fee allowance is not safe"); - sessionOwners[msg.sender].add(newSession.signer); - sessions[newSession.signer].fill(newSession, msg.sender); + require(sessionSpec.feeLimit.limitType != SessionLib.LimitType.Unlimited, "Unlimited fee allowance is not safe"); + // sessionHashes[msg.sender].add(sessionHash); + sessionCounter[msg.sender]++; + sessionStates[sessionHash].status[msg.sender] = SessionLib.Status.Active; + emit SessionCreated(msg.sender, sessionHash, sessionSpec); } function init(bytes calldata data) external { @@ -481,7 +379,8 @@ contract SessionKeyValidator is IHook, IValidationHook, IModuleValidator, IModul // is installed again later, there will be no active sessions from the past. // Problem: if there are too many keys, this will run out of gas. // Solution: before uninstalling, require that all keys are revoked manually. - require(sessionOwners[msg.sender].length() == 0, "Revoke all keys first"); + // require(sessionHashes[msg.sender].length() == 0, "Revoke all keys first"); + require(sessionCounter[msg.sender] == 0, "Revoke all keys first"); } function supportsInterface(bytes4 interfaceId) external pure override returns (bool) { @@ -494,15 +393,16 @@ contract SessionKeyValidator is IHook, IValidationHook, IModuleValidator, IModul } // TODO: make the session owner able revoke its own key, in case it was leaked, to prevent further misuse? - function revokeKey(address sessionOwner) public { - require(sessions[sessionOwner].status[msg.sender] == SessionLib.Status.Active, "Nothing to revoke"); - sessions[sessionOwner].status[msg.sender] = SessionLib.Status.Closed; - sessionOwners[msg.sender].remove(sessionOwner); + function revokeKey(bytes32 sessionHash) public { + require(sessionStates[sessionHash].status[msg.sender] == SessionLib.Status.Active, "Nothing to revoke"); + sessionStates[sessionHash].status[msg.sender] = SessionLib.Status.Closed; + // sessionHashes[msg.sender].remove(sessionHash); + sessionCounter[msg.sender]--; } - function revokeKeys(address[] calldata owners) external { - for (uint256 i = 0; i < owners.length; i++) { - revokeKey(owners[i]); + function revokeKeys(bytes32[] calldata sessionHashes) external { + for (uint256 i = 0; i < sessionHashes.length; i++) { + revokeKey(sessionHashes[i]); } } @@ -525,22 +425,25 @@ contract SessionKeyValidator is IHook, IValidationHook, IModuleValidator, IModul */ function isValidSignature(bytes32 hash, bytes memory signature) public view returns (bytes4 magic) { magic = EIP1271_SUCCESS_RETURN_VALUE; - (address recoveredAddress, ) = ECDSA.tryRecover(hash, signature); - SessionLib.Status status = sessions[recoveredAddress].status[msg.sender]; - if (status != SessionLib.Status.Active) { - magic = bytes4(0); - } + // TODO: Does this method have to work standalone? If not, validtionHook is sufficient for validation. + // (address recoveredAddress, ) = ECDSA.tryRecover(hash, signature); + // SessionLib.Status status = sessions[recoveredAddress].status[msg.sender]; + // if (status != SessionLib.Status.Active) { + // magic = bytes4(0); + // } } - function validationHook(bytes32 signedHash, Transaction calldata transaction, bytes calldata _hookData) external { + function validationHook(bytes32 signedHash, Transaction calldata transaction, bytes calldata hookData) external { (bytes memory signature, address validator, ) = abi.decode(transaction.signature, (bytes, address, bytes[])); if (validator != address(this)) { // This transaction is not meant to be validated by this module return; } + SessionLib.SessionSpec memory spec = abi.decode(hookData, (SessionLib.SessionSpec)); (address recoveredAddress, ) = ECDSA.tryRecover(signedHash, signature); require(recoveredAddress != address(0), "Invalid signer"); - sessions[recoveredAddress].validate(transaction); + bytes32 sessionHash = keccak256(abi.encode(spec)); + sessionStates[sessionHash].validate(transaction, spec); } /** diff --git a/packages/contracts/test/SessionKeyTest.ts b/packages/contracts/test/SessionKeyTest.ts index 217fcfa7..81eac69b 100644 --- a/packages/contracts/test/SessionKeyTest.ts +++ b/packages/contracts/test/SessionKeyTest.ts @@ -70,7 +70,7 @@ class SessionTester { [ this.sessionOwner.signingKey.sign(hash).serialized, sessionKeyModuleAddress, - ["0x"], // this array supplies data for hooks + [await this.encodeSession()], // this array supplies data for hooks ], ), address: this.proxyAccountAddress, @@ -85,12 +85,11 @@ class SessionTester { secret: fixtures.wallet.privateKey, }, provider); - const [oldList] = await sessionKeyModuleContract.sessionList(this.proxyAccountAddress); - const oldState = await sessionKeyModuleContract.sessionState(this.proxyAccountAddress, this.sessionOwner.address); - expect(oldState.status).to.equal(0, "session should not be initialized"); - this.session = this.getSession(newSession); + const oldState = await sessionKeyModuleContract.sessionState(this.proxyAccountAddress, this.session); + expect(oldState.status).to.equal(0, "session should not exist yet"); + const aaTx = { ...await this.aaTxTemplate(), to: await sessionKeyModuleContract.getAddress(), @@ -100,52 +99,42 @@ class SessionTester { const signedTransaction = await smartAccount.signTransaction(aaTx); const tx = await provider.broadcastTransaction(signedTransaction); - await tx.wait(); + const receipt = await tx.wait(); + logInfo(`\`createSession\` gas used: ${receipt.gasUsed.toString()}`); - const [newList] = await sessionKeyModuleContract.sessionList(this.proxyAccountAddress); - expect(newList).to.have.lengthOf(oldList.length + 1, "session should be created"); - const newState = await sessionKeyModuleContract.sessionState(this.proxyAccountAddress, this.sessionOwner.address); + const newState = await sessionKeyModuleContract.sessionState(this.proxyAccountAddress, this.session); expect(newState.status).to.equal(1, "session should be active"); - this.assertSession(await sessionKeyModuleContract.sessionSpec(this.proxyAccountAddress, this.sessionOwner.address)); } - assertSession(session: SessionLib.SessionSpecStruct) { - const deepEqual = (a, b) => Object.keys(a).forEach((key) => { - if (Array.isArray(a[key]) && Array.isArray(b[key])) { - expect(a[key]).to.have.lengthOf(b[key].length, `key ${key} should have same length`); - a[key].forEach((item, i) => deepEqual(item, b[key][i])); - } else if (typeof a[key] === "object" && typeof b[key] === "object") { - deepEqual(a[key], b[key]); - } else { - expect(a[key]).to.equal(b[key], `key ${key} should match`); - } - }); - - deepEqual(this.session, session); + async encodeSession() { + const sessionKeyModuleContract = await fixtures.getSessionKeyContract(); + return "0x" + sessionKeyModuleContract.interface.encodeFunctionData("createSession", [this.session]).slice(10); } async revokeKey() { const sessionKeyModuleContract = await fixtures.getSessionKeyContract(); - let state = await sessionKeyModuleContract.sessionState(this.proxyAccountAddress, this.sessionOwner.address); - expect(state.status).to.equal(1, "session should be active"); + const oldState = await sessionKeyModuleContract.sessionState(this.proxyAccountAddress, this.session); + expect(oldState.status).to.equal(1, "session should be active"); const smartAccount = new SmartAccount({ address: this.proxyAccountAddress, secret: fixtures.wallet.privateKey, }, provider); + const sessionHash = ethers.keccak256(await this.encodeSession()); + const aaTx = { ...await this.aaTxTemplate(), to: await sessionKeyModuleContract.getAddress(), - data: sessionKeyModuleContract.interface.encodeFunctionData("revokeKey", [this.sessionOwner.address]), + data: sessionKeyModuleContract.interface.encodeFunctionData("revokeKey", [sessionHash]), }; aaTx.gasLimit = await provider.estimateGas(aaTx); const signedTransaction = await smartAccount.signTransaction(aaTx); const tx = await provider.broadcastTransaction(signedTransaction); await tx.wait(); - state = await sessionKeyModuleContract.sessionState(this.proxyAccountAddress, this.sessionOwner.address); - expect(state.status).to.equal(2, "session should be revoked"); + const newState = await sessionKeyModuleContract.sessionState(this.proxyAccountAddress, this.session); + expect(newState.status).to.equal(2, "session should be revoked"); } async sendTxSuccess(txRequest: ethers.TransactionRequest = {}) { @@ -384,7 +373,7 @@ describe("SessionKeyModule tests", function () { it("should reject a session key transaction that goes over total limit", async () => { const sessionKeyModuleContract = await fixtures.getSessionKeyContract(); - const remainingLimits = await sessionKeyModuleContract.sessionState(proxyAccountAddress, tester.sessionOwner.address); + const remainingLimits = await sessionKeyModuleContract.sessionState(proxyAccountAddress, tester.session); expect(remainingLimits.callParams[0].remaining).to.equal(500n, "should have 500 tokens remaining in allowance"); await tester.sendTxFail({ From d628d0c717599818219f3c641559310f3b881757 Mon Sep 17 00:00:00 2001 From: Lyova Potyomkin Date: Fri, 1 Nov 2024 12:43:12 +0200 Subject: [PATCH 02/42] feat: signer assertion and more events --- .../src/validators/SessionKeyValidator.sol | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/packages/contracts/src/validators/SessionKeyValidator.sol b/packages/contracts/src/validators/SessionKeyValidator.sol index 8926d5de..12ca49b7 100644 --- a/packages/contracts/src/validators/SessionKeyValidator.sol +++ b/packages/contracts/src/validators/SessionKeyValidator.sol @@ -300,14 +300,14 @@ contract SessionKeyValidator is IHook, IValidationHook, IModuleValidator, IModul using SessionLib for SessionLib.SessionStorage; using EnumerableSet for EnumerableSet.Bytes32Set; - // TODO: add more events for session state changes event SessionCreated(address indexed account, bytes32 indexed sessionHash, SessionLib.SessionSpec sessionSpec); + event SessionRevoked(address indexed account, bytes32 indexed sessionHash); bytes4 constant EIP1271_SUCCESS_RETURN_VALUE = 0x1626ba7e; // account => hashes of session specs - // Can be used to trustlessly revoke all session keys. - // TODO: Is emitting an event sufficient? + // Can be used to revoke all session keys in case offchain storage is not available. + // TODO: Is emitting an event sufficient instead? // mapping(address => EnumerableSet.Bytes32Set) private sessionHashes; mapping(address => uint256) private sessionCounter; // session hash => session state @@ -398,6 +398,7 @@ contract SessionKeyValidator is IHook, IValidationHook, IModuleValidator, IModul sessionStates[sessionHash].status[msg.sender] = SessionLib.Status.Closed; // sessionHashes[msg.sender].remove(sessionHash); sessionCounter[msg.sender]--; + emit SessionRevoked(msg.sender, sessionHash); } function revokeKeys(bytes32[] calldata sessionHashes) external { @@ -425,12 +426,7 @@ contract SessionKeyValidator is IHook, IValidationHook, IModuleValidator, IModul */ function isValidSignature(bytes32 hash, bytes memory signature) public view returns (bytes4 magic) { magic = EIP1271_SUCCESS_RETURN_VALUE; - // TODO: Does this method have to work standalone? If not, validtionHook is sufficient for validation. - // (address recoveredAddress, ) = ECDSA.tryRecover(hash, signature); - // SessionLib.Status status = sessions[recoveredAddress].status[msg.sender]; - // if (status != SessionLib.Status.Active) { - // magic = bytes4(0); - // } + // TODO: Does this method have to work standalone? If not, validationHook is sufficient for validation. } function validationHook(bytes32 signedHash, Transaction calldata transaction, bytes calldata hookData) external { @@ -441,7 +437,7 @@ contract SessionKeyValidator is IHook, IValidationHook, IModuleValidator, IModul } SessionLib.SessionSpec memory spec = abi.decode(hookData, (SessionLib.SessionSpec)); (address recoveredAddress, ) = ECDSA.tryRecover(signedHash, signature); - require(recoveredAddress != address(0), "Invalid signer"); + require(recoveredAddress == spec.signer, "Invalid signer"); bytes32 sessionHash = keccak256(abi.encode(spec)); sessionStates[sessionHash].validate(transaction, spec); } From 82fc11d105250d86a0d8250ffc5d3380c049cc3c Mon Sep 17 00:00:00 2001 From: Lyova Potyomkin Date: Fri, 1 Nov 2024 12:47:18 +0200 Subject: [PATCH 03/42] chore: update abi --- packages/sdk/src/abi/SessionKeyModule.ts | 496 +++++++++++------------ 1 file changed, 227 insertions(+), 269 deletions(-) diff --git a/packages/sdk/src/abi/SessionKeyModule.ts b/packages/sdk/src/abi/SessionKeyModule.ts index 4a811d55..03ed6a25 100644 --- a/packages/sdk/src/abi/SessionKeyModule.ts +++ b/packages/sdk/src/abi/SessionKeyModule.ts @@ -48,23 +48,190 @@ export const SessionKeyModuleAbi = [ type: "event", }, { + anonymous: false, inputs: [ { + indexed: true, internalType: "address", name: "account", type: "address", }, - ], - name: "activeSigners", - outputs: [ { - internalType: "address[]", - name: "", - type: "address[]", + indexed: true, + internalType: "bytes32", + name: "sessionHash", + type: "bytes32", + }, + { + components: [ + { + internalType: "address", + name: "signer", + type: "address", + }, + { + internalType: "uint256", + name: "expiry", + type: "uint256", + }, + { + components: [ + { + internalType: "enum SessionLib.LimitType", + name: "limitType", + type: "uint8", + }, + { + internalType: "uint256", + name: "limit", + type: "uint256", + }, + { + internalType: "uint256", + name: "period", + type: "uint256", + }, + ], + internalType: "struct SessionLib.UsageLimit", + name: "feeLimit", + type: "tuple", + }, + { + components: [ + { + internalType: "address", + name: "target", + type: "address", + }, + { + internalType: "bytes4", + name: "selector", + type: "bytes4", + }, + { + internalType: "uint256", + name: "maxValuePerUse", + type: "uint256", + }, + { + components: [ + { + internalType: "enum SessionLib.LimitType", + name: "limitType", + type: "uint8", + }, + { + internalType: "uint256", + name: "limit", + type: "uint256", + }, + { + internalType: "uint256", + name: "period", + type: "uint256", + }, + ], + internalType: "struct SessionLib.UsageLimit", + name: "valueLimit", + type: "tuple", + }, + { + components: [ + { + internalType: "enum SessionLib.Condition", + name: "condition", + type: "uint8", + }, + { + internalType: "uint64", + name: "index", + type: "uint64", + }, + { + internalType: "bytes32", + name: "refValue", + type: "bytes32", + }, + { + components: [ + { + internalType: "enum SessionLib.LimitType", + name: "limitType", + type: "uint8", + }, + { + internalType: "uint256", + name: "limit", + type: "uint256", + }, + { + internalType: "uint256", + name: "period", + type: "uint256", + }, + ], + internalType: "struct SessionLib.UsageLimit", + name: "limit", + type: "tuple", + }, + ], + internalType: "struct SessionLib.Constraint[]", + name: "constraints", + type: "tuple[]", + }, + ], + internalType: "struct SessionLib.CallSpec[]", + name: "callPolicies", + type: "tuple[]", + }, + { + components: [ + { + internalType: "address", + name: "target", + type: "address", + }, + { + internalType: "uint256", + name: "maxValuePerUse", + type: "uint256", + }, + { + components: [ + { + internalType: "enum SessionLib.LimitType", + name: "limitType", + type: "uint8", + }, + { + internalType: "uint256", + name: "limit", + type: "uint256", + }, + { + internalType: "uint256", + name: "period", + type: "uint256", + }, + ], + internalType: "struct SessionLib.UsageLimit", + name: "valueLimit", + type: "tuple", + }, + ], + internalType: "struct SessionLib.TransferSpec[]", + name: "transferPolicies", + type: "tuple[]", + }, + ], + indexed: false, + internalType: "struct SessionLib.SessionSpec", + name: "sessionSpec", + type: "tuple", }, ], - stateMutability: "view", - type: "function", + name: "SessionCreated", + type: "event", }, { inputs: [ @@ -250,7 +417,7 @@ export const SessionKeyModuleAbi = [ }, ], internalType: "struct SessionLib.SessionSpec", - name: "newSession", + name: "sessionSpec", type: "tuple", }, ], @@ -449,121 +616,9 @@ export const SessionKeyModuleAbi = [ { inputs: [ { - internalType: "address", - name: "account", - type: "address", - }, - { - internalType: "address", - name: "signer", - type: "address", - }, - ], - name: "remainingSessionLimits", - outputs: [ - { - components: [ - { - internalType: "uint256", - name: "fee", - type: "uint256", - }, - { - components: [ - { - internalType: "uint256", - name: "remaining", - type: "uint256", - }, - { - internalType: "address", - name: "target", - type: "address", - }, - { - internalType: "bytes4", - name: "selector", - type: "bytes4", - }, - { - internalType: "uint256", - name: "index", - type: "uint256", - }, - ], - internalType: "struct SessionLib.LimitState[]", - name: "transferValue", - type: "tuple[]", - }, - { - components: [ - { - internalType: "uint256", - name: "remaining", - type: "uint256", - }, - { - internalType: "address", - name: "target", - type: "address", - }, - { - internalType: "bytes4", - name: "selector", - type: "bytes4", - }, - { - internalType: "uint256", - name: "index", - type: "uint256", - }, - ], - internalType: "struct SessionLib.LimitState[]", - name: "callValue", - type: "tuple[]", - }, - { - components: [ - { - internalType: "uint256", - name: "remaining", - type: "uint256", - }, - { - internalType: "address", - name: "target", - type: "address", - }, - { - internalType: "bytes4", - name: "selector", - type: "bytes4", - }, - { - internalType: "uint256", - name: "index", - type: "uint256", - }, - ], - internalType: "struct SessionLib.LimitState[]", - name: "callParams", - type: "tuple[]", - }, - ], - internalType: "struct SessionLib.SessionState", - name: "", - type: "tuple", - }, - ], - stateMutability: "view", - type: "function", - }, - { - inputs: [ - { - internalType: "address", - name: "sessionOwner", - type: "address", + internalType: "bytes32", + name: "sessionHash", + type: "bytes32", }, ], name: "revokeKey", @@ -574,9 +629,9 @@ export const SessionKeyModuleAbi = [ { inputs: [ { - internalType: "address[]", - name: "owners", - type: "address[]", + internalType: "bytes32[]", + name: "sessionHashes", + type: "bytes32[]", }, ], name: "revokeKeys", @@ -591,19 +646,6 @@ export const SessionKeyModuleAbi = [ name: "account", type: "address", }, - { - internalType: "address", - name: "signer", - type: "address", - }, - ], - name: "session", - outputs: [ - { - internalType: "enum SessionLib.Status", - name: "status", - type: "uint8", - }, { components: [ { @@ -771,60 +813,54 @@ export const SessionKeyModuleAbi = [ type: "tuple", }, ], - stateMutability: "view", - type: "function", - }, - { - inputs: [ - { - internalType: "address", - name: "account", - type: "address", - }, - ], - name: "sessionList", + name: "sessionState", outputs: [ - { - internalType: "enum SessionLib.Status[]", - name: "statuses", - type: "uint8[]", - }, { components: [ { - internalType: "address", - name: "signer", - type: "address", + internalType: "enum SessionLib.Status", + name: "status", + type: "uint8", }, { internalType: "uint256", - name: "expiry", + name: "fee", type: "uint256", }, { components: [ - { - internalType: "enum SessionLib.LimitType", - name: "limitType", - type: "uint8", - }, { internalType: "uint256", - name: "limit", + name: "remaining", type: "uint256", }, + { + internalType: "address", + name: "target", + type: "address", + }, + { + internalType: "bytes4", + name: "selector", + type: "bytes4", + }, { internalType: "uint256", - name: "period", + name: "index", type: "uint256", }, ], - internalType: "struct SessionLib.UsageLimit", - name: "feeLimit", - type: "tuple", + internalType: "struct SessionLib.LimitState[]", + name: "transferValue", + type: "tuple[]", }, { components: [ + { + internalType: "uint256", + name: "remaining", + type: "uint256", + }, { internalType: "address", name: "target", @@ -837,123 +873,45 @@ export const SessionKeyModuleAbi = [ }, { internalType: "uint256", - name: "maxValuePerUse", + name: "index", type: "uint256", }, - { - components: [ - { - internalType: "enum SessionLib.LimitType", - name: "limitType", - type: "uint8", - }, - { - internalType: "uint256", - name: "limit", - type: "uint256", - }, - { - internalType: "uint256", - name: "period", - type: "uint256", - }, - ], - internalType: "struct SessionLib.UsageLimit", - name: "valueLimit", - type: "tuple", - }, - { - components: [ - { - internalType: "enum SessionLib.Condition", - name: "condition", - type: "uint8", - }, - { - internalType: "uint64", - name: "index", - type: "uint64", - }, - { - internalType: "bytes32", - name: "refValue", - type: "bytes32", - }, - { - components: [ - { - internalType: "enum SessionLib.LimitType", - name: "limitType", - type: "uint8", - }, - { - internalType: "uint256", - name: "limit", - type: "uint256", - }, - { - internalType: "uint256", - name: "period", - type: "uint256", - }, - ], - internalType: "struct SessionLib.UsageLimit", - name: "limit", - type: "tuple", - }, - ], - internalType: "struct SessionLib.Constraint[]", - name: "constraints", - type: "tuple[]", - }, ], - internalType: "struct SessionLib.CallSpec[]", - name: "callPolicies", + internalType: "struct SessionLib.LimitState[]", + name: "callValue", type: "tuple[]", }, { components: [ + { + internalType: "uint256", + name: "remaining", + type: "uint256", + }, { internalType: "address", name: "target", type: "address", }, { - internalType: "uint256", - name: "maxValuePerUse", - type: "uint256", + internalType: "bytes4", + name: "selector", + type: "bytes4", }, { - components: [ - { - internalType: "enum SessionLib.LimitType", - name: "limitType", - type: "uint8", - }, - { - internalType: "uint256", - name: "limit", - type: "uint256", - }, - { - internalType: "uint256", - name: "period", - type: "uint256", - }, - ], - internalType: "struct SessionLib.UsageLimit", - name: "valueLimit", - type: "tuple", + internalType: "uint256", + name: "index", + type: "uint256", }, ], - internalType: "struct SessionLib.TransferSpec[]", - name: "transferPolicies", + internalType: "struct SessionLib.LimitState[]", + name: "callParams", type: "tuple[]", }, ], - internalType: "struct SessionLib.SessionSpec[]", - name: "specs", - type: "tuple[]", + internalType: "struct SessionLib.SessionState", + name: "", + type: "tuple", }, ], stateMutability: "view", @@ -1074,7 +1032,7 @@ export const SessionKeyModuleAbi = [ }, { internalType: "bytes", - name: "_hookData", + name: "hookData", type: "bytes", }, ], From efd733acc8dc2a8ae2557acb8f7979e00ebf0a38 Mon Sep 17 00:00:00 2001 From: Lyova Potyomkin Date: Fri, 1 Nov 2024 12:53:26 +0200 Subject: [PATCH 04/42] fix: remove max_constraints --- .../contracts/src/validators/SessionKeyValidator.sol | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/packages/contracts/src/validators/SessionKeyValidator.sol b/packages/contracts/src/validators/SessionKeyValidator.sol index 12ca49b7..2c9896a5 100644 --- a/packages/contracts/src/validators/SessionKeyValidator.sol +++ b/packages/contracts/src/validators/SessionKeyValidator.sol @@ -20,9 +20,6 @@ library SessionLib { using SessionLib for SessionLib.Constraint; using SessionLib for SessionLib.UsageLimit; - // TODO: we don't need to store constraints, so we can remove this restriction - uint256 constant MAX_CONSTRAINTS = 16; - // We do not permit session keys to be reused to open multiple sessions // (after one expires or is closed, e.g.). // For each session key, its session status can only be changed @@ -240,9 +237,14 @@ library SessionLib { address account, SessionSpec calldata spec ) internal view returns (SessionState memory) { + uint256 totalConstraints = 0; + for (uint256 i = 0; i < spec.callPolicies.length; i++) { + totalConstraints += spec.callPolicies[i].constraints.length; + } + LimitState[] memory transferValue = new LimitState[](spec.transferPolicies.length); LimitState[] memory callValue = new LimitState[](spec.callPolicies.length); - LimitState[] memory callParams = new LimitState[](MAX_CONSTRAINTS * spec.callPolicies.length); // there will be empty ones at the end + LimitState[] memory callParams = new LimitState[](totalConstraints); // there will be empty ones at the end uint256 paramLimitIndex = 0; for (uint256 i = 0; i < transferValue.length; i++) { From edb247203acd1e27e4a9786821a54166d44626b2 Mon Sep 17 00:00:00 2001 From: Lyova Potyomkin Date: Fri, 1 Nov 2024 14:03:04 +0200 Subject: [PATCH 05/42] chore: rename --- .../src/validators/SessionKeyValidator.sol | 21 ++++++++++--------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/packages/contracts/src/validators/SessionKeyValidator.sol b/packages/contracts/src/validators/SessionKeyValidator.sol index 2c9896a5..e70739fb 100644 --- a/packages/contracts/src/validators/SessionKeyValidator.sol +++ b/packages/contracts/src/validators/SessionKeyValidator.sol @@ -313,13 +313,17 @@ contract SessionKeyValidator is IHook, IValidationHook, IModuleValidator, IModul // mapping(address => EnumerableSet.Bytes32Set) private sessionHashes; mapping(address => uint256) private sessionCounter; // session hash => session state - mapping(bytes32 => SessionLib.SessionStorage) private sessionStates; + mapping(bytes32 => SessionLib.SessionStorage) private sessions; function sessionState( address account, SessionLib.SessionSpec calldata spec ) external view returns (SessionLib.SessionState memory) { - return sessionStates[keccak256(abi.encode(spec))].getState(account, spec); + return sessions[keccak256(abi.encode(spec))].getState(account, spec); + } + + function sessionStatus(address account, bytes32 sessionHash) external view returns (SessionLib.Status) { + return sessions[sessionHash].status[account]; } function handleValidation(bytes32 signedHash, bytes memory signature) external view returns (bool) { @@ -340,14 +344,11 @@ contract SessionKeyValidator is IHook, IValidationHook, IModuleValidator, IModul bytes32 sessionHash = keccak256(abi.encode(sessionSpec)); require(_isInitialized(msg.sender), "Account not initialized"); require(sessionSpec.signer != address(0), "Invalid signer"); - require( - sessionStates[sessionHash].status[msg.sender] == SessionLib.Status.NotInitialized, - "Session already exists" - ); + require(sessions[sessionHash].status[msg.sender] == SessionLib.Status.NotInitialized, "Session already exists"); require(sessionSpec.feeLimit.limitType != SessionLib.LimitType.Unlimited, "Unlimited fee allowance is not safe"); // sessionHashes[msg.sender].add(sessionHash); sessionCounter[msg.sender]++; - sessionStates[sessionHash].status[msg.sender] = SessionLib.Status.Active; + sessions[sessionHash].status[msg.sender] = SessionLib.Status.Active; emit SessionCreated(msg.sender, sessionHash, sessionSpec); } @@ -396,8 +397,8 @@ contract SessionKeyValidator is IHook, IValidationHook, IModuleValidator, IModul // TODO: make the session owner able revoke its own key, in case it was leaked, to prevent further misuse? function revokeKey(bytes32 sessionHash) public { - require(sessionStates[sessionHash].status[msg.sender] == SessionLib.Status.Active, "Nothing to revoke"); - sessionStates[sessionHash].status[msg.sender] = SessionLib.Status.Closed; + require(sessions[sessionHash].status[msg.sender] == SessionLib.Status.Active, "Nothing to revoke"); + sessions[sessionHash].status[msg.sender] = SessionLib.Status.Closed; // sessionHashes[msg.sender].remove(sessionHash); sessionCounter[msg.sender]--; emit SessionRevoked(msg.sender, sessionHash); @@ -441,7 +442,7 @@ contract SessionKeyValidator is IHook, IValidationHook, IModuleValidator, IModul (address recoveredAddress, ) = ECDSA.tryRecover(signedHash, signature); require(recoveredAddress == spec.signer, "Invalid signer"); bytes32 sessionHash = keccak256(abi.encode(spec)); - sessionStates[sessionHash].validate(transaction, spec); + sessions[sessionHash].validate(transaction, spec); } /** From 9c5db0723e3af289f73cd7cdc0c52eb9547fde7a Mon Sep 17 00:00:00 2001 From: Lyova Potyomkin Date: Sun, 3 Nov 2024 00:24:08 +0200 Subject: [PATCH 06/42] fix: update abi --- packages/sdk/src/abi/SessionKeyModule.ts | 544 ++++++++++------------- 1 file changed, 226 insertions(+), 318 deletions(-) diff --git a/packages/sdk/src/abi/SessionKeyModule.ts b/packages/sdk/src/abi/SessionKeyModule.ts index fff115c1..c21f3b2b 100644 --- a/packages/sdk/src/abi/SessionKeyModule.ts +++ b/packages/sdk/src/abi/SessionKeyModule.ts @@ -48,23 +48,209 @@ export const SessionKeyModuleAbi = [ type: "event", }, { + anonymous: false, inputs: [ { + indexed: true, internalType: "address", name: "account", type: "address", }, + { + indexed: true, + internalType: "bytes32", + name: "sessionHash", + type: "bytes32", + }, + { + components: [ + { + internalType: "address", + name: "signer", + type: "address", + }, + { + internalType: "uint256", + name: "expiresAt", + type: "uint256", + }, + { + components: [ + { + internalType: "enum SessionLib.LimitType", + name: "limitType", + type: "uint8", + }, + { + internalType: "uint256", + name: "limit", + type: "uint256", + }, + { + internalType: "uint256", + name: "period", + type: "uint256", + }, + ], + internalType: "struct SessionLib.UsageLimit", + name: "feeLimit", + type: "tuple", + }, + { + components: [ + { + internalType: "address", + name: "target", + type: "address", + }, + { + internalType: "bytes4", + name: "selector", + type: "bytes4", + }, + { + internalType: "uint256", + name: "maxValuePerUse", + type: "uint256", + }, + { + components: [ + { + internalType: "enum SessionLib.LimitType", + name: "limitType", + type: "uint8", + }, + { + internalType: "uint256", + name: "limit", + type: "uint256", + }, + { + internalType: "uint256", + name: "period", + type: "uint256", + }, + ], + internalType: "struct SessionLib.UsageLimit", + name: "valueLimit", + type: "tuple", + }, + { + components: [ + { + internalType: "enum SessionLib.Condition", + name: "condition", + type: "uint8", + }, + { + internalType: "uint64", + name: "index", + type: "uint64", + }, + { + internalType: "bytes32", + name: "refValue", + type: "bytes32", + }, + { + components: [ + { + internalType: "enum SessionLib.LimitType", + name: "limitType", + type: "uint8", + }, + { + internalType: "uint256", + name: "limit", + type: "uint256", + }, + { + internalType: "uint256", + name: "period", + type: "uint256", + }, + ], + internalType: "struct SessionLib.UsageLimit", + name: "limit", + type: "tuple", + }, + ], + internalType: "struct SessionLib.Constraint[]", + name: "constraints", + type: "tuple[]", + }, + ], + internalType: "struct SessionLib.CallSpec[]", + name: "callPolicies", + type: "tuple[]", + }, + { + components: [ + { + internalType: "address", + name: "target", + type: "address", + }, + { + internalType: "uint256", + name: "maxValuePerUse", + type: "uint256", + }, + { + components: [ + { + internalType: "enum SessionLib.LimitType", + name: "limitType", + type: "uint8", + }, + { + internalType: "uint256", + name: "limit", + type: "uint256", + }, + { + internalType: "uint256", + name: "period", + type: "uint256", + }, + ], + internalType: "struct SessionLib.UsageLimit", + name: "valueLimit", + type: "tuple", + }, + ], + internalType: "struct SessionLib.TransferSpec[]", + name: "transferPolicies", + type: "tuple[]", + }, + ], + indexed: false, + internalType: "struct SessionLib.SessionSpec", + name: "sessionSpec", + type: "tuple", + }, ], - name: "activeSigners", - outputs: [ + name: "SessionCreated", + type: "event", + }, + { + anonymous: false, + inputs: [ { - internalType: "address[]", - name: "", - type: "address[]", + indexed: true, + internalType: "address", + name: "account", + type: "address", + }, + { + indexed: true, + internalType: "bytes32", + name: "sessionHash", + type: "bytes32", }, ], - stateMutability: "view", - type: "function", + name: "SessionRevoked", + type: "event", }, { inputs: [ @@ -250,7 +436,7 @@ export const SessionKeyModuleAbi = [ }, ], internalType: "struct SessionLib.SessionSpec", - name: "newSession", + name: "sessionSpec", type: "tuple", }, ], @@ -449,9 +635,9 @@ export const SessionKeyModuleAbi = [ { inputs: [ { - internalType: "address", - name: "sessionOwner", - type: "address", + internalType: "bytes32", + name: "sessionHash", + type: "bytes32", }, ], name: "revokeKey", @@ -462,9 +648,9 @@ export const SessionKeyModuleAbi = [ { inputs: [ { - internalType: "address[]", - name: "owners", - type: "address[]", + internalType: "bytes32[]", + name: "sessionHashes", + type: "bytes32[]", }, ], name: "revokeKeys", @@ -479,292 +665,6 @@ export const SessionKeyModuleAbi = [ name: "account", type: "address", }, - ], - name: "sessionList", - outputs: [ - { - components: [ - { - internalType: "enum SessionLib.Status", - name: "status", - type: "uint8", - }, - { - internalType: "uint256", - name: "fee", - type: "uint256", - }, - { - components: [ - { - internalType: "uint256", - name: "remaining", - type: "uint256", - }, - { - internalType: "address", - name: "target", - type: "address", - }, - { - internalType: "bytes4", - name: "selector", - type: "bytes4", - }, - { - internalType: "uint256", - name: "index", - type: "uint256", - }, - ], - internalType: "struct SessionLib.LimitState[]", - name: "transferValue", - type: "tuple[]", - }, - { - components: [ - { - internalType: "uint256", - name: "remaining", - type: "uint256", - }, - { - internalType: "address", - name: "target", - type: "address", - }, - { - internalType: "bytes4", - name: "selector", - type: "bytes4", - }, - { - internalType: "uint256", - name: "index", - type: "uint256", - }, - ], - internalType: "struct SessionLib.LimitState[]", - name: "callValue", - type: "tuple[]", - }, - { - components: [ - { - internalType: "uint256", - name: "remaining", - type: "uint256", - }, - { - internalType: "address", - name: "target", - type: "address", - }, - { - internalType: "bytes4", - name: "selector", - type: "bytes4", - }, - { - internalType: "uint256", - name: "index", - type: "uint256", - }, - ], - internalType: "struct SessionLib.LimitState[]", - name: "callParams", - type: "tuple[]", - }, - ], - internalType: "struct SessionLib.SessionState[]", - name: "states", - type: "tuple[]", - }, - { - components: [ - { - internalType: "address", - name: "signer", - type: "address", - }, - { - internalType: "uint256", - name: "expiresAt", - type: "uint256", - }, - { - components: [ - { - internalType: "enum SessionLib.LimitType", - name: "limitType", - type: "uint8", - }, - { - internalType: "uint256", - name: "limit", - type: "uint256", - }, - { - internalType: "uint256", - name: "period", - type: "uint256", - }, - ], - internalType: "struct SessionLib.UsageLimit", - name: "feeLimit", - type: "tuple", - }, - { - components: [ - { - internalType: "address", - name: "target", - type: "address", - }, - { - internalType: "bytes4", - name: "selector", - type: "bytes4", - }, - { - internalType: "uint256", - name: "maxValuePerUse", - type: "uint256", - }, - { - components: [ - { - internalType: "enum SessionLib.LimitType", - name: "limitType", - type: "uint8", - }, - { - internalType: "uint256", - name: "limit", - type: "uint256", - }, - { - internalType: "uint256", - name: "period", - type: "uint256", - }, - ], - internalType: "struct SessionLib.UsageLimit", - name: "valueLimit", - type: "tuple", - }, - { - components: [ - { - internalType: "enum SessionLib.Condition", - name: "condition", - type: "uint8", - }, - { - internalType: "uint64", - name: "index", - type: "uint64", - }, - { - internalType: "bytes32", - name: "refValue", - type: "bytes32", - }, - { - components: [ - { - internalType: "enum SessionLib.LimitType", - name: "limitType", - type: "uint8", - }, - { - internalType: "uint256", - name: "limit", - type: "uint256", - }, - { - internalType: "uint256", - name: "period", - type: "uint256", - }, - ], - internalType: "struct SessionLib.UsageLimit", - name: "limit", - type: "tuple", - }, - ], - internalType: "struct SessionLib.Constraint[]", - name: "constraints", - type: "tuple[]", - }, - ], - internalType: "struct SessionLib.CallSpec[]", - name: "callPolicies", - type: "tuple[]", - }, - { - components: [ - { - internalType: "address", - name: "target", - type: "address", - }, - { - internalType: "uint256", - name: "maxValuePerUse", - type: "uint256", - }, - { - components: [ - { - internalType: "enum SessionLib.LimitType", - name: "limitType", - type: "uint8", - }, - { - internalType: "uint256", - name: "limit", - type: "uint256", - }, - { - internalType: "uint256", - name: "period", - type: "uint256", - }, - ], - internalType: "struct SessionLib.UsageLimit", - name: "valueLimit", - type: "tuple", - }, - ], - internalType: "struct SessionLib.TransferSpec[]", - name: "transferPolicies", - type: "tuple[]", - }, - ], - internalType: "struct SessionLib.SessionSpec[]", - name: "specs", - type: "tuple[]", - }, - ], - stateMutability: "view", - type: "function", - }, - { - inputs: [ - { - internalType: "address", - name: "account", - type: "address", - }, - { - internalType: "address", - name: "signer", - type: "address", - }, - ], - name: "sessionSpec", - outputs: [ { components: [ { @@ -932,22 +832,6 @@ export const SessionKeyModuleAbi = [ type: "tuple", }, ], - stateMutability: "view", - type: "function", - }, - { - inputs: [ - { - internalType: "address", - name: "account", - type: "address", - }, - { - internalType: "address", - name: "signer", - type: "address", - }, - ], name: "sessionState", outputs: [ { @@ -959,7 +843,7 @@ export const SessionKeyModuleAbi = [ }, { internalType: "uint256", - name: "fee", + name: "feesRemaining", type: "uint256", }, { @@ -1052,6 +936,30 @@ export const SessionKeyModuleAbi = [ stateMutability: "view", type: "function", }, + { + inputs: [ + { + internalType: "address", + name: "account", + type: "address", + }, + { + internalType: "bytes32", + name: "sessionHash", + type: "bytes32", + }, + ], + name: "sessionStatus", + outputs: [ + { + internalType: "enum SessionLib.Status", + name: "", + type: "uint8", + }, + ], + stateMutability: "view", + type: "function", + }, { inputs: [ { @@ -1167,7 +1075,7 @@ export const SessionKeyModuleAbi = [ }, { internalType: "bytes", - name: "_hookData", + name: "hookData", type: "bytes", }, ], From 3bce3f0f0619311d564d7e1ac4a3a21906a823aa Mon Sep 17 00:00:00 2001 From: Lyova Potyomkin Date: Sun, 3 Nov 2024 00:55:47 +0200 Subject: [PATCH 07/42] fix: gas estimation --- packages/contracts/test/SessionKeyTest.ts | 14 +++++++++++--- packages/contracts/test/utils.ts | 14 +++++++++++++- 2 files changed, 24 insertions(+), 4 deletions(-) diff --git a/packages/contracts/test/SessionKeyTest.ts b/packages/contracts/test/SessionKeyTest.ts index 8781643d..b1b4d1a5 100644 --- a/packages/contracts/test/SessionKeyTest.ts +++ b/packages/contracts/test/SessionKeyTest.ts @@ -142,12 +142,14 @@ class SessionTester { ...await this.aaTxTemplate(), ...txRequest, }; - // FIXME gas estimation is incorrect + // TODO: uncomment once gas estimation is fixed one era-test-node. + // It works fine with the local server. // aaTx.gasLimit = await provider.estimateGas(aaTx); const signedTransaction = await this.sessionAccount.signTransaction(aaTx); const tx = await provider.broadcastTransaction(signedTransaction); - await tx.wait(); + const receipt = await tx.wait(); + logInfo(`\`sessionTx\` gas used: ${receipt.gasUsed}`); } async sendTxFail(tx: ethers.TransactionRequest = {}) { @@ -216,7 +218,13 @@ class SessionTester { chainId: (await provider.getNetwork()).chainId, nonce: await provider.getTransactionCount(this.proxyAccountAddress), gasPrice: await provider.getGasPrice(), - customData: { gasPerPubdata: utils.DEFAULT_GAS_PER_PUBDATA_LIMIT }, + customData: { + gasPerPubdata: utils.DEFAULT_GAS_PER_PUBDATA_LIMIT, + customSignature: abiCoder.encode( + ["bytes", "address", "bytes[]"], + [ethers.zeroPadValue("0x1b", 65), await fixtures.getSessionKeyModuleAddress(), [await this.encodeSession()]], + ), + }, gasLimit: 0n, }; } diff --git a/packages/contracts/test/utils.ts b/packages/contracts/test/utils.ts index b112aec2..0313a10b 100644 --- a/packages/contracts/test/utils.ts +++ b/packages/contracts/test/utils.ts @@ -128,12 +128,24 @@ export class ContractFixtures { // Load env file dotenv.config(); +// TODO: remove once SDK fix is released +class FixedProvider extends Provider { + getRpcTransaction(tx: ethers.TransactionRequest) { + const result = super.getRpcTransaction(tx); + if (tx.customData?.customSignature) { + result.eip712Meta ??= {}; + result.eip712Meta.customSignature = Array.from(ethers.getBytes(tx.customData.customSignature)); + } + return result; + } +} + export const getProvider = () => { const rpcUrl = hre.network.config["url"]; if (!rpcUrl) throw `⛔️ RPC URL wasn't found in "${hre.network.name}"! Please add a "url" field to the network config in hardhat.config.ts`; // Initialize ZKsync Provider - const provider = new Provider(rpcUrl); + const provider = new FixedProvider(rpcUrl); return provider; }; From 109a2fbcbe5917f091aac0a19a704facaa44be86 Mon Sep 17 00:00:00 2001 From: Lyova Potyomkin Date: Sun, 3 Nov 2024 01:16:44 +0200 Subject: [PATCH 08/42] chore: add more logs --- packages/contracts/test/SessionKeyTest.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/contracts/test/SessionKeyTest.ts b/packages/contracts/test/SessionKeyTest.ts index b1b4d1a5..4441f346 100644 --- a/packages/contracts/test/SessionKeyTest.ts +++ b/packages/contracts/test/SessionKeyTest.ts @@ -145,6 +145,7 @@ class SessionTester { // TODO: uncomment once gas estimation is fixed one era-test-node. // It works fine with the local server. // aaTx.gasLimit = await provider.estimateGas(aaTx); + logInfo(`\`sessionTx\` gas estimated: ${await provider.estimateGas(aaTx)}`); const signedTransaction = await this.sessionAccount.signTransaction(aaTx); const tx = await provider.broadcastTransaction(signedTransaction); From 077ec6e40839651911cd38487c42dd127d18cf7a Mon Sep 17 00:00:00 2001 From: Lyova Potyomkin Date: Mon, 11 Nov 2024 15:41:47 +0200 Subject: [PATCH 09/42] chore: update sdk --- packages/contracts/package.json | 2 +- packages/contracts/test/utils.ts | 14 +-- packages/demo-app/package.json | 2 +- packages/nft-quest-contracts/package.json | 2 +- packages/nft-quest/package.json | 2 +- pnpm-lock.yaml | 124 ++++++++++------------ 6 files changed, 64 insertions(+), 82 deletions(-) diff --git a/packages/contracts/package.json b/packages/contracts/package.json index 2a6fd0eb..5fb19fa8 100644 --- a/packages/contracts/package.json +++ b/packages/contracts/package.json @@ -33,7 +33,7 @@ "ts-node": "10.9.2", "typechain": "8.3.2", "typescript": "5.6.2", - "zksync-ethers": "6.13.0" + "zksync-ethers": "6.15.0" }, "dependencies": { "@matterlabs/zksync-contracts": "^0.6.1", diff --git a/packages/contracts/test/utils.ts b/packages/contracts/test/utils.ts index 2e40fd60..93cb1606 100644 --- a/packages/contracts/test/utils.ts +++ b/packages/contracts/test/utils.ts @@ -122,24 +122,12 @@ export class ContractFixtures { // Load env file dotenv.config(); -// TODO: remove once SDK fix is released -class FixedProvider extends Provider { - getRpcTransaction(tx: ethers.TransactionRequest) { - const result = super.getRpcTransaction(tx); - if (tx.customData?.customSignature) { - result.eip712Meta ??= {}; - result.eip712Meta.customSignature = Array.from(ethers.getBytes(tx.customData.customSignature)); - } - return result; - } -} - export const getProvider = () => { const rpcUrl = hre.network.config["url"]; if (!rpcUrl) throw `⛔️ RPC URL wasn't found in "${hre.network.name}"! Please add a "url" field to the network config in hardhat.config.ts`; // Initialize ZKsync Provider - const provider = new FixedProvider(rpcUrl); + const provider = new Provider(rpcUrl); return provider; }; diff --git a/packages/demo-app/package.json b/packages/demo-app/package.json index 187c4121..20e11166 100644 --- a/packages/demo-app/package.json +++ b/packages/demo-app/package.json @@ -21,7 +21,7 @@ "vue": "^3.4.21", "wagmi": "^2.12.17", "zksync-sso": "workspace:*", - "zksync-ethers": "^6.12.1" + "zksync-ethers": "^6.15.0" }, "devDependencies": { "@nuxt/eslint": "^0.5.7", diff --git a/packages/nft-quest-contracts/package.json b/packages/nft-quest-contracts/package.json index edffb729..1b28a380 100644 --- a/packages/nft-quest-contracts/package.json +++ b/packages/nft-quest-contracts/package.json @@ -19,6 +19,6 @@ "mocha": "^10.7.0", "ts-node": "^10.9.2", "typescript": "^5.5.4", - "zksync-ethers": "^6.11.0" + "zksync-ethers": "^6.15.0" } } diff --git a/packages/nft-quest/package.json b/packages/nft-quest/package.json index fa067c30..4e2cf038 100644 --- a/packages/nft-quest/package.json +++ b/packages/nft-quest/package.json @@ -37,7 +37,7 @@ "vue-load-image": "^1.1.0", "vue-router": "latest", "zksync-sso": "workspace:*", - "zksync-ethers": "^6.14.0" + "zksync-ethers": "^6.15.0" }, "devDependencies": { "@nuxtjs/tailwindcss": "^6.12.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index b2dd7f4f..ff3b2f35 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -279,10 +279,10 @@ importers: version: 0.2.2 '@matterlabs/hardhat-zksync': specifier: 1.2.0 - version: 1.2.0(s5mnuinjslozaedgq4f5sjptyy) + version: 1.2.0(e32ijlvs4nitlwogqpjpupt3om) '@matterlabs/hardhat-zksync-deploy': specifier: 1.5.0 - version: 1.5.0(ethers@6.13.2(bufferutil@4.0.8)(utf-8-validate@5.0.10))(hardhat@2.22.15(bufferutil@4.0.8)(ts-node@10.9.2(@swc/core@1.7.26(@swc/helpers@0.5.13))(@types/node@20.16.10)(typescript@5.6.2))(typescript@5.6.2)(utf-8-validate@5.0.10))(zksync-ethers@6.13.0(ethers@6.13.2(bufferutil@4.0.8)(utf-8-validate@5.0.10))) + version: 1.5.0(ethers@6.13.2(bufferutil@4.0.8)(utf-8-validate@5.0.10))(hardhat@2.22.15(bufferutil@4.0.8)(ts-node@10.9.2(@swc/core@1.7.26(@swc/helpers@0.5.13))(@types/node@20.16.10)(typescript@5.6.2))(typescript@5.6.2)(utf-8-validate@5.0.10))(zksync-ethers@6.15.0(ethers@6.13.2(bufferutil@4.0.8)(utf-8-validate@5.0.10))) '@nomicfoundation/hardhat-chai-matchers': specifier: 2.0.8 version: 2.0.8(@nomicfoundation/hardhat-ethers@3.0.8(ethers@6.13.2(bufferutil@4.0.8)(utf-8-validate@5.0.10))(hardhat@2.22.15(bufferutil@4.0.8)(ts-node@10.9.2(@swc/core@1.7.26(@swc/helpers@0.5.13))(@types/node@20.16.10)(typescript@5.6.2))(typescript@5.6.2)(utf-8-validate@5.0.10)))(chai@4.5.0)(ethers@6.13.2(bufferutil@4.0.8)(utf-8-validate@5.0.10))(hardhat@2.22.15(bufferutil@4.0.8)(ts-node@10.9.2(@swc/core@1.7.26(@swc/helpers@0.5.13))(@types/node@20.16.10)(typescript@5.6.2))(typescript@5.6.2)(utf-8-validate@5.0.10)) @@ -341,8 +341,8 @@ importers: specifier: 8.3.2 version: 8.3.2(typescript@5.6.2) zksync-ethers: - specifier: 6.13.0 - version: 6.13.0(ethers@6.13.2(bufferutil@4.0.8)(utf-8-validate@5.0.10)) + specifier: 6.15.0 + version: 6.15.0(ethers@6.13.2(bufferutil@4.0.8)(utf-8-validate@5.0.10)) packages/demo-app: dependencies: @@ -386,8 +386,8 @@ importers: specifier: ^2.12.17 version: 2.12.25(@tanstack/query-core@5.59.16)(@tanstack/react-query@5.59.16(react@18.3.1))(bufferutil@4.0.8)(ioredis@5.4.1)(react-native@0.76.0(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(bufferutil@4.0.8)(react@18.3.1)(utf-8-validate@5.0.10))(react@18.3.1)(typescript@5.6.2)(utf-8-validate@5.0.10)(viem@2.21.14(bufferutil@4.0.8)(typescript@5.6.2)(utf-8-validate@5.0.10)(zod@3.22.4))(zod@3.22.4) zksync-ethers: - specifier: ^6.12.1 - version: 6.14.0(ethers@6.13.4(bufferutil@4.0.8)(utf-8-validate@5.0.10)) + specifier: ^6.15.0 + version: 6.15.0(ethers@6.13.4(bufferutil@4.0.8)(utf-8-validate@5.0.10)) zksync-sso: specifier: workspace:* version: link:../sdk @@ -409,7 +409,7 @@ importers: dependencies: '@matterlabs/hardhat-zksync': specifier: 1.2.0 - version: 1.2.0(jq27lisszh63x44gykkfav2efe) + version: 1.2.0(gzbl74e4hs234pcoapof4dgi5a) '@matterlabs/zksync-contracts': specifier: ^0.6.1 version: 0.6.1(@openzeppelin/contracts-upgradeable@4.9.6)(@openzeppelin/contracts@4.9.6) @@ -492,8 +492,8 @@ importers: specifier: latest version: 4.4.5(vue@3.5.12(typescript@5.6.2)) zksync-ethers: - specifier: ^6.14.0 - version: 6.14.0(ethers@6.13.4(bufferutil@4.0.8)(utf-8-validate@5.0.10)) + specifier: ^6.15.0 + version: 6.15.0(ethers@6.13.4(bufferutil@4.0.8)(utf-8-validate@5.0.10)) zksync-sso: specifier: workspace:* version: link:../sdk @@ -515,7 +515,7 @@ importers: devDependencies: '@matterlabs/hardhat-zksync': specifier: ^1.1.0 - version: 1.2.0(jq27lisszh63x44gykkfav2efe) + version: 1.2.0(gzbl74e4hs234pcoapof4dgi5a) '@matterlabs/zksync-contracts': specifier: ^0.6.1 version: 0.6.1(@openzeppelin/contracts-upgradeable@4.9.6)(@openzeppelin/contracts@4.9.6) @@ -553,8 +553,8 @@ importers: specifier: ^5.5.4 version: 5.6.2 zksync-ethers: - specifier: ^6.11.0 - version: 6.14.0(ethers@6.13.4(bufferutil@4.0.8)(utf-8-validate@5.0.10)) + specifier: ^6.15.0 + version: 6.15.0(ethers@6.13.4(bufferutil@4.0.8)(utf-8-validate@5.0.10)) packages/sdk: dependencies: @@ -11122,14 +11122,8 @@ packages: resolution: {integrity: sha512-zK7YHHz4ZXpW89AHXUPbQVGKI7uvkd3hzusTdotCg1UxyaVtg0zFJSTfW/Dq5f7OBBVnq6cZIaC8Ti4hb6dtCA==} engines: {node: '>= 14'} - zksync-ethers@6.13.0: - resolution: {integrity: sha512-BQH2w9vqinjI4lcC2A+AYU+X/7ZPPMrzn7xPqFtC+yrzWoKhmTaTvyX2ssYuXMStqNyEfDjNNBKkS8IZLaFL6w==} - engines: {node: '>=18.9.0'} - peerDependencies: - ethers: ^6.7.1 - - zksync-ethers@6.14.0: - resolution: {integrity: sha512-wP30kYCB45L8NNWChj+EWbN6lesecMGtVvoPpqPIoSsCLYDDSGCZ2snZ8zI9zAyOQ8AcVyvH8hjQScAJjpXtzg==} + zksync-ethers@6.15.0: + resolution: {integrity: sha512-zafUxA/lysBO+9Wd6B3qNtDElsPwvAc2b4nBc/YiB4QY4H0pIBvV3/JqxHXXTppEo4gyHAX/+M5brW2qb4YnKA==} engines: {node: '>=18.9.0'} peerDependencies: ethers: ^6.7.1 @@ -13251,7 +13245,7 @@ snapshots: - encoding - supports-color - '@matterlabs/hardhat-zksync-deploy@1.5.0(ethers@6.13.2(bufferutil@4.0.8)(utf-8-validate@5.0.10))(hardhat@2.22.15(bufferutil@4.0.8)(ts-node@10.9.2(@swc/core@1.7.26(@swc/helpers@0.5.13))(@types/node@20.16.10)(typescript@5.6.2))(typescript@5.6.2)(utf-8-validate@5.0.10))(zksync-ethers@6.13.0(ethers@6.13.2(bufferutil@4.0.8)(utf-8-validate@5.0.10)))': + '@matterlabs/hardhat-zksync-deploy@1.5.0(ethers@6.13.2(bufferutil@4.0.8)(utf-8-validate@5.0.10))(hardhat@2.22.15(bufferutil@4.0.8)(ts-node@10.9.2(@swc/core@1.7.26(@swc/helpers@0.5.13))(@types/node@20.16.10)(typescript@5.6.2))(typescript@5.6.2)(utf-8-validate@5.0.10))(zksync-ethers@6.15.0(ethers@6.13.2(bufferutil@4.0.8)(utf-8-validate@5.0.10)))': dependencies: '@matterlabs/hardhat-zksync-solc': 1.2.5(hardhat@2.22.15(bufferutil@4.0.8)(ts-node@10.9.2(@swc/core@1.7.26(@swc/helpers@0.5.13))(@types/node@20.16.10)(typescript@5.6.2))(typescript@5.6.2)(utf-8-validate@5.0.10)) chai: 4.5.0 @@ -13264,12 +13258,12 @@ snapshots: sinon: 18.0.1 sinon-chai: 3.7.0(chai@4.5.0)(sinon@18.0.1) ts-morph: 22.0.0 - zksync-ethers: 6.13.0(ethers@6.13.2(bufferutil@4.0.8)(utf-8-validate@5.0.10)) + zksync-ethers: 6.15.0(ethers@6.13.2(bufferutil@4.0.8)(utf-8-validate@5.0.10)) transitivePeerDependencies: - encoding - supports-color - '@matterlabs/hardhat-zksync-deploy@1.5.0(ethers@6.13.4(bufferutil@4.0.8)(utf-8-validate@5.0.10))(hardhat@2.22.15(bufferutil@4.0.8)(ts-node@10.9.2(@swc/core@1.7.26(@swc/helpers@0.5.13))(@types/node@20.16.10)(typescript@5.6.2))(typescript@5.6.2)(utf-8-validate@5.0.10))(zksync-ethers@6.14.0(ethers@6.13.4(bufferutil@4.0.8)(utf-8-validate@5.0.10)))': + '@matterlabs/hardhat-zksync-deploy@1.5.0(ethers@6.13.4(bufferutil@4.0.8)(utf-8-validate@5.0.10))(hardhat@2.22.15(bufferutil@4.0.8)(ts-node@10.9.2(@swc/core@1.7.26(@swc/helpers@0.5.13))(@types/node@20.16.10)(typescript@5.6.2))(typescript@5.6.2)(utf-8-validate@5.0.10))(zksync-ethers@6.15.0(ethers@6.13.2(bufferutil@4.0.8)(utf-8-validate@5.0.10)))': dependencies: '@matterlabs/hardhat-zksync-solc': 1.2.5(hardhat@2.22.15(bufferutil@4.0.8)(ts-node@10.9.2(@swc/core@1.7.26(@swc/helpers@0.5.13))(@types/node@20.16.10)(typescript@5.6.2))(typescript@5.6.2)(utf-8-validate@5.0.10)) chai: 4.5.0 @@ -13282,12 +13276,12 @@ snapshots: sinon: 18.0.1 sinon-chai: 3.7.0(chai@4.5.0)(sinon@18.0.1) ts-morph: 22.0.0 - zksync-ethers: 6.14.0(ethers@6.13.4(bufferutil@4.0.8)(utf-8-validate@5.0.10)) + zksync-ethers: 6.15.0(ethers@6.13.2(bufferutil@4.0.8)(utf-8-validate@5.0.10)) transitivePeerDependencies: - encoding - supports-color - '@matterlabs/hardhat-zksync-deploy@1.5.0(ethers@6.13.4(bufferutil@4.0.8)(utf-8-validate@5.0.10))(hardhat@2.22.15(bufferutil@4.0.8)(ts-node@10.9.2(@swc/core@1.7.26(@swc/helpers@0.5.13))(@types/node@22.8.0)(typescript@5.6.2))(typescript@5.6.2)(utf-8-validate@5.0.10))(zksync-ethers@6.14.0(ethers@6.13.4(bufferutil@4.0.8)(utf-8-validate@5.0.10)))': + '@matterlabs/hardhat-zksync-deploy@1.5.0(ethers@6.13.4(bufferutil@4.0.8)(utf-8-validate@5.0.10))(hardhat@2.22.15(bufferutil@4.0.8)(ts-node@10.9.2(@swc/core@1.7.26(@swc/helpers@0.5.13))(@types/node@22.8.0)(typescript@5.6.2))(typescript@5.6.2)(utf-8-validate@5.0.10))(zksync-ethers@6.15.0(ethers@6.13.4(bufferutil@4.0.8)(utf-8-validate@5.0.10)))': dependencies: '@matterlabs/hardhat-zksync-solc': 1.2.5(hardhat@2.22.15(bufferutil@4.0.8)(ts-node@10.9.2(@swc/core@1.7.26(@swc/helpers@0.5.13))(@types/node@22.8.0)(typescript@5.6.2))(typescript@5.6.2)(utf-8-validate@5.0.10)) chai: 4.5.0 @@ -13300,21 +13294,21 @@ snapshots: sinon: 18.0.1 sinon-chai: 3.7.0(chai@4.5.0)(sinon@18.0.1) ts-morph: 22.0.0 - zksync-ethers: 6.14.0(ethers@6.13.4(bufferutil@4.0.8)(utf-8-validate@5.0.10)) + zksync-ethers: 6.15.0(ethers@6.13.4(bufferutil@4.0.8)(utf-8-validate@5.0.10)) transitivePeerDependencies: - encoding - supports-color - '@matterlabs/hardhat-zksync-ethers@1.2.1(bufferutil@4.0.8)(ethers@6.13.2(bufferutil@4.0.8)(utf-8-validate@5.0.10))(ts-node@10.9.2(@swc/core@1.7.26(@swc/helpers@0.5.13))(@types/node@20.16.10)(typescript@5.6.2))(typescript@5.6.2)(utf-8-validate@5.0.10)(zksync-ethers@6.13.0(ethers@6.13.2(bufferutil@4.0.8)(utf-8-validate@5.0.10)))': + '@matterlabs/hardhat-zksync-ethers@1.2.1(bufferutil@4.0.8)(ethers@6.13.2(bufferutil@4.0.8)(utf-8-validate@5.0.10))(ts-node@10.9.2(@swc/core@1.7.26(@swc/helpers@0.5.13))(@types/node@20.16.10)(typescript@5.6.2))(typescript@5.6.2)(utf-8-validate@5.0.10)(zksync-ethers@6.15.0(ethers@6.13.2(bufferutil@4.0.8)(utf-8-validate@5.0.10)))': dependencies: - '@matterlabs/hardhat-zksync-deploy': 1.5.0(ethers@6.13.2(bufferutil@4.0.8)(utf-8-validate@5.0.10))(hardhat@2.22.15(bufferutil@4.0.8)(ts-node@10.9.2(@swc/core@1.7.26(@swc/helpers@0.5.13))(@types/node@20.16.10)(typescript@5.6.2))(typescript@5.6.2)(utf-8-validate@5.0.10))(zksync-ethers@6.13.0(ethers@6.13.2(bufferutil@4.0.8)(utf-8-validate@5.0.10))) + '@matterlabs/hardhat-zksync-deploy': 1.5.0(ethers@6.13.2(bufferutil@4.0.8)(utf-8-validate@5.0.10))(hardhat@2.22.15(bufferutil@4.0.8)(ts-node@10.9.2(@swc/core@1.7.26(@swc/helpers@0.5.13))(@types/node@20.16.10)(typescript@5.6.2))(typescript@5.6.2)(utf-8-validate@5.0.10))(zksync-ethers@6.15.0(ethers@6.13.2(bufferutil@4.0.8)(utf-8-validate@5.0.10))) '@matterlabs/hardhat-zksync-solc': 1.2.5(hardhat@2.22.15(bufferutil@4.0.8)(ts-node@10.9.2(@swc/core@1.7.26(@swc/helpers@0.5.13))(@types/node@20.16.10)(typescript@5.6.2))(typescript@5.6.2)(utf-8-validate@5.0.10)) '@nomicfoundation/hardhat-ethers': 3.0.8(ethers@6.13.2(bufferutil@4.0.8)(utf-8-validate@5.0.10))(hardhat@2.22.15(bufferutil@4.0.8)(ts-node@10.9.2(@swc/core@1.7.26(@swc/helpers@0.5.13))(@types/node@20.16.10)(typescript@5.6.2))(typescript@5.6.2)(utf-8-validate@5.0.10)) chai: 4.5.0 chalk: 4.1.2 ethers: 6.13.2(bufferutil@4.0.8)(utf-8-validate@5.0.10) hardhat: 2.22.15(bufferutil@4.0.8)(ts-node@10.9.2(@swc/core@1.7.26(@swc/helpers@0.5.13))(@types/node@20.16.10)(typescript@5.6.2))(typescript@5.6.2)(utf-8-validate@5.0.10) - zksync-ethers: 6.13.0(ethers@6.13.2(bufferutil@4.0.8)(utf-8-validate@5.0.10)) + zksync-ethers: 6.15.0(ethers@6.13.2(bufferutil@4.0.8)(utf-8-validate@5.0.10)) transitivePeerDependencies: - bufferutil - c-kzg @@ -13324,16 +13318,16 @@ snapshots: - typescript - utf-8-validate - '@matterlabs/hardhat-zksync-ethers@1.2.1(bufferutil@4.0.8)(ethers@6.13.4(bufferutil@4.0.8)(utf-8-validate@5.0.10))(ts-node@10.9.2(@swc/core@1.7.26(@swc/helpers@0.5.13))(@types/node@20.16.10)(typescript@5.6.2))(typescript@5.6.2)(utf-8-validate@5.0.10)(zksync-ethers@6.14.0(ethers@6.13.4(bufferutil@4.0.8)(utf-8-validate@5.0.10)))': + '@matterlabs/hardhat-zksync-ethers@1.2.1(bufferutil@4.0.8)(ethers@6.13.4(bufferutil@4.0.8)(utf-8-validate@5.0.10))(ts-node@10.9.2(@swc/core@1.7.26(@swc/helpers@0.5.13))(@types/node@20.16.10)(typescript@5.6.2))(typescript@5.6.2)(utf-8-validate@5.0.10)(zksync-ethers@6.15.0(ethers@6.13.2(bufferutil@4.0.8)(utf-8-validate@5.0.10)))': dependencies: - '@matterlabs/hardhat-zksync-deploy': 1.5.0(ethers@6.13.4(bufferutil@4.0.8)(utf-8-validate@5.0.10))(hardhat@2.22.15(bufferutil@4.0.8)(ts-node@10.9.2(@swc/core@1.7.26(@swc/helpers@0.5.13))(@types/node@20.16.10)(typescript@5.6.2))(typescript@5.6.2)(utf-8-validate@5.0.10))(zksync-ethers@6.14.0(ethers@6.13.4(bufferutil@4.0.8)(utf-8-validate@5.0.10))) + '@matterlabs/hardhat-zksync-deploy': 1.5.0(ethers@6.13.4(bufferutil@4.0.8)(utf-8-validate@5.0.10))(hardhat@2.22.15(bufferutil@4.0.8)(ts-node@10.9.2(@swc/core@1.7.26(@swc/helpers@0.5.13))(@types/node@20.16.10)(typescript@5.6.2))(typescript@5.6.2)(utf-8-validate@5.0.10))(zksync-ethers@6.15.0(ethers@6.13.2(bufferutil@4.0.8)(utf-8-validate@5.0.10))) '@matterlabs/hardhat-zksync-solc': 1.2.5(hardhat@2.22.15(bufferutil@4.0.8)(ts-node@10.9.2(@swc/core@1.7.26(@swc/helpers@0.5.13))(@types/node@20.16.10)(typescript@5.6.2))(typescript@5.6.2)(utf-8-validate@5.0.10)) '@nomicfoundation/hardhat-ethers': 3.0.8(ethers@6.13.4(bufferutil@4.0.8)(utf-8-validate@5.0.10))(hardhat@2.22.15(bufferutil@4.0.8)(ts-node@10.9.2(@swc/core@1.7.26(@swc/helpers@0.5.13))(@types/node@20.16.10)(typescript@5.6.2))(typescript@5.6.2)(utf-8-validate@5.0.10)) chai: 4.5.0 chalk: 4.1.2 ethers: 6.13.4(bufferutil@4.0.8)(utf-8-validate@5.0.10) hardhat: 2.22.15(bufferutil@4.0.8)(ts-node@10.9.2(@swc/core@1.7.26(@swc/helpers@0.5.13))(@types/node@20.16.10)(typescript@5.6.2))(typescript@5.6.2)(utf-8-validate@5.0.10) - zksync-ethers: 6.14.0(ethers@6.13.4(bufferutil@4.0.8)(utf-8-validate@5.0.10)) + zksync-ethers: 6.15.0(ethers@6.13.2(bufferutil@4.0.8)(utf-8-validate@5.0.10)) transitivePeerDependencies: - bufferutil - c-kzg @@ -13343,16 +13337,16 @@ snapshots: - typescript - utf-8-validate - '@matterlabs/hardhat-zksync-ethers@1.2.1(bufferutil@4.0.8)(ethers@6.13.4(bufferutil@4.0.8)(utf-8-validate@5.0.10))(ts-node@10.9.2(@swc/core@1.7.26(@swc/helpers@0.5.13))(@types/node@22.8.0)(typescript@5.6.2))(typescript@5.6.2)(utf-8-validate@5.0.10)(zksync-ethers@6.14.0(ethers@6.13.4(bufferutil@4.0.8)(utf-8-validate@5.0.10)))': + '@matterlabs/hardhat-zksync-ethers@1.2.1(bufferutil@4.0.8)(ethers@6.13.4(bufferutil@4.0.8)(utf-8-validate@5.0.10))(ts-node@10.9.2(@swc/core@1.7.26(@swc/helpers@0.5.13))(@types/node@22.8.0)(typescript@5.6.2))(typescript@5.6.2)(utf-8-validate@5.0.10)(zksync-ethers@6.15.0(ethers@6.13.4(bufferutil@4.0.8)(utf-8-validate@5.0.10)))': dependencies: - '@matterlabs/hardhat-zksync-deploy': 1.5.0(ethers@6.13.4(bufferutil@4.0.8)(utf-8-validate@5.0.10))(hardhat@2.22.15(bufferutil@4.0.8)(ts-node@10.9.2(@swc/core@1.7.26(@swc/helpers@0.5.13))(@types/node@22.8.0)(typescript@5.6.2))(typescript@5.6.2)(utf-8-validate@5.0.10))(zksync-ethers@6.14.0(ethers@6.13.4(bufferutil@4.0.8)(utf-8-validate@5.0.10))) + '@matterlabs/hardhat-zksync-deploy': 1.5.0(ethers@6.13.4(bufferutil@4.0.8)(utf-8-validate@5.0.10))(hardhat@2.22.15(bufferutil@4.0.8)(ts-node@10.9.2(@swc/core@1.7.26(@swc/helpers@0.5.13))(@types/node@22.8.0)(typescript@5.6.2))(typescript@5.6.2)(utf-8-validate@5.0.10))(zksync-ethers@6.15.0(ethers@6.13.4(bufferutil@4.0.8)(utf-8-validate@5.0.10))) '@matterlabs/hardhat-zksync-solc': 1.2.5(hardhat@2.22.15(bufferutil@4.0.8)(ts-node@10.9.2(@swc/core@1.7.26(@swc/helpers@0.5.13))(@types/node@22.8.0)(typescript@5.6.2))(typescript@5.6.2)(utf-8-validate@5.0.10)) '@nomicfoundation/hardhat-ethers': 3.0.8(ethers@6.13.4(bufferutil@4.0.8)(utf-8-validate@5.0.10))(hardhat@2.22.15(bufferutil@4.0.8)(ts-node@10.9.2(@swc/core@1.7.26(@swc/helpers@0.5.13))(@types/node@22.8.0)(typescript@5.6.2))(typescript@5.6.2)(utf-8-validate@5.0.10)) chai: 4.5.0 chalk: 4.1.2 ethers: 6.13.4(bufferutil@4.0.8)(utf-8-validate@5.0.10) hardhat: 2.22.15(bufferutil@4.0.8)(ts-node@10.9.2(@swc/core@1.7.26(@swc/helpers@0.5.13))(@types/node@22.8.0)(typescript@5.6.2))(typescript@5.6.2)(utf-8-validate@5.0.10) - zksync-ethers: 6.14.0(ethers@6.13.4(bufferutil@4.0.8)(utf-8-validate@5.0.10)) + zksync-ethers: 6.15.0(ethers@6.13.4(bufferutil@4.0.8)(utf-8-validate@5.0.10)) transitivePeerDependencies: - bufferutil - c-kzg @@ -13436,8 +13430,8 @@ snapshots: '@matterlabs/hardhat-zksync-upgradable@1.7.0(@nomicfoundation/hardhat-ethers@3.0.8(ethers@6.13.2(bufferutil@4.0.8)(utf-8-validate@5.0.10))(hardhat@2.22.15(bufferutil@4.0.8)(ts-node@10.9.2(@swc/core@1.7.26(@swc/helpers@0.5.13))(@types/node@20.16.10)(typescript@5.6.2))(typescript@5.6.2)(utf-8-validate@5.0.10)))(@nomicfoundation/hardhat-verify@2.0.11(hardhat@2.22.15(bufferutil@4.0.8)(ts-node@10.9.2(@swc/core@1.7.26(@swc/helpers@0.5.13))(@types/node@20.16.10)(typescript@5.6.2))(typescript@5.6.2)(utf-8-validate@5.0.10)))(bufferutil@4.0.8)(ts-node@10.9.2(@swc/core@1.7.26(@swc/helpers@0.5.13))(@types/node@20.16.10)(typescript@5.6.2))(typescript@5.6.2)(utf-8-validate@5.0.10)': dependencies: - '@matterlabs/hardhat-zksync-deploy': 1.5.0(ethers@6.13.4(bufferutil@4.0.8)(utf-8-validate@5.0.10))(hardhat@2.22.15(bufferutil@4.0.8)(ts-node@10.9.2(@swc/core@1.7.26(@swc/helpers@0.5.13))(@types/node@20.16.10)(typescript@5.6.2))(typescript@5.6.2)(utf-8-validate@5.0.10))(zksync-ethers@6.14.0(ethers@6.13.4(bufferutil@4.0.8)(utf-8-validate@5.0.10))) - '@matterlabs/hardhat-zksync-ethers': 1.2.1(bufferutil@4.0.8)(ethers@6.13.4(bufferutil@4.0.8)(utf-8-validate@5.0.10))(ts-node@10.9.2(@swc/core@1.7.26(@swc/helpers@0.5.13))(@types/node@20.16.10)(typescript@5.6.2))(typescript@5.6.2)(utf-8-validate@5.0.10)(zksync-ethers@6.14.0(ethers@6.13.4(bufferutil@4.0.8)(utf-8-validate@5.0.10))) + '@matterlabs/hardhat-zksync-deploy': 1.5.0(ethers@6.13.4(bufferutil@4.0.8)(utf-8-validate@5.0.10))(hardhat@2.22.15(bufferutil@4.0.8)(ts-node@10.9.2(@swc/core@1.7.26(@swc/helpers@0.5.13))(@types/node@20.16.10)(typescript@5.6.2))(typescript@5.6.2)(utf-8-validate@5.0.10))(zksync-ethers@6.15.0(ethers@6.13.2(bufferutil@4.0.8)(utf-8-validate@5.0.10))) + '@matterlabs/hardhat-zksync-ethers': 1.2.1(bufferutil@4.0.8)(ethers@6.13.4(bufferutil@4.0.8)(utf-8-validate@5.0.10))(ts-node@10.9.2(@swc/core@1.7.26(@swc/helpers@0.5.13))(@types/node@20.16.10)(typescript@5.6.2))(typescript@5.6.2)(utf-8-validate@5.0.10)(zksync-ethers@6.15.0(ethers@6.13.2(bufferutil@4.0.8)(utf-8-validate@5.0.10))) '@matterlabs/hardhat-zksync-solc': 1.2.5(hardhat@2.22.15(bufferutil@4.0.8)(ts-node@10.9.2(@swc/core@1.7.26(@swc/helpers@0.5.13))(@types/node@20.16.10)(typescript@5.6.2))(typescript@5.6.2)(utf-8-validate@5.0.10)) '@openzeppelin/contracts-hardhat-zksync-upgradable': '@openzeppelin/contracts@5.1.0' '@openzeppelin/defender-sdk-base-client': 1.15.0 @@ -13454,7 +13448,7 @@ snapshots: proper-lockfile: 4.1.2 semver: 7.6.3 solidity-ast: 0.4.59 - zksync-ethers: 6.14.0(ethers@6.13.4(bufferutil@4.0.8)(utf-8-validate@5.0.10)) + zksync-ethers: 6.15.0(ethers@6.13.4(bufferutil@4.0.8)(utf-8-validate@5.0.10)) transitivePeerDependencies: - '@nomicfoundation/hardhat-ethers' - '@nomicfoundation/hardhat-verify' @@ -13469,8 +13463,8 @@ snapshots: '@matterlabs/hardhat-zksync-upgradable@1.7.0(@nomicfoundation/hardhat-ethers@3.0.8(ethers@6.13.4(bufferutil@4.0.8)(utf-8-validate@5.0.10))(hardhat@2.22.15(bufferutil@4.0.8)(ts-node@10.9.2(@swc/core@1.7.26(@swc/helpers@0.5.13))(@types/node@22.8.0)(typescript@5.6.2))(typescript@5.6.2)(utf-8-validate@5.0.10)))(@nomicfoundation/hardhat-verify@2.0.11(hardhat@2.22.15(bufferutil@4.0.8)(ts-node@10.9.2(@swc/core@1.7.26(@swc/helpers@0.5.13))(@types/node@22.8.0)(typescript@5.6.2))(typescript@5.6.2)(utf-8-validate@5.0.10)))(bufferutil@4.0.8)(ts-node@10.9.2(@swc/core@1.7.26(@swc/helpers@0.5.13))(@types/node@22.8.0)(typescript@5.6.2))(typescript@5.6.2)(utf-8-validate@5.0.10)': dependencies: - '@matterlabs/hardhat-zksync-deploy': 1.5.0(ethers@6.13.4(bufferutil@4.0.8)(utf-8-validate@5.0.10))(hardhat@2.22.15(bufferutil@4.0.8)(ts-node@10.9.2(@swc/core@1.7.26(@swc/helpers@0.5.13))(@types/node@22.8.0)(typescript@5.6.2))(typescript@5.6.2)(utf-8-validate@5.0.10))(zksync-ethers@6.14.0(ethers@6.13.4(bufferutil@4.0.8)(utf-8-validate@5.0.10))) - '@matterlabs/hardhat-zksync-ethers': 1.2.1(bufferutil@4.0.8)(ethers@6.13.4(bufferutil@4.0.8)(utf-8-validate@5.0.10))(ts-node@10.9.2(@swc/core@1.7.26(@swc/helpers@0.5.13))(@types/node@22.8.0)(typescript@5.6.2))(typescript@5.6.2)(utf-8-validate@5.0.10)(zksync-ethers@6.14.0(ethers@6.13.4(bufferutil@4.0.8)(utf-8-validate@5.0.10))) + '@matterlabs/hardhat-zksync-deploy': 1.5.0(ethers@6.13.4(bufferutil@4.0.8)(utf-8-validate@5.0.10))(hardhat@2.22.15(bufferutil@4.0.8)(ts-node@10.9.2(@swc/core@1.7.26(@swc/helpers@0.5.13))(@types/node@22.8.0)(typescript@5.6.2))(typescript@5.6.2)(utf-8-validate@5.0.10))(zksync-ethers@6.15.0(ethers@6.13.4(bufferutil@4.0.8)(utf-8-validate@5.0.10))) + '@matterlabs/hardhat-zksync-ethers': 1.2.1(bufferutil@4.0.8)(ethers@6.13.4(bufferutil@4.0.8)(utf-8-validate@5.0.10))(ts-node@10.9.2(@swc/core@1.7.26(@swc/helpers@0.5.13))(@types/node@22.8.0)(typescript@5.6.2))(typescript@5.6.2)(utf-8-validate@5.0.10)(zksync-ethers@6.15.0(ethers@6.13.4(bufferutil@4.0.8)(utf-8-validate@5.0.10))) '@matterlabs/hardhat-zksync-solc': 1.2.5(hardhat@2.22.15(bufferutil@4.0.8)(ts-node@10.9.2(@swc/core@1.7.26(@swc/helpers@0.5.13))(@types/node@22.8.0)(typescript@5.6.2))(typescript@5.6.2)(utf-8-validate@5.0.10)) '@openzeppelin/contracts-hardhat-zksync-upgradable': '@openzeppelin/contracts@5.1.0' '@openzeppelin/defender-sdk-base-client': 1.15.0 @@ -13487,7 +13481,7 @@ snapshots: proper-lockfile: 4.1.2 semver: 7.6.3 solidity-ast: 0.4.59 - zksync-ethers: 6.14.0(ethers@6.13.4(bufferutil@4.0.8)(utf-8-validate@5.0.10)) + zksync-ethers: 6.15.0(ethers@6.13.4(bufferutil@4.0.8)(utf-8-validate@5.0.10)) transitivePeerDependencies: - '@nomicfoundation/hardhat-ethers' - '@nomicfoundation/hardhat-verify' @@ -13538,23 +13532,23 @@ snapshots: - encoding - supports-color - '@matterlabs/hardhat-zksync@1.2.0(jq27lisszh63x44gykkfav2efe)': + '@matterlabs/hardhat-zksync@1.2.0(e32ijlvs4nitlwogqpjpupt3om)': dependencies: - '@matterlabs/hardhat-zksync-deploy': 1.5.0(ethers@6.13.4(bufferutil@4.0.8)(utf-8-validate@5.0.10))(hardhat@2.22.15(bufferutil@4.0.8)(ts-node@10.9.2(@swc/core@1.7.26(@swc/helpers@0.5.13))(@types/node@22.8.0)(typescript@5.6.2))(typescript@5.6.2)(utf-8-validate@5.0.10))(zksync-ethers@6.14.0(ethers@6.13.4(bufferutil@4.0.8)(utf-8-validate@5.0.10))) - '@matterlabs/hardhat-zksync-ethers': 1.2.1(bufferutil@4.0.8)(ethers@6.13.4(bufferutil@4.0.8)(utf-8-validate@5.0.10))(ts-node@10.9.2(@swc/core@1.7.26(@swc/helpers@0.5.13))(@types/node@22.8.0)(typescript@5.6.2))(typescript@5.6.2)(utf-8-validate@5.0.10)(zksync-ethers@6.14.0(ethers@6.13.4(bufferutil@4.0.8)(utf-8-validate@5.0.10))) - '@matterlabs/hardhat-zksync-node': 1.2.0(hardhat@2.22.15(bufferutil@4.0.8)(ts-node@10.9.2(@swc/core@1.7.26(@swc/helpers@0.5.13))(@types/node@22.8.0)(typescript@5.6.2))(typescript@5.6.2)(utf-8-validate@5.0.10)) - '@matterlabs/hardhat-zksync-solc': 1.2.5(hardhat@2.22.15(bufferutil@4.0.8)(ts-node@10.9.2(@swc/core@1.7.26(@swc/helpers@0.5.13))(@types/node@22.8.0)(typescript@5.6.2))(typescript@5.6.2)(utf-8-validate@5.0.10)) - '@matterlabs/hardhat-zksync-upgradable': 1.7.0(@nomicfoundation/hardhat-ethers@3.0.8(ethers@6.13.4(bufferutil@4.0.8)(utf-8-validate@5.0.10))(hardhat@2.22.15(bufferutil@4.0.8)(ts-node@10.9.2(@swc/core@1.7.26(@swc/helpers@0.5.13))(@types/node@22.8.0)(typescript@5.6.2))(typescript@5.6.2)(utf-8-validate@5.0.10)))(@nomicfoundation/hardhat-verify@2.0.11(hardhat@2.22.15(bufferutil@4.0.8)(ts-node@10.9.2(@swc/core@1.7.26(@swc/helpers@0.5.13))(@types/node@22.8.0)(typescript@5.6.2))(typescript@5.6.2)(utf-8-validate@5.0.10)))(bufferutil@4.0.8)(ts-node@10.9.2(@swc/core@1.7.26(@swc/helpers@0.5.13))(@types/node@22.8.0)(typescript@5.6.2))(typescript@5.6.2)(utf-8-validate@5.0.10) - '@matterlabs/hardhat-zksync-verify': 1.6.0(@nomicfoundation/hardhat-verify@2.0.11(hardhat@2.22.15(bufferutil@4.0.8)(ts-node@10.9.2(@swc/core@1.7.26(@swc/helpers@0.5.13))(@types/node@22.8.0)(typescript@5.6.2))(typescript@5.6.2)(utf-8-validate@5.0.10)))(hardhat@2.22.15(bufferutil@4.0.8)(ts-node@10.9.2(@swc/core@1.7.26(@swc/helpers@0.5.13))(@types/node@22.8.0)(typescript@5.6.2))(typescript@5.6.2)(utf-8-validate@5.0.10)) - '@nomicfoundation/hardhat-ethers': 3.0.8(ethers@6.13.4(bufferutil@4.0.8)(utf-8-validate@5.0.10))(hardhat@2.22.15(bufferutil@4.0.8)(ts-node@10.9.2(@swc/core@1.7.26(@swc/helpers@0.5.13))(@types/node@22.8.0)(typescript@5.6.2))(typescript@5.6.2)(utf-8-validate@5.0.10)) - '@nomicfoundation/hardhat-verify': 2.0.11(hardhat@2.22.15(bufferutil@4.0.8)(ts-node@10.9.2(@swc/core@1.7.26(@swc/helpers@0.5.13))(@types/node@22.8.0)(typescript@5.6.2))(typescript@5.6.2)(utf-8-validate@5.0.10)) + '@matterlabs/hardhat-zksync-deploy': 1.5.0(ethers@6.13.2(bufferutil@4.0.8)(utf-8-validate@5.0.10))(hardhat@2.22.15(bufferutil@4.0.8)(ts-node@10.9.2(@swc/core@1.7.26(@swc/helpers@0.5.13))(@types/node@20.16.10)(typescript@5.6.2))(typescript@5.6.2)(utf-8-validate@5.0.10))(zksync-ethers@6.15.0(ethers@6.13.2(bufferutil@4.0.8)(utf-8-validate@5.0.10))) + '@matterlabs/hardhat-zksync-ethers': 1.2.1(bufferutil@4.0.8)(ethers@6.13.2(bufferutil@4.0.8)(utf-8-validate@5.0.10))(ts-node@10.9.2(@swc/core@1.7.26(@swc/helpers@0.5.13))(@types/node@20.16.10)(typescript@5.6.2))(typescript@5.6.2)(utf-8-validate@5.0.10)(zksync-ethers@6.15.0(ethers@6.13.2(bufferutil@4.0.8)(utf-8-validate@5.0.10))) + '@matterlabs/hardhat-zksync-node': 1.2.0(hardhat@2.22.15(bufferutil@4.0.8)(ts-node@10.9.2(@swc/core@1.7.26(@swc/helpers@0.5.13))(@types/node@20.16.10)(typescript@5.6.2))(typescript@5.6.2)(utf-8-validate@5.0.10)) + '@matterlabs/hardhat-zksync-solc': 1.2.5(hardhat@2.22.15(bufferutil@4.0.8)(ts-node@10.9.2(@swc/core@1.7.26(@swc/helpers@0.5.13))(@types/node@20.16.10)(typescript@5.6.2))(typescript@5.6.2)(utf-8-validate@5.0.10)) + '@matterlabs/hardhat-zksync-upgradable': 1.7.0(@nomicfoundation/hardhat-ethers@3.0.8(ethers@6.13.2(bufferutil@4.0.8)(utf-8-validate@5.0.10))(hardhat@2.22.15(bufferutil@4.0.8)(ts-node@10.9.2(@swc/core@1.7.26(@swc/helpers@0.5.13))(@types/node@20.16.10)(typescript@5.6.2))(typescript@5.6.2)(utf-8-validate@5.0.10)))(@nomicfoundation/hardhat-verify@2.0.11(hardhat@2.22.15(bufferutil@4.0.8)(ts-node@10.9.2(@swc/core@1.7.26(@swc/helpers@0.5.13))(@types/node@20.16.10)(typescript@5.6.2))(typescript@5.6.2)(utf-8-validate@5.0.10)))(bufferutil@4.0.8)(ts-node@10.9.2(@swc/core@1.7.26(@swc/helpers@0.5.13))(@types/node@20.16.10)(typescript@5.6.2))(typescript@5.6.2)(utf-8-validate@5.0.10) + '@matterlabs/hardhat-zksync-verify': 1.6.0(@nomicfoundation/hardhat-verify@2.0.11(hardhat@2.22.15(bufferutil@4.0.8)(ts-node@10.9.2(@swc/core@1.7.26(@swc/helpers@0.5.13))(@types/node@20.16.10)(typescript@5.6.2))(typescript@5.6.2)(utf-8-validate@5.0.10)))(hardhat@2.22.15(bufferutil@4.0.8)(ts-node@10.9.2(@swc/core@1.7.26(@swc/helpers@0.5.13))(@types/node@20.16.10)(typescript@5.6.2))(typescript@5.6.2)(utf-8-validate@5.0.10)) + '@nomicfoundation/hardhat-ethers': 3.0.8(ethers@6.13.4(bufferutil@4.0.8)(utf-8-validate@5.0.10))(hardhat@2.22.15(bufferutil@4.0.8)(ts-node@10.9.2(@swc/core@1.7.26(@swc/helpers@0.5.13))(@types/node@20.16.10)(typescript@5.6.2))(typescript@5.6.2)(utf-8-validate@5.0.10)) + '@nomicfoundation/hardhat-verify': 2.0.11(hardhat@2.22.15(bufferutil@4.0.8)(ts-node@10.9.2(@swc/core@1.7.26(@swc/helpers@0.5.13))(@types/node@20.16.10)(typescript@5.6.2))(typescript@5.6.2)(utf-8-validate@5.0.10)) '@openzeppelin/upgrades-core': 1.40.0 chai: 4.5.0 ethers: 6.13.4(bufferutil@4.0.8)(utf-8-validate@5.0.10) - hardhat: 2.22.15(bufferutil@4.0.8)(ts-node@10.9.2(@swc/core@1.7.26(@swc/helpers@0.5.13))(@types/node@22.8.0)(typescript@5.6.2))(typescript@5.6.2)(utf-8-validate@5.0.10) + hardhat: 2.22.15(bufferutil@4.0.8)(ts-node@10.9.2(@swc/core@1.7.26(@swc/helpers@0.5.13))(@types/node@20.16.10)(typescript@5.6.2))(typescript@5.6.2)(utf-8-validate@5.0.10) sinon: 18.0.1 sinon-chai: 3.7.0(chai@4.5.0)(sinon@18.0.1) - zksync-ethers: 6.14.0(ethers@6.13.4(bufferutil@4.0.8)(utf-8-validate@5.0.10)) + zksync-ethers: 6.15.0(ethers@6.13.4(bufferutil@4.0.8)(utf-8-validate@5.0.10)) transitivePeerDependencies: - bufferutil - c-kzg @@ -13563,23 +13557,23 @@ snapshots: - typescript - utf-8-validate - '@matterlabs/hardhat-zksync@1.2.0(s5mnuinjslozaedgq4f5sjptyy)': + '@matterlabs/hardhat-zksync@1.2.0(gzbl74e4hs234pcoapof4dgi5a)': dependencies: - '@matterlabs/hardhat-zksync-deploy': 1.5.0(ethers@6.13.2(bufferutil@4.0.8)(utf-8-validate@5.0.10))(hardhat@2.22.15(bufferutil@4.0.8)(ts-node@10.9.2(@swc/core@1.7.26(@swc/helpers@0.5.13))(@types/node@20.16.10)(typescript@5.6.2))(typescript@5.6.2)(utf-8-validate@5.0.10))(zksync-ethers@6.13.0(ethers@6.13.2(bufferutil@4.0.8)(utf-8-validate@5.0.10))) - '@matterlabs/hardhat-zksync-ethers': 1.2.1(bufferutil@4.0.8)(ethers@6.13.2(bufferutil@4.0.8)(utf-8-validate@5.0.10))(ts-node@10.9.2(@swc/core@1.7.26(@swc/helpers@0.5.13))(@types/node@20.16.10)(typescript@5.6.2))(typescript@5.6.2)(utf-8-validate@5.0.10)(zksync-ethers@6.13.0(ethers@6.13.2(bufferutil@4.0.8)(utf-8-validate@5.0.10))) - '@matterlabs/hardhat-zksync-node': 1.2.0(hardhat@2.22.15(bufferutil@4.0.8)(ts-node@10.9.2(@swc/core@1.7.26(@swc/helpers@0.5.13))(@types/node@20.16.10)(typescript@5.6.2))(typescript@5.6.2)(utf-8-validate@5.0.10)) - '@matterlabs/hardhat-zksync-solc': 1.2.5(hardhat@2.22.15(bufferutil@4.0.8)(ts-node@10.9.2(@swc/core@1.7.26(@swc/helpers@0.5.13))(@types/node@20.16.10)(typescript@5.6.2))(typescript@5.6.2)(utf-8-validate@5.0.10)) - '@matterlabs/hardhat-zksync-upgradable': 1.7.0(@nomicfoundation/hardhat-ethers@3.0.8(ethers@6.13.2(bufferutil@4.0.8)(utf-8-validate@5.0.10))(hardhat@2.22.15(bufferutil@4.0.8)(ts-node@10.9.2(@swc/core@1.7.26(@swc/helpers@0.5.13))(@types/node@20.16.10)(typescript@5.6.2))(typescript@5.6.2)(utf-8-validate@5.0.10)))(@nomicfoundation/hardhat-verify@2.0.11(hardhat@2.22.15(bufferutil@4.0.8)(ts-node@10.9.2(@swc/core@1.7.26(@swc/helpers@0.5.13))(@types/node@20.16.10)(typescript@5.6.2))(typescript@5.6.2)(utf-8-validate@5.0.10)))(bufferutil@4.0.8)(ts-node@10.9.2(@swc/core@1.7.26(@swc/helpers@0.5.13))(@types/node@20.16.10)(typescript@5.6.2))(typescript@5.6.2)(utf-8-validate@5.0.10) - '@matterlabs/hardhat-zksync-verify': 1.6.0(@nomicfoundation/hardhat-verify@2.0.11(hardhat@2.22.15(bufferutil@4.0.8)(ts-node@10.9.2(@swc/core@1.7.26(@swc/helpers@0.5.13))(@types/node@20.16.10)(typescript@5.6.2))(typescript@5.6.2)(utf-8-validate@5.0.10)))(hardhat@2.22.15(bufferutil@4.0.8)(ts-node@10.9.2(@swc/core@1.7.26(@swc/helpers@0.5.13))(@types/node@20.16.10)(typescript@5.6.2))(typescript@5.6.2)(utf-8-validate@5.0.10)) - '@nomicfoundation/hardhat-ethers': 3.0.8(ethers@6.13.4(bufferutil@4.0.8)(utf-8-validate@5.0.10))(hardhat@2.22.15(bufferutil@4.0.8)(ts-node@10.9.2(@swc/core@1.7.26(@swc/helpers@0.5.13))(@types/node@20.16.10)(typescript@5.6.2))(typescript@5.6.2)(utf-8-validate@5.0.10)) - '@nomicfoundation/hardhat-verify': 2.0.11(hardhat@2.22.15(bufferutil@4.0.8)(ts-node@10.9.2(@swc/core@1.7.26(@swc/helpers@0.5.13))(@types/node@20.16.10)(typescript@5.6.2))(typescript@5.6.2)(utf-8-validate@5.0.10)) + '@matterlabs/hardhat-zksync-deploy': 1.5.0(ethers@6.13.4(bufferutil@4.0.8)(utf-8-validate@5.0.10))(hardhat@2.22.15(bufferutil@4.0.8)(ts-node@10.9.2(@swc/core@1.7.26(@swc/helpers@0.5.13))(@types/node@22.8.0)(typescript@5.6.2))(typescript@5.6.2)(utf-8-validate@5.0.10))(zksync-ethers@6.15.0(ethers@6.13.4(bufferutil@4.0.8)(utf-8-validate@5.0.10))) + '@matterlabs/hardhat-zksync-ethers': 1.2.1(bufferutil@4.0.8)(ethers@6.13.4(bufferutil@4.0.8)(utf-8-validate@5.0.10))(ts-node@10.9.2(@swc/core@1.7.26(@swc/helpers@0.5.13))(@types/node@22.8.0)(typescript@5.6.2))(typescript@5.6.2)(utf-8-validate@5.0.10)(zksync-ethers@6.15.0(ethers@6.13.4(bufferutil@4.0.8)(utf-8-validate@5.0.10))) + '@matterlabs/hardhat-zksync-node': 1.2.0(hardhat@2.22.15(bufferutil@4.0.8)(ts-node@10.9.2(@swc/core@1.7.26(@swc/helpers@0.5.13))(@types/node@22.8.0)(typescript@5.6.2))(typescript@5.6.2)(utf-8-validate@5.0.10)) + '@matterlabs/hardhat-zksync-solc': 1.2.5(hardhat@2.22.15(bufferutil@4.0.8)(ts-node@10.9.2(@swc/core@1.7.26(@swc/helpers@0.5.13))(@types/node@22.8.0)(typescript@5.6.2))(typescript@5.6.2)(utf-8-validate@5.0.10)) + '@matterlabs/hardhat-zksync-upgradable': 1.7.0(@nomicfoundation/hardhat-ethers@3.0.8(ethers@6.13.4(bufferutil@4.0.8)(utf-8-validate@5.0.10))(hardhat@2.22.15(bufferutil@4.0.8)(ts-node@10.9.2(@swc/core@1.7.26(@swc/helpers@0.5.13))(@types/node@22.8.0)(typescript@5.6.2))(typescript@5.6.2)(utf-8-validate@5.0.10)))(@nomicfoundation/hardhat-verify@2.0.11(hardhat@2.22.15(bufferutil@4.0.8)(ts-node@10.9.2(@swc/core@1.7.26(@swc/helpers@0.5.13))(@types/node@22.8.0)(typescript@5.6.2))(typescript@5.6.2)(utf-8-validate@5.0.10)))(bufferutil@4.0.8)(ts-node@10.9.2(@swc/core@1.7.26(@swc/helpers@0.5.13))(@types/node@22.8.0)(typescript@5.6.2))(typescript@5.6.2)(utf-8-validate@5.0.10) + '@matterlabs/hardhat-zksync-verify': 1.6.0(@nomicfoundation/hardhat-verify@2.0.11(hardhat@2.22.15(bufferutil@4.0.8)(ts-node@10.9.2(@swc/core@1.7.26(@swc/helpers@0.5.13))(@types/node@22.8.0)(typescript@5.6.2))(typescript@5.6.2)(utf-8-validate@5.0.10)))(hardhat@2.22.15(bufferutil@4.0.8)(ts-node@10.9.2(@swc/core@1.7.26(@swc/helpers@0.5.13))(@types/node@22.8.0)(typescript@5.6.2))(typescript@5.6.2)(utf-8-validate@5.0.10)) + '@nomicfoundation/hardhat-ethers': 3.0.8(ethers@6.13.4(bufferutil@4.0.8)(utf-8-validate@5.0.10))(hardhat@2.22.15(bufferutil@4.0.8)(ts-node@10.9.2(@swc/core@1.7.26(@swc/helpers@0.5.13))(@types/node@22.8.0)(typescript@5.6.2))(typescript@5.6.2)(utf-8-validate@5.0.10)) + '@nomicfoundation/hardhat-verify': 2.0.11(hardhat@2.22.15(bufferutil@4.0.8)(ts-node@10.9.2(@swc/core@1.7.26(@swc/helpers@0.5.13))(@types/node@22.8.0)(typescript@5.6.2))(typescript@5.6.2)(utf-8-validate@5.0.10)) '@openzeppelin/upgrades-core': 1.40.0 chai: 4.5.0 ethers: 6.13.4(bufferutil@4.0.8)(utf-8-validate@5.0.10) - hardhat: 2.22.15(bufferutil@4.0.8)(ts-node@10.9.2(@swc/core@1.7.26(@swc/helpers@0.5.13))(@types/node@20.16.10)(typescript@5.6.2))(typescript@5.6.2)(utf-8-validate@5.0.10) + hardhat: 2.22.15(bufferutil@4.0.8)(ts-node@10.9.2(@swc/core@1.7.26(@swc/helpers@0.5.13))(@types/node@22.8.0)(typescript@5.6.2))(typescript@5.6.2)(utf-8-validate@5.0.10) sinon: 18.0.1 sinon-chai: 3.7.0(chai@4.5.0)(sinon@18.0.1) - zksync-ethers: 6.14.0(ethers@6.13.4(bufferutil@4.0.8)(utf-8-validate@5.0.10)) + zksync-ethers: 6.15.0(ethers@6.13.4(bufferutil@4.0.8)(utf-8-validate@5.0.10)) transitivePeerDependencies: - bufferutil - c-kzg @@ -25410,11 +25404,11 @@ snapshots: compress-commons: 6.0.2 readable-stream: 4.5.2 - zksync-ethers@6.13.0(ethers@6.13.2(bufferutil@4.0.8)(utf-8-validate@5.0.10)): + zksync-ethers@6.15.0(ethers@6.13.2(bufferutil@4.0.8)(utf-8-validate@5.0.10)): dependencies: ethers: 6.13.2(bufferutil@4.0.8)(utf-8-validate@5.0.10) - zksync-ethers@6.14.0(ethers@6.13.4(bufferutil@4.0.8)(utf-8-validate@5.0.10)): + zksync-ethers@6.15.0(ethers@6.13.4(bufferutil@4.0.8)(utf-8-validate@5.0.10)): dependencies: ethers: 6.13.4(bufferutil@4.0.8)(utf-8-validate@5.0.10) From 9e5a41723f24a5344dc9bc70cc2b9fe96b90b24d Mon Sep 17 00:00:00 2001 From: Lyova Potyomkin Date: Tue, 12 Nov 2024 07:06:34 +0200 Subject: [PATCH 10/42] feat: pass session in sdk --- packages/auth-server/nuxt.config.ts | 2 +- packages/auth-server/stores/client.ts | 2 +- .../src/validators/SessionKeyValidator.sol | 9 ++------- packages/sdk/src/client-auth-server/Signer.ts | 2 +- packages/sdk/src/client/actions/account.ts | 4 ++-- packages/sdk/src/client/clients/session.ts | 13 ++++++++++++- packages/sdk/src/utils/encoding.ts | 2 +- 7 files changed, 20 insertions(+), 14 deletions(-) diff --git a/packages/auth-server/nuxt.config.ts b/packages/auth-server/nuxt.config.ts index f181fd92..e0fa63f8 100644 --- a/packages/auth-server/nuxt.config.ts +++ b/packages/auth-server/nuxt.config.ts @@ -44,7 +44,7 @@ export default defineNuxtConfig({ runtimeConfig: { public: { chain: zksyncInMemoryNode, - paymaster: "0x0683E542081D9CeBBFe83f07A3102eB2Da318613", + paymaster: "0x2d4E123dEe0554cC19CdE4A8914BDdF1F4192B93", }, }, $production: { diff --git a/packages/auth-server/stores/client.ts b/packages/auth-server/stores/client.ts index 10dde900..6e7eb070 100644 --- a/packages/auth-server/stores/client.ts +++ b/packages/auth-server/stores/client.ts @@ -33,7 +33,7 @@ export const contractsByChain: Record = { accountFactory: "0x", }, [zksyncInMemoryNode.id]: { - session: "0xCfcCD82F2fA50d86e8C91c1cE75f6935806Ae4D2", + session: "0xc81BdB6e98da8e23aa646969A7e942752b9B10c4", passkey: "0x07734BA326b6AD13BfC0115b0903EB14268F1617", accountFactory: "0xaAF5f437fB0524492886fbA64D703df15BF619AE", }, diff --git a/packages/contracts/src/validators/SessionKeyValidator.sol b/packages/contracts/src/validators/SessionKeyValidator.sol index 1e5bbd3b..52367f84 100644 --- a/packages/contracts/src/validators/SessionKeyValidator.sol +++ b/packages/contracts/src/validators/SessionKeyValidator.sol @@ -308,10 +308,8 @@ contract SessionKeyValidator is IHook, IValidationHook, IModuleValidator, IModul bytes4 constant EIP1271_SUCCESS_RETURN_VALUE = 0x1626ba7e; - // account => hashes of session specs - // Can be used to revoke all session keys in case offchain storage is not available. - // TODO: Is emitting an event sufficient instead? - // mapping(address => EnumerableSet.Bytes32Set) private sessionHashes; + // account => number of open sessions + // NOTE: expired sessions are still counted if not explicitly revoked mapping(address => uint256) private sessionCounter; // session hash => session state mapping(bytes32 => SessionLib.SessionStorage) private sessions; @@ -347,7 +345,6 @@ contract SessionKeyValidator is IHook, IValidationHook, IModuleValidator, IModul require(sessionSpec.signer != address(0), "Invalid signer"); require(sessions[sessionHash].status[msg.sender] == SessionLib.Status.NotInitialized, "Session already exists"); require(sessionSpec.feeLimit.limitType != SessionLib.LimitType.Unlimited, "Unlimited fee allowance is not safe"); - // sessionHashes[msg.sender].add(sessionHash); sessionCounter[msg.sender]++; sessions[sessionHash].status[msg.sender] = SessionLib.Status.Active; emit SessionCreated(msg.sender, sessionHash, sessionSpec); @@ -383,7 +380,6 @@ contract SessionKeyValidator is IHook, IValidationHook, IModuleValidator, IModul // is installed again later, there will be no active sessions from the past. // Problem: if there are too many keys, this will run out of gas. // Solution: before uninstalling, require that all keys are revoked manually. - // require(sessionHashes[msg.sender].length() == 0, "Revoke all keys first"); require(sessionCounter[msg.sender] == 0, "Revoke all keys first"); } @@ -400,7 +396,6 @@ contract SessionKeyValidator is IHook, IValidationHook, IModuleValidator, IModul function revokeKey(bytes32 sessionHash) public { require(sessions[sessionHash].status[msg.sender] == SessionLib.Status.Active, "Nothing to revoke"); sessions[sessionHash].status[msg.sender] = SessionLib.Status.Closed; - // sessionHashes[msg.sender].remove(sessionHash); sessionCounter[msg.sender]--; emit SessionRevoked(msg.sender, sessionHash); } diff --git a/packages/sdk/src/client-auth-server/Signer.ts b/packages/sdk/src/client-auth-server/Signer.ts index dbdc940f..b18d5e30 100644 --- a/packages/sdk/src/client-auth-server/Signer.ts +++ b/packages/sdk/src/client-auth-server/Signer.ts @@ -8,7 +8,7 @@ import type { AppMetadata, RequestArguments, SessionPreferences } from "./interf import type { AuthServerRpcSchema, ExtractParams, ExtractReturnType, Method, RPCRequestMessage, RPCResponseMessage, RpcSchema } from "./rpc.js"; import type { WalletProviderSessionPreferences } from "./WalletProvider.js"; -type Account = { +export type Account = { address: Address; activeChainId: Chain["id"]; session?: SessionPreferences & { sessionKey: Hash } | undefined; diff --git a/packages/sdk/src/client/actions/account.ts b/packages/sdk/src/client/actions/account.ts index e6dff661..04b02518 100644 --- a/packages/sdk/src/client/actions/account.ts +++ b/packages/sdk/src/client/actions/account.ts @@ -4,7 +4,7 @@ import { getGeneralPaymasterInput } from "viem/zksync"; import { FactoryAbi } from "../../abi/Factory.js"; import type { SessionData } from "../../client-auth-server/interface.js"; -import { encodeCreateSessionParameters, encodeModuleData, encodePasskeyModuleParameters } from "../../utils/encoding.js"; +import { encodeModuleData, encodePasskeyModuleParameters, encodeSession } from "../../utils/encoding.js"; import { noThrow } from "../../utils/helpers.js"; import { getPasskeySignatureFromPublicKeyBytes, getPublicKeyBytesFromPasskeySignature } from "../../utils/passkey.js"; @@ -80,7 +80,7 @@ export const deployAccount = async < const encodedSessionKeyModuleData = encodeModuleData({ address: args.contracts.session, - parameters: args.initialSession == null ? "0x" : encodeCreateSessionParameters(args.initialSession), + parameters: args.initialSession == null ? "0x" : encodeSession(args.initialSession), }); let deployProxyArgs = { diff --git a/packages/sdk/src/client/clients/session.ts b/packages/sdk/src/client/clients/session.ts index 6b7261b8..479be8f4 100644 --- a/packages/sdk/src/client/clients/session.ts +++ b/packages/sdk/src/client/clients/session.ts @@ -1,6 +1,9 @@ import { type Account, type Address, type Chain, type Client, createClient, encodeAbiParameters, getAddress, type Hash, type Prettify, publicActions, type PublicRpcSchema, type RpcSchema, type Transport, type WalletClientConfig, type WalletRpcSchema } from "viem"; import { privateKeyToAccount } from "viem/accounts"; +import { type Account as ZKsyncAccount } from "../../client-auth-server/Signer.js"; +import { encodeSession } from "../../utils/encoding.js"; +import { StorageItem } from "../../utils/storage.js"; import { type ZksyncAccountSessionActions, zksyncAccountSessionActions } from "../decorators/session.js"; import { type ZksyncAccountWalletActions, zksyncAccountWalletActions } from "../decorators/session_wallet.js"; import { toSmartAccount } from "../smart-account.js"; @@ -24,12 +27,20 @@ export function createZksyncSessionClient< const account = toSmartAccount({ address: parameters.address, sign: async ({ hash }) => { + console.log("SIGNING SESSION TX"); + const accountInfo = new StorageItem(StorageItem.scopedStorageKey("account"), null).get(); if (!parameters.sessionKey) throw new Error("Session key wasn't provided, can't sign"); + if (!accountInfo?.session) throw new Error("Session not found in local storage"); + if (accountInfo.session.sessionKey != parameters.sessionKey) throw new Error("Session key doesn't match the one in local storage"); const sessionKeySigner = privateKeyToAccount(parameters.sessionKey); + const sessionPublicKey = sessionKeySigner.address; + console.log("session signer", sessionPublicKey); + const session = { ...accountInfo.session, sessionPublicKey }; + console.log(session); const hashSignature = await sessionKeySigner.sign({ hash }); return encodeAbiParameters( [{ type: "bytes" }, { type: "address" }, { type: "bytes[]" }], - [hashSignature, parameters.contracts.session, ["0x"]], // FIXME: this is assuming there are no other hooks + [hashSignature, parameters.contracts.session, [encodeSession(session)]], // FIXME: this is assuming there are no other hooks ); }, }); diff --git a/packages/sdk/src/utils/encoding.ts b/packages/sdk/src/utils/encoding.ts index 6713918e..1be57d5a 100644 --- a/packages/sdk/src/utils/encoding.ts +++ b/packages/sdk/src/utils/encoding.ts @@ -3,7 +3,7 @@ import { type Address, encodeAbiParameters, type Hash, parseAbiParameters, toHex import type { SessionData } from "../client-auth-server/interface.js"; import { getSession } from "../utils/session.js"; -export const encodeCreateSessionParameters = (session: SessionData) => { +export const encodeSession = (session: SessionData) => { const sessionSpec = { components: [ { name: "signer", type: "address" }, From fbefbfe3c403ee52248986d1404022de54493761 Mon Sep 17 00:00:00 2001 From: Lyova Potyomkin Date: Tue, 12 Nov 2024 08:06:13 +0200 Subject: [PATCH 11/42] fix: sdk bug --- packages/contracts/test/SessionKeyTest.ts | 6 +++++- packages/sdk/src/client/clients/session.ts | 3 --- packages/sdk/src/utils/encoding.ts | 6 ++---- packages/sdk/src/utils/session.ts | 2 +- 4 files changed, 8 insertions(+), 9 deletions(-) diff --git a/packages/contracts/test/SessionKeyTest.ts b/packages/contracts/test/SessionKeyTest.ts index 61dad54b..839d2cf8 100644 --- a/packages/contracts/test/SessionKeyTest.ts +++ b/packages/contracts/test/SessionKeyTest.ts @@ -224,7 +224,11 @@ class SessionTester { gasPerPubdata: utils.DEFAULT_GAS_PER_PUBDATA_LIMIT, customSignature: abiCoder.encode( ["bytes", "address", "bytes[]"], - [ethers.zeroPadValue("0x1b", 65), await fixtures.getSessionKeyModuleAddress(), [await this.encodeSession()]], + [ + ethers.zeroPadValue("0x1b", 65), + await fixtures.getSessionKeyModuleAddress(), + [await this.encodeSession()], + ], ), }, gasLimit: 0n, diff --git a/packages/sdk/src/client/clients/session.ts b/packages/sdk/src/client/clients/session.ts index 479be8f4..8cca37f5 100644 --- a/packages/sdk/src/client/clients/session.ts +++ b/packages/sdk/src/client/clients/session.ts @@ -27,16 +27,13 @@ export function createZksyncSessionClient< const account = toSmartAccount({ address: parameters.address, sign: async ({ hash }) => { - console.log("SIGNING SESSION TX"); const accountInfo = new StorageItem(StorageItem.scopedStorageKey("account"), null).get(); if (!parameters.sessionKey) throw new Error("Session key wasn't provided, can't sign"); if (!accountInfo?.session) throw new Error("Session not found in local storage"); if (accountInfo.session.sessionKey != parameters.sessionKey) throw new Error("Session key doesn't match the one in local storage"); const sessionKeySigner = privateKeyToAccount(parameters.sessionKey); const sessionPublicKey = sessionKeySigner.address; - console.log("session signer", sessionPublicKey); const session = { ...accountInfo.session, sessionPublicKey }; - console.log(session); const hashSignature = await sessionKeySigner.sign({ hash }); return encodeAbiParameters( [{ type: "bytes" }, { type: "address" }, { type: "bytes[]" }], diff --git a/packages/sdk/src/utils/encoding.ts b/packages/sdk/src/utils/encoding.ts index 1be57d5a..15d55156 100644 --- a/packages/sdk/src/utils/encoding.ts +++ b/packages/sdk/src/utils/encoding.ts @@ -75,10 +75,8 @@ export const encodeSession = (session: SessionData) => { type: "tuple", }; - return encodeAbiParameters( - [sessionSpec], - [{ ...getSession(session), signer: session.sessionPublicKey }], - ); + const fullSession = { ...getSession(session), signer: session.sessionPublicKey }; + return encodeAbiParameters([sessionSpec], [fullSession]); }; export const encodePasskeyModuleParameters = (passkey: { passkeyPublicKey: [Buffer, Buffer]; expectedOrigin: string }) => { diff --git a/packages/sdk/src/utils/session.ts b/packages/sdk/src/utils/session.ts index 74692b06..5962cc18 100644 --- a/packages/sdk/src/utils/session.ts +++ b/packages/sdk/src/utils/session.ts @@ -23,7 +23,7 @@ export function getLimit(limit: bigint | Limit | undefined) { period: 0n, }; } - if (!limit.period) { + if (!limit.period || limit.period == 0n) { return { limitType: LimitType.Lifetime, limit: BigInt(limit.limit), From 499c6809ccc3b39cc77f45838151560452dad310 Mon Sep 17 00:00:00 2001 From: Lyova Potyomkin Date: Tue, 12 Nov 2024 08:09:25 +0200 Subject: [PATCH 12/42] fix: remove hardcoded gas limits --- packages/contracts/test/SessionKeyTest.ts | 5 +---- packages/sdk/src/client/smart-account.ts | 1 - 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/packages/contracts/test/SessionKeyTest.ts b/packages/contracts/test/SessionKeyTest.ts index 839d2cf8..aed13e03 100644 --- a/packages/contracts/test/SessionKeyTest.ts +++ b/packages/contracts/test/SessionKeyTest.ts @@ -143,9 +143,7 @@ class SessionTester { ...await this.aaTxTemplate(), ...txRequest, }; - // TODO: uncomment once gas estimation is fixed one era-test-node. - // It works fine with the local server. - // aaTx.gasLimit = await provider.estimateGas(aaTx); + aaTx.gasLimit = await provider.estimateGas(aaTx); logInfo(`\`sessionTx\` gas estimated: ${await provider.estimateGas(aaTx)}`); const signedTransaction = await this.sessionAccount.signTransaction(aaTx); @@ -381,7 +379,6 @@ describe("SessionKeyModule tests", function () { await tester.sendTxSuccess({ to: await erc20.getAddress(), data: erc20.interface.encodeFunctionData("transfer", [sessionTarget, 1000n]), - gasLimit: 10_000_000n, }); expect(await erc20.balanceOf(sessionTarget)) .to.equal(1000n, "session target should have received the tokens"); diff --git a/packages/sdk/src/client/smart-account.ts b/packages/sdk/src/client/smart-account.ts index c215a699..acb33ed1 100644 --- a/packages/sdk/src/client/smart-account.ts +++ b/packages/sdk/src/client/smart-account.ts @@ -41,7 +41,6 @@ export function toSmartAccount( ...transaction, from: this.address!, type: "eip712", - gas: 100_000_000n, // TODO remove when gas estimation is fixed } as ZksyncTransactionSerializableEIP712; const eip712DomainAndMessage = getEip712Domain(signableTransaction); From 89c631cd2b5466d8aac5a20e7fc1d6eb6a415254 Mon Sep 17 00:00:00 2001 From: Lyova Potyomkin Date: Tue, 12 Nov 2024 08:32:00 +0200 Subject: [PATCH 13/42] fix: leave hardcoded gas limit in sdk for now --- packages/sdk/src/client/smart-account.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/sdk/src/client/smart-account.ts b/packages/sdk/src/client/smart-account.ts index acb33ed1..c215a699 100644 --- a/packages/sdk/src/client/smart-account.ts +++ b/packages/sdk/src/client/smart-account.ts @@ -41,6 +41,7 @@ export function toSmartAccount( ...transaction, from: this.address!, type: "eip712", + gas: 100_000_000n, // TODO remove when gas estimation is fixed } as ZksyncTransactionSerializableEIP712; const eip712DomainAndMessage = getEip712Domain(signableTransaction); From 2bd1bb3a8f54f3d426a649f4198b27fb4e8d9458 Mon Sep 17 00:00:00 2001 From: Jack Hamer Date: Tue, 12 Nov 2024 16:44:24 +0200 Subject: [PATCH 14/42] fix: session interface improvements --- .../auth-server/components/views/Connect.vue | 10 +- .../views/confirmation/RequestSession.vue | 49 +++-- packages/demo-app/pages/index.vue | 6 +- packages/nft-quest/stores/connector.ts | 20 +- packages/sdk/src/client-auth-server/Signer.ts | 37 ++-- .../src/client-auth-server/WalletProvider.ts | 8 +- packages/sdk/src/client-auth-server/index.ts | 1 + .../sdk/src/client-auth-server/interface.ts | 48 +---- packages/sdk/src/client-auth-server/rpc.ts | 17 +- .../sdk/src/client-auth-server/session.ts | 105 ++++++++++ packages/sdk/src/client/actions/account.ts | 4 +- packages/sdk/src/client/actions/session.ts | 11 +- packages/sdk/src/client/clients/common.ts | 6 - packages/sdk/src/client/clients/session.ts | 28 +-- packages/sdk/src/client/decorators/passkey.ts | 11 +- .../src/client/decorators/session_wallet.ts | 2 - packages/sdk/src/client/index.ts | 1 - packages/sdk/src/connector/index.ts | 4 +- packages/sdk/src/index.ts | 5 +- packages/sdk/src/utils/encoding.ts | 89 ++------- packages/sdk/src/utils/session.ts | 186 ++++++++++++------ 21 files changed, 351 insertions(+), 297 deletions(-) create mode 100644 packages/sdk/src/client-auth-server/session.ts delete mode 100644 packages/sdk/src/client/clients/common.ts diff --git a/packages/auth-server/components/views/Connect.vue b/packages/auth-server/components/views/Connect.vue index 7c12b313..ca497aac 100644 --- a/packages/auth-server/components/views/Connect.vue +++ b/packages/auth-server/components/views/Connect.vue @@ -1,8 +1,8 @@ @@ -11,10 +11,10 @@ import type { SessionPreferences } from "zksync-sso"; const { request } = storeToRefs(useRequestsStore()); -const session = computed(() => { +const sessionPreferences = computed(() => { if (request.value?.content.action.method !== "eth_requestAccounts") return undefined; - if ("session" in (request.value.content.action.params!)) { - return request.value.content.action.params.session; + if ("sessionPreferences" in (request.value.content.action.params!)) { + return request.value.content.action.params.sessionPreferences; } return undefined; }); diff --git a/packages/auth-server/components/views/confirmation/RequestSession.vue b/packages/auth-server/components/views/confirmation/RequestSession.vue index b4e62412..9ddd2784 100644 --- a/packages/auth-server/components/views/confirmation/RequestSession.vue +++ b/packages/auth-server/components/views/confirmation/RequestSession.vue @@ -88,7 +88,7 @@ -
{{ JSON.stringify(formattedSession, null, 4) }}
+
{{ JSON.stringify(sessionConfig, null, 4) }}
@@ -116,14 +116,15 @@