From af5a1b3f4221e844eebc5e083caff58205003a03 Mon Sep 17 00:00:00 2001 From: lgalende Date: Mon, 11 May 2026 14:38:29 -0300 Subject: [PATCH 1/3] evm: support safe upgrades --- packages/evm/.env.sample | 2 + packages/evm/package.json | 2 + packages/evm/scripts/deploy-contracts.ts | 11 +- packages/evm/scripts/upgrade-settler.ts | 70 +++++++- yarn.lock | 214 +++++++++++++++++++++-- 5 files changed, 276 insertions(+), 23 deletions(-) diff --git a/packages/evm/.env.sample b/packages/evm/.env.sample index aed0018..bd9d777 100644 --- a/packages/evm/.env.sample +++ b/packages/evm/.env.sample @@ -4,6 +4,8 @@ SOLVER=0xE0D76433Edd9f5df370561bd0AF231E72c83Cd3a VALIDATOR=0xc76B16fA2Fa75D93e08099DC16413D9a083404A1 SETTLER_PROXY= +SAFE= +SAFE_API_KEY= ETHERSCAN_KEY= DEPLOYER_PRIVATE_KEY= diff --git a/packages/evm/package.json b/packages/evm/package.json index fa9e172..747c47a 100644 --- a/packages/evm/package.json +++ b/packages/evm/package.json @@ -29,6 +29,8 @@ "@nomicfoundation/hardhat-toolbox-mocha-ethers": "^3.0.0-next.23", "@nomicfoundation/hardhat-typechain": "^3.0.0-next.23", "@nomicfoundation/hardhat-verify": "^3.0.0-next.23", + "@safe-global/api-kit": "^4.0.0", + "@safe-global/protocol-kit": "^6.0.0", "@types/chai": "^4.3.20", "@types/chai-as-promised": "^8.0.2", "@types/mocha": "^10.0.10", diff --git a/packages/evm/scripts/deploy-contracts.ts b/packages/evm/scripts/deploy-contracts.ts index 0182b2c..5d39061 100644 --- a/packages/evm/scripts/deploy-contracts.ts +++ b/packages/evm/scripts/deploy-contracts.ts @@ -15,7 +15,8 @@ async function main(): Promise { if (!process.env.ADMIN) throw Error('ADMIN env variable not provided') if (!process.env.SOLVER) throw Error('SOLVER env variable not provided') if (!process.env.VALIDATOR) throw Error('VALIDATOR env variable not provided') - const { ADMIN, SOLVER, AXIA, VALIDATOR } = process.env + if (!process.env.SAFE) throw Error('SAFE env variable not provided') + const { ADMIN, SOLVER, AXIA, VALIDATOR, SAFE } = process.env const controllerArgs = [ADMIN, [SOLVER], [], [AXIA], [VALIDATOR], MIN_VALIDATORS] const controller = await deployCreate3(ControllerArtifact, controllerArgs, '0x17') @@ -25,12 +26,16 @@ async function main(): Promise { const initializeData = new Interface(SettlerArtifact.abi).encodeFunctionData('initialize', [ controller.target, - ADMIN, + ADMIN, // settler owner dynamicCallEncoder.target, ]) const settlerProxy = await deployCreate3( ProxyArtifact, - [settlerImplementation.target, ADMIN, initializeData], + [ + settlerImplementation.target, + SAFE, // proxy owner + initializeData, + ], '0x04302603' ) diff --git a/packages/evm/scripts/upgrade-settler.ts b/packages/evm/scripts/upgrade-settler.ts index be47964..eaf2f5a 100644 --- a/packages/evm/scripts/upgrade-settler.ts +++ b/packages/evm/scripts/upgrade-settler.ts @@ -1,5 +1,7 @@ import { HardhatEthers, HardhatEthersSigner } from '@nomicfoundation/hardhat-ethers/types' -import { Contract, getAddress } from 'ethers' +import SafeApiKit from '@safe-global/api-kit' +import Safe from '@safe-global/protocol-kit' +import { Contract, getAddress, Wallet } from 'ethers' import { network } from 'hardhat' import ProxyAdminArtifact from '../artifacts/@openzeppelin/contracts/proxy/transparent/ProxyAdmin.sol/ProxyAdmin.json' @@ -9,7 +11,7 @@ import { deployCreate3 } from './deploy-create3' const ERC1967_ADMIN_SLOT = '0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103' async function main(): Promise { - const { ethers } = await network.connect() + const { ethers, networkConfig } = await network.connect() const [signer] = await ethers.getSigners() if (!process.env.SETTLER_PROXY) throw Error('SETTLER_PROXY env variable not provided') @@ -17,14 +19,68 @@ async function main(): Promise { const proxyAdmin = await getProxyAdmin(ethers, proxy, signer) const proxyAdminOwner = await proxyAdmin.owner() - if (proxyAdminOwner !== signer.address) { - throw Error(`Signer ${signer.address} is not the ProxyAdmin owner ${proxyAdminOwner}`) + + const safeAddress = process.env.SAFE ? getAddress(process.env.SAFE) : undefined + const expectedOwner = safeAddress ?? signer.address + + if (proxyAdminOwner !== expectedOwner) { + throw Error(`Expected owner ${expectedOwner} does not match ProxyAdmin owner ${proxyAdminOwner}`) } const implementation = await deployCreate3(SettlerArtifact, [], '0x04302605', 'V1') - const tx = await proxyAdmin.upgradeAndCall(proxy, implementation.target, '0x') - await tx.wait() - console.log(`✅ Settler ${proxy} upgraded in tx ${tx.hash}`) + + if (safeAddress) { + const { chainId } = await ethers.provider.getNetwork() + if (networkConfig.type !== 'http') throw Error('Safe proposal requires an HTTP network') + const rpcUrl = await networkConfig.url.getUrl() + await proposeTransaction(safeAddress, proxyAdmin, proxy, implementation.target, chainId, rpcUrl) + } else { + const tx = await proxyAdmin.upgradeAndCall(proxy, implementation.target, '0x') + await tx.wait() + console.log(`✅ Settler ${proxy} upgraded in tx ${tx.hash}`) + } +} + +async function proposeTransaction( + safeAddress: string, + proxyAdmin: Contract, + proxy: string, + implementation: string, + chainId: bigint, + rpcUrl: string +): Promise { + if (!process.env.SAFE_API_KEY) throw Error('SAFE_API_KEY env variable required for Safe proposal') + + if (!process.env.DEPLOYER_PRIVATE_KEY) throw Error('DEPLOYER_PRIVATE_KEY env variable required for Safe proposal') + const signer = new Wallet(process.env.DEPLOYER_PRIVATE_KEY) + + const safe = await Safe.init({ + provider: rpcUrl, + safeAddress, + }) + + const apiKit = new SafeApiKit({ chainId, apiKey: process.env.SAFE_API_KEY }) + + const data = proxyAdmin.interface.encodeFunctionData('upgradeAndCall', [proxy, implementation, '0x']) + const to = String(await proxyAdmin.getAddress()) + + const safeTransaction = await safe.createTransaction({ + transactions: [{ to, value: '0', data }], + }) + + const safeTxHash = await safe.getTransactionHash(safeTransaction) + const senderSignature = signer.signingKey.sign(safeTxHash).serialized + + await apiKit.proposeTransaction({ + safeAddress, + safeTransactionData: safeTransaction.data, + safeTxHash, + senderAddress: signer.address, + senderSignature, + }) + + console.log(`✅ Upgrade proposed to Safe ${safeAddress}`) + console.log(` Safe TX Hash: ${safeTxHash}`) } async function getProxyAdmin(ethers: HardhatEthers, proxy: string, signer: HardhatEthersSigner): Promise { diff --git a/yarn.lock b/yarn.lock index b55b7a7..b977d06 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7,6 +7,11 @@ resolved "https://registry.yarnpkg.com/@adraffy/ens-normalize/-/ens-normalize-1.10.1.tgz#63430d04bd8c5e74f8d7d049338f1cd9d4f02069" integrity sha512-96Z2IP3mYmF1Xg2cDm8f1gWGf/HUVedQ3FMifV4kG/PQ4yEP51xDtRAEfhVNt5f/uzpNkZHwWQuUcu6D6K+Ekw== +"@adraffy/ens-normalize@^1.11.0": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@adraffy/ens-normalize/-/ens-normalize-1.11.1.tgz#6c2d657d4b2dfb37f8ea811dcb3e60843d4ac24a" + integrity sha512-nhCBV3quEgesuf7c7KYfperqSS14T8bYuvJ8PcLJp6znkZpFc0AuW4qBtr8eKVyPPe/8RSr7sglCWPU5eaxwKQ== + "@babel/code-frame@7.12.11": version "7.12.11" resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.12.11.tgz#f4ad435aa263db935b8f10f2c552d23fb716a63f" @@ -499,6 +504,11 @@ resolved "https://registry.yarnpkg.com/@noble/ciphers/-/ciphers-1.2.1.tgz#3812b72c057a28b44ff0ad4aff5ca846e5b9cdc9" integrity sha512-rONPWMC7PeExE077uLE4oqWrZ1IvAfz3oH9LibVAcVCopJiA9R62uavnbEzdkVmJYI6M6Zgkbeb07+tWjlq2XA== +"@noble/ciphers@^1.3.0": + version "1.3.0" + resolved "https://registry.yarnpkg.com/@noble/ciphers/-/ciphers-1.3.0.tgz#f64b8ff886c240e644e5573c097f86e5b43676dc" + integrity sha512-2I0gnIVPtfnMw9ee9h1dJG7tp81+8Ob3OJb3Mv37rx5L40/b0i7djjCVvGOVqc9AEIQyvyu1i6ypKdFw8R8gQw== + "@noble/curves@1.2.0": version "1.2.0" resolved "https://registry.yarnpkg.com/@noble/curves/-/curves-1.2.0.tgz#92d7e12e4e49b23105a2555c6984d41733d65c35" @@ -513,7 +523,14 @@ dependencies: "@noble/hashes" "1.4.0" -"@noble/curves@^1.4.2": +"@noble/curves@1.9.1": + version "1.9.1" + resolved "https://registry.yarnpkg.com/@noble/curves/-/curves-1.9.1.tgz#9654a0bc6c13420ae252ddcf975eaf0f58f0a35c" + integrity sha512-k11yZxZg+t+gWvBbIswW0yoJlu8cHOC7dhunwOzoWH/mXGBiYyR4YY6hAEK/3EUs4UpB8la1RfdRpeGsFHkWsA== + dependencies: + "@noble/hashes" "1.8.0" + +"@noble/curves@^1.4.2", "@noble/curves@^1.6.0", "@noble/curves@~1.9.0": version "1.9.7" resolved "https://registry.yarnpkg.com/@noble/curves/-/curves-1.9.7.tgz#79d04b4758a43e4bca2cbdc62e7771352fa6b951" integrity sha512-gbKGcRUYIjA3/zCCNaWDciTMFI0dCkvou3TL8Zmy5Nc7sJ47a0jtOeZoTaMxkuqRo9cRhjOdZJXegxYE5FN/xw== @@ -547,7 +564,7 @@ resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.7.2.tgz#d53c65a21658fb02f3303e7ee3ba89d6754c64b4" integrity sha512-biZ0NUSxyjLLqo6KxEJ1b+C2NAx0wtDoFvCaXHGgUkeHzf3Xc1xKumFKREuT7f7DARNZ/slvYUwFG6B0f2b6hQ== -"@noble/hashes@1.8.0", "@noble/hashes@^1.3.1", "@noble/hashes@^1.4.0": +"@noble/hashes@1.8.0", "@noble/hashes@^1.3.1", "@noble/hashes@^1.4.0", "@noble/hashes@^1.8.0", "@noble/hashes@~1.8.0": version "1.8.0" resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.8.0.tgz#cee43d801fcef9644b11b8194857695acd5f815a" integrity sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A== @@ -790,6 +807,22 @@ resolved "https://registry.yarnpkg.com/@openzeppelin/contracts/-/contracts-5.3.0.tgz#0a90ce16f5c855e3c8239691f1722cd4999ae741" integrity sha512-zj/KGoW7zxWUE8qOI++rUM18v+VeLTTzKs/DJFkSzHpQFPD/jKKF0TrMxBfGLl3kpdELCNccvB3zmofSzm4nlA== +"@peculiar/asn1-schema@^2.3.13": + version "2.7.0" + resolved "https://registry.yarnpkg.com/@peculiar/asn1-schema/-/asn1-schema-2.7.0.tgz#f2dcb25995ce7cac8687ba1039f043e5eff43820" + integrity sha512-W8ZfWzLmQnrcky+eh3tni4IozMdqBDiHWU0N+vve/UGjMaUs8c0L7A2oEdkBXS8rTpWDpK/aoI3DG/L/hxmxPg== + dependencies: + "@peculiar/utils" "^2.0.2" + asn1js "^3.0.6" + tslib "^2.8.1" + +"@peculiar/utils@^2.0.2": + version "2.0.3" + resolved "https://registry.yarnpkg.com/@peculiar/utils/-/utils-2.0.3.tgz#a27ca4c4b73652e110f19a7d16d664f458a5528e" + integrity sha512-+oL3HPFRIZ1St2K50lWCXiioIgSoxzz7R1J3uF6neO2yl1sgmpgY6XXJH4BdpoDkMWznQTeYF6oWNDZLCdQ4eQ== + dependencies: + tslib "^2.8.1" + "@pkgjs/parseargs@^0.11.0": version "0.11.0" resolved "https://registry.yarnpkg.com/@pkgjs/parseargs/-/parseargs-0.11.0.tgz#a77ea742fab25775145434eb1d2328cf5013ac33" @@ -800,6 +833,70 @@ resolved "https://registry.yarnpkg.com/@rtsao/scc/-/scc-1.1.0.tgz#927dd2fae9bc3361403ac2c7a00c32ddce9ad7e8" integrity sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g== +"@safe-global/api-kit@^4.0.0": + version "4.1.0" + resolved "https://registry.yarnpkg.com/@safe-global/api-kit/-/api-kit-4.1.0.tgz#8cb3426a53757e938649b830743d2cf68b7ea6a2" + integrity sha512-UlLG5bY1dR3zKKJxv0/d4bsR0zkFiC52aXJDg4/BTXGge51CZdG/d/5Z+V/IQX6fC09QiLPT1D3VquO0oc9Ecg== + dependencies: + "@safe-global/protocol-kit" "^7.0.0" + "@safe-global/types-kit" "^3.1.0" + node-fetch "^2.7.0" + viem "^2.21.8" + +"@safe-global/protocol-kit@^6.0.0": + version "6.1.2" + resolved "https://registry.yarnpkg.com/@safe-global/protocol-kit/-/protocol-kit-6.1.2.tgz#6cafd55aaf119998b794ff3a0cdaa2556ba2374c" + integrity sha512-cTpPdUAS2AMfGCkD1T601rQNjT0rtMQLA2TH7L/C+iFPAC6WrrDFop2B9lzeHjczlnVzrRpfFe4cL1bLrJ9NZw== + dependencies: + "@safe-global/safe-deployments" "^1.37.49" + "@safe-global/safe-modules-deployments" "^2.2.21" + "@safe-global/types-kit" "^3.0.0" + abitype "^1.0.2" + semver "^7.7.2" + viem "^2.21.8" + optionalDependencies: + "@noble/curves" "^1.6.0" + "@peculiar/asn1-schema" "^2.3.13" + +"@safe-global/protocol-kit@^7.0.0": + version "7.1.0" + resolved "https://registry.yarnpkg.com/@safe-global/protocol-kit/-/protocol-kit-7.1.0.tgz#c0107877408d9c63482a223a3f6dfb8967099942" + integrity sha512-eFJ6SwxF9TIDpQkQj8bTP9ma1zpf1C1nhdhAwx16rUX749CWT6styg7e9dSmeV40zSleWFeQUWcqgLOaRnxj1g== + dependencies: + "@safe-global/safe-deployments" "^1.37.54" + "@safe-global/safe-modules-deployments" "^3.0.2" + "@safe-global/types-kit" "^3.1.0" + abitype "^1.0.2" + semver "^7.7.2" + viem "^2.21.8" + optionalDependencies: + "@noble/curves" "^1.6.0" + "@peculiar/asn1-schema" "^2.3.13" + +"@safe-global/safe-deployments@^1.37.49", "@safe-global/safe-deployments@^1.37.54": + version "1.37.56" + resolved "https://registry.yarnpkg.com/@safe-global/safe-deployments/-/safe-deployments-1.37.56.tgz#8a13d2aed4d8bfb5ab8fcc105fec3025b45114e5" + integrity sha512-HF3ETre/KSP3nCOZ72XEbq5U56gOGgYLJ22LxOAnR8+YzMjzZ8cpnHpx5Z31Zt1xkUTGSCMi9XF950lJt6WbsQ== + dependencies: + semver "^7.6.2" + +"@safe-global/safe-modules-deployments@^2.2.21": + version "2.2.25" + resolved "https://registry.yarnpkg.com/@safe-global/safe-modules-deployments/-/safe-modules-deployments-2.2.25.tgz#d0942c5d4f854a7221bcbf82bc13e15269c6822a" + integrity sha512-KjgenKhBRyFHEfo8xlBgNzKAy25vrmGyCGZwTjIuA81yOSRJRe85GE5Yfg/FBKeeyHqR2dD1WPZr6c2Uqd6C/g== + +"@safe-global/safe-modules-deployments@^3.0.2": + version "3.0.4" + resolved "https://registry.yarnpkg.com/@safe-global/safe-modules-deployments/-/safe-modules-deployments-3.0.4.tgz#36fae3e242f4a5caab7fd8a61aec3bdd6fe2af2e" + integrity sha512-aOFcv5tLPA/CS50Lknuo0QyB+zbwTCLKhnwzOoHRU9az6YDhB1q7ppq3jYk7+xhvzluhpPEfDd8HGKAOxHpLoQ== + +"@safe-global/types-kit@^3.0.0", "@safe-global/types-kit@^3.1.0": + version "3.1.0" + resolved "https://registry.yarnpkg.com/@safe-global/types-kit/-/types-kit-3.1.0.tgz#c18a784d365df8757a1f51bb2ee56c1d73889f0c" + integrity sha512-uI6lFV8wOji4rb7juu0/LRMND0rq2NWaqH4zFzE2FUjO8lTvbCT+/5W/+flUUfkcaqyLDlJ1OPjasa2bEakrbw== + dependencies: + abitype "^1.0.2" + "@scure/base@~1.1.6": version "1.1.9" resolved "https://registry.yarnpkg.com/@scure/base/-/base-1.1.9.tgz#e5e142fbbfe251091f9c5f1dd4c834ac04c3dbd1" @@ -819,6 +916,15 @@ "@noble/hashes" "~1.4.0" "@scure/base" "~1.1.6" +"@scure/bip32@1.7.0", "@scure/bip32@^1.7.0": + version "1.7.0" + resolved "https://registry.yarnpkg.com/@scure/bip32/-/bip32-1.7.0.tgz#b8683bab172369f988f1589640e53c4606984219" + integrity sha512-E4FFX/N3f4B80AKWp5dP6ow+flD1LQZo/w8UnLGYZO674jS6YnYeepycOOksv+vLPSpgN35wgKgy+ybfTb2SMw== + dependencies: + "@noble/curves" "~1.9.0" + "@noble/hashes" "~1.8.0" + "@scure/base" "~1.2.5" + "@scure/bip39@1.3.0": version "1.3.0" resolved "https://registry.yarnpkg.com/@scure/bip39/-/bip39-1.3.0.tgz#0f258c16823ddd00739461ac31398b4e7d6a18c3" @@ -827,6 +933,14 @@ "@noble/hashes" "~1.4.0" "@scure/base" "~1.1.6" +"@scure/bip39@1.6.0", "@scure/bip39@^1.6.0": + version "1.6.0" + resolved "https://registry.yarnpkg.com/@scure/bip39/-/bip39-1.6.0.tgz#475970ace440d7be87a6086cbee77cb8f1a684f9" + integrity sha512-+lF0BbLiJNwVlev4eKelw1WWLaiKXw7sSl8T6FvBlWkdX+94aGJ4o8XjUdlyhTCjd8c+B3KT3JfS8P0bLRNU6A== + dependencies: + "@noble/hashes" "~1.8.0" + "@scure/base" "~1.2.5" + "@sentry/core@^9.4.0": version "9.19.0" resolved "https://registry.yarnpkg.com/@sentry/core/-/core-9.19.0.tgz#b0c291494abd4fdefb8f77d200e381c3f7167c3f" @@ -1195,6 +1309,16 @@ "@typescript-eslint/types" "4.33.0" eslint-visitor-keys "^2.0.0" +abitype@1.2.3: + version "1.2.3" + resolved "https://registry.yarnpkg.com/abitype/-/abitype-1.2.3.tgz#bec3e09dea97d99ef6c719140bee663a329ad1f4" + integrity sha512-Ofer5QUnuUdTFsBRwARMoWKOH1ND5ehwYhJ3OJ/BQO+StkwQjHw0XyVh4vDttzHB7QOFhPHa/o413PJ82gU/Tg== + +abitype@^1.0.2, abitype@^1.2.3: + version "1.2.4" + resolved "https://registry.yarnpkg.com/abitype/-/abitype-1.2.4.tgz#8aab72949bcad4107031862ae998e5bd20eec76e" + integrity sha512-dpKH+N27vRjarMVTFFkeY445VTKftzGWpL0FiT7xmVmzQRKazZexzC5uHG0f6XKsVLAuUlndnbGau6lRejClxg== + acorn-jsx@^5.3.1: version "5.3.2" resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz#7ed5bb55908b3b2f1bc55c6af1653bada7f07937" @@ -1391,6 +1515,15 @@ arrify@^1.0.0: resolved "https://registry.yarnpkg.com/arrify/-/arrify-1.0.1.tgz#898508da2226f380df904728456849c1501a4b0d" integrity sha512-3CYzex9M9FGQjCGMGyi6/31c8GJbgb0qGyrx5HWxPd0aCwh4cB2YjMb2Xf9UuoogrMrlO9cTqnB5rI5GHZTcUA== +asn1js@^3.0.6: + version "3.0.10" + resolved "https://registry.yarnpkg.com/asn1js/-/asn1js-3.0.10.tgz#df26c874c8a8b41ca605efea47b2ad07551013dd" + integrity sha512-S2s3aOytiKdFRdulw2qPE51MzjzVOisppcVv7jVFR+Kw0kxwvFrDcYA0h7Ndqbmj0HkMIXYWaoj7fli8kgx1eg== + dependencies: + pvtsutils "^1.3.6" + pvutils "^1.1.5" + tslib "^2.8.1" + assertion-error@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/assertion-error/-/assertion-error-2.0.1.tgz#f641a196b335690b1070bf00b6e7593fec190bf7" @@ -2335,16 +2468,16 @@ ethers@^6.14.1: tslib "2.7.0" ws "8.17.1" +eventemitter3@5.0.1, eventemitter3@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-5.0.1.tgz#53f5ffd0a492ac800721bb42c66b841de96423c4" + integrity sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA== + eventemitter3@^4.0.7: version "4.0.7" resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-4.0.7.tgz#2de9b68f6528d5644ef5c59526a1b4a07306169f" integrity sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw== -eventemitter3@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-5.0.1.tgz#53f5ffd0a492ac800721bb42c66b841de96423c4" - integrity sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA== - eyes@^0.1.8: version "0.1.8" resolved "https://registry.yarnpkg.com/eyes/-/eyes-0.1.8.tgz#62cf120234c683785d902348a800ef3e0cc20bc0" @@ -3021,6 +3154,11 @@ isomorphic-ws@^4.0.1: resolved "https://registry.yarnpkg.com/isomorphic-ws/-/isomorphic-ws-4.0.1.tgz#55fd4cd6c5e6491e76dc125938dd863f5cd4f2dc" integrity sha512-BhBvN2MBpWTaSHdWRb/bwdZJ1WaehQ2L1KngkCkfLUGF0mAWAT1sQUQacEmQ0jXkFw/czDXPNQSL5u2/Krsz1w== +isows@1.0.7: + version "1.0.7" + resolved "https://registry.yarnpkg.com/isows/-/isows-1.0.7.tgz#1c06400b7eed216fbba3bcbd68f12490fc342915" + integrity sha512-I1fSfDCZL5P0v33sVqeTDSpcstAg/N+wF5HS033mogOVIp4B+oHC7oOCsA3axAbBSGTJ8QubbNmnIRN/h8U7hg== + jackspeak@^3.1.2: version "3.4.3" resolved "https://registry.yarnpkg.com/jackspeak/-/jackspeak-3.4.3.tgz#8833a9d89ab4acde6188942bd1c53b6390ed5a8a" @@ -3476,6 +3614,20 @@ own-keys@^1.0.1: object-keys "^1.1.1" safe-push-apply "^1.0.0" +ox@0.14.20: + version "0.14.20" + resolved "https://registry.yarnpkg.com/ox/-/ox-0.14.20.tgz#b9ff923c88976508b63648fa7a01b6106cf71ff4" + integrity sha512-rby38C3nDn8eQkf29Zgw4hkCZJ64Qqi0zRPWL8ENUQ7JVuoITqrVtwWQgM/He19SCMUEc7hS/Sjw0jIOSLJhOw== + dependencies: + "@adraffy/ens-normalize" "^1.11.0" + "@noble/ciphers" "^1.3.0" + "@noble/curves" "1.9.1" + "@noble/hashes" "^1.8.0" + "@scure/bip32" "^1.7.0" + "@scure/bip39" "^1.6.0" + abitype "^1.2.3" + eventemitter3 "5.0.1" + p-limit@^3.0.2: version "3.1.0" resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-3.1.0.tgz#e1daccbe78d0d1388ca18c64fea38e3e57e3706b" @@ -3626,6 +3778,18 @@ punycode@^2.1.0: resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.3.1.tgz#027422e2faec0b25e1549c3e1bd8309b9133b6e5" integrity sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg== +pvtsutils@^1.3.6: + version "1.3.6" + resolved "https://registry.yarnpkg.com/pvtsutils/-/pvtsutils-1.3.6.tgz#ec46e34db7422b9e4fdc5490578c1883657d6001" + integrity sha512-PLgQXQ6H2FWCaeRak8vvk1GW462lMxB5s3Jm673N82zI4vqtVUPuZdffdZbPDFRoU8kAhItWFtPCWiPpp4/EDg== + dependencies: + tslib "^2.8.1" + +pvutils@^1.1.5: + version "1.1.5" + resolved "https://registry.yarnpkg.com/pvutils/-/pvutils-1.1.5.tgz#84b0dea4a5d670249aa9800511804ee0b7c2809c" + integrity sha512-KTqnxsgGiQ6ZAzZCVlJH5eOjSnvlyEgx1m8bkRJfOhmGRqfo5KLvmAlACQkrjEtOQ4B7wF9TdSLIs9O90MX9xA== + queue-microtask@^1.2.2: version "1.2.3" resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243" @@ -3810,6 +3974,16 @@ semver@^7.2.1, semver@^7.3.5, semver@^7.5.2, semver@^7.6.3: resolved "https://registry.yarnpkg.com/semver/-/semver-7.7.2.tgz#67d99fdcd35cec21e6f8b87a7fd515a33f982b58" integrity sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA== +semver@^7.6.2: + version "7.7.4" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.7.4.tgz#28464e36060e991fa7a11d0279d2d3f3b57a7e8a" + integrity sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA== + +semver@^7.7.2: + version "7.8.0" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.8.0.tgz#ed0661039fcbcda2ce71f01fa6adbefaa77040df" + integrity sha512-AcM7dV/5ul4EekoQ29Agm5vri8JNqRyj39o0qpX6vDF2GZrtutZl5RwgD1XnZjiTAfncsJhMI48QQH3sN87YNA== + serialize-javascript@^6.0.2: version "6.0.2" resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-6.0.2.tgz#defa1e055c83bf6d59ea805d8da862254eb6a6c2" @@ -4261,7 +4435,7 @@ tslib@^1.8.1: resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== -tslib@^2.8.0: +tslib@^2.8.0, tslib@^2.8.1: version "2.8.1" resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.8.1.tgz#612efe4ed235d567e8aba5f2a5fab70280ade83f" integrity sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w== @@ -4435,6 +4609,20 @@ v8-compile-cache@^2.0.3: resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.4.0.tgz#cdada8bec61e15865f05d097c5f4fd30e94dc128" integrity sha512-ocyWc3bAHBB/guyqJQVI5o4BZkPhznPYUG2ea80Gond/BgNWpap8TOmLSeeQG7bnh2KMISxskdADG59j7zruhw== +viem@^2.21.8: + version "2.48.8" + resolved "https://registry.yarnpkg.com/viem/-/viem-2.48.8.tgz#ce3f6dd8d5cfe31f3bb0c0c368bdd3f7c331150f" + integrity sha512-Xj3Nrt66SKtn06kczU91ELn9Difr84ZM5A62BTlaisT5lpgt058i2mBkfMZCXHGb1ocOLjzC2ztPhD0Lvky7uQ== + dependencies: + "@noble/curves" "1.9.1" + "@noble/hashes" "1.8.0" + "@scure/bip32" "1.7.0" + "@scure/bip39" "1.6.0" + abitype "1.2.3" + isows "1.0.7" + ox "0.14.20" + ws "8.18.3" + webidl-conversions@^3.0.0: version "3.0.1" resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz#24534275e2a7bc6be7bc86611cc16ae0a5654871" @@ -4563,6 +4751,11 @@ ws@8.17.1: resolved "https://registry.yarnpkg.com/ws/-/ws-8.17.1.tgz#9293da530bb548febc95371d90f9c878727d919b" integrity sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ== +ws@8.18.3, ws@^8.5.0: + version "8.18.3" + resolved "https://registry.yarnpkg.com/ws/-/ws-8.18.3.tgz#b56b88abffde62791c639170400c93dcb0c95472" + integrity sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg== + ws@^7.5.10: version "7.5.10" resolved "https://registry.yarnpkg.com/ws/-/ws-7.5.10.tgz#58b5c20dc281633f6c19113f39b349bd8bd558d9" @@ -4573,11 +4766,6 @@ ws@^8.18.0: resolved "https://registry.yarnpkg.com/ws/-/ws-8.18.2.tgz#42738b2be57ced85f46154320aabb51ab003705a" integrity sha512-DMricUmwGZUVr++AEAe2uiVM7UoO9MAVZMDu05UQOaUII0lp+zOzLLU4Xqh/JvTqklB1T4uELaaPBKyjE1r4fQ== -ws@^8.5.0: - version "8.18.3" - resolved "https://registry.yarnpkg.com/ws/-/ws-8.18.3.tgz#b56b88abffde62791c639170400c93dcb0c95472" - integrity sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg== - y18n@^5.0.5: version "5.0.8" resolved "https://registry.yarnpkg.com/y18n/-/y18n-5.0.8.tgz#7f4934d0f7ca8c56f95314939ddcd2dd91ce1d55" From 7d1fde433a4ad488ae4bb265918c0c0140c83c5b Mon Sep 17 00:00:00 2001 From: lgalende Date: Mon, 11 May 2026 17:51:42 -0300 Subject: [PATCH 2/3] chore: rename function and improve params --- packages/evm/scripts/upgrade-settler.ts | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/packages/evm/scripts/upgrade-settler.ts b/packages/evm/scripts/upgrade-settler.ts index eaf2f5a..4634044 100644 --- a/packages/evm/scripts/upgrade-settler.ts +++ b/packages/evm/scripts/upgrade-settler.ts @@ -1,6 +1,7 @@ import { HardhatEthers, HardhatEthersSigner } from '@nomicfoundation/hardhat-ethers/types' import SafeApiKit from '@safe-global/api-kit' import Safe from '@safe-global/protocol-kit' +import { MetaTransactionData as Transaction } from '@safe-global/types-kit' import { Contract, getAddress, Wallet } from 'ethers' import { network } from 'hardhat' @@ -32,8 +33,11 @@ async function main(): Promise { if (safeAddress) { const { chainId } = await ethers.provider.getNetwork() if (networkConfig.type !== 'http') throw Error('Safe proposal requires an HTTP network') + const to = await proxyAdmin.getAddress() + const data = proxyAdmin.interface.encodeFunctionData('upgradeAndCall', [proxy, implementation.target, '0x']) + const transactions = [{ to, value: '0', data }] const rpcUrl = await networkConfig.url.getUrl() - await proposeTransaction(safeAddress, proxyAdmin, proxy, implementation.target, chainId, rpcUrl) + await proposeSafeTransaction(safeAddress, transactions, chainId, rpcUrl) } else { const tx = await proxyAdmin.upgradeAndCall(proxy, implementation.target, '0x') await tx.wait() @@ -41,11 +45,9 @@ async function main(): Promise { } } -async function proposeTransaction( +async function proposeSafeTransaction( safeAddress: string, - proxyAdmin: Contract, - proxy: string, - implementation: string, + transactions: Transaction[], chainId: bigint, rpcUrl: string ): Promise { @@ -61,12 +63,7 @@ async function proposeTransaction( const apiKit = new SafeApiKit({ chainId, apiKey: process.env.SAFE_API_KEY }) - const data = proxyAdmin.interface.encodeFunctionData('upgradeAndCall', [proxy, implementation, '0x']) - const to = String(await proxyAdmin.getAddress()) - - const safeTransaction = await safe.createTransaction({ - transactions: [{ to, value: '0', data }], - }) + const safeTransaction = await safe.createTransaction({ transactions }) const safeTxHash = await safe.getTransactionHash(safeTransaction) const senderSignature = signer.signingKey.sign(safeTxHash).serialized From bdee9d698ef6555cdb3b073267f02ec33eda2d5b Mon Sep 17 00:00:00 2001 From: lgalende Date: Mon, 11 May 2026 18:20:38 -0300 Subject: [PATCH 3/3] evm: use ethers signer --- packages/evm/scripts/upgrade-settler.ts | 31 +++++++++---------------- 1 file changed, 11 insertions(+), 20 deletions(-) diff --git a/packages/evm/scripts/upgrade-settler.ts b/packages/evm/scripts/upgrade-settler.ts index 4634044..f1fe37b 100644 --- a/packages/evm/scripts/upgrade-settler.ts +++ b/packages/evm/scripts/upgrade-settler.ts @@ -2,7 +2,7 @@ import { HardhatEthers, HardhatEthersSigner } from '@nomicfoundation/hardhat-eth import SafeApiKit from '@safe-global/api-kit' import Safe from '@safe-global/protocol-kit' import { MetaTransactionData as Transaction } from '@safe-global/types-kit' -import { Contract, getAddress, Wallet } from 'ethers' +import { Contract, Eip1193Provider, getAddress } from 'ethers' import { network } from 'hardhat' import ProxyAdminArtifact from '../artifacts/@openzeppelin/contracts/proxy/transparent/ProxyAdmin.sol/ProxyAdmin.json' @@ -12,7 +12,7 @@ import { deployCreate3 } from './deploy-create3' const ERC1967_ADMIN_SLOT = '0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103' async function main(): Promise { - const { ethers, networkConfig } = await network.connect() + const { ethers, networkConfig, provider } = await network.connect() const [signer] = await ethers.getSigners() if (!process.env.SETTLER_PROXY) throw Error('SETTLER_PROXY env variable not provided') @@ -36,8 +36,7 @@ async function main(): Promise { const to = await proxyAdmin.getAddress() const data = proxyAdmin.interface.encodeFunctionData('upgradeAndCall', [proxy, implementation.target, '0x']) const transactions = [{ to, value: '0', data }] - const rpcUrl = await networkConfig.url.getUrl() - await proposeSafeTransaction(safeAddress, transactions, chainId, rpcUrl) + await proposeSafeTransaction(safeAddress, transactions, chainId, signer, provider) } else { const tx = await proxyAdmin.upgradeAndCall(proxy, implementation.target, '0x') await tx.wait() @@ -49,31 +48,23 @@ async function proposeSafeTransaction( safeAddress: string, transactions: Transaction[], chainId: bigint, - rpcUrl: string + signer: HardhatEthersSigner, + provider: Eip1193Provider ): Promise { if (!process.env.SAFE_API_KEY) throw Error('SAFE_API_KEY env variable required for Safe proposal') - - if (!process.env.DEPLOYER_PRIVATE_KEY) throw Error('DEPLOYER_PRIVATE_KEY env variable required for Safe proposal') - const signer = new Wallet(process.env.DEPLOYER_PRIVATE_KEY) - - const safe = await Safe.init({ - provider: rpcUrl, - safeAddress, - }) - const apiKit = new SafeApiKit({ chainId, apiKey: process.env.SAFE_API_KEY }) - const safeTransaction = await safe.createTransaction({ transactions }) - - const safeTxHash = await safe.getTransactionHash(safeTransaction) - const senderSignature = signer.signingKey.sign(safeTxHash).serialized + const safe = await Safe.init({ safeAddress, signer: signer.address, provider }) + const safeTx = await safe.createTransaction({ transactions }) + const safeTxHash = await safe.getTransactionHash(safeTx) + const senderSignature = await safe.signHash(safeTxHash) await apiKit.proposeTransaction({ safeAddress, - safeTransactionData: safeTransaction.data, + safeTransactionData: safeTx.data, safeTxHash, senderAddress: signer.address, - senderSignature, + senderSignature: senderSignature.data, }) console.log(`✅ Upgrade proposed to Safe ${safeAddress}`)