Guides
Pearl
Overview
Pearl is the native asset of the Pearl blockchain. It uses:
- UTXO model
- BIP-340 Schnorr signature algorithm
- BIP-341 script-path spending with a nothing-up-my-sleeve (NUMS) internal key
Pearl blockchain is a taproot-only Layer 1 network, forked from btcd and built by Pearl Research Labs. It secures the chain with Proof-of-Useful-Work (PoUW) consensus, where miners perform matrix multiplication instead of traditional hashcash. Every output is a Pay-to-Taproot (P2TR) output with a NUMS internal key and a taptree of 2-of-2 OP_CHECKSIG leaves, which together form a 2-of-3 script-path multisig. Pearl supports only taproot (P2TR) addresses with bech32m encoding, so it has no legacy or SegWit v0 output types.
Explorer
https://blockbook.pearlresearch.ai/Testnet explorer: https://blockbook.testnet.pearlresearch.ai/
Wallet Types
BitGo enables holding pearl in the following wallet types:
| Multisig Cold | Multisig Hot | MPC Cold | MPC Hot | |
|---|---|---|---|---|
| Custody | ✅ | ❌ | ❌ | ❌ |
| Self-Custody | ✅ | ✅ | ❌ | ❌ |
Ticker Symbols
| Mainnet | Testnet |
|---|---|
| PEARL | TPEARL |
Faucet
Pearl doesn't have a public faucet to obtain testnet tpearl for development and testing.
Units
Pearl is divisible by 10-8 and the base unit is a grain:
- 1 pearl = 100,000,000 grain
- 1 grain = 0.00000001 pearl
You can pass balances in string or integer format. However, BitGo recommends using string format to ensure values don't exceed the programmable number limit.
Tokens
The Pearl blockchain doesn't natively support tokens.
Fees
Pearl has the following fees:
- Minimum fee rate = 1 grain/vByte (1000 grain/kvByte)
- Default fee rate = 10 grain/vByte
Dust Threshold
A dust threshold is the minimum amount of Pearl that you can create in a single output. Pearl computes the dust threshold dynamically based on the output type, using a dust relay fee of 3000 grain/kvByte.
Create Wallet
export BITGO_EXPRESS_HOST="<YOUR_LOCALHOST>"
export COIN="tpearl"
export ACCESS_TOKEN="<YOUR_ACCESS_TOKEN>"
export LABEL="<DESIRED_WALLET_NAME>"
export PASSPHRASE="<YOUR_BITGO_LOGIN_PASSPHRASE>"
export ENTERPRISE_ID="<YOUR_ENTERPRISE_ID>"
curl -X POST \
http://$BITGO_EXPRESS_HOST/api/v2/$COIN/wallet/generate \
-H 'Content-Type: application/json' \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-d '{
"label": "'"$LABEL"'",
"passphrase": "'"$PASSPHRASE"'",
"enterprise": "'"$ENTERPRISE_ID"'",
"disableTransactionNotifications": true,
"disableKRSEmail": true
}'
const { BitGo } = require('bitgo');
const accessToken = '<YOUR_ACCESS_TOKEN>';
// Initialize the SDK
const bitgo = new BitGo({
accessToken: accessToken,
env: 'test',
});
// Generate hot wallet
async function createHotWalletSimple() {
const newWallet = await bitgo.coin('tpearl').wallets().generateWallet({
label: '<DESIRED_WALLET_NAME>',
passphrase: '<YOUR_BITGO_LOGIN_PASSWORD>',
});
// Print wallet details
console.log(JSON.stringify(newWallet, undefined, 2));
}
Create Address
export COIN="tpearl"
export WALLET_ID="<YOUR_WALLET_ID>"
export ACCESS_TOKEN="<YOUR_ACCESS_TOKEN>"
curl -X POST \
https://app.bitgo-test.com/api/v2/$COIN/wallet/$WALLET_ID/address \
-H 'Content-Type: application/json' \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-d '{"chain": 30}'
const { BitGo } = require('bitgo');
const accessToken = '<YOUR_ACCESS_TOKEN>';
// Initialize the SDK
const bitgo = new BitGo({
accessToken: accessToken,
env: 'test',
});
const wallet = await bitgo.coin('tpearl').wallets().generateWallet({
label: '<DESIRED_WALLET_NAME>',
passphrase: '<YOUR_BITGO_LOGIN_PASSPHRASE>',
});
const address = await wallet.createAddress({ chain: 30 });
console.log(JSON.stringify(address, undefined, 2));
Note: Pearl supports only the taproot address type (p2tr). To learn more, see UTXO Address Types.
Consolidate Balance
Pearl is a UTXO asset and therefore doesn't require consolidating to the base address in order to use the maximum spendable amount.
Estimate Fee
export COIN="tpearl"
export ACCESS_TOKEN="<YOUR_ACCESS_TOKEN>"
curl -X GET \
https://app.bitgo-test.com/api/v2/$COIN/tx/fee \
-H 'Content-Type: application/json' \
-H "Authorization: Bearer $ACCESS_TOKEN"
const BitGoJS = require('../../../src/index.js');
const bitgo = new BitGoJS.BitGo({ env: 'test' });
const Promise = require('bluebird');
const accessToken = '<YOUR_ACCESS_TOKEN>';
const coin = 'tpearl';
Promise.coroutine(function *() {
bitgo.authenticateWithAccessToken({ accessToken });
bitgo.coin(coin).feeEstimate({ numBlocks: 2 }, function callback(err, res) {
console.dir(res);
});
})();
Transact
export BITGO_EXPRESS_HOST="<YOUR_LOCALHOST>"
export COIN="tpearl"
export WALLET_ID="<YOUR_WALLET_ID>"
export ACCESS_TOKEN="<YOUR_ACCESS_TOKEN>"
export ADDRESS="<DESTINATION_ADDRESS>"
export AMOUNT="<AMOUNT_IN_BASE_UNITS>"
export WALLET_PASSPHRASE="<YOUR_WALLET_PASSPHRASE>"
curl -X POST \
http://$BITGO_EXPRESS_HOST/api/v2/$COIN/wallet/$WALLET_ID/sendcoins \
-H 'Content-Type: application/json' \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-d '{
"address": "'"$ADDRESS"'",
"amount": "'"$AMOUNT"'",
"walletPassphrase": "'"$WALLET_PASSPHRASE"'",
"txFormat": "psbt"
}'
export BITGO_EXPRESS_HOST="<YOUR_LOCALHOST>"
export COIN="tpearl"
export WALLET_ID="<YOUR_WALLET_ID>"
export ACCESS_TOKEN="<YOUR_ACCESS_TOKEN>"
export ADDRESS_1="<DESTINATION_ADDRESS_1>"
export ADDRESS_2="<DESTINATION_ADDRESS_2>"
export AMOUNT_1="<AMOUNT_1_IN_BASE_UNITS>"
export AMOUNT_2="<AMOUNT_2_IN_BASE_UNITS>"
export WALLET_PASSPHRASE="<YOUR_WALLET_PASSPHRASE>"
curl -X POST \
http://$BITGO_EXPRESS_HOST/api/v2/$COIN/wallet/$WALLET_ID/sendmany \
-H 'Content-Type: application/json' \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-d '{
"recipients": [
{
"address": "'"$ADDRESS_1"'",
"amount": "'"$AMOUNT_1"'"
},
{
"address": "'"$ADDRESS_2"'",
"amount": "'"$AMOUNT_2"'"
}
],
"walletPassphrase": "'"$WALLET_PASSPHRASE"'",
"txFormat": "psbt"
}'
const tx = await fundedWallet.send({
address: `<DESTINATION_ADDRESS>`,
amount: `<AMOUNT>`,
walletPassphrase: process.env.PASSWORD as string,
});
let params = {
recipients: [
{
amount: "<AMOUNT_1>",
address: "<DESTINATION_ADDRESS_1>",
},
{
amount: "<AMOUNT_2>",
address: "<DESTINATION_ADDRESS_2>",
},
],
walletPassphrase: "<YOUR_WALLET_PASSPHRASE>",
};
wallet.sendMany(params).then(function (transaction) {
// Print transaction details
console.dir(transaction);
});
Stake
Pearl isn't a stakeable asset.