diff --git a/.gas-snapshot b/.gas-snapshot index f8ad8e0..3d409f7 100644 --- a/.gas-snapshot +++ b/.gas-snapshot @@ -1,31 +1,31 @@ -MulticallerTest:testMultiCallerWithSignerIncrementNonceSalt(uint256) (runs: 256, μ: 80066, ~: 81872) -MulticallerTest:testMultiCallerWithSignerIncrementNonceSaltWithERC1271(uint256) (runs: 256, μ: 580304, ~: 580357) -MulticallerTest:testMulticallerCdFallback(string) (runs: 256, μ: 306501, ~: 301746) +MulticallerTest:testMultiCallerWithSignerIncrementNonceSalt(uint256) (runs: 256, μ: 83521, ~: 82301) +MulticallerTest:testMultiCallerWithSignerIncrementNonceSaltWithERC1271(uint256) (runs: 256, μ: 614878, ~: 614930) +MulticallerTest:testMulticallerCdFallback(string) (runs: 256, μ: 295907, ~: 281868) MulticallerTest:testMulticallerForwardsMessageValue() (gas: 214013) MulticallerTest:testMulticallerGetNames() (gas: 147637) MulticallerTest:testMulticallerReentrancyGuard() (gas: 19980) -MulticallerTest:testMulticallerRefund(uint256) (runs: 256, μ: 169898, ~: 172026) +MulticallerTest:testMulticallerRefund(uint256) (runs: 256, μ: 169978, ~: 172012) MulticallerTest:testMulticallerReturnDataIsProperlyEncoded() (gas: 122173) -MulticallerTest:testMulticallerReturnDataIsProperlyEncoded(string,string,uint256) (runs: 256, μ: 520631, ~: 527233) +MulticallerTest:testMulticallerReturnDataIsProperlyEncoded(string,string,uint256) (runs: 256, μ: 487938, ~: 508582) MulticallerTest:testMulticallerReturnDataIsProperlyEncoded(uint256,uint256,uint256,uint256) (runs: 256, μ: 122252, ~: 122252) MulticallerTest:testMulticallerRevertWithCustomError() (gas: 35485) MulticallerTest:testMulticallerRevertWithMessage() (gas: 38244) -MulticallerTest:testMulticallerRevertWithMessage(string) (runs: 256, μ: 39122, ~: 39181) +MulticallerTest:testMulticallerRevertWithMessage(string) (runs: 256, μ: 38922, ~: 38644) MulticallerTest:testMulticallerRevertWithNothing() (gas: 35306) MulticallerTest:testMulticallerSenderDoesNotRevertWithoutMulticallerDeployed() (gas: 3423) MulticallerTest:testMulticallerTargetGetMulticallerSender() (gas: 27448) MulticallerTest:testMulticallerWithNoData() (gas: 16213) -MulticallerTest:testMulticallerWithSigner(uint256) (runs: 256, μ: 127763, ~: 118802) +MulticallerTest:testMulticallerWithSigner(uint256) (runs: 256, μ: 131230, ~: 119355) MulticallerTest:testMulticallerWithSignerEIP712Domain() (gas: 12375) -MulticallerTest:testMulticallerWithSignerGetMulticallerSigner() (gas: 135610) -MulticallerTest:testMulticallerWithSignerInvalidateNonces(uint256) (runs: 256, μ: 79498, ~: 77716) -MulticallerTest:testMulticallerWithSignerInvalidateNoncesWithERC1271(uint256) (runs: 256, μ: 584890, ~: 584632) +MulticallerTest:testMulticallerWithSignerGetMulticallerSigner() (gas: 136389) +MulticallerTest:testMulticallerWithSignerInvalidateNonces(uint256) (runs: 256, μ: 81419, ~: 79804) +MulticallerTest:testMulticallerWithSignerInvalidateNoncesWithERC1271(uint256) (runs: 256, μ: 616664, ~: 616391) MulticallerTest:testMulticallerWithSignerNonPayableFunctions() (gas: 48884) -MulticallerTest:testMulticallerWithSignerReentrancyGuard() (gas: 124037) -MulticallerTest:testMulticallerWithSignerRevert() (gas: 203818) -MulticallerTest:testMulticallerWithSignerWithERC1271(uint256) (runs: 256, μ: 613068, ~: 601565) -MulticallerTest:testMulticallerWithSignerWithNoData() (gas: 128593) +MulticallerTest:testMulticallerWithSignerReentrancyGuard() (gas: 124909) +MulticallerTest:testMulticallerWithSignerRevert() (gas: 206240) +MulticallerTest:testMulticallerWithSignerWithERC1271(uint256) (runs: 256, μ: 659790, ~: 651359) +MulticallerTest:testMulticallerWithSignerWithNoData() (gas: 130147) MulticallerTest:testNastyCalldataRevert() (gas: 3420) MulticallerTest:testOffsetTrick(uint256,uint256,uint256) (runs: 256, μ: 571, ~: 571) -MulticallerTest:test__codesize() (gas: 49524) +MulticallerTest:test__codesize() (gas: 50276) TestPlus:test__codesize() (gas: 1102) \ No newline at end of file diff --git a/API.md b/API.md index 4f0fe2f..427f8f2 100644 --- a/API.md +++ b/API.md @@ -101,13 +101,14 @@ If you need them in your code, please copy and paste them. #### `_AGGREGATE_WITH_SIGNER_TYPEHASH` ```solidity bytes32 private constant _AGGREGATE_WITH_SIGNER_TYPEHASH = - 0xc4d2f044d99707794280032fc14879a220a3f7dc766d75100809624f91d69e97; + 0xfb989fd34c8af81a76f18167f528fc7315f92cacc19a0e63215abd54633f8a28; ``` For EIP-712 signature digest calculation for the `aggregateWithSigner` function. -`keccak256("AggregateWithSigner(address[] targets,bytes[] data,uint256[] values,uint256 nonce,uint256 nonceSalt)")`. +`keccak256("AggregateWithSigner(address signer,address[] targets,bytes[] data,uint256[] values,uint256 nonce,uint256 nonceSalt)")`. +- `signer`: The signer of the signature. - `targets`: An array of addresses to call. - `data`: An array of calldata to forward to the targets. - `values`: How much ETH to forward to each target. @@ -117,26 +118,28 @@ For EIP-712 signature digest calculation for the `aggregateWithSigner` function. #### `_INVALIDATE_NONCES_FOR_SIGNER_TYPEHASH` ```solidity bytes32 private constant _INVALIDATE_NONCES_FOR_SIGNER_TYPEHASH = - 0xe75b4aefef1358e66ac7ed2f180022e0a7f661dcd2781630ce58e05bb8bdb1c1; + 0x12b047058eea3df4085cdc159a103d9c100c4e78cfb7029cc39d02cb8b9e48f5; ``` For EIP-712 signature digest calculation for the `invalidateNoncesForSigner` function. -`keccak256("InvalidateNoncesForSigner(uint256[] nonces,uint256 nonceSalt)")`. +`keccak256("InvalidateNoncesForSigner(address signer,uint256[] nonces,uint256 nonceSalt)")`. +- `signer`: The signer of the signature. - `nonces`: The array of nonces for the signer. - `nonceSalt`: The current nonce salt of the signer. #### `_INCREMENT_NONCE_SALT_FOR_SIGNER_TYPEHASH` ```solidity bytes32 private constant _INCREMENT_NONCE_SALT_FOR_SIGNER_TYPEHASH = - 0x898da98c106c91ce6f05405740b0ed23b5c4dc847a0dd1996fb93189d8310bef; + 0xfa181078c7d1d4d369301511d3c5611e9367d0cebbf65eefdee9dfc75849c1d3; ``` For EIP-712 signature digest calculation for the `incrementNonceSaltForSigner` function. -`keccak256("IncrementNonceSaltForSigner(uint256 nonceSalt)")`. +`keccak256("IncrementNonceSaltForSigner(address signer,uint256 nonceSalt)")`. +- `signer`: The signer of the signature. - `nonceSalt`: The current nonce salt of the signer. #### `_DOMAIN_TYPEHASH` @@ -327,7 +330,7 @@ The address of the multicaller with sender contract. #### `MULTICALLER_WITH_SIGNER` ```solidity address internal constant MULTICALLER_WITH_SIGNER = - 0x0000000000005e17F9eA3651537Cffda3946E0be; + 0x000000000000D9ECebf3C23529de49815Dac1c4c; ``` The address of the multicaller with signer contract. diff --git a/README.md b/README.md index 5b07a0d..01ec733 100644 --- a/README.md +++ b/README.md @@ -14,31 +14,31 @@ Please open an issue if you need help to deploy to an EVM chain of your choice. - Ethereum - Multicaller: [`0x0000000000002Bdbf1Bf3279983603Ec279CC6dF`](https://etherscan.io/address/0x0000000000002Bdbf1Bf3279983603Ec279CC6dF) - MulticallerWithSender: [`0x00000000002Fd5Aeb385D324B580FCa7c83823A0`](https://etherscan.io/address/0x00000000002Fd5Aeb385D324B580FCa7c83823A0) - - MulticallerWithSigner: [`0x0000000000005e17F9eA3651537Cffda3946E0be`](https://etherscan.io/address/0x0000000000005e17F9eA3651537Cffda3946E0be) + - MulticallerWithSigner: [`0x000000000000D9ECebf3C23529de49815Dac1c4c`](https://etherscan.io/address/0x000000000000D9ECebf3C23529de49815Dac1c4c) - Goerli - Multicaller: [`0x0000000000002Bdbf1Bf3279983603Ec279CC6dF`](https://goerli.etherscan.io/address/0x0000000000002Bdbf1Bf3279983603Ec279CC6dF) - MulticallerWithSender: [`0x00000000002Fd5Aeb385D324B580FCa7c83823A0`](https://goerli.etherscan.io/address/0x00000000002Fd5Aeb385D324B580FCa7c83823A0) - - MulticallerWithSigner: [`0x0000000000005e17F9eA3651537Cffda3946E0be`](https://goerli.etherscan.io/address/0x0000000000005e17F9eA3651537Cffda3946E0be) + - MulticallerWithSigner: [`0x000000000000D9ECebf3C23529de49815Dac1c4c`](https://goerli.etherscan.io/address/0x000000000000D9ECebf3C23529de49815Dac1c4c) - Sepolia - Multicaller: [`0x0000000000002Bdbf1Bf3279983603Ec279CC6dF`](https://sepolia.etherscan.io/address/0x0000000000002Bdbf1Bf3279983603Ec279CC6dF) - MulticallerWithSender: [`0x00000000002Fd5Aeb385D324B580FCa7c83823A0`](https://sepolia.etherscan.io/address/0x00000000002Fd5Aeb385D324B580FCa7c83823A0) - - MulticallerWithSigner: [`0x0000000000005e17F9eA3651537Cffda3946E0be`](https://sepolia.etherscan.io/address/0x0000000000005e17F9eA3651537Cffda3946E0be) + - MulticallerWithSigner: [`0x000000000000D9ECebf3C23529de49815Dac1c4c`](https://sepolia.etherscan.io/address/0x000000000000D9ECebf3C23529de49815Dac1c4c) - Polygon - Multicaller: [`0x0000000000002Bdbf1Bf3279983603Ec279CC6dF`](https://polygonscan.com/address/0x0000000000002Bdbf1Bf3279983603Ec279CC6dF) - MulticallerWithSender: [`0x00000000002Fd5Aeb385D324B580FCa7c83823A0`](https://polygonscan.com/address/0x00000000002Fd5Aeb385D324B580FCa7c83823A0) - - MulticallerWithSigner: [`0x0000000000005e17F9eA3651537Cffda3946E0be`](https://polygonscan.com/address/0x0000000000005e17F9eA3651537Cffda3946E0be) + - MulticallerWithSigner: [`0x000000000000D9ECebf3C23529de49815Dac1c4c`](https://polygonscan.com/address/0x000000000000D9ECebf3C23529de49815Dac1c4c) - Mumbai - Multicaller: [`0x0000000000002Bdbf1Bf3279983603Ec279CC6dF`](https://mumbai.polygonscan.com/address/0x0000000000002Bdbf1Bf3279983603Ec279CC6dF) - MulticallerWithSender: [`0x00000000002Fd5Aeb385D324B580FCa7c83823A0`](https://mumbai.polygonscan.com/address/0x00000000002Fd5Aeb385D324B580FCa7c83823A0) - - MulticallerWithSigner: [`0x0000000000005e17F9eA3651537Cffda3946E0be`](https://mumbai.polygonscan.com/address/0x0000000000005e17F9eA3651537Cffda3946E0be) + - MulticallerWithSigner: [`0x000000000000D9ECebf3C23529de49815Dac1c4c`](https://mumbai.polygonscan.com/address/0x000000000000D9ECebf3C23529de49815Dac1c4c) - Optimism - Multicaller: [`0x0000000000002Bdbf1Bf3279983603Ec279CC6dF`](https://optimistic.etherscan.io/address/0x0000000000002Bdbf1Bf3279983603Ec279CC6dF) - MulticallerWithSender: [`0x00000000002Fd5Aeb385D324B580FCa7c83823A0`](https://optimistic.etherscan.io/address/0x00000000002Fd5Aeb385D324B580FCa7c83823A0) - - MulticallerWithSigner: [`0x0000000000005e17F9eA3651537Cffda3946E0be`](https://optimistic.etherscan.io/address/0x0000000000005e17F9eA3651537Cffda3946E0be) + - MulticallerWithSigner: [`0x000000000000D9ECebf3C23529de49815Dac1c4c`](https://optimistic.etherscan.io/address/0x000000000000D9ECebf3C23529de49815Dac1c4c) - Arbitrum - Multicaller: [`0x0000000000002Bdbf1Bf3279983603Ec279CC6dF`](https://arbiscan.io/address/0x0000000000002Bdbf1Bf3279983603Ec279CC6dF) - MulticallerWithSender: [`0x00000000002Fd5Aeb385D324B580FCa7c83823A0`](https://arbiscan.io/address/0x00000000002Fd5Aeb385D324B580FCa7c83823A0) - - MulticallerWithSigner: [`0x0000000000005e17F9eA3651537Cffda3946E0be`](https://arbiscan.io/address/0x0000000000005e17F9eA3651537Cffda3946E0be) + - MulticallerWithSigner: [`0x000000000000D9ECebf3C23529de49815Dac1c4c`](https://arbiscan.io/address/0x000000000000D9ECebf3C23529de49815Dac1c4c) ## Contracts diff --git a/package.json b/package.json index 8c8ac09..d31ebaf 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "multicaller", "license": "MIT", - "version": "1.3.0", + "version": "1.3.1", "description": "Efficient multicaller contract", "files": [ "src/**/*.sol" diff --git a/src/LibMulticaller.sol b/src/LibMulticaller.sol index 02cdedc..76aaefc 100644 --- a/src/LibMulticaller.sol +++ b/src/LibMulticaller.sol @@ -30,7 +30,7 @@ library LibMulticaller { /** * @dev The address of the multicaller with signer contract. */ - address internal constant MULTICALLER_WITH_SIGNER = 0x0000000000005e17F9eA3651537Cffda3946E0be; + address internal constant MULTICALLER_WITH_SIGNER = 0x000000000000D9ECebf3C23529de49815Dac1c4c; /** * @dev Returns the caller of `aggregateWithSender` on `MULTICALLER_WITH_SENDER`. diff --git a/src/MulticallerEtcher.sol b/src/MulticallerEtcher.sol index a6896bf..9e88b47 100644 --- a/src/MulticallerEtcher.sol +++ b/src/MulticallerEtcher.sol @@ -48,14 +48,14 @@ library MulticallerEtcher { * @dev The initcode for the multicaller with signer. */ bytes internal constant MULTICALLER_WITH_SIGNER_INITCODE = - hex"60808060405260013d55610a5d90816100168239f3fe6040608081526004361015610020575b50361561001b57600080fd5b610783565b6000803560e01c91826317447cf1146100aa57505080632eb48a80146100a55780633aeb2206146100a057806356b1a87f1461009b57806384b0196e1461009657806387ec11ca14610091578063ad3aacb81461008c5763f0c60f1a14610087573861000f565b61072d565b61069d565b6104a1565b61044c565b61028f565b61023e565b6101a3565b346101275780600319360112610127576100c261012b565b9060243567ffffffffffffffff8111610123576100e3903690600401610172565b909284528060051b92845b848103610102575050602084526020520190f35b80602091830135808352603f8820549060ff161c60011681860152016100ee565b8380fd5b5080fd5b600435906001600160a01b038216820361014157565b600080fd5b602435906001600160a01b038216820361014157565b608435906001600160a01b038216820361014157565b9181601f840112156101415782359167ffffffffffffffff8311610141576020808501948460051b01011161014157565b34610141576020806003193601126101415760043567ffffffffffffffff8111610141576101d5903690600401610172565b6000913383528160051b91835b83810361021f5750848495849552526040377fc45e3a0dd412bcad8d62398d74d66b1c8449f38beb10da275e4da0c6d3a811a4339160400183a280f35b8086918401358083526001603f88209160ff161b8154179055016101e2565b346101415760203660031901126101415761025761012b565b3001543d5260203df35b9181601f840112156101415782359167ffffffffffffffff8311610141576020838186019501011161014157565b34610141576040366003190112610141576102a861012b565b60243567ffffffffffffffff8111610141576102c8903690600401610261565b9190308201908154907f898da98c106c91ce6f05405740b0ed23b5c4dc847a0dd1996fb93189d8310bef3d5260209482865260403d206040527f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f6060527f301013e8a31863902646dc218ecd889c37491c2967a8104d5ff1cf42af0f9ea46080527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc660a0524660c0523060e05260a060602086526119013d52856042601e209160009360418214610429575b84156103ef575b50505050156103e15760019060001943014060e01c01018091556000527f997a42216df16c8b9e7caf2fc71c59dba956f1f2b12320f87a80a5879464217d826000a26000f35b638baa579f6000526004601cfd5b6024929394509080606492630b135d3f60e11b968760005260045260408552816044528337016000875afa9060245114163885818061039b565b93600160808492863d52848860403781513d1a8452825afa5187143d0293610394565b3461014157600036600319011261014157600f3d5360e060205275154d756c746963616c6c6572576974685369676e657260f55261012060405261013161012152466060523060805261016060c0526101803df35b346101415760603660031901126101415767ffffffffffffffff600435818111610141576104d3903690600401610172565b6104de929192610146565b91604435908111610141576104f7903690600401610261565b90938260051b927fe75b4aefef1358e66ac7ed2f180022e0a7f661dcd2781630ce58e05bb8bdb1c13d526020958483883784872087523086015493604094855260603d2085527f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f6060527f301013e8a31863902646dc218ecd889c37491c2967a8104d5ff1cf42af0f9ea46080527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc660a0524660c0523060e05260a060602088526119013d52876042601e20916000936041821461067b575b8415610642575b50505050156103e1578460005260005b8481036106225750908391867fc45e3a0dd412bcad8d62398d74d66b1c8449f38beb10da275e4da0c6d3a811a49697600052528237016000a2005b8087918401358083526001603f6000209160ff161b8154179055016105e7565b6024929394509080606492630b135d3f60e11b9687600052600452898552816044528337016000895afa906024511416388781806105d7565b93600160808492863d5284888c3781513d1a8452825afa5189143d02936105d0565b60c03660031901126101415767ffffffffffffffff600435818111610141576106ca903690600401610172565b9091602435818111610141576106e4903690600401610172565b604494919435838111610141576106ff903690600401610172565b9161070861015c565b9460a43590811161014157610721903690600401610261565b9790966064359561078d565b3461014157600080600319360112610780576020903033016001815460001943014060e01c01018091558152337f997a42216df16c8b9e7caf2fc71c59dba956f1f2b12320f87a80a5879464217d8383a2f35b80fd5b3d54600c5260203df35b97919490969298959860609181148189141615610a1a573d5460011615610a0d5760051b9283853d37833d20993d5b8581036109f15750843d2093858b3d37853d207f7d4195b902a78aa23ae8c64d4cecdf8424f3171e7c7e34ed94e6fab3efd018ab3d526020998a91825260409d8e9788528652836080523085015460a05260c03d2087527f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f86527f301013e8a31863902646dc218ecd889c37491c2967a8104d5ff1cf42af0f9ea46080527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc660a0524660c0523060e05260a0862082526119013d526042601e2092600097604183146109cf575b8815610993575b50505083915052808b52603f9384892091600183549160ff161b918183169015176103e1571790558660005260018752807fc45e3a0dd412bcad8d62398d74d66b1c8449f38beb10da275e4da0c6d3a811a4836000a2831561098b57819895981b600055889280898b37808a01955b8a6000808a8d89510193860193803591829101853783603f19808b8d010135908b880101355af115610981578289918d9488523d90523d60008683013e85601f19913d010116950199878b146109725799949150610919565b82868b8b526001600055016000f35b3d6000803e3d6000fd5b898488526000f35b60249394959850918091606493630b135d3f60e11b97886000526004528552816044528337016000855afa90602451141692388881808e6108aa565b97600160808592873d5285858d3781513d1a8452825afa5186143d02976108a3565b80602080928a01358a01803591829101833781208152016107bc565b63ab143c063d526004601cfd5b633b800a463d526004601cfdfea2646970667358221220b8de01d46ec7716c4271aa1bbc40baf8fa8bca536b5923f361c16810a8e7ffed64736f6c63430008120033"; + hex"60808060405260013d55610b6d90816100168239f3fe6040608081526004361015610020575b50361561001b57600080fd5b610839565b6000803560e01c91826317447cf1146100aa57505080632eb48a80146100a55780633aeb2206146100a057806356b1a87f1461009b57806384b0196e1461009657806387ec11ca14610091578063ad3aacb81461008c5763f0c60f1a14610087573861000f565b6107e3565b610753565b610507565b6104b2565b61028f565b61023e565b6101a3565b346101275780600319360112610127576100c261012b565b9060243567ffffffffffffffff8111610123576100e3903690600401610172565b909284528060051b92845b848103610102575050602084526020520190f35b80602091830135808352603f8820549060ff161c60011681860152016100ee565b8380fd5b5080fd5b600435906001600160a01b038216820361014157565b600080fd5b602435906001600160a01b038216820361014157565b608435906001600160a01b038216820361014157565b9181601f840112156101415782359167ffffffffffffffff8311610141576020808501948460051b01011161014157565b34610141576020806003193601126101415760043567ffffffffffffffff8111610141576101d5903690600401610172565b6000913383528160051b91835b83810361021f5750848495849552526040377fc45e3a0dd412bcad8d62398d74d66b1c8449f38beb10da275e4da0c6d3a811a4339160400183a280f35b8086918401358083526001603f88209160ff161b8154179055016101e2565b346101415760203660031901126101415761025761012b565b3001543d5260203df35b9181601f840112156101415782359167ffffffffffffffff8311610141576020838186019501011161014157565b3461014157604080600319360112610141576102a961012b565b602491823567ffffffffffffffff8111610141576102cc60049136908301610261565b85929192308601948554947ffa181078c7d1d4d369301511d3c5611e9367d0cebbf65eefdee9dfc75849c1d33d526020988991898352878452606095863d2085527f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f87528360807f301013e8a31863902646dc218ecd889c37491c2967a8104d5ff1cf42af0f9ea481527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc660a0524660c0523060e05260a0892082526119013d526042601e209887841461045b575b506041831461041d575b5050630b135d3f60e11b94600097868952895283528060445280606492833701858a5afa91511416156104125750506001905b60001943014060e01c01018091556000527f997a42216df16c8b9e7caf2fc71c59dba956f1f2b12320f87a80a5879464217d826000a26000f35b638baa579f9052601cfd5b9091929350873d528284873780513d1a82526001906000825afa518a183d15171561044c5790849183386103a5565b505050505050506001906103d8565b3d8a90528685013560ff81901c601b018852853589526001600160ff1b0316905292935090919050836001826000825afa518b183d1517156104a25790838693923861039b565b50505050505050506001906103d8565b3461014157600036600319011261014157600f3d5360e060205275154d756c746963616c6c6572576974685369676e657260f55261012060405261013161012152466060523060805261016060c0526101803df35b346101415760608060031936011261014157600467ffffffffffffffff81358181116101415761053a9036908401610172565b929091610545610146565b9260449182359081116101415761055f9036908501610261565b9390968660051b947f12b047058eea3df4085cdc159a103d9c100c4e78cfb7029cc39d02cb8b9e48f53d52602098878a5289604096888789378888208852308a01548552816080803d208a527f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f87527f301013e8a31863902646dc218ecd889c37491c2967a8104d5ff1cf42af0f9ea481527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc660a0524660c0523060e05260a0872082526119013d526042601e20968a8714610708575b50604186146106d6575b5050630b135d3f60e11b9260009584875287528460249586938b85525280606492833701858b5afa91511416156104125750505b600094848652855b8481036106b757509083918787987fc45e3a0dd412bcad8d62398d74d66b1c8449f38beb10da275e4da0c6d3a811a49798525282370183a280f35b8088918401358083526001603f8a209160ff161b81541790550161067c565b863d5285858b3780513d1a82526001906000825afa518a183d1517156106fd578138610640565b505050505050610674565b3d8890528585013560ff81901c601b01865286358c526001600160ff1b031690529050826001826000825afa518b183d15171561074757829038610636565b50505050505050610674565b60c03660031901126101415767ffffffffffffffff60043581811161014157610780903690600401610172565b90916024358181116101415761079a903690600401610172565b604494919435838111610141576107b5903690600401610172565b916107be61015c565b9460a435908111610141576107d7903690600401610261565b97909660643595610843565b3461014157600080600319360112610836576020903033016001815460001943014060e01c01018091558152337f997a42216df16c8b9e7caf2fc71c59dba956f1f2b12320f87a80a5879464217d8383a2f35b80fd5b3d54600c5260203df35b969893949195929790976060928114818a141615610b2a573d5460011615610b1d5760051b9384863d37843d20913d5b868103610b015750853d20868a3d37863d207ffb989fd34c8af81a76f18167f528fc7315f92cacc19a0e63215abd54633f8a283d528c602052604052845260809283528460a052308b015460c05260e03d206040527f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f84527f301013e8a31863902646dc218ecd889c37491c2967a8104d5ff1cf42af0f9ea483527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc660a0524660c0523060e05260a084206020526119013d526042601e209260408314610ac2575b60418314610a91575b50630b135d3f60e11b602060009382855260049586528d856024958693604085528060445280606492833701915afa91511416156104125750505b8760205281604052603f918260202090600182549160ff161b90808216610a8357179055600097602089526001602052807fc45e3a0dd412bcad8d62398d74d66b1c8449f38beb10da275e4da0c6d3a811a4838ba28315610a7a5781969395961b885587604093868860403786604001965b8551890190838060206040840194803591829101863784603f198b8d0181013590888d0101355af115610a71576020918188523d90523d848683013e85601f19913d010116950197878914610a61579794610a0b565b826040878c602052600183550190f35b833d81803e3d90fd5b60408985602052f35b638baa579f6000526004601cfd5b6001602091853d52848460403780513d1a83526000825afa518b183d151715610aba573861095e565b505050610999565b3d84905260208281013560ff81901c601b01825283356040526001600160ff1b031686526001826000825afa518c183d15176109555750505050610999565b80602080928b01358b0180359182910183378120815201610873565b63ab143c063d526004601cfd5b633b800a463d526004601cfdfea2646970667358221220b683a260ba0dddc73675b5b1b1f3f56075ddbb13397d349dfdb5e7fc3e1e3bb164736f6c63430008120033"; /** * @dev The salt for the multicaller with signer to be deployed via * 0age's immutable create2 factory. */ bytes32 internal constant MULTICALLER_WITH_SIGNER_CREATE2_SALT = - 0x00000000000000000000000000000000000000008464708f40b03f03ab30866f; + 0x0000000000000000000000000000000000000000d7eebd756f8ae3022dc33bdb; // ============================================================= // OPERATIONS diff --git a/src/MulticallerWithSigner.sol b/src/MulticallerWithSigner.sol index fc5ab8a..0e6fe3c 100644 --- a/src/MulticallerWithSigner.sol +++ b/src/MulticallerWithSigner.sol @@ -48,26 +48,26 @@ contract MulticallerWithSigner { /** * @dev For EIP-712 signature digest calculation for the * `aggregateWithSigner` function. - * `keccak256("AggregateWithSigner(address[] targets,bytes[] data,uint256[] values,uint256 nonce,uint256 nonceSalt)")`. + * `keccak256("AggregateWithSigner(address signer,address[] targets,bytes[] data,uint256[] values,uint256 nonce,uint256 nonceSalt)")`. */ bytes32 private constant _AGGREGATE_WITH_SIGNER_TYPEHASH = - 0x7d4195b902a78aa23ae8c64d4cecdf8424f3171e7c7e34ed94e6fab3efd018ab; + 0xfb989fd34c8af81a76f18167f528fc7315f92cacc19a0e63215abd54633f8a28; /** * @dev For EIP-712 signature digest calculation for the * `invalidateNoncesForSigner` function. - * `keccak256("InvalidateNoncesForSigner(uint256[] nonces,uint256 nonceSalt)")`. + * `keccak256("InvalidateNoncesForSigner(address signer,uint256[] nonces,uint256 nonceSalt)")`. */ bytes32 private constant _INVALIDATE_NONCES_FOR_SIGNER_TYPEHASH = - 0xe75b4aefef1358e66ac7ed2f180022e0a7f661dcd2781630ce58e05bb8bdb1c1; + 0x12b047058eea3df4085cdc159a103d9c100c4e78cfb7029cc39d02cb8b9e48f5; /** * @dev For EIP-712 signature digest calculation for the * `incrementNonceSaltForSigner` function. - * `keccak256("IncrementNonceSaltForSigner(uint256 nonceSalt)")`. + * `keccak256("IncrementNonceSaltForSigner(address signer,uint256 nonceSalt)")`. */ bytes32 private constant _INCREMENT_NONCE_SALT_FOR_SIGNER_TYPEHASH = - 0x898da98c106c91ce6f05405740b0ed23b5c4dc847a0dd1996fb93189d8310bef; + 0xfa181078c7d1d4d369301511d3c5611e9367d0cebbf65eefdee9dfc75849c1d3; /** * @dev For EIP-712 signature digest calculation. @@ -194,12 +194,13 @@ contract MulticallerWithSigner { // Layout the fields of the struct hash. mstore(returndatasize(), _AGGREGATE_WITH_SIGNER_TYPEHASH) - mstore(0x20, targetsHash) - mstore(0x40, dataHash) - mstore(0x60, valuesHash) - mstore(0x80, nonce) - mstore(0xa0, sload(add(signer, address()))) // Store the nonce salt. - mstore(0x40, keccak256(returndatasize(), 0xc0)) // Compute and store the struct hash. + mstore(0x20, signer) + mstore(0x40, targetsHash) + mstore(0x60, dataHash) + mstore(0x80, valuesHash) + mstore(0xa0, nonce) + mstore(0xc0, sload(add(signer, address()))) // Store the nonce salt. + mstore(0x40, keccak256(returndatasize(), 0xe0)) // Compute and store the struct hash. // Layout the fields of the domain separator. mstore(0x60, _DOMAIN_TYPEHASH) mstore(0x80, _NAME_HASH) @@ -210,16 +211,24 @@ contract MulticallerWithSigner { // Layout the fields of `ecrecover`. mstore(returndatasize(), 0x1901) // Store "\x19\x01". let digest := keccak256(0x1e, 0x42) // Compute the digest. - let signatureIsValid := 0 - if eq(signature.length, 65) { - mstore(returndatasize(), digest) // Store the digest. - calldatacopy(0x40, signature.offset, signature.length) // Copy `r`, `s`, `v`. - mstore(0x20, byte(returndatasize(), mload(0x80))) // `v`. - let t := staticcall(gas(), 1, 0x00, 0x80, 0x01, 0x20) - signatureIsValid := mul(returndatasize(), eq(signer, mload(t))) - } - // ERC1271 fallback. - if iszero(signatureIsValid) { + for {} 1 {} { + if eq(signature.length, 64) { + mstore(returndatasize(), digest) // Store the digest. + let vs := calldataload(add(signature.offset, 0x20)) + mstore(0x20, add(shr(255, vs), 27)) // `v`. + mstore(0x40, calldataload(signature.offset)) // `r`. + mstore(0x60, shr(1, shl(1, vs))) // `s`. + let t := staticcall(gas(), 1, 0x00, 0x80, 0x01, 0x20) + if iszero(or(iszero(returndatasize()), xor(signer, mload(t)))) { break } + } + if eq(signature.length, 65) { + mstore(returndatasize(), digest) // Store the digest. + calldatacopy(0x40, signature.offset, signature.length) // Copy `r`, `s`, `v`. + mstore(0x20, byte(returndatasize(), mload(0x80))) // `v`. + let t := staticcall(gas(), 1, 0x00, 0x80, 0x01, 0x20) + if iszero(or(iszero(returndatasize()), xor(signer, mload(t)))) { break } + } + // ERC1271 fallback. let f := shl(224, 0x1626ba7e) // `isValidSignature(bytes32,bytes)`. mstore(0x00, f) mstore(0x04, digest) @@ -227,7 +236,11 @@ contract MulticallerWithSigner { mstore(0x44, signature.length) calldatacopy(0x64, signature.offset, signature.length) let t := staticcall(gas(), signer, 0x00, add(signature.length, 0x64), 0x24, 0x20) - signatureIsValid := and(eq(mload(0x24), f), t) + if iszero(and(eq(mload(0x24), f), t)) { + mstore(0x00, 0x8baa579f) // `InvalidSignature()`. + revert(0x1c, 0x04) + } + break } // Check the nonce. @@ -236,7 +249,7 @@ contract MulticallerWithSigner { let bucketSlot := keccak256(0x20, 0x3f) let bucketValue := sload(bucketSlot) let bit := shl(and(0xff, nonce), 1) - if or(iszero(signatureIsValid), and(bit, bucketValue)) { + if and(bit, bucketValue) { mstore(0x00, 0x8baa579f) // `InvalidSignature()`. revert(0x1c, 0x04) } @@ -362,11 +375,12 @@ contract MulticallerWithSigner { let end := shl(5, nonces.length) // Layout the fields of the struct hash. mstore(returndatasize(), _INVALIDATE_NONCES_FOR_SIGNER_TYPEHASH) + mstore(0x20, signer) // Compute and store `keccak256(abi.encodePacked(nonces))`. - calldatacopy(0x20, nonces.offset, end) - mstore(0x20, keccak256(0x20, end)) - mstore(0x40, sload(add(signer, address()))) // Store the nonce salt. - mstore(0x40, keccak256(returndatasize(), 0x60)) // Compute and store the struct hash. + calldatacopy(0x40, nonces.offset, end) + mstore(0x40, keccak256(0x40, end)) + mstore(0x60, sload(add(signer, address()))) // Store the nonce salt. + mstore(0x40, keccak256(returndatasize(), 0x80)) // Compute and store the struct hash. // Layout the fields of the domain separator. mstore(0x60, _DOMAIN_TYPEHASH) mstore(0x80, _NAME_HASH) @@ -377,16 +391,24 @@ contract MulticallerWithSigner { // Layout the fields of `ecrecover`. mstore(returndatasize(), 0x1901) // Store "\x19\x01". let digest := keccak256(0x1e, 0x42) // Compute the digest. - let signatureIsValid := 0 - if eq(signature.length, 65) { - mstore(returndatasize(), digest) // Store the digest. - calldatacopy(0x40, signature.offset, signature.length) // Copy `r`, `s`, `v`. - mstore(0x20, byte(returndatasize(), mload(0x80))) // `v`. - let t := staticcall(gas(), 1, 0x00, 0x80, 0x01, 0x20) - signatureIsValid := mul(returndatasize(), eq(signer, mload(t))) - } - // ERC1271 fallback. - if iszero(signatureIsValid) { + for {} 1 {} { + if eq(signature.length, 64) { + mstore(returndatasize(), digest) // Store the digest. + let vs := calldataload(add(signature.offset, 0x20)) + mstore(0x20, add(shr(255, vs), 27)) // `v`. + mstore(0x40, calldataload(signature.offset)) // `r`. + mstore(0x60, shr(1, shl(1, vs))) // `s`. + let t := staticcall(gas(), 1, 0x00, 0x80, 0x01, 0x20) + if iszero(or(iszero(returndatasize()), xor(signer, mload(t)))) { break } + } + if eq(signature.length, 65) { + mstore(returndatasize(), digest) // Store the digest. + calldatacopy(0x40, signature.offset, signature.length) // Copy `r`, `s`, `v`. + mstore(0x20, byte(returndatasize(), mload(0x80))) // `v`. + let t := staticcall(gas(), 1, 0x00, 0x80, 0x01, 0x20) + if iszero(or(iszero(returndatasize()), xor(signer, mload(t)))) { break } + } + // ERC1271 fallback. let f := shl(224, 0x1626ba7e) // `isValidSignature(bytes32,bytes)`. mstore(0x00, f) mstore(0x04, digest) @@ -394,11 +416,11 @@ contract MulticallerWithSigner { mstore(0x44, signature.length) calldatacopy(0x64, signature.offset, signature.length) let t := staticcall(gas(), signer, 0x00, add(signature.length, 0x64), 0x24, 0x20) - signatureIsValid := and(eq(mload(0x24), f), t) - } - if iszero(signatureIsValid) { - mstore(0x00, 0x8baa579f) // `InvalidSignature()`. - revert(0x1c, 0x04) + if iszero(and(eq(mload(0x24), f), t)) { + mstore(0x00, 0x8baa579f) // `InvalidSignature()`. + revert(0x1c, 0x04) + } + break } mstore(0x00, signer) @@ -483,8 +505,9 @@ contract MulticallerWithSigner { let nonceSalt := sload(nonceSaltSlot) // Layout the fields of the struct hash. mstore(returndatasize(), _INCREMENT_NONCE_SALT_FOR_SIGNER_TYPEHASH) - mstore(0x20, nonceSalt) // Store the nonce salt. - mstore(0x40, keccak256(returndatasize(), 0x40)) // Compute and store the struct hash. + mstore(0x20, signer) + mstore(0x40, nonceSalt) // Store the nonce salt. + mstore(0x40, keccak256(returndatasize(), 0x60)) // Compute and store the struct hash. // Layout the fields of the domain separator. mstore(0x60, _DOMAIN_TYPEHASH) mstore(0x80, _NAME_HASH) @@ -495,16 +518,24 @@ contract MulticallerWithSigner { // Layout the fields of `ecrecover`. mstore(returndatasize(), 0x1901) // Store "\x19\x01". let digest := keccak256(0x1e, 0x42) // Compute the digest. - let signatureIsValid := 0 - if eq(signature.length, 65) { - mstore(returndatasize(), digest) // Store the digest. - calldatacopy(0x40, signature.offset, signature.length) // Copy `r`, `s`, `v`. - mstore(0x20, byte(returndatasize(), mload(0x80))) // `v`. - let t := staticcall(gas(), 1, 0x00, 0x80, 0x01, 0x20) - signatureIsValid := mul(returndatasize(), eq(signer, mload(t))) - } - // ERC1271 fallback. - if iszero(signatureIsValid) { + for {} 1 {} { + if eq(signature.length, 64) { + mstore(returndatasize(), digest) // Store the digest. + let vs := calldataload(add(signature.offset, 0x20)) + mstore(0x20, add(shr(255, vs), 27)) // `v`. + mstore(0x40, calldataload(signature.offset)) // `r`. + mstore(0x60, shr(1, shl(1, vs))) // `s`. + let t := staticcall(gas(), 1, 0x00, 0x80, 0x01, 0x20) + if iszero(or(iszero(returndatasize()), xor(signer, mload(t)))) { break } + } + if eq(signature.length, 65) { + mstore(returndatasize(), digest) // Store the digest. + calldatacopy(0x40, signature.offset, signature.length) // Copy `r`, `s`, `v`. + mstore(0x20, byte(returndatasize(), mload(0x80))) // `v`. + let t := staticcall(gas(), 1, 0x00, 0x80, 0x01, 0x20) + if iszero(or(iszero(returndatasize()), xor(signer, mload(t)))) { break } + } + // ERC1271 fallback. let f := shl(224, 0x1626ba7e) // `isValidSignature(bytes32,bytes)`. mstore(0x00, f) mstore(0x04, digest) @@ -512,11 +543,11 @@ contract MulticallerWithSigner { mstore(0x44, signature.length) calldatacopy(0x64, signature.offset, signature.length) let t := staticcall(gas(), signer, 0x00, add(signature.length, 0x64), 0x24, 0x20) - signatureIsValid := and(eq(mload(0x24), f), t) - } - if iszero(signatureIsValid) { - mstore(0x00, 0x8baa579f) // `InvalidSignature()`. - revert(0x1c, 0x04) + if iszero(and(eq(mload(0x24), f), t)) { + mstore(0x00, 0x8baa579f) // `InvalidSignature()`. + revert(0x1c, 0x04) + } + break } // Increment by some pseudorandom amount from [1..4294967296]. diff --git a/test/Multicaller.t.sol b/test/Multicaller.t.sol index f35153a..5beb6b7 100644 --- a/test/Multicaller.t.sol +++ b/test/Multicaller.t.sol @@ -460,8 +460,9 @@ contract MulticallerTest is TestPlus { keccak256( abi.encode( keccak256( - "AggregateWithSigner(address[] targets,bytes[] data,uint256[] values,uint256 nonce,uint256 nonceSalt)" + "AggregateWithSigner(address signer,address[] targets,bytes[] data,uint256[] values,uint256 nonce,uint256 nonceSalt)" ), + t.signer, keccak256(abi.encodePacked(t.targets)), keccak256(abi.encodePacked(dataHashes)), keccak256(abi.encodePacked(t.values)), @@ -753,7 +754,7 @@ contract MulticallerTest is TestPlus { returns (bytes[] memory results) { results = multicallerWithSigner.aggregateWithSigner{value: value}( - t.targets, t.data, t.values, t.nonce, t.signer, t.signature + t.targets, t.data, t.values, t.nonce, t.signer, _maybeMake2098(t.signature) ); } @@ -816,7 +817,9 @@ contract MulticallerTest is TestPlus { _generateInvalidateNoncesSignature(nonces, signer, privateKey); vm.expectEmit(true, true, true, true); emit NoncesInvalidated(signer, nonces); - multicallerWithSigner.invalidateNoncesForSigner(nonces, signer, signature); + multicallerWithSigner.invalidateNoncesForSigner( + nonces, signer, _maybeMake2098(signature) + ); } invalidated = multicallerWithSigner.noncesInvalidated(signer, nonces); @@ -861,14 +864,20 @@ contract MulticallerTest is TestPlus { _generateInvalidateNoncesSignature(nonces, erc1271Wallet, erc721SignerPrivateKey); vm.expectRevert(MulticallerWithSigner.InvalidSignature.selector); - multicallerWithSigner.invalidateNoncesForSigner(nonces, erc1271Malicious, signature); + multicallerWithSigner.invalidateNoncesForSigner( + nonces, erc1271Malicious, _maybeMake2098(signature) + ); vm.expectEmit(true, true, true, true); emit NoncesInvalidated(erc1271Wallet, nonces); - multicallerWithSigner.invalidateNoncesForSigner(nonces, erc1271Wallet, signature); + multicallerWithSigner.invalidateNoncesForSigner( + nonces, erc1271Wallet, _maybeMake2098(signature) + ); vm.expectRevert(MulticallerWithSigner.InvalidSignature.selector); - multicallerWithSigner.invalidateNoncesForSigner(nonces, erc1271Malicious, signature); + multicallerWithSigner.invalidateNoncesForSigner( + nonces, erc1271Malicious, _maybeMake2098(signature) + ); } } @@ -887,10 +896,10 @@ contract MulticallerTest is TestPlus { bytes memory signature = _generateIncrementNonceSaltSignature(signer, privateKey); vm.expectEmit(true, true, true, true); emit NonceSaltIncremented(signer, nextNonceSalt); - multicallerWithSigner.incrementNonceSaltForSigner(signer, signature); + multicallerWithSigner.incrementNonceSaltForSigner(signer, _maybeMake2098(signature)); vm.expectRevert(MulticallerWithSigner.InvalidSignature.selector); - multicallerWithSigner.incrementNonceSaltForSigner(signer, signature); + multicallerWithSigner.incrementNonceSaltForSigner(signer, _maybeMake2098(signature)); } uint256 nonceSaltAfter = multicallerWithSigner.nonceSaltOf(signer); assertEq(nextNonceSalt, nonceSaltAfter); @@ -905,13 +914,15 @@ contract MulticallerTest is TestPlus { _generateIncrementNonceSaltSignature(erc1271Wallet, erc721SignerPrivateKey); vm.expectRevert(MulticallerWithSigner.InvalidSignature.selector); - multicallerWithSigner.incrementNonceSaltForSigner(erc1271Malicious, signature); + multicallerWithSigner.incrementNonceSaltForSigner( + erc1271Malicious, _maybeMake2098(signature) + ); emit NonceSaltIncremented(erc1271Wallet, nextNonceSalt); - multicallerWithSigner.incrementNonceSaltForSigner(erc1271Wallet, signature); + multicallerWithSigner.incrementNonceSaltForSigner(erc1271Wallet, _maybeMake2098(signature)); vm.expectRevert(MulticallerWithSigner.InvalidSignature.selector); - multicallerWithSigner.incrementNonceSaltForSigner(erc1271Wallet, signature); + multicallerWithSigner.incrementNonceSaltForSigner(erc1271Wallet, _maybeMake2098(signature)); } function _generateInvalidateNoncesSignature( @@ -925,7 +936,10 @@ contract MulticallerTest is TestPlus { _multicallerWithSignerDomainSeparator(), keccak256( abi.encode( - keccak256("InvalidateNoncesForSigner(uint256[] nonces,uint256 nonceSalt)"), + keccak256( + "InvalidateNoncesForSigner(address signer,uint256[] nonces,uint256 nonceSalt)" + ), + signer, keccak256(abi.encodePacked(nonces)), multicallerWithSigner.nonceSaltOf(signer) ) @@ -946,7 +960,8 @@ contract MulticallerTest is TestPlus { _multicallerWithSignerDomainSeparator(), keccak256( abi.encode( - keccak256("IncrementNonceSaltForSigner(uint256 nonceSalt)"), + keccak256("IncrementNonceSaltForSigner(address signer,uint256 nonceSalt)"), + signer, multicallerWithSigner.nonceSaltOf(signer) ) ) @@ -970,6 +985,27 @@ contract MulticallerTest is TestPlus { ); } + function _maybeMake2098(bytes memory signature) + internal + returns (bytes memory shortSignature) + { + if (_random() % 2 == 0 || signature.length != 65) { + shortSignature = signature; + } else { + /// @solidity memory-safe-assembly + assembly { + let r := mload(add(signature, 0x20)) + let s := mload(add(signature, 0x40)) + let v := byte(0, mload(add(signature, 0x60))) + shortSignature := mload(0x40) + mstore(shortSignature, 0x40) + mstore(add(shortSignature, 0x20), r) + mstore(add(shortSignature, 0x40), or(shl(255, sub(v, 27)), s)) + mstore(0x40, add(shortSignature, 0x60)) + } + } + } + function testOffsetTrick(uint256 a, uint256 b, uint256 c) public { unchecked { uint256 aDiff = a - c; @@ -985,6 +1021,7 @@ contract MulticallerTest is TestPlus { } function testNastyCalldataRevert() public { + /// @solidity memory-safe-assembly assembly { let m := mload(0x40) diff --git a/test/utils/mocks/MockERC1271Wallet.sol b/test/utils/mocks/MockERC1271Wallet.sol index 17b0f7e..e501078 100644 --- a/test/utils/mocks/MockERC1271Wallet.sol +++ b/test/utils/mocks/MockERC1271Wallet.sol @@ -35,6 +35,93 @@ abstract contract ERC1155TokenReceiver { } } +library SignatureCheckerLib { + function isValidSignatureNowCalldata(address signer, bytes32 hash, bytes calldata signature) + internal + view + returns (bool isValid) + { + /// @solidity memory-safe-assembly + assembly { + // Clean the upper 96 bits of `signer` in case they are dirty. + for { signer := shr(96, shl(96, signer)) } signer {} { + let m := mload(0x40) + mstore(0x00, hash) + if eq(signature.length, 64) { + let vs := calldataload(add(signature.offset, 0x20)) + mstore(0x20, add(shr(255, vs), 27)) // `v`. + mstore(0x40, calldataload(signature.offset)) // `r`. + mstore(0x60, shr(1, shl(1, vs))) // `s`. + let t := + staticcall( + gas(), // Amount of gas left for the transaction. + 1, // Address of `ecrecover`. + 0x00, // Start of input. + 0x80, // Size of input. + 0x01, // Start of output. + 0x20 // Size of output. + ) + // `returndatasize()` will be `0x20` upon success, and `0x00` otherwise. + if iszero(or(iszero(returndatasize()), xor(signer, mload(t)))) { + isValid := 1 + mstore(0x60, 0) // Restore the zero slot. + mstore(0x40, m) // Restore the free memory pointer. + break + } + } + if eq(signature.length, 65) { + mstore(0x20, byte(0, calldataload(add(signature.offset, 0x40)))) // `v`. + calldatacopy(0x40, signature.offset, 0x40) // `r`, `s`. + let t := + staticcall( + gas(), // Amount of gas left for the transaction. + 1, // Address of `ecrecover`. + 0x00, // Start of input. + 0x80, // Size of input. + 0x01, // Start of output. + 0x20 // Size of output. + ) + // `returndatasize()` will be `0x20` upon success, and `0x00` otherwise. + if iszero(or(iszero(returndatasize()), xor(signer, mload(t)))) { + isValid := 1 + mstore(0x60, 0) // Restore the zero slot. + mstore(0x40, m) // Restore the free memory pointer. + break + } + } + mstore(0x60, 0) // Restore the zero slot. + mstore(0x40, m) // Restore the free memory pointer. + + let f := shl(224, 0x1626ba7e) + mstore(m, f) // `bytes4(keccak256("isValidSignature(bytes32,bytes)"))`. + mstore(add(m, 0x04), hash) + let d := add(m, 0x24) + mstore(d, 0x40) // The offset of the `signature` in the calldata. + mstore(add(m, 0x44), signature.length) + // Copy the `signature` over. + calldatacopy(add(m, 0x64), signature.offset, signature.length) + // forgefmt: disable-next-item + isValid := and( + // Whether the returndata is the magic value `0x1626ba7e` (left-aligned). + eq(mload(d), f), + // Whether the staticcall does not revert. + // This must be placed at the end of the `and` clause, + // as the arguments are evaluated from right to left. + staticcall( + gas(), // Remaining gas. + signer, // The `signer` address. + m, // Offset of calldata in memory. + add(signature.length, 0x64), // Length of calldata in memory. + d, // Offset of returndata. + 0x20 // Length of returndata to write. + ) + ) + break + } + } + } +} + /// @dev WARNING! This mock is strictly intended for testing purposes only. /// Do NOT copy anything here into production code unless you really know what you are doing. contract MockERC1271Wallet is ERC721TokenReceiver, ERC1155TokenReceiver { @@ -52,42 +139,8 @@ contract MockERC1271Wallet is ERC721TokenReceiver, ERC1155TokenReceiver { view returns (bytes4) { - return _recoverCalldata(hash, signature) == signer ? bytes4(0x1626ba7e) : bytes4(0); - } - - function _recoverCalldata(bytes32 hash, bytes calldata signature) - internal - view - returns (address result) - { - assembly { - let m := mload(0x40) // Cache the free memory pointer. - mstore(0x00, hash) - mstore(0x20, byte(0, calldataload(add(signature.offset, 0x40)))) // `v`. - calldatacopy(0x40, signature.offset, 0x40) // Copy `r` and `s`. - pop( - staticcall( - gas(), // Amount of gas left for the transaction. - and( - // If the signature is exactly 65 bytes in length. - eq(signature.length, 65), - // If `s` in lower half order, such that the signature is not malleable. - lt(mload(0x60), _MALLEABILITY_THRESHOLD_PLUS_ONE) - ), // Address of `ecrecover`. - 0x00, // Start of input. - 0x80, // Size of input. - 0x00, // Start of output. - 0x20 // Size of output. - ) - ) - result := mload(0x00) - // `returndatasize()` will be `0x20` upon success, and `0x00` otherwise. - if iszero(returndatasize()) { - mstore(0x00, 0x8baa579f) // `InvalidSignature()`. - revert(0x1c, 0x04) - } - mstore(0x60, 0) // Restore the zero slot. - mstore(0x40, m) // Restore the free memory pointer. - } + return SignatureCheckerLib.isValidSignatureNowCalldata(signer, hash, signature) + ? bytes4(0x1626ba7e) + : bytes4(0); } }