Skip to content

Commit 79a51de

Browse files
authored
feat: safe api key support (#7090)
1 parent a514d2b commit 79a51de

File tree

12 files changed

+406
-1607
lines changed

12 files changed

+406
-1607
lines changed

.changeset/weak-trainers-join.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@hyperlane-xyz/sdk": minor
3+
---
4+
5+
Update all @safe-global dependencies to latest, to support usage of Safe API Keys. Add gnosisSafeApiKey to chain metadata schema.

typescript/infra/package.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,9 @@
2020
"@hyperlane-xyz/utils": "19.4.0",
2121
"@inquirer/prompts": "3.3.2",
2222
"@nomiclabs/hardhat-etherscan": "^3.0.3",
23-
"@safe-global/api-kit": "1.3.0",
24-
"@safe-global/protocol-kit": "1.3.0",
25-
"@safe-global/safe-core-sdk-types": "2.3.0",
23+
"@safe-global/api-kit": "4.0.0",
24+
"@safe-global/protocol-kit": "6.1.1",
25+
"@safe-global/safe-core-sdk-types": "5.1.0",
2626
"@solana/web3.js": "^1.98.4",
2727
"@turnkey/api-key-stamper": "^0.5.0",
2828
"@turnkey/sdk-server": "^4.10.4",

typescript/infra/scripts/safe-delegate.ts

Lines changed: 0 additions & 72 deletions
This file was deleted.

typescript/infra/scripts/safes/create-safe.ts

Lines changed: 17 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,5 @@
1-
import {
2-
EthersAdapter,
3-
SafeAccountConfig,
4-
SafeFactory,
5-
} from '@safe-global/protocol-kit';
6-
import { ethers } from 'ethers';
1+
import Safe, { SafeAccountConfig } from '@safe-global/protocol-kit';
2+
import { BigNumber } from 'ethers';
73

84
import { rootLogger } from '@hyperlane-xyz/utils';
95

@@ -33,62 +29,33 @@ async function main() {
3329
[chain],
3430
);
3531

36-
const signer = multiProvider.getSigner(chain);
37-
const ethAdapter = new EthersAdapter({
38-
ethers,
39-
signerOrProvider: signer,
40-
});
41-
42-
let safeFactory;
43-
try {
44-
safeFactory = await SafeFactory.create({
45-
ethAdapter,
46-
});
47-
} catch (e) {
48-
rootLogger.error(`Error initializing SafeFactory: ${e}`);
49-
process.exit(1);
50-
}
51-
5232
const { signers, threshold: defaultThreshold } =
5333
getGovernanceSigners(governanceType);
5434
const safeAccountConfig: SafeAccountConfig = {
5535
owners: signers,
5636
threshold: threshold ?? defaultThreshold,
5737
};
5838

59-
let safe;
60-
try {
61-
safe = await safeFactory.deploySafe({ safeAccountConfig });
62-
} catch (e) {
63-
rootLogger.error(`Error deploying Safe: ${e}`);
64-
process.exit(1);
65-
}
39+
// @ts-ignore
40+
const safe = await Safe.init({
41+
provider: multiProvider.getChainMetadata(chain).rpcUrls[0].http,
42+
predictedSafe: {
43+
safeAccountConfig,
44+
},
45+
});
46+
47+
const { to, data, value } = await safe.createSafeDeploymentTransaction();
48+
await multiProvider.sendTransaction(chain, {
49+
to,
50+
data,
51+
value: BigNumber.from(value),
52+
});
6653

6754
const safeAddress = await safe.getAddress();
6855

6956
rootLogger.info(`Safe address: ${safeAddress}`);
7057
rootLogger.info(`Safe url: ${safeHomeUrl}/home?safe=${chain}:${safeAddress}`);
71-
rootLogger.info('url may not be correct, please check by following the link');
72-
73-
try {
74-
// TODO: check https://app.safe.global for officially supported chains, filter by chain id
75-
const chainsUrl = `${safeHomeUrl.replace(
76-
'https://',
77-
'https://gateway.',
78-
)}/v1/chains`;
79-
rootLogger.info(`Fetching chain data from ${chainsUrl}`);
80-
const response = await fetch(chainsUrl);
81-
82-
const resultsJson = await response.json();
83-
84-
const transactionService = resultsJson.results[0].transactionService;
85-
rootLogger.info(`Chains: ${JSON.stringify(transactionService)}`);
86-
rootLogger.info(
87-
`Add the transaction service url ${transactionService} as gnosisSafeTransactionServiceUrl to the metadata.yml in the registry`,
88-
);
89-
} catch (e) {
90-
rootLogger.error(`Could not fetch safe tx service url: ${e}`);
91-
}
58+
rootLogger.info('Please confirm the safe is created by following the link');
9259
}
9360

9461
main()

typescript/infra/src/config/chain.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import {
77
ChainName,
88
HyperlaneSmartProvider,
99
ProviderRetryOptions,
10+
safeApiKeyRequired,
1011
} from '@hyperlane-xyz/sdk';
1112
import {
1213
Address,
@@ -18,6 +19,7 @@ import {
1819

1920
import { getChain, getRegistryWithOverrides } from '../../config/registry.js';
2021
import { getSecretRpcEndpoints } from '../agents/index.js';
22+
import { getSafeApiKey } from '../utils/safe.js';
2123

2224
import { DeployEnvironment } from './environment.js';
2325

@@ -171,6 +173,9 @@ export async function getSecretMetadataOverrides(
171173
): Promise<ChainMap<Partial<ChainMetadata>>> {
172174
const chainMetadataOverrides: ChainMap<Partial<ChainMetadata>> = {};
173175

176+
// Fetch Safe API key once
177+
const safeApiKey = await getSafeApiKey();
178+
174179
const secretRpcUrls = await Promise.all(
175180
chains.map(async (chain) => {
176181
const rpcUrls = await getSecretRpcEndpoints(deployEnv, chain);
@@ -192,6 +197,13 @@ export async function getSecretMetadataOverrides(
192197
chainMetadataOverrides[chain] = {
193198
rpcUrls: metadataRpcUrls,
194199
};
200+
201+
// Add Safe API key if required
202+
const chainMetadata = getChain(chain);
203+
const txServiceUrl = chainMetadata.gnosisSafeTransactionServiceUrl;
204+
if (txServiceUrl && safeApiKeyRequired(txServiceUrl)) {
205+
chainMetadataOverrides[chain].gnosisSafeApiKey = safeApiKey;
206+
}
195207
}
196208

197209
return chainMetadataOverrides;

typescript/infra/src/tx/govern-transaction-reader.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import { Result } from '@ethersproject/abi';
2-
import { decodeMultiSendData } from '@safe-global/protocol-kit/dist/src/utils/index.js';
32
import {
43
MetaTransactionData,
54
OperationType,
@@ -71,7 +70,7 @@ import {
7170
Owner,
7271
determineGovernanceType,
7372
} from '../governance.js';
74-
import { getSafeTx, parseSafeTx } from '../utils/safe.js';
73+
import { decodeMultiSendData, getSafeTx, parseSafeTx } from '../utils/safe.js';
7574

7675
export interface GovernTransaction extends Record<string, any> {
7776
chain: ChainName;

0 commit comments

Comments
 (0)