Documentation Index
Fetch the complete documentation index at: https://initialabs-mintlify-changelog-interwovenkit-1777853576.mintlify.app/llms.txt
Use this file to discover all available pages before exploring further.
Sometimes, you may want to sign a transaction without broadcasting it. This is
useful in situations where you want to sign a transaction and then broadcast it
later. To showcase this, you will write a script that will sign a transaction,
compute the transaction hash from the signed transaction, and compare the
transaction hash to what you receive from broadcasting the transaction.
First, import the necessary classes and functions.
Coins: A class that represents a list of
Cosmos SDK coins.
Fee: A class that’s used to define the fee for a transaction.
RESTClient: A class that represents a REST client.
MnemonicKey: A class that’s used to create a key from a mnemonic.
MsgSend: A class that represents a message to send.
Wallet: A class that represents a wallet.
import {
Coins,
Fee,
RESTClient,
MnemonicKey,
MsgSend,
Wallet,
} from '@initia/initia.js'
import crypto from 'crypto'
Next, set up your environment variables. You will need the following:
mnemonic: The mnemonic of the account that will be signing the transaction.
chainId: The chain ID of the network you are working on.
restUrl: The URL of the Initia REST.
gasPrices: The gas prices for the transaction.
const mnemonic = process.env.MNEMONIC
const chainId = process.env.CHAIN_ID || 'initiation-2'
const restUrl = process.env.REST_URL || 'https://rest.testnet.initia.xyz'
const gasPrices = process.env.GAS_PRICES || '0.015uinit' // Will be INIT for mainnet
You will also need to create a helper function to convert the signed transaction
data into a transaction hash hex string.
export function getTxHash(tx: Uint8Array): string {
const s256Buffer = crypto
.createHash(`sha256`)
.update(Buffer.from(tx))
.digest()
const txbytes = new Uint8Array(s256Buffer)
return Buffer.from(txbytes.slice(0, 32)).toString(`hex`).toUpperCase()
}
Finally, create the main function to sign the transaction and compare the
transaction hash. Let’s call this function offlineSigningTest.
To start, create two RESTClient instances. One that is connected to the
network, and one that is offline. You will use the offline REST client to sign
the transaction, and the online REST client to broadcast the transaction to
later compare.
const offlineRestClient = new RESTClient(``, {
chainId: chainId,
gasPrices: gasPrices,
})
// rest client that is connected
const onlineRestClient = new RESTClient(restUrl, {
chainId: chainId,
gasPrices: gasPrices,
})
Next, generate the wallet client, as well as define the message, gas limit, and
fee for the transaction. You need to define the latter two because you will be
signing the transaction completely offline without interacting with the network
or any nodes.
// set up key
const key = new MnemonicKey({
mnemonic: mnemonic,
})
const account = await onlineRestClient.auth.accountInfo(key.accAddress) // you have to know account number and current sequence
const wallet = new Wallet(offlineRestClient, key)
// msg to send
const msg = new MsgSend(key.accAddress, key.accAddress, '100uinit')
// use fixed fee to not estimate gas
const gasLimit = 500000
const feeAmount = new Coins(offlineRestClient.config.gasPrices)
.toArray()[0]
.mul(gasLimit)
const fee = new Fee(gasLimit, new Coins([feeAmount]))
Once you have all of that, create the transaction by calling
wallet.createAndSignTx. This function takes
msgs: The message to send.
accountNumber: The account number of the account that will be signing the
transaction.
sequence: The sequence number of the account that will be signing the
transaction.
fee: The fee for the transaction.
and returns a signed transaction object. Then convert the signed transaction
object to a byte array and compute the transaction hash using the helper
function created earlier.
const signedTx = await wallet.createAndSignTx({
msgs: [msg],
accountNumber: account.getAccountNumber(),
sequence: account.getSequenceNumber(),
fee,
})
const signedTxBytes = signedTx.toBytes()
const txHash = getTxHash(signedTxBytes)
Finally, if you want to broadcast the transaction to the network later, you can
do so by using the onlineRestClient client. If you then retrieve the
transaction hash from the online REST client and compare it to the transaction
hash you computed earlier, you should see that they match.
const broadcastRes = await onlineRestClient.tx.broadcastSync(signedTx)
// true
console.log(txHash === broadcastRes.txhash)
Full Example
src/signing-transaction.ts
import {
Coins,
Fee,
RESTClient,
MnemonicKey,
MsgSend,
Wallet,
} from '@initia/initia.js'
import crypto from 'crypto'
const mnemonic = process.env.MNEMONIC
const chainId = process.env.CHAIN_ID || 'initiation-2'
const restUrl = process.env.REST_URL || 'https://rest.testnet.initia.xyz'
const gasPrices = process.env.GAS_PRICES || '0.015uinit' // Will be INIT for mainnet
export function getTxHash(tx: Uint8Array): string {
const s256Buffer = crypto
.createHash(`sha256`)
.update(Buffer.from(tx))
.digest()
const txbytes = new Uint8Array(s256Buffer)
return Buffer.from(txbytes.slice(0, 32)).toString(`hex`).toUpperCase()
}
async function offlineSigningTest() {
// rest client that is not connected
const offlineRestClient = new RESTClient(``, {
chainId: chainId,
gasPrices: gasPrices,
})
// rest client that is connected
const onlineRestClient = new RESTClient(restUrl, {
chainId: chainId,
gasPrices: gasPrices,
})
// set up key
const key = new MnemonicKey({
mnemonic: mnemonic,
})
const account = await onlineRestClient.auth.accountInfo(key.accAddress) // you have to know account number and current sequence
const wallet = new Wallet(offlineRestClient, key)
// msg to send
const msg = new MsgSend(key.accAddress, key.accAddress, '100uinit')
// use fixed fee to not estimate gas
const gasLimit = 500000
const feeAmount = new Coins(offlineRestClient.config.gasPrices)
.toArray()[0]
.mul(gasLimit)
const fee = new Fee(gasLimit, new Coins([feeAmount]))
const signedTx = await wallet.createAndSignTx({
msgs: [msg],
accountNumber: account.getAccountNumber(),
sequence: account.getSequenceNumber(),
fee,
})
const signedTxBytes = signedTx.toBytes()
const txHash = getTxHash(signedTxBytes)
const broadcastRes = await onlineRestClient.tx.broadcastSync(signedTx)
// true
console.log(txHash === broadcastRes.txhash)
}
offlineSigningTest()