fix: use known safe multisend addresses in getSafe (#4415)

- fix: use known safe addresses in getSafe
- also requires updating the MultiSend governor helper to handle cases
where there is no known `MultiSend` contract
- hardcodes the `safeDeploymentsVersions` mapping, as it's not exposed
by the safe protocol-kit
- introduce utilities in the MultiSend to delete specific or all pending
transactions
- add helper scripts for safe tx delete operations

---------

Signed-off-by: pbio <10051819+paulbalaji@users.noreply.github.com>
pull/4426/head
Paul Balaji 3 months ago committed by GitHub
parent a5afd20f3a
commit 88589eb2a3
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 2
      .github/workflows/test.yml
  2. 4
      typescript/infra/package.json
  3. 21
      typescript/infra/scripts/safes/create-safe.ts
  4. 40
      typescript/infra/scripts/safes/delete-pending-txs.ts
  5. 51
      typescript/infra/scripts/safes/delete-tx.ts
  6. 102
      typescript/infra/src/govern/multisend.ts
  7. 207
      typescript/infra/src/utils/safe.ts
  8. 1
      typescript/sdk/package.json
  9. 10
      typescript/sdk/src/index.ts
  10. 75
      typescript/sdk/src/utils/gnosisSafe.js
  11. 131
      yarn.lock

@ -410,7 +410,7 @@ jobs:
MAINNET3_ARBITRUM_RPC_URLS: ${{ secrets.MAINNET3_ARBITRUM_RPC_URLS }}
MAINNET3_OPTIMISM_RPC_URLS: ${{ secrets.MAINNET3_OPTIMISM_RPC_URLS }}
timeout-minutes: 4
timeout-minutes: 5
needs: [yarn-build]
strategy:
fail-fast: false

@ -18,7 +18,9 @@
"@hyperlane-xyz/sdk": "5.1.0",
"@hyperlane-xyz/utils": "5.1.0",
"@nomiclabs/hardhat-etherscan": "^3.0.3",
"@safe-global/protocol-kit": "^4.0.2",
"@safe-global/api-kit": "1.3.0",
"@safe-global/protocol-kit": "1.3.0",
"@safe-global/safe-core-sdk-types": "2.3.0",
"@solana/web3.js": "^1.78.0",
"asn1.js": "5.4.1",
"aws-kms-ethers-signer": "^0.1.3",

@ -1,5 +1,6 @@
import { SafeFactory } from '@safe-global/protocol-kit';
import { EthersAdapter, SafeFactory } from '@safe-global/protocol-kit';
import { SafeAccountConfig } from '@safe-global/protocol-kit';
import { ethers } from 'ethers';
import { Contexts } from '../../config/contexts.js';
import { getChain } from '../../config/registry.js';
@ -24,11 +25,17 @@ async function main() {
const rpcUrls = chainMetadata.rpcUrls;
const deployerPrivateKey = await getDeployerPrivateKey();
// Create ethers signer with deployer key
const provider = new ethers.providers.JsonRpcProvider(rpcUrls[0].http);
const ethAdapter = new EthersAdapter({
ethers,
signerOrProvider: new ethers.Wallet(deployerPrivateKey, provider),
});
let safeFactory;
try {
safeFactory = await SafeFactory.init({
provider: rpcUrls[0].http,
signer: deployerPrivateKey,
safeFactory = await SafeFactory.create({
ethAdapter,
});
} catch (e) {
console.error(`Error initializing SafeFactory: ${e}`);
@ -79,11 +86,7 @@ async function main() {
}
const getDeployerPrivateKey = async () => {
const key = await getKeyForRole(
'mainnet3',
Contexts.Hyperlane,
Role.Deployer,
);
const key = getKeyForRole('mainnet3', Contexts.Hyperlane, Role.Deployer);
await key.fetch();
return key.privateKey;

@ -0,0 +1,40 @@
import yargs from 'yargs';
import { Contexts } from '../../config/contexts.js';
import { safes } from '../../config/environments/mainnet3/owners.js';
import { Role } from '../../src/roles.js';
import { deleteAllPendingSafeTxs } from '../../src/utils/safe.js';
import { withChains } from '../agent-utils.js';
import { getEnvironmentConfig } from '../core-utils.js';
async function main() {
const { chains } = await withChains(yargs(process.argv.slice(2))).argv;
if (!chains || chains.length === 0) {
console.error('No chains provided');
process.exit(1);
}
const envConfig = getEnvironmentConfig('mainnet3');
const multiProvider = await envConfig.getMultiProvider(
Contexts.Hyperlane,
Role.Deployer,
true,
chains,
);
for (const chain of chains) {
try {
await deleteAllPendingSafeTxs(chain, multiProvider, safes[chain]);
} catch (error) {
console.error(`Error deleting pending transactions for ${chain}:`, error);
}
}
}
main()
.then()
.catch((e) => {
console.error(e);
process.exit(1);
});

@ -0,0 +1,51 @@
import yargs from 'yargs';
import { Contexts } from '../../config/contexts.js';
import { safes } from '../../config/environments/mainnet3/owners.js';
import { Role } from '../../src/roles.js';
import { deleteSafeTx } from '../../src/utils/safe.js';
import { withChains } from '../agent-utils.js';
import { getEnvironmentConfig } from '../core-utils.js';
async function main() {
const { chains, tx } = await withChains(
yargs(process.argv.slice(2)).option('tx', {
type: 'string',
description: 'Transaction hash to delete',
demandOption: true,
}),
).argv;
if (!chains || chains.length === 0) {
console.error('No chains provided');
process.exit(1);
}
if (!tx) {
console.error('No transaction hash provided');
process.exit(1);
}
const envConfig = getEnvironmentConfig('mainnet3');
const multiProvider = await envConfig.getMultiProvider(
Contexts.Hyperlane,
Role.Deployer,
true,
chains,
);
for (const chain of chains) {
try {
await deleteSafeTx(chain, multiProvider, safes[chain], tx);
} catch (error) {
console.error(`Error deleting transaction ${tx} for ${chain}:`, error);
}
}
}
main()
.then()
.catch((e) => {
console.error(e);
process.exit(1);
});

@ -1,7 +1,16 @@
import SafeApiKit from '@safe-global/api-kit';
import Safe from '@safe-global/protocol-kit';
import { SafeTransaction } from '@safe-global/safe-core-sdk-types';
import { ChainName, MultiProvider } from '@hyperlane-xyz/sdk';
// @ts-ignore
import { getSafe, getSafeService } from '@hyperlane-xyz/sdk';
import { CallData } from '@hyperlane-xyz/utils';
import { Address, CallData, eqAddress } from '@hyperlane-xyz/utils';
import {
createSafeTransaction,
createSafeTransactionData,
getSafeAndService,
proposeSafeTransaction,
} from '../utils/safe.js';
export abstract class MultiSend {
abstract sendTransactions(calls: CallData[]): Promise<void>;
@ -45,41 +54,80 @@ export class SafeMultiSend extends MultiSend {
constructor(
public readonly multiProvider: MultiProvider,
public readonly chain: ChainName,
public readonly safeAddress: string,
public readonly safeAddress: Address,
) {
super();
}
async sendTransactions(calls: CallData[]) {
const safeSdk = await getSafe(
const { safeSdk, safeService } = await getSafeAndService(
this.chain,
this.multiProvider,
this.safeAddress,
);
const safeService = getSafeService(this.chain, this.multiProvider);
const safeTransactionData = calls.map((call) => {
return {
to: call.to,
data: call.data.toString(),
value: call.value?.toString() || '0',
};
});
const nextNonce = await safeService.getNextNonce(this.safeAddress);
const safeTransaction = await safeSdk.createTransaction({
// If the multiSend address is the same as the safe address, we need to
// propose the transactions individually. See: gnosisSafe.js in the SDK.
if (eqAddress(safeSdk.getMultiSendAddress(), this.safeAddress)) {
console.log(
`MultiSend contract not deployed on ${this.chain}. Proposing transactions individually.`,
);
await this.proposeIndividualTransactions(calls, safeSdk, safeService);
} else {
await this.proposeMultiSendTransaction(calls, safeSdk, safeService);
}
}
// Helper function to propose individual transactions
private async proposeIndividualTransactions(
calls: CallData[],
safeSdk: Safe.default,
safeService: SafeApiKit.default,
) {
for (const call of calls) {
const safeTransactionData = createSafeTransactionData(call);
const safeTransaction = await createSafeTransaction(
safeSdk,
safeService,
this.safeAddress,
[safeTransactionData],
);
await this.proposeSafeTransaction(safeSdk, safeService, safeTransaction);
}
}
// Helper function to propose a multi-send transaction
private async proposeMultiSendTransaction(
calls: CallData[],
safeSdk: Safe.default,
safeService: SafeApiKit.default,
) {
const safeTransactionData = calls.map((call) =>
createSafeTransactionData(call),
);
const safeTransaction = await createSafeTransaction(
safeSdk,
safeService,
this.safeAddress,
safeTransactionData,
options: { nonce: nextNonce },
});
const safeTxHash = await safeSdk.getTransactionHash(safeTransaction);
const senderSignature = await safeSdk.signTransactionHash(safeTxHash);
);
await this.proposeSafeTransaction(safeSdk, safeService, safeTransaction);
}
const senderAddress = await this.multiProvider.getSignerAddress(this.chain);
await safeService.proposeTransaction({
safeAddress: this.safeAddress,
safeTransactionData: safeTransaction.data,
safeTxHash,
senderAddress,
senderSignature: senderSignature.data,
});
// Helper function to propose a safe transaction
private async proposeSafeTransaction(
safeSdk: Safe.default,
safeService: SafeApiKit.default,
safeTransaction: SafeTransaction,
) {
const signer = this.multiProvider.getSigner(this.chain);
await proposeSafeTransaction(
this.chain,
safeSdk,
safeService,
safeTransaction,
this.safeAddress,
signer,
);
}
}

@ -0,0 +1,207 @@
import { JsonRpcSigner } from '@ethersproject/providers';
import SafeApiKit from '@safe-global/api-kit';
import Safe from '@safe-global/protocol-kit';
import {
MetaTransactionData,
SafeTransaction,
} from '@safe-global/safe-core-sdk-types';
import { ethers } from 'ethers';
import {
ChainNameOrId,
MultiProvider,
getSafe,
getSafeService,
} from '@hyperlane-xyz/sdk';
import { Address, CallData } from '@hyperlane-xyz/utils';
export async function getSafeAndService(
chain: ChainNameOrId,
multiProvider: MultiProvider,
safeAddress: Address,
) {
const safeSdk: Safe.default = await getSafe(
chain,
multiProvider,
safeAddress,
);
const safeService: SafeApiKit.default = getSafeService(chain, multiProvider);
return { safeSdk, safeService };
}
export function createSafeTransactionData(call: CallData): MetaTransactionData {
return {
to: call.to,
data: call.data.toString(),
value: call.value?.toString() || '0',
};
}
export async function createSafeTransaction(
safeSdk: Safe.default,
safeService: SafeApiKit.default,
safeAddress: Address,
safeTransactionData: MetaTransactionData[],
): Promise<SafeTransaction> {
const nextNonce = await safeService.getNextNonce(safeAddress);
return safeSdk.createTransaction({
safeTransactionData,
options: { nonce: nextNonce },
});
}
export async function proposeSafeTransaction(
chain: ChainNameOrId,
safeSdk: Safe.default,
safeService: SafeApiKit.default,
safeTransaction: SafeTransaction,
safeAddress: Address,
signer: ethers.Signer,
): Promise<void> {
const safeTxHash = await safeSdk.getTransactionHash(safeTransaction);
const senderSignature = await safeSdk.signTransactionHash(safeTxHash);
const senderAddress = await signer.getAddress();
await safeService.proposeTransaction({
safeAddress: safeAddress,
safeTransactionData: safeTransaction.data,
safeTxHash,
senderAddress,
senderSignature: senderSignature.data,
});
console.log(`Proposed transaction on ${chain} with hash ${safeTxHash}`);
}
export async function deleteAllPendingSafeTxs(
chain: ChainNameOrId,
multiProvider: MultiProvider,
safeAddress: Address,
): Promise<void> {
const txServiceUrl =
multiProvider.getChainMetadata(chain).gnosisSafeTransactionServiceUrl;
// Fetch all pending transactions
const pendingTxsUrl = `${txServiceUrl}/api/v1/safes/${safeAddress}/multisig-transactions/?executed=false&limit=100`;
const pendingTxsResponse = await fetch(pendingTxsUrl, {
method: 'GET',
headers: { 'Content-Type': 'application/json' },
});
if (!pendingTxsResponse.ok) {
console.error(`Failed to fetch pending transactions for ${safeAddress}`);
return;
}
const pendingTxs = await pendingTxsResponse.json();
// Delete each pending transaction
for (const tx of pendingTxs.results) {
await deleteSafeTx(chain, multiProvider, safeAddress, tx.safeTxHash);
}
console.log(
`Deleted all pending transactions on ${chain} for ${safeAddress}\n`,
);
}
export async function deleteSafeTx(
chain: ChainNameOrId,
multiProvider: MultiProvider,
safeAddress: Address,
safeTxHash: string,
): Promise<void> {
const signer = multiProvider.getSigner(chain);
const domainId = multiProvider.getDomainId(chain);
const txServiceUrl =
multiProvider.getChainMetadata(chain).gnosisSafeTransactionServiceUrl;
// Fetch the transaction details to get the proposer
const txDetailsUrl = `${txServiceUrl}/api/v1/multisig-transactions/${safeTxHash}/`;
const txDetailsResponse = await fetch(txDetailsUrl, {
method: 'GET',
headers: { 'Content-Type': 'application/json' },
});
if (!txDetailsResponse.ok) {
console.error(`Failed to fetch transaction details for ${safeTxHash}`);
return;
}
const txDetails = await txDetailsResponse.json();
const proposer = txDetails.proposer;
if (!proposer) {
console.error(`No proposer found for transaction ${safeTxHash}`);
return;
}
// Compare proposer to signer
const signerAddress = await signer.getAddress();
if (proposer !== signerAddress) {
console.log(
`Skipping deletion of transaction ${safeTxHash} proposed by ${proposer}`,
);
return;
}
console.log(`Deleting transaction ${safeTxHash} proposed by ${proposer}`);
try {
// Generate the EIP-712 signature
const totp = Math.floor(Date.now() / 1000 / 3600);
const typedData = {
types: {
EIP712Domain: [
{ name: 'name', type: 'string' },
{ name: 'version', type: 'string' },
{ name: 'chainId', type: 'uint256' },
{ name: 'verifyingContract', type: 'address' },
],
DeleteRequest: [
{ name: 'safeTxHash', type: 'bytes32' },
{ name: 'totp', type: 'uint256' },
],
},
domain: {
name: 'Safe Transaction Service',
version: '1.0',
chainId: domainId,
verifyingContract: safeAddress,
},
primaryType: 'DeleteRequest',
message: {
safeTxHash: safeTxHash,
totp: totp,
},
};
const signature = await (signer as JsonRpcSigner)._signTypedData(
typedData.domain,
{ DeleteRequest: typedData.types.DeleteRequest },
typedData.message,
);
// Make the API call to delete the transaction
const deleteUrl = `${txServiceUrl}/api/v1/multisig-transactions/${safeTxHash}/`;
const res = await fetch(deleteUrl, {
method: 'DELETE',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ safeTxHash: safeTxHash, signature: signature }),
});
if (res.status === 204) {
console.log(`Successfully deleted transaction ${safeTxHash} on ${chain}`);
return;
}
const errorBody = await res.text();
console.error(
`Failed to delete transaction ${safeTxHash} on ${chain}: Status ${res.status} ${res.statusText}. Response body: ${errorBody}`,
);
} catch (error) {
console.error(
`Failed to delete transaction ${safeTxHash} on ${chain}:`,
error,
);
}
}

@ -11,6 +11,7 @@
"@hyperlane-xyz/utils": "5.1.0",
"@safe-global/api-kit": "1.3.0",
"@safe-global/protocol-kit": "1.3.0",
"@safe-global/safe-deployments": "1.37.3",
"@solana/spl-token": "^0.3.8",
"@solana/web3.js": "^1.78.0",
"@types/coingecko-api": "^1.0.10",

@ -513,9 +513,13 @@ export {
} from './token/schemas.js';
export { isCompliant } from './utils/schemas.js';
// prettier-ignore
// @ts-ignore
export { canProposeSafeTransactions, getSafe, getSafeDelegates, getSafeService } from './utils/gnosisSafe.js';
export {
canProposeSafeTransactions,
getSafe,
getSafeDelegates,
getSafeService,
// @ts-ignore
} from './utils/gnosisSafe.js';
export { EvmCoreModule } from './core/EvmCoreModule.js';
export { EvmIsmModule } from './ism/EvmIsmModule.js';

@ -1,6 +1,10 @@
// This file is JS because of https://github.com/safe-global/safe-core-sdk/issues/805
import SafeApiKit from '@safe-global/api-kit';
import Safe, { EthersAdapter } from '@safe-global/protocol-kit';
import {
getMultiSendCallOnlyDeployment,
getMultiSendDeployment,
} from '@safe-global/safe-deployments';
import { ethers } from 'ethers';
export function getSafeService(chain, multiProvider) {
@ -13,22 +17,77 @@ export function getSafeService(chain, multiProvider) {
return new SafeApiKit.default({ txServiceUrl, ethAdapter });
}
export function getSafe(chain, multiProvider, safeAddress) {
// 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',
},
};
export async function getSafe(chain, multiProvider, safeAddress) {
// Create Ethers Adapter
const signer = multiProvider.getSigner(chain);
const ethAdapter = new EthersAdapter({ ethers, signerOrProvider: signer });
// Get the domain id for the given chain
const domainId = multiProvider.getDomainId(chain);
const contractNetworks = {
[domainId]: {
multiSendAddress: safeAddress,
multiSendCallOnlyAddress: safeAddress,
},
};
// 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 (safeDeploymentsVersions[safeVersion]) {
const { multiSendVersion, multiSendCallOnlyVersion } =
safeDeploymentsVersions[safeVersion];
multiSend = getMultiSendDeployment({
version: multiSendVersion,
network: domainId,
released: true,
});
multiSendCallOnly = getMultiSendCallOnlyDeployment({
version: multiSendCallOnlyVersion,
network: domainId,
released: true,
});
}
return Safe.default.create({
ethAdapter,
safeAddress,
contractNetworks,
contractNetworks: {
[domainId]: {
// Use the safe address for multiSendAddress and multiSendCallOnlyAddress
// if the contract is not deployed or if the version is not found
multiSendAddress: multiSend?.defaultAddress || safeAddress,
multiSendCallOnlyAddress:
multiSendCallOnly?.defaultAddress || safeAddress,
},
},
});
}

@ -26,13 +26,6 @@ __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
"@alloc/quick-lru@npm:^5.2.0":
version: 5.2.0
resolution: "@alloc/quick-lru@npm:5.2.0"
@ -7470,7 +7463,9 @@ __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"
"@safe-global/api-kit": "npm:1.3.0"
"@safe-global/protocol-kit": "npm:1.3.0"
"@safe-global/safe-core-sdk-types": "npm:2.3.0"
"@solana/web3.js": "npm:^1.78.0"
"@types/chai": "npm:^4.2.21"
"@types/json-stable-stringify": "npm:^1.0.36"
@ -7543,6 +7538,7 @@ __metadata:
"@nomiclabs/hardhat-waffle": "npm:^2.0.6"
"@safe-global/api-kit": "npm:1.3.0"
"@safe-global/protocol-kit": "npm:1.3.0"
"@safe-global/safe-deployments": "npm:1.37.3"
"@solana/spl-token": "npm:^0.3.8"
"@solana/web3.js": "npm:^1.78.0"
"@types/coingecko-api": "npm:^1.0.10"
@ -8499,13 +8495,6 @@ __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/hashes@npm:~1.3.2":
version: 1.3.3
resolution: "@noble/hashes@npm:1.3.3"
@ -10218,18 +10207,16 @@ __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"
"@safe-global/safe-core-sdk-types@npm:2.3.0":
version: 2.3.0
resolution: "@safe-global/safe-core-sdk-types@npm:2.3.0"
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
"@ethersproject/bignumber": "npm:^5.7.0"
"@ethersproject/contracts": "npm:^5.7.0"
"@safe-global/safe-deployments": "npm:^1.26.0"
web3-core: "npm:^1.8.1"
web3-utils: "npm:^1.8.1"
checksum: 4205f8a024730d303ac50441ac8265e6aa3dcb90d46b94f3acaaf6966db1d508281867a804986b0c90bc901a117b51ed75b2d3669b97ee4afc55125bddd70c42
languageName: node
linkType: hard
@ -10246,12 +10233,12 @@ __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"
"@safe-global/safe-deployments@npm:1.37.3":
version: 1.37.3
resolution: "@safe-global/safe-deployments@npm:1.37.3"
dependencies:
abitype: "npm:^1.0.2"
checksum: 53f0221e1c86b5b04f75cc773527e5e9c59ebb13ec21fe9a9246f6834c45b107e9a165da08ed58d40ed2564952f5360fb4c02051f236bfcc61bbfdb6015e3663
semver: "npm:^7.6.2"
checksum: 3d1fcaac850a1d1100eaa5ff753c88c9bb889c678bb09248323c6b0c9d6228225a88be47973a89bb32829fe2d13ed17c21f854b9fdc29cc1b3c734021761f15c
languageName: node
linkType: hard
@ -10264,15 +10251,6 @@ __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
"@scure/base@npm:~1.0.0":
version: 1.0.0
resolution: "@scure/base@npm:1.0.0"
@ -12656,13 +12634,6 @@ __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"
@ -13436,21 +13407,6 @@ __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"
@ -13603,13 +13559,6 @@ __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
"agent-base@npm:5":
version: 5.1.1
resolution: "agent-base@npm:5.1.1"
@ -18066,21 +18015,6 @@ __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"
@ -28714,13 +28648,6 @@ __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:^1.11.1, tslib@npm:^1.13.0, tslib@npm:^1.8.1, tslib@npm:^1.9.0, tslib@npm:^1.9.3":
version: 1.14.1
resolution: "tslib@npm:1.14.1"
@ -28735,6 +28662,13 @@ __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
"tslib@npm:^2.6.2":
version: 2.6.2
resolution: "tslib@npm:2.6.2"
@ -30394,21 +30328,6 @@ __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