Transaction Requests API
TransactionRequests
are off-chain requests for all sorts of blockchain
transactions before they are sent to the blockchain.
Typically, a transaction request is created when a user wants to perform a transaction on the blockchain. The transaction request will then be validated against the wallet's existing policies, and then sent to the wallet's approval quorum for approval. Once the transaction request is approved, the transaction needs to be signed by the wallet's signer before it is sent to the blockchain.
Refer to the Transaction Request Workflow for more information on the transaction request lifecycle.
Create
Native Token Transfer
To perform native crypto transfers, you can use the SDK or the GraphQL mutation as follows.
You can toggle between TypeScript
and GraphQL
to see the code examples.
import { LevainGraphClient } from '@levain/wallet-sdk';
const client = new LevainGraphClient({
// Get your personal access token from https://app.levain.tech/account/tokens
accessToken: '<Your access token>',
});
const walletId = '8b7a9f2d-194b-4e9b-a0f5-d500b9a0201a';
// initiate a "send" transaction of 0.001 ETH to 0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045
const { requestId } = await client.sendAsset({
walletId,
to: '0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045',
amount: '0.001',
/*
The asset identifier is a CAIP-19 asset identifier, which is a standardized format for identifying assets across
different blockchains.
- Ethereum mainnet eth: caip19:eip155:1/slip44:60
- Ethereum mainnet weth: caip19:eip155:1/erc20:0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2
- Bitcoin mainnet UTXO: caip19:bip122:000000000019d6689c085ae165831e93/slip44:0
- Bitcoin testnet UTXO: caip19:bip122:000000000933ea01ad0ee984209779ba/slip44:1
For more examples, see https://developer.levain.tech/products/graph/docs/levain-fundamentals/supported-tokens
*/
asset: 'caip19:eip155:1/slip44:60',
});
// explicit approval
await client.approveTransactionRequest({ requestId });
// create the digests to be signed client-side
const { digests } = await client.createTransactionDigests({ requestId });
// client-side signing is performed on the digests, and the signatures are sent to Levain
// the transaction is then broadcasted to the blockchain network
const executedTransaction = await client.executeTransaction({
walletId,
requestId,
digests,
walletPassword: '...',
});
The walletId
is provided by the createWallet
mutation
(i.e. at wallet creation time).
ERC-20 Token Transfer
To perform ERC-20 token transfers on EVM-compatible blockchains, you can use the SDK or the GraphQL mutation as follows.
import { LevainGraphClient } from '@levain/wallet-sdk';
const client = new LevainGraphClient({
// Get your personal access token from https://app.levain.tech/account/tokens
accessToken: '<Your access token>',
});
const walletId = '8b7a9f2d-194b-4e9b-a0f5-d500b9a0201a';
const { requestId } = await client.sendAsset({
walletId,
// Sepolia wETH
// https://sepolia.etherscan.io/address/0x7b79995e5f793a07bc00c21412e50ecae098e7f9
asset: 'caip19:eip155:11155111/erc20:0x7b79995e5f793A07Bc00c21412e50Ecae098E7f9',
to: '0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045',
amount: '0.001',
clientRequestId: '...', // Optional, you can pass in a unique reference ID for the transaction for idempotency
});
// explicit approval
await client.approveTransactionRequest({ requestId });
// create the digests to be signed client-side
const { digests } = await client.createTransactionDigests({ requestId });
// client-side signing is performed on the digests, and the signatures are sent to Levain
// the transaction is then broadcasted to the blockchain network
const executedTransaction = await client.executeTransaction({
walletId,
requestId,
digests,
walletPassword: '...',
});
TRC-20 Token Transfers
Largely similar to ERC-20 token transfers, you can use the SDK or the GraphQL mutation as follows.
import { LevainGraphClient } from '@levain/wallet-sdk';
const client = new LevainGraphClient({
// Get your personal access token from https://app.levain.tech/account/tokens
accessToken: '<Your access token>',
});
const walletId = '8b7a9f2d-194b-4e9b-a0f5-d500b9a0201a';
const { requestId } = await client.sendAsset({
walletId,
// Tron USDT - https://tronscan.org/#/token20/TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t
asset: 'caip19:tip474:728126428/trc20:TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t',
to: 'TT2T17KZhoDu47i2E4FWxfG79zdkEWkU9N',
amount: '0.001',
});
// explicit approval
await client.approveTransactionRequest({ requestId });
// create the digests to be signed client-side
const { digests } = await client.createTransactionDigests({ requestId });
// client-side signing is performed on the digests, and the signatures are sent to Levain
// the transaction is then broadcasted to the blockchain network
const executedTransaction = await client.executeTransaction({
walletId,
requestId,
digests,
walletPassword: '...',
});
Retrieve
By Transaction Request ID
You can retrieve a transaction request using the following GraphQL query with
the TransactionRequest
object.
query TransactionRequestById {
wallet(walletId: "d628e653-becd-412d-bdef-dbab620631d9") {
transactionRequest(requestId: "f33e01d2-25e9-4f63-9e61-788ae20df7c3") {
status
transactionHash
transactionSignature
transactionSigned
asset {
name
decimals
isNative
}
initiator {
user {
email
firstName
lastName
}
}
approvals {
edges {
node {
actor {
user {
email
firstName
lastName
}
}
}
}
}
}
}
}
{
"data": {
"wallet": {
"transactionRequest": {
"status": "SIGNED",
"transactionHash": "0x5c386f2c2cdc9d55d73ce96b9a5b929ea1693cddad4b5500b13a214a9c9b2b52",
"transactionSignature": "0xad56808e1dae318db5e48c9efc85b913cb29ad8f1d9d5b3e32a5228d1df314c35f579924e8c5330ff531728121eadfc6cda5999f0e7aa77520886b8cdce25e531b5c42986377c38755633a7c2e61ae2363f5f9d72ae8e2ec931ed9c82dbfb6b9bb092421103538bb7d506d47c82b3cfe4113976612779c8b2257ae90ac39ddbcb91b",
"transactionSigned": "0x02f9021383aa36a7038459682f008459682f8e82f75d946886c0a002c3de06481330adb9e25e76d5bf2d2e80b901a460b4cda700000000000000000000000000000000000000000000000000000000000000c00000000000000000000000008d080e0d0ff69f5801dd3c4f628fb72f595a1bd00000000000000000000000000000000000000000000000000000886c98b760000000000000000000000000000000000000000000000000000000000000000180000000000000000000000000a060029846886406d05bb5df82d417c4200ac90000000000000000000000000000000000000000000000000000000000000052080000000000000000000000000000000000000000000000000000000000000082ad56808e1dae318db5e48c9efc85b913cb29ad8f1d9d5b3e32a5228d1df314c35f579924e8c5330ff531728121eadfc6cda5999f0e7aa77520886b8cdce25e531b5c42986377c38755633a7c2e61ae2363f5f9d72ae8e2ec931ed9c82dbfb6b9bb092421103538bb7d506d47c82b3cfe4113976612779c8b2257ae90ac39ddbcb91b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c001a00c0d39743ee31ea6c9a1a792966dcbf263732ba563de891d22b3f6cf57e9492ea003dca15020c2337e55c4b3ead1ba91f867af7cc20fe0060a49e312d37db68ade",
"asset": {
"name": "Sepolia Uniswap",
"decimals": 18,
"isNative": false
},
"initiator": {
"user": {
"email": "[email protected]",
"firstName": "API Initiator",
"lastName": "Service Account"
}
},
"approvals": {
"edges": [
{
"node": {
"actor": {
"user": {
"email": "[email protected]",
"firstName": "API Approver",
"lastName": "Service Account"
}
}
}
}
]
}
}
}
}
}