Wallet API
Build Inscription Wallet

Build Inscription Wallet#

The Wallet API supports five popular inscription assets: BRC-20, Runes, ARC-20, SRC-20, and Ordinals_NFT.

Please make sure you have completed the preparation work, then you can directly use this case to familiarize yourself with querying inscription data, constructing, and broadcasting inscription transactions.

Step 1: Generate Wallet Mnemonic and Address#

You can use our provided Signature SDK to create wallet mnemonics and addresses.

npm install#

First, install the latest version of the Signature SDK. For the BTC network, use the following commands:

npm install @okxweb3/crypto-lib
npm install @okxweb3/coin-base
npm install @okxweb3/coin-bitcoin

Build Locally#

  1. Download the project source code
git clone https://github.com/okx/js-wallet-sdk.git
  1. Run the build script
sh build.sh

For the BTC network, you can use the following code to create a BTC wallet object with the Signature SDK and derive the corresponding address.

import { BtcWallet,MessageTypes} from "@okxweb3/coin-bitcoin";
// btc wallet
let wallet = new BtcWallet()

// get mnemonic
let mnemonic = await getMnemonic(128);
let param = {
  mnemonic: mnemonic,
  hdPath: "m/44'/0'/0'/0/0"
};
// get derived key
let privateKey = await wallet.getDerivedPrivateKey(param);


// get new address
import { BtcWallet } from "@okxweb3/coin-bitcoin";

let wallet = new BtcWallet()

// legacy address
let params: NewAddressParams = {
  privateKey: "L22jGDH5pKE4WHb2m9r2MdiWTtGarDhTYRqMrntsjD5uCq5z9ahY"
};
let address = await wallet.getNewAddress(params);

// native segwit address
let params2: NewAddressParams = {
  privateKey: "L22jGDH5pKE4WHb2m9r2MdiWTtGarDhTYRqMrntsjD5uCq5z9ahY",
  addressType: "segwit_native",
};
let address2 = await wallet.getNewAddress(params2);

// nested segwit address
let params3: NewAddressParams = {
  privateKey: "L22jGDH5pKE4WHb2m9r2MdiWTtGarDhTYRqMrntsjD5uCq5z9ahY",
  addressType: "segwit_nested",
};
let address3 = await wallet.getNewAddress(params3);

// taproot segwit address
let params4: NewAddressParams = {
  privateKey: "L22jGDH5pKE4WHb2m9r2MdiWTtGarDhTYRqMrntsjD5uCq5z9ahY",
  addressType: "segwit_taproot",
};
let address4 = await wallet.getNewAddress(params4);

// get the public key
let publicKey = newAddress.publicKey;
console.log("the corresponding public key:", publicKey);

Demo Program#

We have prepared an open-source demo program,to showcase the functionalities of the Signature SDK mentioned above. Get the demo program source code here.


Step 2: Create an Account#

In the previous step, you generated mnemonics and addresses. Now you can create an account [(AccountId)] (./walletapi-resources-definitions)to aggregate multiple addresses for batch querying of token balances and transaction history.

Explanation
Typically, a Web3 wallet has three concepts:

- Wallet: The owner of the mnemonic owns the wallet.
- Account: Based on the BIP-44 standard, multiple accounts can be derived from a set of mnemonics.
- Address: Each chain under each account corresponds to an address.

Call the API to create a wallet account.

For example, to create a BTC wallet account supporting different address types:

// Define your parameters
const addresses = [
    {
        "chainIndex":"0",
        "address":"bc1peqgjr3cwl09mmsh6kvjsvv3ffu4waha00x7xrqrt85wt3zgdwphs72ctnu",
    },
    {
        "chainIndex":"0",
        "address":"18u8nvU5rx1drgwiT4M9sGTD9JX8r53KM9",
    }
];

const getCreateAccountBody = {
    addresses: addresses,
    signMessage: '1717062864123', // UNIX Timestamp in millisecond
};

// Define auxiliary function
const getCreateAccountData = async () => {
    const apiRequestUrl = getRequestUrl(
      apiBaseUrl,
      '/api/v5/wallet/account/create-wallet-account'
    );
    return fetch(apiRequestUrl, {
      method: 'post',
      headers: headersParams,
      body: JSON.stringify(getCreateAccountBody),
    })
      .then((res) => res.json())
      .then((res) => {
        return res;
    });
};

const { data: createAccountData } = await getCreateAccountData();

Step 3: Construct and Send Inscription Transactions#

Get Signature Required Information#

First, call the POST /api/v5/wallet/pre-transaction/sign-info interface to query some data required for signing, such as BTC chain fees, inscription output sizes, etc.

// Define your parameters
// BTC
const postSignInfoBody = {
    chainIndex: '0',
    fromAddr: 'bc1psnr548clz3f4fz6jmpnw5eqzj2v2musk082wp8fvq5ac3p5ete6qg05u8u',
    toAddr: 'bc1psnr548clz3f4fz6jmpnw5eqzj2v2musk082wp8fvq5ac3p5ete6qg05u8u',
    txAmount: '0',
    extJson: {
    }
};

// Define auxiliary function
const signInfoData = async () => {
    const apiRequestUrl = getRequestUrl(
        apiBaseUrl,
        '/api/v5/wallet/pre-transaction/sign-info'
    );
    return fetch(apiRequestUrl, {
         method: 'post',
         headers: headersParams,
         body: JSON.stringify(postSignInfoBody),
    })
    .then((res) => res.json())
    .then((res) => {
        return res;
    });
  };

const { data: signInfoData } = await signInfoData();

After querying the relevant information, you will receive a response like this:

{
    "code": "0",
    "msg": "success",
    "data": [
        {
            "normalFeeRate": "5",
            "maxFeeRate": "5",
            "minFeeRate": "5",
            "inscriptionOutput": "546",
            "minOutput": "546",
            "normalCost": "1800",
            "maxCost": "3600",
            "minCost": "600"
        }
    ]
}

Get Full UTXO#

Call the GET /api/v5/wallet/utxo/utxo interface to query all available UTXOs for the current address.

// Define your parameters
// BTC
const postSignInfoBody = {
    chainIndex: '0',
    fromAddr: 'bc1psnr548clz3f4fz6jmpnw5eqzj2v2musk082wp8fvq5ac3p5ete6qg05u8u',
    toAddr: 'bc1psnr548clz3f4fz6jmpnw5eqzj2v2musk082wp8fvq5ac3p5ete6qg05u8u',
    txAmount: '0',
    extJson: {
    }
};

// Define auxiliary function
const signInfoData = async () => {
    const apiRequestUrl = getRequestUrl(
        apiBaseUrl,
        '/api/v5/wallet/pre-transaction/sign-info'
    );
    return fetch(apiRequestUrl, {
         method: 'get',
         headers: headersParams,
         body: JSON.stringify(postSignInfoBody),
    })
    .then((res) => res.json())
    .then((res) => {
        return res;
    });
  };

const { data: signInfoData } = await signInfoData();

Get Inscription Asset Details on UTXO#

Call the POST /api/v5/wallet/utxo/utxo-detail interface to query the inscription details on the UTXO.

// Define your parameters
// BTC
const postSignInfoBody = {
    chainIndex: '0',
    fromAddr: 'bc1psnr548clz3f4fz6jmpnw5eqzj2v2musk082wp8fvq5ac3p5ete6qg05u8u',
    toAddr: 'bc1psnr548clz3f4fz6jmpnw5eqzj2v2musk082wp8fvq5ac3p5ete6qg05u8u',
    txAmount: '0',
    extJson: {
    }
};

// Define auxiliary function
const signInfoData = async () => {
    const apiRequestUrl = getRequestUrl(
        apiBaseUrl,
        '/api/v5/wallet/pre-transaction/sign-info'
    );
    return fetch(apiRequestUrl, {
         method: 'post',
         headers: headersParams,
         body: JSON.stringify(postSignInfoBody),
    })
    .then((res) => res.json())
    .then((res) => {
        return res;
    });
  };

const { data: signInfoData } = await signInfoData();

Verify Address and Build Transaction#

Use the signing SDK to first verify address validity and then build the transaction.

// Verify address
let valid = await wallet.validAddress({
    address: newAddress.address
});
console.log("verify address isValid:", valid.isValid);

// Sign a transaction
let signParams = {
    privateKey: derivePrivateKey,
    data: {
        to: newAddress.address,
        value: new BigNumber(0),
        nonce: 5,
        gasPrice: new BigNumber(100 * 1000000000),
        gasLimit: new BigNumber(21000),
        chainId: 42
    }
};

let signedTx = await wallet.signTransaction(signParams);
console.log("signed tx:", signedTx);

Broadcast Transaction#

Call the interface to broadcast the transaction to the blockchain.

// Define your parameters
const postSendTransactionBody = {
    signedTx: "02000000000101a92808fb32063058e3c752ad2c4a0a6f8957e858dd01483ccff504d4f5ca791d0500000000fdffffff02c405000000000000225120728b5d2f0cf833264adac833e997931155b4aec3020bc87c32fa91509bb2abe61f71080000000000225120f0513064fe1e5b5c31bedff43b943f2f1211d14ab2891687241b138d214888e30140393a287212d5c7341a5d44ba2409dda5db95a854e500475ec8bf2ea0f7f63d35c849102c0f906f48d1833f3b5b7a7ca726e14fc2d715b4cbbecb8488e028baab00000000"
    accountId:"c79e7775-9e78-4a2d-b27f-9021f3bf5fca",
    address: "bc1p7pgnqe87red4cvd7ml6rh9pl9ufpr522k2y3dpeyrvfc6g2g3r3s3ae9dr",
};

// Define auxiliary function
const sendTransactionData = async () => {
    const apiRequestUrl = getRequestUrl(
        apiBaseUrl,
        'api/v5/wallet/pre-transaction/broadcast-transaction'
    );
    return fetch(apiRequestUrl, {
        method: 'post',
        headers: headersParams,
        body: JSON.stringify(postSendTransactionBody),
    })
    .then((res) => res.json())
    .then((res) => {
        return res;
    });
  };

const { data: sendTransactionData } = await sendTransactionData();

After broadcasting, you will receive the following response:

{
    "code": 0,
    "msg": "success",
    "data": [{
        "orderId": "469356614923743232"
    }]
}
Note
Click to see the orderId definition

Step 5: Query Inscription Transaction Details#

After sending the transaction, use the GET /api/v5/wallet/post-transaction/inscription-transaction-detail-by-txhash interface to obtain the inscription transaction details via txhash.

// Define your parameters
const params = {
    accountId: '13886e05-1265-4b79-8ac3-b7ab46211001',
    orderId: '469356614923743232',
    chainIndex: '1'
  };

// Define auxiliary function
const getTransactionDetailData = async () => {
    const apiRequestUrl = getRequestUrl(
        apiBaseUrl,
        '/api/v5/wallet/post-transaction/transaction-detail-by-ordid',
        params
    );
    return fetch(apiRequestUrl, {
        method: 'get',
        headers: headersParams,
    })
    .then((res) => res.json())
    .then((res) => {
        return res;
    });
  };

const { data: transactionDetailData } = await getTransactionDetailData();

After successfully querying the details, you will receive a response like the following:

{
    "code": 0,
    "msg": "success",
    "data": [
        {
            "chainIndex": "1",
            "orderId": "469356614923743232",
            "txhash": "0xcbf411766d65f3cf92839ababa73c4afec69a83442e8b67a68b5104b50a04ejb",
            "blockHash" : "0x3ee63382b883fc40e35da6023fb341dd01cd2ec011f992bb54cf312f517740c9",
            "blockHeight" : "19235519",
            "blockTime" : "1708026551000",
            "feeUsdValue" : "138.846919",
            "fees" : "49102595635945621",
            "gasLimit" : "2000000",
            "gasPrice" : "87504603347",
            "gasUsed" : "561143",
            "txType": "0",  
            "txTime": "0", 
            "txStatus": "0",
            "txDetail": [
                {
                    "iType" : "0",  
                    "txAmount": "0",
                    "tokenAddress":""
                    "contractCall" : true,
                    "fromAddr" : "0x3ee63382b883fc40e35da6023fb341dd01cd2ec011f992bb54cf312f517740c9",
                    "toAddr" : "0x3ee63382b883fc40e35da6023fb341dd01cd2ec011f992bb54cf312f517740c9",
                    "logIndex" : "-1",
                    "status" : "SUCCESS"
                }
            ]
        }
    ]
}

Additionally, you can subscribe to Webhooks to get real-time and accurate information on the status of your transaction after it has been sent,See details.

At this point, you have basically implemented the essential functions required for developing an inscription wallet.

Moreover, the wallet API provides a rich set of interfaces to meet the needs of Web3 wallet developers. For more details, please refer to the following content.