Skip to content

Commit

Permalink
Workaround TS bug in Safe protocol-lib (#3717)
Browse files Browse the repository at this point in the history
### 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

safe-global/safe-core-sdk#805
  • Loading branch information
jmrossy authored May 6, 2024
1 parent 78b77ee commit c900da1
Show file tree
Hide file tree
Showing 10 changed files with 49 additions and 72 deletions.
5 changes: 5 additions & 0 deletions .changeset/tricky-walls-care.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@hyperlane-xyz/sdk': patch
---

Workaround TS bug in Safe protocol-lib
1 change: 1 addition & 0 deletions typescript/infra/scripts/safe-delegate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down
3 changes: 2 additions & 1 deletion typescript/infra/src/govern/HyperlaneAppGovernor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,9 @@ import {
InterchainAccount,
OwnableConfig,
OwnerViolation,
canProposeSafeTransactions,
} from '@hyperlane-xyz/sdk';
// @ts-ignore
import { canProposeSafeTransactions } from '@hyperlane-xyz/sdk';
import {
Address,
CallData,
Expand Down
9 changes: 3 additions & 6 deletions typescript/infra/src/govern/multisend.ts
Original file line number Diff line number Diff line change
@@ -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 {
Expand Down
4 changes: 2 additions & 2 deletions typescript/sdk/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
2 changes: 1 addition & 1 deletion typescript/sdk/src/hook/read.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { assert } from 'console';
import { ethers, providers } from 'ethers';

import {
Expand All @@ -18,6 +17,7 @@ import {
import {
Address,
WithAddress,
assert,
concurrentMap,
eqAddress,
rootLogger,
Expand Down
33 changes: 16 additions & 17 deletions typescript/sdk/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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';
Expand Down Expand Up @@ -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,
Expand All @@ -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';
Original file line number Diff line number Diff line change
@@ -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';
Expand All @@ -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,
Expand All @@ -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(
Expand Down
Original file line number Diff line number Diff line change
@@ -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';
Expand Down Expand Up @@ -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 };
},
);
Expand Down
Original file line number Diff line number Diff line change
@@ -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 =
Expand All @@ -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({
Expand All @@ -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);
Expand Down

0 comments on commit c900da1

Please sign in to comment.