From bb00b8a3d2307fe7035c898ef299a93c1f93ebc0 Mon Sep 17 00:00:00 2001 From: Duncan Townsend Date: Wed, 17 Jul 2024 10:37:52 -0400 Subject: [PATCH 01/19] Add Linea to list of chains that do not have EIP-1559 --- sh/upgrade_deployer.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sh/upgrade_deployer.sh b/sh/upgrade_deployer.sh index 127073fe..de7921f2 100755 --- a/sh/upgrade_deployer.sh +++ b/sh/upgrade_deployer.sh @@ -187,7 +187,7 @@ if [[ ${1:-unset} = 'deploy' ]] ; then echo '' >&2 declare -a gas_price_args - if [[ $(get_config isLondon) = 'true' ]] ; then + if (( chainid != 56 )) && (( chainid != 534352 )) ; then gas_price_args=( --gas-price $gas_price --priority-gas-price $gas_price ) From 9f1b9806cdf87fd1e695b048b8d1d07b967e3aad Mon Sep 17 00:00:00 2001 From: Duncan Townsend Date: Wed, 17 Jul 2024 10:38:33 -0400 Subject: [PATCH 02/19] Revert "Remove Linea-specific files now that we're not deploying there" This reverts commit 1d9e7c5d1785bf464cac290149ec2ebe9e76ce24. --- CHANGELOG.md | 3 + src/chains/Linea.sol | 132 ++++++++++++++++++++++++++++++++++ src/core/univ3forks/Lynex.sol | 6 ++ 3 files changed, 141 insertions(+) create mode 100644 src/chains/Linea.sol create mode 100644 src/core/univ3forks/Lynex.sol diff --git a/CHANGELOG.md b/CHANGELOG.md index 8684f0b5..6c9d444a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,9 +13,12 @@ Master list of UniV3 forks: 10. BladeSwap (Algebra-like) 11. Fenix (Algebra-like) 12. ZebraV3 + 13. Lynex (Algebra-like) --- +* Deployed Settler to Linea +* Added Lynex Algebra-style UniV3 fork to Linea * Update Velodrome Slipstream factory address (and inithash) to migrated one ## 2024-07-15 diff --git a/src/chains/Linea.sol b/src/chains/Linea.sol new file mode 100644 index 00000000..09c487b3 --- /dev/null +++ b/src/chains/Linea.sol @@ -0,0 +1,132 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.25; + +import {SettlerBase} from "../SettlerBase.sol"; +import {Settler} from "../Settler.sol"; +import {SettlerMetaTxn} from "../SettlerMetaTxn.sol"; + +import {FreeMemory} from "../utils/FreeMemory.sol"; + +import {ISettlerActions} from "../ISettlerActions.sol"; +import {ISignatureTransfer} from "permit2/src/interfaces/ISignatureTransfer.sol"; +import {UnknownForkId} from "../core/SettlerErrors.sol"; + +import { + uniswapV3InitHash, + IUniswapV3Callback +} from "../core/univ3forks/UniswapV3.sol"; +import {sushiswapV3Factory, sushiswapV3ForkId} from "../core/univ3forks/SushiswapV3.sol"; +import { + pancakeSwapV3Factory, + pancakeSwapV3InitHash, + pancakeSwapV3ForkId, + IPancakeSwapV3Callback +} from "../core/univ3forks/PancakeSwapV3.sol"; +import {IAlgebraCallback} from "../core/univ3forks/Algebra.sol"; +import { + lynexFactory, + lynexInitHash, + lynexForkId +} from "../core/univ3forks/Lynex.sol"; + +// Solidity inheritance is stupid +import {SettlerAbstract} from "../SettlerAbstract.sol"; +import {AbstractContext} from "../Context.sol"; +import {Permit2PaymentAbstract} from "../core/Permit2PaymentAbstract.sol"; + +abstract contract LineaMixin is FreeMemory, SettlerBase { + constructor() { + assert(block.chainid == 59144 || block.chainid == 31337); + } + + function _dispatch(uint256 i, bytes4 action, bytes calldata data) + internal + virtual + override + DANGEROUS_freeMemory + returns (bool) + { + return super._dispatch(i, action, data); + } + + function _uniV3ForkInfo(uint8 forkId) + internal + pure + override + returns (address factory, bytes32 initHash, uint32 callbackSelector) + { + if (forkId == pancakeSwapV3ForkId) { + factory = pancakeSwapV3Factory; + initHash = pancakeSwapV3InitHash; + callbackSelector = uint32(IPancakeSwapV3Callback.pancakeV3SwapCallback.selector); + } else if (forkId == sushiswapV3ForkId) { + factory = sushiswapV3Factory; + initHash = uniswapV3InitHash; + callbackSelector = uint32(IUniswapV3Callback.uniswapV3SwapCallback.selector); + } else if (forkId == lynexForkId) { + factory = lynexFactory; + initHash = lynexInitHash; + callbackSelector = uint32(IAlgebraCallback.algebraSwapCallback.selector); + } else { + revert UnknownForkId(forkId); + } + } +} + +/// @custom:security-contact security@0x.org +contract LineaSettler is Settler, LineaMixin { + constructor(bytes20 gitCommit) SettlerBase(gitCommit) {} + + function _dispatchVIP(bytes4 action, bytes calldata data) internal override DANGEROUS_freeMemory returns (bool) { + return super._dispatchVIP(action, data); + } + + // Solidity inheritance is stupid + function _isRestrictedTarget(address target) + internal + pure + override(Settler, Permit2PaymentAbstract) + returns (bool) + { + return super._isRestrictedTarget(target); + } + + function _dispatch(uint256 i, bytes4 action, bytes calldata data) + internal + override(SettlerAbstract, SettlerBase, LineaMixin) + returns (bool) + { + return super._dispatch(i, action, data); + } + + function _msgSender() internal view override(Settler, AbstractContext) returns (address) { + return super._msgSender(); + } +} + +/// @custom:security-contact security@0x.org +contract LineaSettlerMetaTxn is SettlerMetaTxn, LineaMixin { + constructor(bytes20 gitCommit) SettlerBase(gitCommit) {} + + function _dispatchVIP(bytes4 action, bytes calldata data, bytes calldata sig) + internal + override + DANGEROUS_freeMemory + returns (bool) + { + return super._dispatchVIP(action, data, sig); + } + + // Solidity inheritance is stupid + function _dispatch(uint256 i, bytes4 action, bytes calldata data) + internal + override(SettlerAbstract, SettlerBase, LineaMixin) + returns (bool) + { + return super._dispatch(i, action, data); + } + + function _msgSender() internal view override(SettlerMetaTxn, AbstractContext) returns (address) { + return super._msgSender(); + } +} diff --git a/src/core/univ3forks/Lynex.sol b/src/core/univ3forks/Lynex.sol new file mode 100644 index 00000000..7a132351 --- /dev/null +++ b/src/core/univ3forks/Lynex.sol @@ -0,0 +1,6 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.25; + +address constant lynexFactory = 0x9A89490F1056A7BC607EC53F93b921fE666A2C48; +bytes32 constant lynexInitHash = 0xc65e01e65f37c1ec2735556a24a9c10e4c33b2613ad486dd8209d465524bc3f4; +uint8 constant lynexForkId = 13; From e9bd10a46a4e0a92b53de0f18fe5c3dcad0c80fb Mon Sep 17 00:00:00 2001 From: Duncan Townsend Date: Wed, 17 Jul 2024 11:04:23 -0400 Subject: [PATCH 03/19] Add a new `AllowanceHolder` address for London chainsn --- secrets.json.template | 5 +++++ sh/common_secrets.sh | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/secrets.json.template b/secrets.json.template index 1adf067c..359f438e 100644 --- a/secrets.json.template +++ b/secrets.json.template @@ -18,5 +18,10 @@ "address": "0x0000000000005E88410CcDFaDe4a5EfaE4b49562", "deployer": "0x4f05532AD8c7C87C22Bd793661DB6A174e09cbb5", "key": "" + }, + "allowanceHolderLondon": { + "address": "0x000000000000175a8b9bC6d539B3708EEd92EA6c", + "deployer": "0x5c50b56D83Db01245d4B7db9eAc9199c9CdbAEE1", + "key": "" } } diff --git a/sh/common_secrets.sh b/sh/common_secrets.sh index 3e81e9d6..68607157 100644 --- a/sh/common_secrets.sh +++ b/sh/common_secrets.sh @@ -14,7 +14,7 @@ if [[ $(ls -l secrets.json | cut -d' ' -f1 | cut -d. -f1) != '-rw-------' ]] ; t exit 1 fi -if ! sha256sum -c <<<'24290900be9575d1fb6349098b1c11615a2eac8091bc486bec6cf67239b7846a secrets.json' >/dev/null ; then +if ! sha256sum -c <<<'bb82de121880f1182dbae410b341749e5ac1355954ae6c03151a1826e7bba745 secrets.json' >/dev/null ; then echo 'Secrets are wrong' >&2 exit 1 fi From c71824492b1f76c62534e42d40344c4b5c3740ce Mon Sep 17 00:00:00 2001 From: Duncan Townsend Date: Wed, 17 Jul 2024 11:06:22 -0400 Subject: [PATCH 04/19] `forge fmt` --- src/chains/Linea.sol | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/src/chains/Linea.sol b/src/chains/Linea.sol index 09c487b3..0e259bf0 100644 --- a/src/chains/Linea.sol +++ b/src/chains/Linea.sol @@ -11,10 +11,7 @@ import {ISettlerActions} from "../ISettlerActions.sol"; import {ISignatureTransfer} from "permit2/src/interfaces/ISignatureTransfer.sol"; import {UnknownForkId} from "../core/SettlerErrors.sol"; -import { - uniswapV3InitHash, - IUniswapV3Callback -} from "../core/univ3forks/UniswapV3.sol"; +import {uniswapV3InitHash, IUniswapV3Callback} from "../core/univ3forks/UniswapV3.sol"; import {sushiswapV3Factory, sushiswapV3ForkId} from "../core/univ3forks/SushiswapV3.sol"; import { pancakeSwapV3Factory, @@ -23,11 +20,7 @@ import { IPancakeSwapV3Callback } from "../core/univ3forks/PancakeSwapV3.sol"; import {IAlgebraCallback} from "../core/univ3forks/Algebra.sol"; -import { - lynexFactory, - lynexInitHash, - lynexForkId -} from "../core/univ3forks/Lynex.sol"; +import {lynexFactory, lynexInitHash, lynexForkId} from "../core/univ3forks/Lynex.sol"; // Solidity inheritance is stupid import {SettlerAbstract} from "../SettlerAbstract.sol"; From 7ce174e4f2bfe422320f28f95af3aa40bf038d8e Mon Sep 17 00:00:00 2001 From: Duncan Townsend Date: Wed, 17 Jul 2024 11:09:18 -0400 Subject: [PATCH 05/19] Update Linea `chain_config.json` for salvaged deployment --- chain_config.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/chain_config.json b/chain_config.json index 91fdbf81..3d622485 100644 --- a/chain_config.json +++ b/chain_config.json @@ -338,9 +338,10 @@ "governance": { "upgradeSafe": "0xf36b9f50E59870A24F42F9Ba43b2aD0A4b8f2F51", "deploymentSafe": "0x8E5DE7118a596E99B0563D3022039c11927f4827", + "pause": "0x2F01FA51F49526da65E70A60EFDDD8e12077D120" }, "deployment": { - "allowanceHolder": "VANITY ADDRESS IS BURNED" + "allowanceHolder": "0x000000000000175a8b9bC6d539B3708EEd92EA6c" }, "etherscanApi": "https://api.lineascan.build/api" }, From 0dd8c4ea1418e89b35952a228ba2054b3972a374 Mon Sep 17 00:00:00 2001 From: Duncan Townsend Date: Wed, 17 Jul 2024 11:15:28 -0400 Subject: [PATCH 06/19] Document that ice cold coffees is actually deployed to Linea, just not working yet --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index d8654ae9..5a8be5eb 100644 --- a/README.md +++ b/README.md @@ -1039,7 +1039,9 @@ like deploying a new `Settler`. `0x1CeC01DC0fFEE5eB5aF47DbEc1809F2A7c601C30` address on all chains unless somebody screwed up the vanity addresses and didn't update this document. On Linea, the address of the pauser contract is `0x2F01FA51F49526da65E70A60EFDDD8e12077D120` because whoever did their EVM -compatibility documentation documented the opposite of the truth 🤬. +compatibility documentation documented the opposite of the truth 🤬. When Linea +adopts the Shanghai hardfork (`PUSH0`), remove the preceeding sentence from this +document. 0. Go to that address on the relevant block explorer. From 93a82f1c88987a53d241885161369910932888b2 Mon Sep 17 00:00:00 2001 From: Duncan Townsend Date: Wed, 17 Jul 2024 12:32:11 -0400 Subject: [PATCH 07/19] Fix London Create3 shim inithash --- src/utils/Create3.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/utils/Create3.sol b/src/utils/Create3.sol index 7c449f35..f7f7e927 100644 --- a/src/utils/Create3.sol +++ b/src/utils/Create3.sol @@ -110,7 +110,7 @@ library Create3 { uint256 private constant _SHIM0_LONDON = 0x7f36583d54601d573d553d3d37363d34f03d816017573dfd5b5260203df35b30; uint48 private constant _SHIM1_LONDON = 0xff3d52593df3; - bytes32 private constant _SHIM_INITHASH_LONDON = 0x4181fd95643bb6bf1be20faa449de3be679a53ec38d829a0a789397a5d5d4887; + bytes32 private constant _SHIM_INITHASH_LONDON = 0x1774bbdc4a308eaf5967722c7a4708ea7a3097859cb8768a10611448c29981c3; function _createFromCalldata(bytes32 salt, bytes calldata initCode, uint256 value, uint256 shim0, uint48 shim1) private From 0ecd72e8bd4ec5bc4a06e96fb80cf3885ffadea2 Mon Sep 17 00:00:00 2001 From: Duncan Townsend Date: Wed, 17 Jul 2024 13:21:30 -0400 Subject: [PATCH 08/19] Skip sourcify verification on chains it doesn't support --- sh/deploy_allowanceholder.sh | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/sh/deploy_allowanceholder.sh b/sh/deploy_allowanceholder.sh index 7fdb3acb..9e5b208e 100755 --- a/sh/deploy_allowanceholder.sh +++ b/sh/deploy_allowanceholder.sh @@ -143,7 +143,9 @@ export FOUNDRY_OPTIMIZER_RUNS=1000000 forge clean forge create --private-key "$(get_secret allowanceHolder key)" --chain "$(get_config chainId)" --rpc-url "$rpc_url" --gas-price "$gas_price" --gas-limit 4000000 --etherscan-api-key "$(get_api_secret etherscanKey)" --verifier-url "$(get_config etherscanApi)" --verify $(get_config extraFlags) src/allowanceholder/AllowanceHolder.sol:AllowanceHolder -forge verify-contract --watch --chain "$(get_config chainId)" --verifier sourcify --optimizer-runs 1000000 --constructor-args 0x "$(get_secret allowanceHolder address)" src/allowanceholder/AllowanceHolder.sol:AllowanceHolder +if (( chainid != 81457 )) && (( chainid != 59144 )) ; then # sourcify doesn't support Blast or Linea + forge verify-contract --watch --chain "$(get_config chainId)" --verifier sourcify --optimizer-runs 1000000 --constructor-args 0x "$(get_secret allowanceHolder address)" src/allowanceholder/AllowanceHolder.sol:AllowanceHolder +fi echo 'Deployment is complete' >&2 echo 'Add the following to your chain_config.json' >&2 From 3c64133a99a095dc92ef2be924f92e5a634ea826 Mon Sep 17 00:00:00 2001 From: Duncan Townsend Date: Wed, 17 Jul 2024 14:21:22 -0400 Subject: [PATCH 09/19] Add deployed Linea configuration --- README.md | 2 +- chain_config.json | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 5a8be5eb..bf79ee73 100644 --- a/README.md +++ b/README.md @@ -1038,7 +1038,7 @@ like deploying a new `Settler`. `0x1CeC01DC0fFEE5eB5aF47DbEc1809F2A7c601C30` (ice cold coffees) is the address of the pauser contract. It's at the same address on all chains unless somebody screwed up the vanity addresses and didn't update this document. On Linea, the address of the pauser contract is -`0x2F01FA51F49526da65E70A60EFDDD8e12077D120` because whoever did their EVM +`0xBE71A746C7AE0f9D18E6DB4f71d09732B0Ee5b9c` because whoever did their EVM compatibility documentation documented the opposite of the truth 🤬. When Linea adopts the Shanghai hardfork (`PUSH0`), remove the preceeding sentence from this document. diff --git a/chain_config.json b/chain_config.json index 3d622485..9e8a3782 100644 --- a/chain_config.json +++ b/chain_config.json @@ -338,9 +338,10 @@ "governance": { "upgradeSafe": "0xf36b9f50E59870A24F42F9Ba43b2aD0A4b8f2F51", "deploymentSafe": "0x8E5DE7118a596E99B0563D3022039c11927f4827", - "pause": "0x2F01FA51F49526da65E70A60EFDDD8e12077D120" + "pause": "0xBE71A746C7AE0f9D18E6DB4f71d09732B0Ee5b9c" }, "deployment": { + "deployer": "0x00000000000004533Fe15556B1E086BB1A72cEae", "allowanceHolder": "0x000000000000175a8b9bC6d539B3708EEd92EA6c" }, "etherscanApi": "https://api.lineascan.build/api" From 34b927c3d60841da6ae22a890aa257c71f670e93 Mon Sep 17 00:00:00 2001 From: Duncan Townsend Date: Wed, 17 Jul 2024 16:15:54 -0400 Subject: [PATCH 10/19] WIP: handle chains that don't have Safe Transaction Service support --- sh/confirm_new_settler.sh | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/sh/confirm_new_settler.sh b/sh/confirm_new_settler.sh index 0697c727..82be3b9b 100755 --- a/sh/confirm_new_settler.sh +++ b/sh/confirm_new_settler.sh @@ -168,6 +168,19 @@ else fi declare -r signature +declare safe_url +safe_url="$(get_config safe.apiUrl)" +declare -r safe_url + +if [[ $safe_url = 'NOT SUPPORTED' ]] ; then + declare signature_file + signature_file="$project_root"/settler_confirmation_"$chain_display_name"_"$(git rev-parse --short HEAD)"_"$(tr '[:lower:]' '[:uppser:]' <<<"$signer")".txt + declare -r signature_file + echo "$signature" >"$signature_file" + echo "Signature saved to '$signature_file'" >&2 + exit 1 +fi + declare signing_hash signing_hash="$(eip712_hash "$deploy_calldata" 1)" declare -r signing_hash @@ -200,6 +213,6 @@ safe_multisig_transaction="$( declare -r safe_multisig_transaction # call the API -curl --fail -s "$(get_config safe.apiUrl)"'/v1/safes/'"$safe_address"'/multisig-transactions/' -X POST -H 'Content-Type: application/json' --data "$safe_multisig_transaction" +curl --fail -s "$safe_url"'/v1/safes/'"$safe_address"'/multisig-transactions/' -X POST -H 'Content-Type: application/json' --data "$safe_multisig_transaction" echo 'Signature submitted' >&2 From beea1e50c25dc18de48f2facfc82b82fc21d7edc Mon Sep 17 00:00:00 2001 From: Duncan Townsend Date: Wed, 17 Jul 2024 16:41:26 -0400 Subject: [PATCH 11/19] Refactor scripts to support non-Safe Transaction Service chains --- sh/common_safe.sh | 63 --------------------------------------- sh/common_safe_owner.sh | 22 ++++++++++++++ sh/common_wallet_type.sh | 41 +++++++++++++++++++++++++ sh/confirm_new_feature.sh | 2 ++ sh/confirm_new_settler.sh | 2 ++ sh/upgrade_deployer.sh | 2 ++ 6 files changed, 69 insertions(+), 63 deletions(-) create mode 100644 sh/common_safe_owner.sh create mode 100644 sh/common_wallet_type.sh diff --git a/sh/common_safe.sh b/sh/common_safe.sh index 2a31996f..bc5d4e6d 100644 --- a/sh/common_safe.sh +++ b/sh/common_safe.sh @@ -12,75 +12,12 @@ declare deployer_address deployer_address="$(get_config deployment.deployer)" declare -r deployer_address -declare -r get_owners_sig='getOwners()(address[])' -declare owners -owners="$(cast abi-decode "$get_owners_sig" "$(cast call --rpc-url "$rpc_url" "$safe_address" "$(cast calldata "$get_owners_sig")")")" -owners="${owners:1:$((${#owners} - 2))}" -owners="${owners//, /;}" -declare -r owners - declare -r nonce_sig='nonce()(uint256)' declare -i nonce nonce="$(cast abi-decode "$nonce_sig" "$(cast call --rpc-url "$rpc_url" "$safe_address" "$(cast calldata "$nonce_sig")")")" nonce=$((${SAFE_NONCE_INCREMENT:-0} + nonce)) declare -r -i nonce -declare -a owners_array -IFS=';' read -r -a owners_array <<<"$owners" -declare -r -a owners_array - -PS3='Who are you?: ' -declare signer -select signer in "${owners_array[@]}" ; do break ; done -declare -r signer - -if [[ ${signer:-unset} = 'unset' ]] ; then - echo 'I do not know who that is' >&2 - exit 1 -fi - -PS3='What kind of wallet are you using? ' -declare wallet_type -select wallet_type in ledger trezor hot frame ; do break ; done -declare -r wallet_Type - -if [[ ${wallet_type:-unset} = 'unset' ]] ; then - exit 1 -fi - -declare -a wallet_args -case $wallet_type in - 'ledger') - wallet_args=(--ledger) - ;; - 'trezor') - wallet_args=(--trezor) - ;; - 'hot') - wallet_args=(--interactive) - ;; - 'frame') - wallet_args=(--unlocked) - ;; - *) - echo 'Unrecognized wallet type: '"$wallet_type" >&2 - exit 1 - ;; -esac - -if [[ $wallet_type = 'ledger' ]] ; then - IFS='' read -r -e -p 'Ledger wallet HD path (BIP32) [default '"44'/60'/0'/0"']: ' - if [[ ${REPLY:-unset} = 'unset' ]] ; then - wallet_args+=( - --mnemonic-derivation-path "44'/60'/0'/0" - ) - else - wallet_args+=( - --mnemonic-derivation-path "$REPLY" - ) - fi -fi - # calls encoded as operation (always zero) 1 byte # target address 20 bytes # value 32 bytes diff --git a/sh/common_safe_owner.sh b/sh/common_safe_owner.sh new file mode 100644 index 00000000..14cf343b --- /dev/null +++ b/sh/common_safe_owner.sh @@ -0,0 +1,22 @@ +declare -r get_owners_sig='getOwners()(address[])' +declare owners +owners="$(cast abi-decode "$get_owners_sig" "$(cast call --rpc-url "$rpc_url" "$safe_address" "$(cast calldata "$get_owners_sig")")")" +owners="${owners:1:$((${#owners} - 2))}" +owners="${owners//, /;}" +declare -r owners + +declare -a owners_array +IFS=';' read -r -a owners_array <<<"$owners" +declare -r -a owners_array + +PS3='Who are you?: ' +declare signer +select signer in "${owners_array[@]}" ; do break ; done +declare -r signer + +echo "$signer" >&2 + +if [[ ${signer:-unset} = 'unset' ]] ; then + echo 'I do not know who that is' >&2 + exit 1 +fi diff --git a/sh/common_wallet_type.sh b/sh/common_wallet_type.sh new file mode 100644 index 00000000..9cc7f538 --- /dev/null +++ b/sh/common_wallet_type.sh @@ -0,0 +1,41 @@ +PS3='What kind of wallet are you using? ' +declare wallet_type +select wallet_type in ledger trezor hot frame ; do break ; done +declare -r wallet_Type + +if [[ ${wallet_type:-unset} = 'unset' ]] ; then + exit 1 +fi + +declare -a wallet_args +case $wallet_type in + 'ledger') + wallet_args=(--ledger) + ;; + 'trezor') + wallet_args=(--trezor) + ;; + 'hot') + wallet_args=(--interactive) + ;; + 'frame') + wallet_args=(--unlocked) + ;; + *) + echo 'Unrecognized wallet type: '"$wallet_type" >&2 + exit 1 + ;; +esac + +if [[ $wallet_type = 'ledger' ]] ; then + IFS='' read -r -e -p 'Ledger wallet HD path (BIP32) [default '"44'/60'/0'/0"']: ' + if [[ ${REPLY:-unset} = 'unset' ]] ; then + wallet_args+=( + --mnemonic-derivation-path "44'/60'/0'/0" + ) + else + wallet_args+=( + --mnemonic-derivation-path "$REPLY" + ) + fi +fi diff --git a/sh/confirm_new_feature.sh b/sh/confirm_new_feature.sh index fb78c2dd..6e6536e9 100755 --- a/sh/confirm_new_feature.sh +++ b/sh/confirm_new_feature.sh @@ -126,6 +126,8 @@ safe_address="$(get_config governance.upgradeSafe)" declare -r safe_address . "$project_root"/sh/common_safe.sh +. "$project_root"/sh/common_safe_owner.sh +. "$project_root"/sh/common_wallet_type.sh declare -r -i feature="$1" shift diff --git a/sh/confirm_new_settler.sh b/sh/confirm_new_settler.sh index 82be3b9b..70ba5f31 100755 --- a/sh/confirm_new_settler.sh +++ b/sh/confirm_new_settler.sh @@ -126,6 +126,8 @@ safe_address="$(get_config governance.deploymentSafe)" declare -r safe_address . "$project_root"/sh/common_safe.sh +. "$project_root"/sh/common_safe_owner.sh +. "$project_root"/sh/common_wallet_type.sh . "$project_root"/sh/common_deploy_settler.sh declare deploy_calldata diff --git a/sh/upgrade_deployer.sh b/sh/upgrade_deployer.sh index de7921f2..901a40fa 100755 --- a/sh/upgrade_deployer.sh +++ b/sh/upgrade_deployer.sh @@ -208,6 +208,8 @@ if [[ ${1:-unset} = 'confirm' ]] ; then declare -r safe_address . "$project_root"/sh/common_safe.sh + . "$project_root"/sh/common_safe_owner.sh + . "$project_root"/sh/common_wallet_type.sh if [[ ${deployed_address-unset} = 'unset' ]] ; then declare deployed_address From 5d9efabc1422e99d4613d80928f6d1a96f97bf4e Mon Sep 17 00:00:00 2001 From: Duncan Townsend Date: Wed, 17 Jul 2024 16:41:59 -0400 Subject: [PATCH 12/19] Refactor `sh/deploy_new_settler.sh` to work with non-owner signers --- sh/confirm_new_settler.sh | 2 +- sh/deploy_new_settler.sh | 66 +++++++++++++++++++++++---------------- 2 files changed, 40 insertions(+), 28 deletions(-) diff --git a/sh/confirm_new_settler.sh b/sh/confirm_new_settler.sh index 70ba5f31..0951673a 100755 --- a/sh/confirm_new_settler.sh +++ b/sh/confirm_new_settler.sh @@ -176,7 +176,7 @@ declare -r safe_url if [[ $safe_url = 'NOT SUPPORTED' ]] ; then declare signature_file - signature_file="$project_root"/settler_confirmation_"$chain_display_name"_"$(git rev-parse --short HEAD)"_"$(tr '[:lower:]' '[:uppser:]' <<<"$signer")".txt + signature_file="$project_root"/settler_confirmation_"$chain_display_name"_"$(git rev-parse --short HEAD)"_"$(tr '[:lower:]' '[:upper:]' <<<"$signer")".txt declare -r signature_file echo "$signature" >"$signature_file" echo "Signature saved to '$signature_file'" >&2 diff --git a/sh/deploy_new_settler.sh b/sh/deploy_new_settler.sh index 766e0cbd..8093f48a 100755 --- a/sh/deploy_new_settler.sh +++ b/sh/deploy_new_settler.sh @@ -126,6 +126,12 @@ safe_address="$(get_config governance.deploymentSafe)" declare -r safe_address . "$project_root"/sh/common_safe.sh + +declare signer +IFS='' read -p 'What address will you submit with?: ' -e -r signer +declare -r signer + +. "$project_root"/sh/common_wallet_type.sh . "$project_root"/sh/common_deploy_settler.sh declare deploy_calldata @@ -136,39 +142,45 @@ declare signing_hash signing_hash="$(eip712_hash "$deploy_calldata" 1)" declare -r signing_hash -declare signatures -signatures="$(curl --fail -s "$(get_config safe.apiUrl)"'/v1/multisig-transactions/'"$signing_hash"'/confirmations/?executed=false' -X GET)" -declare -r signatures +declare safe_url +safe_url="$(get_config safe.apiUrl)" +declare -r safe_url -if (( $(jq -Mr .count <<<"$signatures") != 1 )) ; then - echo 'Bad number of signatures' >&2 - exit 1 -fi +declare -a signatures=() +if [[ $safe_url = 'NOT SUPPORTED' ]] ; then + set +f + for confirmation in "$project_root"/settler_confirmation_"$chain_display_name"_"$(git rev-parse --short HEAD)"_*.txt ; do + signatures+=("$(<"$confirmation")") + done + set -f -declare other_signer -other_signer="$(jq -Mr '.results[0].owner' <<<"$signatures")" -declare -r other_signer -declare other_signature -other_signature="$(jq -Mr '.results[0].signature' <<<"$signatures")" -declare -r other_signature + if [[ "${#signatures[@]}" != '2' ]] ; then + echo 'Bad number of signatures' >&2 + exit 1 + fi +else + declare signatures_json + signatures_json="$(curl --fail -s "$safe_url"'/v1/multisig-transactions/'"$signing_hash"'/confirmations/?executed=false' -X GET)" + declare -r signatures_json -declare signer_lower -signer_lower="$(tr '[:upper:]' '[:lower:]' <<<"$signer")" -declare -r signer_lower -declare other_signer_lower -other_signer_lower="$(tr '[:upper:]' '[:lower:]' <<<"$other_signer")" -declare -r other_signer_lower + if (( $(jq -Mr .count <<<"$signatures_json") != 2 )) ; then + echo 'Bad number of signatures' >&2 + exit 1 + fi -declare signature -signature="$(cast concat-hex "$(cast to-uint256 "$signer")" "$(cast hash-zero)" 0x01)" -declare -r signature + if [ "$(jq -Mr '.results[1].owner' <<<"$signatures_json" | tr '[:lower:]' '[:upper:]')" \< "$(jq -Mr '.results[0].owner' <<<"$signatures_json" | tr '[:lower:]' '[:upper:]')" ] ; then + signatures+=( "$(jq -Mr '.results[1].signature' <<<"$signatures_json")" ) + signatures+=( "$(jq -Mr '.results[0].signature' <<<"$signatures_json")" ) + else + signatures+=( "$(jq -Mr '.results[0].signature' <<<"$signatures_json")" ) + signatures+=( "$(jq -Mr '.results[1].signature' <<<"$signatures_json")" ) + fi +fi +declare -r -a signatures declare packed_signatures -if [ "$other_signer_lower" \< "$signer_lower" ] ; then - packed_signatures="$(cast concat-hex "$other_signature" "$signature")" -else - packed_signatures="$(cast concat-hex "$signature" "$other_signature")" -fi +packed_signatures="$(cast concat-hex "${signatures[@]}")" +declare -r packed_signatures # set minimum gas price to (mostly for Arbitrum and BNB) declare -i min_gas_price From 73bb89b117cd73bf41252e83c8cd7baaac11c80a Mon Sep 17 00:00:00 2001 From: Duncan Townsend Date: Wed, 17 Jul 2024 23:33:15 -0400 Subject: [PATCH 13/19] Homogenize --- sh/deploy_new_settler.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sh/deploy_new_settler.sh b/sh/deploy_new_settler.sh index 8093f48a..b8547766 100755 --- a/sh/deploy_new_settler.sh +++ b/sh/deploy_new_settler.sh @@ -154,7 +154,7 @@ if [[ $safe_url = 'NOT SUPPORTED' ]] ; then done set -f - if [[ "${#signatures[@]}" != '2' ]] ; then + if (( ${#signatures[@]} != 2 )) ; then echo 'Bad number of signatures' >&2 exit 1 fi From 93f845bf5e92db79f7b9e79c5daefb6a2d489580 Mon Sep 17 00:00:00 2001 From: Duncan Townsend Date: Thu, 18 Jul 2024 09:35:59 -0400 Subject: [PATCH 14/19] Update `address.sh` for London hardfork Create3 shim inithash --- sh/address.sh | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/sh/address.sh b/sh/address.sh index caca5ffe..6d8a0a3e 100755 --- a/sh/address.sh +++ b/sh/address.sh @@ -172,7 +172,11 @@ function create3 { declare -r salt # this is the "create3" shim inithash - declare -r inithash='0x3bf3f97f0be1e2c00023033eefeb4fc062ac552ff36778b17060d90b6764902f' + if [[ $(get_config isShanghai) != [Tt]rue ]] ; then + declare -r inithash='0x1774bbdc4a308eaf5967722c7a4708ea7a3097859cb8768a10611448c29981c3' + else + declare -r inithash='0x3bf3f97f0be1e2c00023033eefeb4fc062ac552ff36778b17060d90b6764902f' + fi declare shim shim="$(cast concat-hex 0xff "$factory" "$salt" "$inithash")" From be3d46b5719d5dbaf666a8bded61acc268e9c524 Mon Sep 17 00:00:00 2001 From: Duncan Townsend Date: Thu, 18 Jul 2024 09:37:42 -0400 Subject: [PATCH 15/19] Formatting --- src/utils/Create3.sol | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/utils/Create3.sol b/src/utils/Create3.sol index f7f7e927..50ec101c 100644 --- a/src/utils/Create3.sol +++ b/src/utils/Create3.sol @@ -126,10 +126,10 @@ library Create3 { if iszero(call(gas(), shim, value, ptr, initCode.length, 0x00, 0x20)) { revert(0x00, 0x00) } deployed := mload(0x00) - // This causes the shim to selfdestruct. On some chains, selfdestruct reverts, consuming - // all available gas. We swallow this revert with `pop` and the 51k gas limit gives a - // 10x multiplier over the expected gas consumption of this call without being *too* - // wasteful when `SELFDESTRUCT` is unimplemented. + // This causes the shim to selfdestruct. On some chains, `SELFDESTRUCT` reverts, + // consuming all available gas. We swallow this revert with `pop` and the 51k gas limit + // gives a 10x multiplier over the expected gas consumption of this call without being + // *too* wasteful when `SELFDESTRUCT` is unimplemented. pop(call(51220, shim, 0x00, 0x00, 0x00, 0x00, 0x00)) } } From 0173b1e17f0ba42af92443feda35153435daaaef Mon Sep 17 00:00:00 2001 From: Duncan Townsend Date: Thu, 18 Jul 2024 09:45:46 -0400 Subject: [PATCH 16/19] Add deploy-time bytecode hash check to `Create3` --- src/utils/Create3.sol | 28 ++++++++++++++++++++-------- 1 file changed, 20 insertions(+), 8 deletions(-) diff --git a/src/utils/Create3.sol b/src/utils/Create3.sol index 50ec101c..c13ad381 100644 --- a/src/utils/Create3.sol +++ b/src/utils/Create3.sol @@ -107,19 +107,22 @@ library Create3 { uint8 private constant _SHIM1_LENGTH = 0x06; uint8 private constant _SHIM_LENGTH = 0x26; bytes32 private constant _SHIM_INITHASH = 0x3bf3f97f0be1e2c00023033eefeb4fc062ac552ff36778b17060d90b6764902f; + bytes32 private constant _SHIM_RUNTIME_HASH = 0xa9549013530fb1542c6fac59b531052d9fd0c0433910571c379618caa172f2cb; uint256 private constant _SHIM0_LONDON = 0x7f36583d54601d573d553d3d37363d34f03d816017573dfd5b5260203df35b30; uint48 private constant _SHIM1_LONDON = 0xff3d52593df3; bytes32 private constant _SHIM_INITHASH_LONDON = 0x1774bbdc4a308eaf5967722c7a4708ea7a3097859cb8768a10611448c29981c3; + bytes32 private constant _SHIM_RUNTIME_HASH_LONDON = 0x4181fd95643bb6bf1be20faa449de3be679a53ec38d829a0a789397a5d5d4887; - function _createFromCalldata(bytes32 salt, bytes calldata initCode, uint256 value, uint256 shim0, uint48 shim1) + function _createFromCalldata(bytes32 salt, bytes calldata initCode, uint256 value, uint256 shim0, uint48 shim1, bytes32 shimRuntimeHash) private returns (address deployed) { + address shim; assembly ("memory-safe") { mstore(_SHIM1_LENGTH, shim1) mstore(0x00, shim0) - let shim := create2(0x00, 0x00, _SHIM_LENGTH, salt) + shim := create2(0x00, 0x00, _SHIM_LENGTH, salt) if iszero(shim) { revert(0x00, 0x00) } let ptr := mload(0x40) calldatacopy(ptr, initCode.offset, initCode.length) @@ -132,17 +135,21 @@ library Create3 { // *too* wasteful when `SELFDESTRUCT` is unimplemented. pop(call(51220, shim, 0x00, 0x00, 0x00, 0x00, 0x00)) } + + if (shim.codehash != shimRuntimeHash) { + revert(); + } } function createFromCalldata(bytes32 salt, bytes calldata initCode, uint256 value) internal returns (address) { - return _createFromCalldata(salt, initCode, value, _SHIM0, _SHIM1); + return _createFromCalldata(salt, initCode, value, _SHIM0, _SHIM1, _SHIM_RUNTIME_HASH); } function createFromCalldataLondon(bytes32 salt, bytes calldata initCode, uint256 value) internal returns (address) { - return _createFromCalldata(salt, initCode, value, _SHIM0_LONDON, _SHIM1_LONDON); + return _createFromCalldata(salt, initCode, value, _SHIM0_LONDON, _SHIM1_LONDON, _SHIM_RUNTIME_HASH_LONDON); } function createFromCalldata(bytes32 salt, bytes calldata initCode) internal returns (address) { @@ -153,27 +160,32 @@ library Create3 { return createFromCalldataLondon(salt, initCode, 0); } - function _createFromMemory(bytes32 salt, bytes memory initCode, uint256 value, uint256 shim0, uint48 shim1) + function _createFromMemory(bytes32 salt, bytes memory initCode, uint256 value, uint256 shim0, uint48 shim1, bytes32 shimRuntimeHash) private returns (address deployed) { + address shim; assembly ("memory-safe") { mstore(_SHIM1_LENGTH, shim1) mstore(0x00, shim0) - let shim := create2(0x00, 0x00, _SHIM_LENGTH, salt) + shim := create2(0x00, 0x00, _SHIM_LENGTH, salt) if iszero(shim) { revert(0x00, 0x00) } if iszero(call(gas(), shim, value, add(0x20, initCode), mload(initCode), 0x00, 0x20)) { revert(0x00, 0x00) } deployed := mload(0x00) pop(call(gas(), shim, 0x00, 0x00, 0x00, 0x00, 0x00)) } + + if (shim.codehash != shimRuntimeHash) { + revert(); + } } function createFromMemory(bytes32 salt, bytes memory initCode, uint256 value) internal returns (address) { - return _createFromMemory(salt, initCode, value, _SHIM0, _SHIM1); + return _createFromMemory(salt, initCode, value, _SHIM0, _SHIM1, _SHIM_RUNTIME_HASH); } function createFromMemoryLondon(bytes32 salt, bytes memory initCode, uint256 value) internal returns (address) { - return _createFromMemory(salt, initCode, value, _SHIM0_LONDON, _SHIM1_LONDON); + return _createFromMemory(salt, initCode, value, _SHIM0_LONDON, _SHIM1_LONDON, _SHIM_RUNTIME_HASH_LONDON); } function createFromMemory(bytes32 salt, bytes memory initCode) internal returns (address) { From 7de94fca8a0ce28cadf1ae29d79693d4b2c8a61f Mon Sep 17 00:00:00 2001 From: Duncan Townsend Date: Thu, 18 Jul 2024 09:45:58 -0400 Subject: [PATCH 17/19] Code duplication is the enemy of all that is good in the world --- src/utils/Create3.sol | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/utils/Create3.sol b/src/utils/Create3.sol index c13ad381..bb283e61 100644 --- a/src/utils/Create3.sol +++ b/src/utils/Create3.sol @@ -172,7 +172,12 @@ library Create3 { if iszero(shim) { revert(0x00, 0x00) } if iszero(call(gas(), shim, value, add(0x20, initCode), mload(initCode), 0x00, 0x20)) { revert(0x00, 0x00) } deployed := mload(0x00) - pop(call(gas(), shim, 0x00, 0x00, 0x00, 0x00, 0x00)) + + // This causes the shim to selfdestruct. On some chains, `SELFDESTRUCT` reverts, + // consuming all available gas. We swallow this revert with `pop` and the 51k gas limit + // gives a 10x multiplier over the expected gas consumption of this call without being + // *too* wasteful when `SELFDESTRUCT` is unimplemented. + pop(call(51220, shim, 0x00, 0x00, 0x00, 0x00, 0x00)) } if (shim.codehash != shimRuntimeHash) { From adf1d94026cdd02c89f205d60690d2ea477e742b Mon Sep 17 00:00:00 2001 From: Duncan Townsend Date: Thu, 18 Jul 2024 11:52:40 -0400 Subject: [PATCH 18/19] Cleanup --- src/utils/Create3.sol | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/src/utils/Create3.sol b/src/utils/Create3.sol index bb283e61..1bbac005 100644 --- a/src/utils/Create3.sol +++ b/src/utils/Create3.sol @@ -124,6 +124,7 @@ library Create3 { mstore(0x00, shim0) shim := create2(0x00, 0x00, _SHIM_LENGTH, salt) if iszero(shim) { revert(0x00, 0x00) } + if iszero(eq(extcodehash(shim), shimRuntimeHash)) { revert(0x00, 0x00) } let ptr := mload(0x40) calldatacopy(ptr, initCode.offset, initCode.length) if iszero(call(gas(), shim, value, ptr, initCode.length, 0x00, 0x20)) { revert(0x00, 0x00) } @@ -135,10 +136,6 @@ library Create3 { // *too* wasteful when `SELFDESTRUCT` is unimplemented. pop(call(51220, shim, 0x00, 0x00, 0x00, 0x00, 0x00)) } - - if (shim.codehash != shimRuntimeHash) { - revert(); - } } function createFromCalldata(bytes32 salt, bytes calldata initCode, uint256 value) internal returns (address) { @@ -170,6 +167,7 @@ library Create3 { mstore(0x00, shim0) shim := create2(0x00, 0x00, _SHIM_LENGTH, salt) if iszero(shim) { revert(0x00, 0x00) } + if iszero(eq(extcodehash(shim), shimRuntimeHash)) { revert(0x00, 0x00) } if iszero(call(gas(), shim, value, add(0x20, initCode), mload(initCode), 0x00, 0x20)) { revert(0x00, 0x00) } deployed := mload(0x00) @@ -179,10 +177,6 @@ library Create3 { // *too* wasteful when `SELFDESTRUCT` is unimplemented. pop(call(51220, shim, 0x00, 0x00, 0x00, 0x00, 0x00)) } - - if (shim.codehash != shimRuntimeHash) { - revert(); - } } function createFromMemory(bytes32 salt, bytes memory initCode, uint256 value) internal returns (address) { From e1397e99907b4f043f02ae159c36a083e7e1fecc Mon Sep 17 00:00:00 2001 From: Duncan Townsend Date: Thu, 18 Jul 2024 11:53:39 -0400 Subject: [PATCH 19/19] `forge fmt` --- src/utils/Create3.sol | 29 +++++++++++++++++++---------- 1 file changed, 19 insertions(+), 10 deletions(-) diff --git a/src/utils/Create3.sol b/src/utils/Create3.sol index 1bbac005..cf43d869 100644 --- a/src/utils/Create3.sol +++ b/src/utils/Create3.sol @@ -112,12 +112,17 @@ library Create3 { uint256 private constant _SHIM0_LONDON = 0x7f36583d54601d573d553d3d37363d34f03d816017573dfd5b5260203df35b30; uint48 private constant _SHIM1_LONDON = 0xff3d52593df3; bytes32 private constant _SHIM_INITHASH_LONDON = 0x1774bbdc4a308eaf5967722c7a4708ea7a3097859cb8768a10611448c29981c3; - bytes32 private constant _SHIM_RUNTIME_HASH_LONDON = 0x4181fd95643bb6bf1be20faa449de3be679a53ec38d829a0a789397a5d5d4887; - - function _createFromCalldata(bytes32 salt, bytes calldata initCode, uint256 value, uint256 shim0, uint48 shim1, bytes32 shimRuntimeHash) - private - returns (address deployed) - { + bytes32 private constant _SHIM_RUNTIME_HASH_LONDON = + 0x4181fd95643bb6bf1be20faa449de3be679a53ec38d829a0a789397a5d5d4887; + + function _createFromCalldata( + bytes32 salt, + bytes calldata initCode, + uint256 value, + uint256 shim0, + uint48 shim1, + bytes32 shimRuntimeHash + ) private returns (address deployed) { address shim; assembly ("memory-safe") { mstore(_SHIM1_LENGTH, shim1) @@ -157,10 +162,14 @@ library Create3 { return createFromCalldataLondon(salt, initCode, 0); } - function _createFromMemory(bytes32 salt, bytes memory initCode, uint256 value, uint256 shim0, uint48 shim1, bytes32 shimRuntimeHash) - private - returns (address deployed) - { + function _createFromMemory( + bytes32 salt, + bytes memory initCode, + uint256 value, + uint256 shim0, + uint48 shim1, + bytes32 shimRuntimeHash + ) private returns (address deployed) { address shim; assembly ("memory-safe") { mstore(_SHIM1_LENGTH, shim1)