I am using https://github.com/gnosis/ethers-multisend to encode batch transactions into Meta transactions. And following https://docs.gnosis-safe.io/tutorials/tutorial_tx_service_initiate_sign to send my encoded transaction to gnosis. The transactions get encoded but I get the following error. Can anyone help me how to submit transactions to gnosis transaction service?
Following is the code snippet that I am using
import { encodeMulti, encodeSingle, MetaTransaction } from 'ethers-multisend'
const [transactions, setTransactions] = useState<MetaTransaction[]>([])
const addToBatch = () => {
const encodedTx = encodeSingle({
type: TransactionType.transferFunds,
id: '1',
token: tokenAddress,
to: recipientAddress,
amount: ethers.utils.parseUnits(fundAmount, decimals).toString(),
decimals: decimals,
})
if(!transactions) {
setTransactions([encodedTx])
} else {
console.log('transactions', transactions)
setTransactions([...transactions, encodedTx])
}
const executeTransaction = () => {
const encodedMultiTransactions = encodeMulti(transactions)
submitTx(accountData?.address, accountData?.address, PRIVATE_KEY, encodedMultiTransactions)
}
const submitTx = async(safe, sender, privateKey, tx) => {
const safeDomain = new EIP712Domain({
verifyingContract: safe,
})
const SafeTx = safeDomain.createType('SafeTx', [
{ type: 'address', name: 'to' },
{ type: 'uint256', name: 'value' },
{ type: 'bytes', name: 'data' },
{ type: 'uint8', name: 'operation' },
{ type: 'uint256', name: 'safeTxGas' },
{ type: 'uint256', name: 'baseGas' },
{ type: 'uint256', name: 'gasPrice' },
{ type: 'address', name: 'gasToken' },
{ type: 'address', name: 'refundReceiver' },
{ type: 'uint256', name: 'nonce' },
])
tx['operation'] = 1
const baseTxn = tx
console.log(JSON.stringify({ baseTxn }))
// Let the Safe service estimate the tx and retrieve the nonce
const { safeTxGas, lastUsedNonce } = await gnosisEstimateTransaction(
safe,
baseTxn,
)
const txn = {
...baseTxn,
safeTxGas,
// Here we can also set any custom nonce
nonce: lastUsedNonce === undefined ? 0 : lastUsedNonce + 1,
// We don't want to use the refund logic of the safe to lets use the default values
baseGas: 0,
gasPrice: 0,
gasToken: '0x0000000000000000000000000000000000000000',
refundReceiver: '0x0000000000000000000000000000000000000000',
}
console.log({ txn })
const safeTx = new SafeTx({
...txn,
data: utils.arrayify(txn.data)
})
const signer = async data => {
const { r, s, v } = ethUtil.ecsign(data, ethUtil.toBuffer(privateKey))
return ethUtil.toRpcSig(v, r, s)
}
const signature = await safeTx.sign(signer)
console.log({ signature })
const toSend = {
...txn,
sender,
contractTransactionHash: '0x' + safeTx.signHash().toString('hex'),
signature: signature,
}
console.log(JSON.stringify({ toSend }))
const { data } = await gnosisProposeTx(safe, toSend)
console.log({ data })
console.log('Done?')
}
"data":"0x8d80ff0a000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000001cb01e3d997d569b5b03b577c6a2edd1d2613fe776cb000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000044a9059cbb0000000000000000000000004bed464ce9d43758e826cfa173f1cda82964b8940000000000000000000000000000000000000000000000000de0b6b3a764000001e3d997d569b5b03b577c6a2edd1d2613fe776cb000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000044a9059cbb0000000000000000000000004bed464ce9d43758e826cfa173f1cda82964b8940000000000000000000000000000000000000000000000000de0b6b3a764000001e3d997d569b5b03b577c6a2edd1d2613fe776cb000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000044a9059cbb0000000000000000000000004bed464ce9d43758e826cfa173f1cda82964b8940000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000000000000000000000"
safe: "0x7723d6CD277F0670fcB84eA8E9Efe14f1b16acBB"