Created
September 6, 2024 14:17
-
-
Save Pitasi/15dde7839bb12a71776458cfdb543286 to your computer and use it in GitHub Desktop.
[draft] signing Cosmos SDK tx using ethers.js (+ evmos)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { makeAuthInfoBytes, makeSignDoc } from "@cosmjs/proto-signing"; | |
import { toBech32 } from "@cosmjs/encoding"; | |
import { Int53 } from "@cosmjs/math"; | |
import { ethers } from "ethers"; | |
import { ethermint, cosmos, google, warden, getSigningWardenClientOptions } from "@wardenprotocol/wardenjs"; | |
const { Any } = google.protobuf; | |
const { TxBody, TxRaw, SignDoc } = cosmos.tx.v1beta1; | |
const { MsgNewSpace } = warden.warden.v1beta3; | |
const PubKey = ethermint.crypto.v1.ethsecp256k1.PubKey; | |
main(); | |
async function main() { | |
// init an ethers wallet from mnemonic | |
const mnemonic = "surround miss nominee dream gap cross assault thank captain prosper drop duty group candy wealth weather scale put"; | |
const ethWallet = ethers.Wallet.fromPhrase(mnemonic); | |
const ethAddress = ethWallet.address; | |
const wardenAddress = toBech32("warden", ethers.getBytes(ethAddress)); | |
const pubkey = ethers.getBytes(ethWallet.publicKey); | |
console.log("Wallet:", ethAddress, wardenAddress); | |
// prepare the content of the transaction | |
const fee = { | |
amount: [{ denom: "award", amount: "100" }], | |
gas: "200000", | |
}; | |
const txBody = TxBody.fromPartial({ | |
messages: [{ | |
typeUrl: MsgNewSpace.typeUrl, | |
value: MsgNewSpace.fromPartial({ | |
creator: wardenAddress, | |
}), | |
}], | |
}); | |
// bundle the transaction and sign it | |
const signDoc = await buildSignDoc("warden_1337-1", wardenAddress, pubkey, txBody, fee); | |
const signedTx = await signTransaction(ethWallet, signDoc); | |
// broadcast | |
const broadcastRes = await broadcastTx(signedTx); | |
console.log(broadcastRes); | |
} | |
async function buildSignDoc(chainId, wardenAddr, pubkey, txBody, fee) { | |
const account = await fetchAccount(wardenAddr); | |
const pubk = Any.fromPartial({ | |
typeUrl: PubKey.typeUrl, | |
value: PubKey.encode({ | |
key: pubkey, | |
}).finish(), | |
}); | |
const txBodyEncodeObject = { | |
typeUrl: TxBody.typeUrl, | |
value: txBody, | |
}; | |
const { registry } = getSigningWardenClientOptions(); | |
const txBodyBytes = registry.encode(txBodyEncodeObject); | |
const gasLimit = Int53.fromString(fee.gas).toNumber(); | |
const authInfoBytes = makeAuthInfoBytes( | |
[{ pubkey: pubk, sequence: account.sequence }], | |
fee.amount, | |
gasLimit, | |
fee.granter, | |
fee.payer, | |
); | |
const signDoc = makeSignDoc(txBodyBytes, authInfoBytes, chainId, Number(account.accountNumber)); | |
return signDoc; | |
} | |
async function signTransaction(wallet, signDoc) { | |
const signDocBytes = SignDoc.encode(signDoc).finish(); | |
const signatureRaw = wallet.signingKey.sign(ethers.keccak256(signDocBytes)); | |
const signature = ethers.Signature.from(signatureRaw); | |
const signatureRS = ethers.concat([signature.r, signature.s]) | |
const signatureRSBytes = ethers.getBytes(signatureRS); | |
const signedTx = TxRaw.encode(TxRaw.fromPartial({ | |
authInfoBytes: signDoc.authInfoBytes, | |
bodyBytes: signDoc.bodyBytes, | |
signatures: [signatureRSBytes], | |
})).finish(); | |
return signedTx; | |
} | |
async function fetchAccount(address) { | |
const client = await warden.ClientFactory.createRPCQueryClient({ | |
rpcEndpoint: "http://localhost:26657", | |
}) | |
const { account } = await client.cosmos.auth.v1beta1.account({ address }); | |
if (!account) { | |
throw new Error("Failed to retrieve account from chain", account); | |
} | |
return account; | |
} | |
async function broadcastTx(bytes) { | |
const res = await fetch("http://localhost:1317/cosmos/tx/v1beta1/txs", { | |
method: "POST", | |
headers: { | |
"Content-Type": "application/json", | |
}, | |
body: JSON.stringify({ | |
"tx_bytes": ethers.encodeBase64(bytes), | |
"mode": "BROADCAST_MODE_SYNC" | |
}), | |
}) | |
const resJson = await res.json(); | |
return resJson; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment