UNPKG

@hyperlane-xyz/sdk

Version:

The official SDK for the Hyperlane Network

73 lines 3.86 kB
import { assert, rootLogger } from '@hyperlane-xyz/utils'; import { canProposeSafeTransactions, getSafe, getSafeService, } from '../../../../utils/gnosisSafe.js'; import { TxSubmitterType } from '../TxSubmitterTypes.js'; export class EV5GnosisSafeTxSubmitter { multiProvider; props; safe; safeService; txSubmitterType = TxSubmitterType.GNOSIS_SAFE; logger = rootLogger.child({ module: 'gnosis-safe-submitter', }); constructor(multiProvider, props, safe, safeService) { this.multiProvider = multiProvider; this.props = props; this.safe = safe; this.safeService = safeService; } static async create(multiProvider, props) { const { chain, safeAddress } = props; const { gnosisSafeTransactionServiceUrl } = multiProvider.getChainMetadata(chain); assert(gnosisSafeTransactionServiceUrl, `Must set gnosisSafeTransactionServiceUrl in the Registry metadata for ${chain}`); const signerAddress = await multiProvider.getSigner(chain).getAddress(); const authorized = await canProposeSafeTransactions(signerAddress, chain, multiProvider, safeAddress); assert(authorized, `Signer ${signerAddress} is not an authorized Safe Proposer for ${safeAddress}`); const safe = await getSafe(chain, multiProvider, safeAddress); const safeService = await getSafeService(chain, multiProvider); return new EV5GnosisSafeTxSubmitter(multiProvider, props, safe, safeService); } async getNextNonce() { const nextNonce = await this.safeService.getNextNonce(this.props.safeAddress); return parseInt(nextNonce); } async createSafeTransaction(...transactions) { const nextNonce = await this.getNextNonce(); const submitterChainId = this.multiProvider.getChainId(this.props.chain); const safeTransactionData = transactions.map(({ to, data, value, chainId }) => { assert(chainId, 'Invalid AnnotatedEV5Transaction: chainId is required'); assert(chainId === submitterChainId, `Invalid AnnotatedEV5Transaction: Cannot submit tx for chain ID ${chainId} to submitter for chain ID ${submitterChainId}.`); assert(data, `Invalid AnnotatedEV5Transaction: calldata is required for gnosis safe transaction on chain with ID ${submitterChainId}`); assert(to, `Invalid AnnotatedEV5Transaction: target address is required for gnosis safe transaction on chain with ID ${submitterChainId}`); return { to, data, value: value?.toString() ?? '0' }; }); const isMultiSend = transactions.length > 1; const safeTransaction = await this.safe.createTransaction({ transactions: safeTransactionData, onlyCalls: isMultiSend, options: { nonce: nextNonce, }, }); return safeTransaction; } async submit(...txs) { const safeTransaction = await this.createSafeTransaction(...txs); return this.proposeSafeTransaction(safeTransaction); } async proposeSafeTransaction(safeTransaction) { const safeTxHash = await this.safe.getTransactionHash(safeTransaction); const senderAddress = await this.multiProvider.getSignerAddress(this.props.chain); const safeSignature = await this.safe.signTypedData(safeTransaction); const senderSignature = safeSignature.data; this.logger.info(`Submitting transaction proposal to ${this.props.safeAddress} on ${this.props.chain}: ${safeTxHash}`); return this.safeService.proposeTransaction({ safeAddress: this.props.safeAddress, safeTransactionData: safeTransaction.data, safeTxHash, senderAddress, senderSignature, }); } } //# sourceMappingURL=EV5GnosisSafeTxSubmitter.js.map