@hyperlane-xyz/sdk
Version:
The official SDK for the Hyperlane Network
73 lines • 3.65 kB
JavaScript
import { OperationType, } from '@safe-global/safe-core-sdk-types';
import { assert, rootLogger } from '@hyperlane-xyz/utils';
// prettier-ignore
// @ts-ignore
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 createSafeTransaction(...transactions) {
const nextNonce = await this.safeService.getNextNonce(this.props.safeAddress);
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}.`);
return { to, data, value: value?.toString() ?? '0' };
});
const isMultiSend = transactions.length > 1;
const safeTransaction = await this.safe.createTransaction({
safeTransactionData,
onlyCalls: isMultiSend,
options: {
nonce: nextNonce,
operation: isMultiSend
? OperationType.DelegateCall
: OperationType.Call,
},
});
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