feat(infra): Add script to create safes and add safe addresses for new chains (#4127)

### Description

<!--
What's included in this PR?
-->

- Add an infra script to create a safe on specific chain using the
`safeSigners.json` config where the safe signers are defined

### Drive-by changes

<!--
Are there any minor or drive-by changes also included?
-->

### Related issues

<!--
- Fixes #[issue number here]
-->

### Backward compatibility

<!--
Are these changes backward compatible? Are there any infrastructure
implications, e.g. changes that would prohibit deploying older commits
using this infra tooling?

Yes/No
-->

### Testing

<!--
What kind of testing have these changes undergone?

None/Manual/Unit Tests
-->
Manual
pull/4176/head
Mohammed Hussan 4 months ago committed by GitHub
parent 97588b6fc1
commit 944b2f65e1
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 8
      typescript/infra/config/environments/mainnet3/owners.ts
  2. 13
      typescript/infra/config/environments/mainnet3/safe/safeSigners.json
  3. 1
      typescript/infra/package.json
  4. 13
      typescript/infra/scripts/agent-utils.ts
  5. 79
      typescript/infra/scripts/safes/create-safe.ts
  6. 130
      yarn.lock

@ -42,6 +42,14 @@ export const safes: ChainMap<Address | undefined> = {
blast: '0xaCD1865B262C89Fb0b50dcc8fB095330ae8F35b5',
linea: '0xaCD1865B262C89Fb0b50dcc8fB095330ae8F35b5',
mode: '0xaCD1865B262C89Fb0b50dcc8fB095330ae8F35b5',
ancient8: '0xD2BFA0F0654E3f2139b8cDC56c32eeC54D32b133',
taiko: '0xa4864301d3fa2a3e68256309F9F0F570270a1BD0',
fraxtal: '0x66e9f52800E9F89F0569fddc594Acd5EE609f762',
sei: '0xCed197FBc360C26C19889745Cf73511b71D03d5D',
redstone: '0xa1a50ff5FD859558E1899fEC5C3064483177FA23',
mantle: '0x8aFE6EECc6CcB02aA20DA8Fff7d29aadEBbc2DCd',
bob: '0x9e2fe7723b018d02cDE4f5cC1A9bC9C65b922Fc8',
zetachain: '0x9d399876522Fc5C044D048594de399A2349d6026',
};
export const DEPLOYER = '0xa7ECcdb9Be08178f896c26b7BbD8C3D4E844d9Ba';

@ -0,0 +1,13 @@
{
"signers": [
"0xa7ECcdb9Be08178f896c26b7BbD8C3D4E844d9Ba",
"0xc3E966E79eF1aA4751221F55fB8A36589C24C0cA",
"0x3b7f8f68A4FD0420FeA2F42a1eFc53422f205599",
"0x88436919fAa2310d32A36D20d13E0a441D24fAc3",
"0x003DDD9eEAb62013b7332Ab4CC6B10077a8ca961",
"0xd00d6A31485C93c597D1d8231eeeE0ed17B9844B",
"0x483fd7284A696343FEc0819DDF2cf7E06E8A06E5",
"0x5b73A98165778BCCE72979B4EE3faCdb31728b8E",
"0x5dd9a0814022A61777938263308EBB336174f13D"
]
}

@ -18,6 +18,7 @@
"@hyperlane-xyz/sdk": "4.1.0",
"@hyperlane-xyz/utils": "4.1.0",
"@nomiclabs/hardhat-etherscan": "^3.0.3",
"@safe-global/protocol-kit": "^4.0.2",
"@solana/web3.js": "^1.78.0",
"asn1.js": "5.4.1",
"aws-kms-ethers-signer": "^0.1.3",

@ -109,6 +109,19 @@ export function withChainRequired<T>(args: Argv<T>) {
return withChain(args).demandOption('chain');
}
export function withSafeTxServiceUrlRequired<T>(args: Argv<T>) {
return args
.describe('safeTxServiceUrl', 'Custom safe transaction service url')
.demandOption('safeTxServiceUrl');
}
export function withThreshold<T>(args: Argv<T>) {
return args
.describe('threshold', 'threshold for multisig')
.number('threshold')
.default('threshold', 4);
}
export function withChain<T>(args: Argv<T>) {
return args
.describe('chain', 'chain name')

@ -0,0 +1,79 @@
import { SafeFactory } from '@safe-global/protocol-kit';
import { SafeAccountConfig } from '@safe-global/protocol-kit';
import { Contexts } from '../../config/contexts.js';
import { getChain } from '../../config/registry.js';
import { Role } from '../../src/roles.js';
import { readJSONAtPath } from '../../src/utils/utils.js';
import {
getArgs,
getKeyForRole,
withChainRequired,
withSafeTxServiceUrlRequired,
withThreshold,
} from '../agent-utils.js';
const OWNERS_FILE_PATH = 'config/environments/mainnet3/safe/safeSigners.json';
async function main() {
const { chain, safeTxServiceUrl, threshold } = await withThreshold(
withSafeTxServiceUrlRequired(withChainRequired(getArgs())),
).argv;
const chainMetadata = await getChain(chain);
const rpcUrls = chainMetadata.rpcUrls;
const deployerPrivateKey = await getDeployerPrivateKey();
let safeFactory;
try {
safeFactory = await SafeFactory.init({
provider: rpcUrls[0].http,
signer: deployerPrivateKey,
});
} catch (e) {
console.error(`Error initializing SafeFactory: ${e}`);
process.exit(1);
}
const ownersConfig = readJSONAtPath(OWNERS_FILE_PATH);
const owners = ownersConfig.signers;
const safeAccountConfig: SafeAccountConfig = {
owners,
threshold,
};
let safe;
try {
safe = await safeFactory.deploySafe({ safeAccountConfig });
} catch (e) {
console.error(`Error deploying Safe: ${e}`);
process.exit(1);
}
const safeAddress = await safe.getAddress();
console.log(`Safe address: ${safeAddress}`);
console.log(
`Safe url: ${safeTxServiceUrl}/home?safe=${chain}:${safeAddress}`,
);
console.log('url may not be correct, please check by following the link');
}
const getDeployerPrivateKey = async () => {
const key = await getKeyForRole(
'mainnet3',
Contexts.Hyperlane,
Role.Deployer,
);
await key.fetch();
return key.privateKey;
};
main()
.then()
.catch((e) => {
console.error(e);
process.exit(1);
});

@ -19,6 +19,13 @@ __metadata:
languageName: node
linkType: hard
"@adraffy/ens-normalize@npm:1.10.1":
version: 1.10.1
resolution: "@adraffy/ens-normalize@npm:1.10.1"
checksum: 4cb938c4abb88a346d50cb0ea44243ab3574330c81d4f5aaaf9dfee584b96189d0faa404de0fcbef5a1b73909ea4ebc3e63d84bd23f9949e5c8d4085207a5091
languageName: node
linkType: hard
"@ampproject/remapping@npm:^2.2.0":
version: 2.2.1
resolution: "@ampproject/remapping@npm:2.2.1"
@ -5843,6 +5850,7 @@ __metadata:
"@nomiclabs/hardhat-ethers": "npm:^2.2.3"
"@nomiclabs/hardhat-etherscan": "npm:^3.0.3"
"@nomiclabs/hardhat-waffle": "npm:^2.0.6"
"@safe-global/protocol-kit": "npm:^4.0.2"
"@solana/web3.js": "npm:^1.78.0"
"@types/chai": "npm:^4.2.21"
"@types/json-stable-stringify": "npm:^1.0.36"
@ -7054,6 +7062,13 @@ __metadata:
languageName: node
linkType: hard
"@noble/hashes@npm:^1.3.3":
version: 1.4.0
resolution: "@noble/hashes@npm:1.4.0"
checksum: e156e65794c473794c52fa9d06baf1eb20903d0d96719530f523cc4450f6c721a957c544796e6efd0197b2296e7cd70efeb312f861465e17940a3e3c7e0febc6
languageName: node
linkType: hard
"@noble/secp256k1@npm:1.5.5, @noble/secp256k1@npm:~1.5.2":
version: 1.5.5
resolution: "@noble/secp256k1@npm:1.5.5"
@ -8067,6 +8082,21 @@ __metadata:
languageName: node
linkType: hard
"@safe-global/protocol-kit@npm:^4.0.2":
version: 4.0.2
resolution: "@safe-global/protocol-kit@npm:4.0.2"
dependencies:
"@noble/hashes": "npm:^1.3.3"
"@safe-global/safe-core-sdk-types": "npm:^5.0.2"
"@safe-global/safe-deployments": "npm:^1.37.0"
abitype: "npm:^1.0.2"
ethereumjs-util: "npm:^7.1.5"
ethers: "npm:^6.13.1"
semver: "npm:^7.6.2"
checksum: aff8dfda28e2adc0a965969fb3513354eda7d4bf8de574075ccdac932b48337063f519fcffcf71b53b97658009e390ec7dbea84bd6c0a19ec6ff18c0a4570b68
languageName: node
linkType: hard
"@safe-global/safe-apps-provider@npm:^0.15.2":
version: 0.15.2
resolution: "@safe-global/safe-apps-provider@npm:0.15.2"
@ -8110,6 +8140,15 @@ __metadata:
languageName: node
linkType: hard
"@safe-global/safe-core-sdk-types@npm:^5.0.2":
version: 5.0.2
resolution: "@safe-global/safe-core-sdk-types@npm:5.0.2"
dependencies:
abitype: "npm:^1.0.2"
checksum: 53f0221e1c86b5b04f75cc773527e5e9c59ebb13ec21fe9a9246f6834c45b107e9a165da08ed58d40ed2564952f5360fb4c02051f236bfcc61bbfdb6015e3663
languageName: node
linkType: hard
"@safe-global/safe-deployments@npm:^1.26.0":
version: 1.26.0
resolution: "@safe-global/safe-deployments@npm:1.26.0"
@ -8119,6 +8158,15 @@ __metadata:
languageName: node
linkType: hard
"@safe-global/safe-deployments@npm:^1.37.0":
version: 1.37.1
resolution: "@safe-global/safe-deployments@npm:1.37.1"
dependencies:
semver: "npm:^7.6.2"
checksum: 2cb05ad0d1768264885d9e92d1fcc1340af77f88605ac46fd99b8aa4118d923671e4bb3d380e3dd7caa13ca4e8ed6edae4765dd5394b78966a51f391375d683b
languageName: node
linkType: hard
"@safe-global/safe-gateway-typescript-sdk@npm:^3.5.3":
version: 3.17.0
resolution: "@safe-global/safe-gateway-typescript-sdk@npm:3.17.0"
@ -9770,6 +9818,13 @@ __metadata:
languageName: node
linkType: hard
"@types/node@npm:18.15.13":
version: 18.15.13
resolution: "@types/node@npm:18.15.13"
checksum: b9bbe923573797ef7c5fd2641a6793489e25d9369c32aeadcaa5c7c175c85b42eb12d6fe173f6781ab6f42eaa1ebd9576a419eeaa2a1ec810094adb8adaa9a54
languageName: node
linkType: hard
"@types/node@npm:>=13.7.0":
version: 20.8.9
resolution: "@types/node@npm:20.8.9"
@ -10864,6 +10919,21 @@ __metadata:
languageName: node
linkType: hard
"abitype@npm:^1.0.2":
version: 1.0.5
resolution: "abitype@npm:1.0.5"
peerDependencies:
typescript: ">=5.0.4"
zod: ^3 >=3.22.0
peerDependenciesMeta:
typescript:
optional: true
zod:
optional: true
checksum: 1acd0d9687945dd78442b71bd84ff3b9dceae27d15f0d8b14b16554a0c8c9518eeb971ff8e94d507f4d9f05a8a8b91eb8fafd735eaecebac37d5c5a4aac06d8e
languageName: node
linkType: hard
"abort-controller@npm:^3.0.0":
version: 3.0.0
resolution: "abort-controller@npm:3.0.0"
@ -10991,6 +11061,13 @@ __metadata:
languageName: node
linkType: hard
"aes-js@npm:4.0.0-beta.5":
version: 4.0.0-beta.5
resolution: "aes-js@npm:4.0.0-beta.5"
checksum: 8f745da2e8fb38e91297a8ec13c2febe3219f8383303cd4ed4660ca67190242ccfd5fdc2f0d1642fd1ea934818fb871cd4cc28d3f28e812e3dc6c3d0f1f97c24
languageName: node
linkType: hard
"aes-js@npm:^3.1.2":
version: 3.1.2
resolution: "aes-js@npm:3.1.2"
@ -14788,6 +14865,21 @@ __metadata:
languageName: node
linkType: hard
"ethers@npm:^6.13.1":
version: 6.13.1
resolution: "ethers@npm:6.13.1"
dependencies:
"@adraffy/ens-normalize": "npm:1.10.1"
"@noble/curves": "npm:1.2.0"
"@noble/hashes": "npm:1.3.2"
"@types/node": "npm:18.15.13"
aes-js: "npm:4.0.0-beta.5"
tslib: "npm:2.4.0"
ws: "npm:8.17.1"
checksum: efc3e8d4d13101cad01823ba524dad797a23f60088ca9f8677bd6dbfad5087e4187ede121e43aa0758d704525976f935860c5d5d27183a4247deaccf7cf19950
languageName: node
linkType: hard
"ethjs-unit@npm:0.1.6":
version: 0.1.6
resolution: "ethjs-unit@npm:0.1.6"
@ -22928,6 +23020,15 @@ __metadata:
languageName: node
linkType: hard
"semver@npm:^7.6.2":
version: 7.6.2
resolution: "semver@npm:7.6.2"
bin:
semver: bin/semver.js
checksum: 296b17d027f57a87ef645e9c725bff4865a38dfc9caf29b26aa084b85820972fbe7372caea1ba6857162fa990702c6d9c1d82297cecb72d56c78ab29070d2ca2
languageName: node
linkType: hard
"send@npm:0.18.0":
version: 0.18.0
resolution: "send@npm:0.18.0"
@ -24644,6 +24745,13 @@ __metadata:
languageName: node
linkType: hard
"tslib@npm:2.4.0, tslib@npm:^2.1.0, tslib@npm:^2.3.0, tslib@npm:^2.3.1, tslib@npm:^2.4.0":
version: 2.4.0
resolution: "tslib@npm:2.4.0"
checksum: d8379e68b36caf082c1905ec25d17df8261e1d68ddc1abfd6c91158a064f6e4402039ae7c02cf4c81d12e3a2a2c7cd8ea2f57b233eb80136a2e3e7279daf2911
languageName: node
linkType: hard
"tslib@npm:^2.0.0, tslib@npm:^2.6.2":
version: 2.6.2
resolution: "tslib@npm:2.6.2"
@ -24651,13 +24759,6 @@ __metadata:
languageName: node
linkType: hard
"tslib@npm:^2.1.0, tslib@npm:^2.3.0, tslib@npm:^2.3.1, tslib@npm:^2.4.0":
version: 2.4.0
resolution: "tslib@npm:2.4.0"
checksum: d8379e68b36caf082c1905ec25d17df8261e1d68ddc1abfd6c91158a064f6e4402039ae7c02cf4c81d12e3a2a2c7cd8ea2f57b233eb80136a2e3e7279daf2911
languageName: node
linkType: hard
"tsort@npm:0.0.1":
version: 0.0.1
resolution: "tsort@npm:0.0.1"
@ -26237,6 +26338,21 @@ __metadata:
languageName: node
linkType: hard
"ws@npm:8.17.1":
version: 8.17.1
resolution: "ws@npm:8.17.1"
peerDependencies:
bufferutil: ^4.0.1
utf-8-validate: ">=5.0.2"
peerDependenciesMeta:
bufferutil:
optional: true
utf-8-validate:
optional: true
checksum: 4264ae92c0b3e59c7e309001e93079b26937aab181835fb7af79f906b22cd33b6196d96556dafb4e985742dd401e99139572242e9847661fdbc96556b9e6902d
languageName: node
linkType: hard
"ws@npm:^3.0.0":
version: 3.3.3
resolution: "ws@npm:3.3.3"

Loading…
Cancel
Save