소스 검색

Implement ERC-7821 calldata compression in ERC7579Utils (#5602)

Hadrien Croubois 6 달 전
부모
커밋
952775e4f1
2개의 변경된 파일49개의 추가작업 그리고 4개의 파일을 삭제
  1. 4 2
      contracts/account/utils/draft-ERC7579Utils.sol
  2. 45 2
      test/account/utils/draft-ERC7579Utils.test.js

+ 4 - 2
contracts/account/utils/draft-ERC7579Utils.sol

@@ -218,7 +218,9 @@ library ERC7579Utils {
         uint256 value,
         bytes calldata data
     ) private returns (bytes memory) {
-        (bool success, bytes memory returndata) = target.call{value: value}(data);
+        (bool success, bytes memory returndata) = (target == address(0) ? address(this) : target).call{value: value}(
+            data
+        );
         return _validateExecutionMode(index, execType, success, returndata);
     }
 
@@ -229,7 +231,7 @@ library ERC7579Utils {
         address target,
         bytes calldata data
     ) private returns (bytes memory) {
-        (bool success, bytes memory returndata) = target.delegatecall(data);
+        (bool success, bytes memory returndata) = (target == address(0) ? address(this) : target).delegatecall(data);
         return _validateExecutionMode(index, execType, success, returndata);
     }
 

+ 45 - 2
test/account/utils/draft-ERC7579Utils.test.js

@@ -2,13 +2,14 @@ const { ethers } = require('hardhat');
 const { expect } = require('chai');
 const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers');
 const {
+  CALL_TYPE_CALL,
+  CALL_TYPE_BATCH,
+  CALL_TYPE_DELEGATE,
   EXEC_TYPE_DEFAULT,
   EXEC_TYPE_TRY,
   encodeSingle,
   encodeBatch,
   encodeDelegate,
-  CALL_TYPE_CALL,
-  CALL_TYPE_BATCH,
   encodeMode,
 } = require('../../helpers/erc7579');
 const { selector } = require('../../helpers/methods');
@@ -29,6 +30,14 @@ describe('ERC7579Utils', function () {
     Object.assign(this, await loadFixture(fixture));
   });
 
+  it('constants', async function () {
+    await expect(this.utils.$CALLTYPE_SINGLE()).to.eventually.equal(CALL_TYPE_CALL);
+    await expect(this.utils.$CALLTYPE_BATCH()).to.eventually.equal(CALL_TYPE_BATCH);
+    await expect(this.utils.$CALLTYPE_DELEGATECALL()).to.eventually.equal(CALL_TYPE_DELEGATE);
+    await expect(this.utils.$EXECTYPE_DEFAULT()).to.eventually.equal(EXEC_TYPE_DEFAULT);
+    await expect(this.utils.$EXECTYPE_TRY()).to.eventually.equal(EXEC_TYPE_TRY);
+  });
+
   describe('execSingle', function () {
     it('calls the target with value', async function () {
       const value = 0x012;
@@ -54,6 +63,18 @@ describe('ERC7579Utils', function () {
       await expect(ethers.provider.getBalance(this.target)).to.eventually.equal(value);
     });
 
+    it('default to calling self is target is address(0) (ERC-7821 calldata compression)', async function () {
+      const data = encodeSingle(
+        ethers.ZeroAddress, // address(0)
+        0,
+        this.utils.interface.encodeFunctionData('$CALLTYPE_SINGLE', []),
+      );
+
+      await expect(this.utils.$execSingle(data, EXEC_TYPE_DEFAULT))
+        .to.emit(this.utils, 'return$execSingle')
+        .withArgs([ethers.zeroPadBytes(CALL_TYPE_CALL, 32)]);
+    });
+
     it('reverts when target reverts in default ExecType', async function () {
       const value = 0x012;
       const data = encodeSingle(
@@ -131,6 +152,17 @@ describe('ERC7579Utils', function () {
       await expect(ethers.provider.getBalance(this.anotherTarget)).to.eventually.equal(value2);
     });
 
+    it('default to calling self is target is address(0) (ERC-7821 calldata compression)', async function () {
+      const data = encodeBatch(
+        [ethers.ZeroAddress, 0, this.utils.interface.encodeFunctionData('$CALLTYPE_SINGLE', [])],
+        [ethers.ZeroAddress, 0, this.utils.interface.encodeFunctionData('$CALLTYPE_BATCH', [])],
+      );
+
+      await expect(this.utils.$execBatch(data, EXEC_TYPE_DEFAULT))
+        .to.emit(this.utils, 'return$execBatch')
+        .withArgs([ethers.zeroPadBytes(CALL_TYPE_CALL, 32), ethers.zeroPadBytes(CALL_TYPE_BATCH, 32)]);
+    });
+
     it('reverts when any target reverts in default ExecType', async function () {
       const value1 = 0x012;
       const value2 = 0x234;
@@ -193,6 +225,17 @@ describe('ERC7579Utils', function () {
       await expect(ethers.provider.getStorage(this.utils.target, slot)).to.eventually.equal(value);
     });
 
+    it('default to calling self is target is address(0) (ERC-7821 calldata compression)', async function () {
+      const data = encodeDelegate(
+        ethers.ZeroAddress,
+        this.utils.interface.encodeFunctionData('$CALLTYPE_DELEGATECALL', []),
+      );
+
+      await expect(this.utils.$execDelegateCall(data, EXEC_TYPE_DEFAULT))
+        .to.emit(this.utils, 'return$execDelegateCall')
+        .withArgs([ethers.zeroPadBytes(CALL_TYPE_DELEGATE, 32)]);
+    });
+
     it('reverts when target reverts in default ExecType', async function () {
       const data = encodeDelegate(this.target, this.target.interface.encodeFunctionData('mockFunctionRevertsReason'));
       await expect(this.utils.$execDelegateCall(data, EXEC_TYPE_DEFAULT)).to.be.revertedWith(