Workaround TS bug in Safe protocol-lib (#3717)

### Description

Replace SDK's `gnosisSafe.ts` utils file with a pure JS version to avoid TS checks on Safe lib which has an incorrectly placed TS file in it's lib dist folder.

### Drive-by changes

Fix assert import

## Related issues

https://github.com/safe-global/safe-core-sdk/issues/805
pull/3718/head
J M Rossy 6 months ago committed by GitHub
parent 78b77eecff
commit c900da1877
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 5
      .changeset/tricky-walls-care.md
  2. 1
      typescript/infra/scripts/safe-delegate.ts
  3. 3
      typescript/infra/src/govern/HyperlaneAppGovernor.ts
  4. 9
      typescript/infra/src/govern/multisend.ts
  5. 4
      typescript/sdk/package.json
  6. 2
      typescript/sdk/src/hook/read.ts
  7. 33
      typescript/sdk/src/index.ts
  8. 25
      typescript/sdk/src/providers/transactions/submitter/ethersV5/EV5GnosisSafeTxSubmitter.ts
  9. 9
      typescript/sdk/src/providers/transactions/transformer/ethersV5/EV5InterchainAccountTxTransformer.ts
  10. 30
      typescript/sdk/src/utils/gnosisSafe.js

@ -0,0 +1,5 @@
---
'@hyperlane-xyz/sdk': patch
---
Workaround TS bug in Safe protocol-lib

@ -4,6 +4,7 @@ import { LedgerSigner } from '@ethersproject/hardware-wallets';
import '@ethersproject/hardware-wallets/thirdparty';
import { AddSafeDelegateProps } from '@safe-global/api-kit';
// @ts-ignore
import { getSafeDelegates, getSafeService } from '@hyperlane-xyz/sdk';
import { getChains } from '../config/registry.js';

@ -11,8 +11,9 @@ import {
InterchainAccount,
OwnableConfig,
OwnerViolation,
canProposeSafeTransactions,
} from '@hyperlane-xyz/sdk';
// @ts-ignore
import { canProposeSafeTransactions } from '@hyperlane-xyz/sdk';
import {
Address,
CallData,

@ -1,9 +1,6 @@
import {
ChainName,
MultiProvider,
getSafe,
getSafeService,
} from '@hyperlane-xyz/sdk';
import { ChainName, MultiProvider } from '@hyperlane-xyz/sdk';
// @ts-ignore
import { getSafe, getSafeService } from '@hyperlane-xyz/sdk';
import { CallData } from '@hyperlane-xyz/utils';
export abstract class MultiSend {

@ -66,8 +66,8 @@
],
"license": "Apache-2.0",
"scripts": {
"build": "yarn build:fixSafeGlobalLib; tsc",
"build:fixSafeGlobalLib": "rm -rf ../../node_modules/@safe-global/protocol-kit/dist/typechain/src/web3-v1/**/Multi_send.ts",
"build": "tsc && yarn copy-js",
"copy-js": "cp ./src/utils/*.js ./dist/utils",
"dev": "tsc --watch",
"check": "tsc --noEmit",
"clean": "rm -rf ./dist ./cache",

@ -1,4 +1,3 @@
import { assert } from 'console';
import { ethers, providers } from 'ethers';
import {
@ -18,6 +17,7 @@ import {
import {
Address,
WithAddress,
assert,
concurrentMap,
eqAddress,
rootLogger,

@ -236,17 +236,6 @@ export {
InterchainQueryDeployer,
} from './middleware/query/InterchainQueryDeployer.js';
export { interchainQueryFactories } from './middleware/query/contracts.js';
export { TxSubmitterBuilder } from './providers/transactions/submitter/builder/TxSubmitterBuilder.js';
export { EV5GnosisSafeTxSubmitter } from './providers/transactions/submitter/ethersV5/EV5GnosisSafeTxSubmitter.js';
export { EV5ImpersonatedAccountTxSubmitter } from './providers/transactions/submitter/ethersV5/EV5ImpersonatedAccountTxSubmitter.js';
export { EV5JsonRpcTxSubmitter } from './providers/transactions/submitter/ethersV5/EV5JsonRpcTxSubmitter.js';
export { EV5TxSubmitterInterface } from './providers/transactions/submitter/ethersV5/EV5TxSubmitterInterface.js';
export { TxSubmitterInterface } from './providers/transactions/submitter/TxSubmitterInterface.js';
export { TxSubmitterType } from './providers/transactions/submitter/TxSubmitterTypes.js';
export { EV5InterchainAccountTxTransformer } from './providers/transactions/transformer/ethersV5/EV5InterchainAccountTxTransformer.js';
export { EV5TxTransformerInterface } from './providers/transactions/transformer/ethersV5/EV5TxTransformerInterface.js';
export { TxTransformerInterface } from './providers/transactions/transformer/TxTransformerInterface.js';
export { TxTransformerType } from './providers/transactions/transformer/TxTransformerTypes.js';
export {
MultiProtocolProvider,
MultiProtocolProviderOptions,
@ -314,6 +303,17 @@ export {
defaultViemProviderBuilder,
protocolToDefaultProviderBuilder,
} from './providers/providerBuilders.js';
export { TxSubmitterInterface } from './providers/transactions/submitter/TxSubmitterInterface.js';
export { TxSubmitterType } from './providers/transactions/submitter/TxSubmitterTypes.js';
export { TxSubmitterBuilder } from './providers/transactions/submitter/builder/TxSubmitterBuilder.js';
export { EV5GnosisSafeTxSubmitter } from './providers/transactions/submitter/ethersV5/EV5GnosisSafeTxSubmitter.js';
export { EV5ImpersonatedAccountTxSubmitter } from './providers/transactions/submitter/ethersV5/EV5ImpersonatedAccountTxSubmitter.js';
export { EV5JsonRpcTxSubmitter } from './providers/transactions/submitter/ethersV5/EV5JsonRpcTxSubmitter.js';
export { EV5TxSubmitterInterface } from './providers/transactions/submitter/ethersV5/EV5TxSubmitterInterface.js';
export { TxTransformerInterface } from './providers/transactions/transformer/TxTransformerInterface.js';
export { TxTransformerType } from './providers/transactions/transformer/TxTransformerTypes.js';
export { EV5InterchainAccountTxTransformer } from './providers/transactions/transformer/ethersV5/EV5InterchainAccountTxTransformer.js';
export { EV5TxTransformerInterface } from './providers/transactions/transformer/ethersV5/EV5TxTransformerInterface.js';
export { GasRouterDeployer } from './router/GasRouterDeployer.js';
export { HyperlaneRouterChecker } from './router/HyperlaneRouterChecker.js';
export { HyperlaneRouterDeployer } from './router/HyperlaneRouterDeployer.js';
@ -453,12 +453,7 @@ export {
setFork,
stopImpersonatingAccount,
} from './utils/fork.js';
export {
getSafeService,
getSafe,
getSafeDelegates,
canProposeSafeTransactions,
} from './utils/gnosisSafe.js';
export { multisigIsmVerificationCost } from './utils/ism.js';
export {
SealevelAccountDataWrapper,
@ -483,3 +478,7 @@ export {
TokenRouterConfigSchema as tokenRouterConfigSchema,
} from './token/schemas.js';
export { TokenRouterConfig, WarpRouteDeployConfig } from './token/types.js';
// prettier-ignore
// @ts-ignore
export { canProposeSafeTransactions, getSafe, getSafeDelegates, getSafeService } from './utils/gnosisSafe.js';

@ -1,16 +1,10 @@
import SafeApiKit from '@safe-global/api-kit';
import Safe, { EthSafeSignature } from '@safe-global/protocol-kit';
import {
MetaTransactionData,
SafeTransactionData,
} from '@safe-global/safe-core-sdk-types';
import assert from 'assert';
import { PopulatedTransaction } from 'ethers';
import { Logger } from 'pino';
import { Address, rootLogger } from '@hyperlane-xyz/utils';
import { Address, assert, rootLogger } from '@hyperlane-xyz/utils';
import { ChainName } from '../../../../types.js';
// @ts-ignore
import { getSafe, getSafeService } from '../../../../utils/gnosisSafe.js';
import { MultiProvider } from '../../../MultiProvider.js';
import { TxSubmitterType } from '../TxSubmitterTypes.js';
@ -36,19 +30,16 @@ export class EV5GnosisSafeTxSubmitter implements EV5TxSubmitterInterface {
) {}
public async submit(...txs: PopulatedTransaction[]): Promise<void> {
const safe: Safe.default = await getSafe(
const safe = await getSafe(
this.chain,
this.multiProvider,
this.props.safeAddress,
);
const safeService: SafeApiKit.default = getSafeService(
this.chain,
this.multiProvider,
);
const safeService = await getSafeService(this.chain, this.multiProvider);
const nextNonce: number = await safeService.getNextNonce(
this.props.safeAddress,
);
const safeTransactionBatch: MetaTransactionData[] = txs.map(
const safeTransactionBatch: any[] = txs.map(
({ to, data, value }: PopulatedTransaction) => {
assert(
to && data,
@ -61,14 +52,12 @@ export class EV5GnosisSafeTxSubmitter implements EV5TxSubmitterInterface {
safeTransactionData: safeTransactionBatch,
options: { nonce: nextNonce },
});
const safeTransactionData: SafeTransactionData = safeTransaction.data;
const safeTransactionData: any = safeTransaction.data;
const safeTxHash: string = await safe.getTransactionHash(safeTransaction);
const senderAddress: Address = await this.multiProvider.getSignerAddress(
this.chain,
);
const safeSignature: EthSafeSignature = await safe.signTransactionHash(
safeTxHash,
);
const safeSignature: any = await safe.signTransactionHash(safeTxHash);
const senderSignature: string = safeSignature.data;
this.logger.debug(

@ -1,8 +1,7 @@
import assert from 'assert';
import { PopulatedTransaction } from 'ethers';
import { Logger } from 'pino';
import { CallData, rootLogger } from '@hyperlane-xyz/utils';
import { CallData, assert, rootLogger } from '@hyperlane-xyz/utils';
import { InterchainAccount } from '../../../../middleware/account/InterchainAccount.js';
import { AccountConfig } from '../../../../middleware/account/types.js';
@ -43,10 +42,8 @@ export class EV5InterchainAccountTxTransformer
const innerCalls: CallData[] = txs.map(
({ to, data, value }: PopulatedTransaction) => {
assert(
to && data,
'Invalid PopulatedTransaction: Missing required field to or data.',
);
assert(to, 'Invalid PopulatedTransaction: Missing to field');
assert(data, 'Invalid PopulatedTransaction: Missing data field');
return { to, data, value };
},
);

@ -1,14 +1,9 @@
// 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 { ethers } from 'ethers';
import { MultiProvider } from '../providers/MultiProvider.js';
import { ChainName } from '../types.js';
export function getSafeService(
chain: ChainName,
multiProvider: MultiProvider,
): SafeApiKit.default {
export function getSafeService(chain, multiProvider) {
const signer = multiProvider.getSigner(chain);
const ethAdapter = new EthersAdapter({ ethers, signerOrProvider: signer });
const txServiceUrl =
@ -18,11 +13,7 @@ export function getSafeService(
return new SafeApiKit.default({ txServiceUrl, ethAdapter });
}
export function getSafe(
chain: ChainName,
multiProvider: MultiProvider,
safeAddress: string,
): Promise<Safe.default> {
export function getSafe(chain, multiProvider, safeAddress) {
const signer = multiProvider.getSigner(chain);
const ethAdapter = new EthersAdapter({ ethers, signerOrProvider: signer });
return Safe.default.create({
@ -31,20 +22,17 @@ export function getSafe(
});
}
export async function getSafeDelegates(
service: SafeApiKit.default,
safeAddress: string,
) {
export async function getSafeDelegates(service, safeAddress) {
const delegateResponse = await service.getSafeDelegates({ safeAddress });
return delegateResponse.results.map((r) => r.delegate);
}
export async function canProposeSafeTransactions(
proposer: string,
chain: ChainName,
multiProvider: MultiProvider,
safeAddress: string,
): Promise<boolean> {
proposer,
chain,
multiProvider,
safeAddress,
) {
let safeService;
try {
safeService = getSafeService(chain, multiProvider);
Loading…
Cancel
Save