UNPKG

@hyperlane-xyz/sdk

Version:

The official SDK for the Hyperlane Network

135 lines 5.48 kB
import SafeApiKit from '@safe-global/api-kit'; import Safe from '@safe-global/protocol-kit'; import { getMultiSendCallOnlyDeployment, getMultiSendDeployment, } from '@safe-global/safe-deployments'; export function safeApiKeyRequired(txServiceUrl) { return /safe\.global|5afe\.dev/.test(txServiceUrl); } export function getSafeService(chain, multiProvider) { const { gnosisSafeTransactionServiceUrl, gnosisSafeApiKey } = multiProvider.getChainMetadata(chain); let txServiceUrl = gnosisSafeTransactionServiceUrl; if (!txServiceUrl) { throw new Error(`must provide tx service url for ${chain}`); } // Ensure txServiceUrl ends with /api if (!txServiceUrl.endsWith('/api') && !txServiceUrl.endsWith('/api/') && !txServiceUrl.endsWith('api')) { // Remove trailing slash if present to avoid double slashes txServiceUrl = txServiceUrl.replace(/\/+$/, ''); txServiceUrl = `${txServiceUrl}/api`; } const chainId = multiProvider.getEvmChainId(chain); if (!chainId) { throw new Error(`Chain is not an EVM chain: ${chain}`); } // @ts-ignore return new SafeApiKit({ chainId: BigInt(chainId), txServiceUrl, // Only provide apiKey if the url contains safe.global or 5afe.dev apiKey: safeApiKeyRequired(txServiceUrl) ? gnosisSafeApiKey : undefined, }); } // This is the version of the Safe contracts that the SDK is compatible with. // Copied the MVP fields from https://github.com/safe-global/safe-core-sdk/blob/4d1c0e14630f951c2498e1d4dd521403af91d6e1/packages/protocol-kit/src/contracts/config.ts#L19 // because the SDK doesn't expose this value. const safeDeploymentsVersions = { '1.4.1': { multiSendVersion: '1.4.1', multiSendCallOnlyVersion: '1.4.1', }, '1.3.0': { multiSendVersion: '1.3.0', multiSendCallOnlyVersion: '1.3.0', }, '1.2.0': { multiSendVersion: '1.1.1', multiSendCallOnlyVersion: '1.3.0', }, '1.1.1': { multiSendVersion: '1.1.1', multiSendCallOnlyVersion: '1.3.0', }, '1.0.0': { multiSendVersion: '1.1.1', multiSendCallOnlyVersion: '1.3.0', }, }; // Override for chains that haven't yet been published in the safe-deployments package. // Temporary until PR to safe-deployments package is merged and SDK dependency is updated. const chainOverrides = { // zeronetwork 543210: { multiSend: '0x0dFcccB95225ffB03c6FBB2559B530C2B7C8A912', multiSendCallOnly: '0xf220D3b4DFb23C4ade8C88E526C1353AbAcbC38F', }, // berachain 80094: { multiSend: '0xA238CBeb142c10Ef7Ad8442C6D1f9E89e07e7761', multiSendCallOnly: '0x40A2aCCbd92BCA938b02010E17A5b8929b49130D', }, }; export async function getSafe(chain, multiProvider, safeAddress, signer) { // Get the chain id for the given chain const chainId = `${multiProvider.getEvmChainId(chain)}`; // Get the safe version const safeService = getSafeService(chain, multiProvider); const { version: rawSafeVersion } = await safeService.getSafeInfo(safeAddress); // Remove any build metadata from the version e.g. 1.3.0+L2 --> 1.3.0 const safeVersion = rawSafeVersion.split(' ')[0].split('+')[0].split('-')[0]; // Get the multiSend and multiSendCallOnly deployments for the given chain let multiSend, multiSendCallOnly; if (chainOverrides[chainId]) { multiSend = { networkAddresses: { [chainId]: chainOverrides[chainId].multiSend }, }; multiSendCallOnly = { networkAddresses: { [chainId]: chainOverrides[chainId].multiSendCallOnly, }, }; } else if (safeDeploymentsVersions[safeVersion]) { const { multiSendVersion, multiSendCallOnlyVersion } = safeDeploymentsVersions[safeVersion]; multiSend = getMultiSendDeployment({ version: multiSendVersion, network: chainId, }); multiSendCallOnly = getMultiSendCallOnlyDeployment({ version: multiSendCallOnlyVersion, network: chainId, }); } // @ts-ignore return Safe.init({ provider: multiProvider.getChainMetadata(chain).rpcUrls[0].http, signer, safeAddress, contractNetworks: { [chainId]: { // Use the safe address for multiSendAddress and multiSendCallOnlyAddress // if the contract is not deployed or if the version is not found. multiSendAddress: multiSend?.networkAddresses[chainId] || safeAddress, multiSendCallOnlyAddress: multiSendCallOnly?.networkAddresses[chainId] || safeAddress, }, }, }); } export async function getSafeDelegates(service, safeAddress) { const delegateResponse = await service.getSafeDelegates({ safeAddress }); return delegateResponse.results.map((r) => r.delegate); } export async function canProposeSafeTransactions(proposer, chain, multiProvider, safeAddress) { let safeService; try { safeService = getSafeService(chain, multiProvider); } catch { return false; } const safe = await getSafe(chain, multiProvider, safeAddress); const delegates = await getSafeDelegates(safeService, safeAddress); const owners = await safe.getOwners(); return delegates.includes(proposer) || owners.includes(proposer); } //# sourceMappingURL=gnosisSafe.js.map