Pontis Frontend SDK

The Pontis Bridge SDK enables frontend applications to integrate Pontis bridging capabilities and build custom dApp logic, such as DeFi applications, on top of it.

Installation

To install the Pontis Bridge Frontend SDK, run:

npm install @pontis/core-sdk

Supported Cross-Chain Assets

The first SDK version supports the following assets:

  • BTC

  • Runes

Workflow

1. Authorization

Authorize using an extension wallet or a private key (for wallet integration) to sign the authorization message.

Supported Wallets:

  • Bitcoin: Xverse, Leather, Unisat, Asigna Multisig

  • Stacks: Xverse, Leather

  • EVM: Metamask

Fields Required for Authorization:

  • publicKey (not required for EVM)

  • address

  • signature: A signature from the connected wallet for the message: "Welcome to Pontis!"

2. Authorize via Pontis API

Each network requires separate authentication. The authorization request returns a JWT token for each chain. (See the API documentation for more details.)

3. Load History

Use the following function to fetch the transaction history for the specified chain:

getTransaction('active' | 'completed');

The chain is determined by the JWT token obtained during the authorization step.

4. Create Bridge Transactions

Create bridge transactions for different chains. Refer to the detailed guides below.

Bitcoin Blockchain Actions

Hook: useBitcoinBlockchainActions

1. createSendBtc

Send BTC via the bridge.

Parameters:

  • amount: The amount of BTC to send.

  • feeRate: The fee rate for the bridge transaction.

  • recipientAddress: The recipient’s address.

  • destinationChain: The target blockchain.

  • doSignAndBroadcastPsbt: Function to sign and broadcast the generated PSBT.

Example:

async (psbt) => {
  const txId = await signAndBroadcastPsbtXverse(psbt);
  return txId;
};

2. doSignMessage

Function to sign the bridge message (a required step for Bitcoin transactions).

Example:

async (message) => {
  const signature = await signCustomMessage(message);
  return signature;
};

3. createSendRune

Send Rune assets via the Bitcoin chain.

Parameters:

The parameters are the same as createSendBtc with one additional field:

  • rune: The Rune to send.

Pending Transactions

For Bitcoin, the bridge transaction process involves two steps:

  1. The bridge transaction is created.

  2. The message with the txId and destination parameters is signed by the sender's wallet.

Developers should account for the users that accidentally closes the sign message window.

  • Unsigned transactions are stored in localStorage under the key: pending_transactions.

Hook: usePendingTransactions

This hook:

  • Returns stored transactions.

  • Provides functions to handle the state of stored data.

By default, the stored data is managed within the library.

Signing Pending Transactions: signMessageForTx

Parameters:

  • txId: The transaction ID.

  • async doSignMessage(message: string): The message signing handler.

  • onFinish(claim: Claim): A callback triggered when the transaction is created on the backend.

Example:

const { txs, signMessageForTx } = usePendingTransactions();

{txs.length > 0 && (
  <div
    onClick={() => {
      signMessageForTx(
        txs[0].txId,
        async (message: string) => {
          return await signMessage(message) as string;
        },
        () => {
          navigate('history');
        }
      );
    }}
  >
    Pending
  </div>
)}

Stacks Blockchain Actions

Hook: useStxBlockchainActions

Supported Properties

Parameters:

  • publicKey: Signer’s public key.

  • amount: Amount to transfer.

  • recipientAddress: Destination address.

  • targetChain: Target blockchain.

  • stacksNetwork: "testnet" or "mainnet".

  • doSignAndBroadcast: Function to sign and broadcast the generated StacksTransaction. Returns txId.

Example:

async (stacksTransaction) => {
  const txId = await openSignTransaction({
    txHex: bytesToHex(stacksTransaction.serialize()),
  });
  return txId;
};

unlockRunesUnsignedCall

Send Rune assets on the Stacks chain.

Parameters:

The parameters are the same as unlockBtcUnsignedCall with one additional field:

  • rune: Rune to send.

unlockBtc and unlockRunes

These are helper functions to sign and broadcast transactions using the wallet.

Supported EVM Chains

The SDK supports the following EVM testnets:

  • Sepolia (SEP)

  • Merlin Testnet (MERL)

EVM Blockchain Actions

Hook: useEvmBlockchainActions

If permission hasn’t been granted yet, the approve token contract function will be called automatically.

createBridgeOutBTC

Send BTC via the EVM chain.

Parameters:

  • amount: The amount to send.

  • recipientAddress: The destination address.

  • sourceChain: SEP (Sepolia) or MERL (Merlin Network).

  • targetChain: The target blockchain.

  • serviceValue: The service fee.

createSendRune

Send Rune assets via the EVM chain.

Parameters:

The parameters are the same as createBridgeOutBTC with one additional field:

  • rune: Rune to send.

Pontis API

Axios Instance: pontisAxiosInstance

This is an Axios instance used to interact with the Pontis API.

Authorization

Functions:

  • evmLoginRequest

  • stacksLoginRequest

  • bitcoinLoginRequest

These functions return a JWT token for their respective chains.

Bitcoin Multisig Authentication

Used for integration with Asigna Multisig.

Connect to your dApp using the @asigna/btc-connect package.

Pass the information from the useAsignaSafeInfo() hook or connectToExtension() function to bitcoinLoginRequestMultisig().

Parameters:

  • finalSignature: Signature from the multisig owners.

  • multiSigType: The multisig type.

  • multisigAddress: The multisig address.

  • ownersPublicKeys: Public keys of the multisig owners.

  • ownersAddresses: Addresses of the multisig owners.

  • threshold: Multisig threshold.

Integration Example:

import { useAsignaExtension, validateMessage } from '@asigna/btc-connect';

const { openSignMessage } = useAsignaExtension();
const { asignaSafeInfo } = useAsignaSafeInfo();

const info = await connectToExtension();
const signature = await openSignMessage('Welcome to Pontis');

bitcoinLoginRequestMultisig({
  finalSignature: signature,
  multiSigType: info.multisigType,
  multisigAddress: info.address,
  ownersPublicKeys: info.users.map(user => user.publicKey || ''),
  ownersAddresses: info.users.map(user => user.address),
  threshold: info.threshold,
});

Get Transactions

Use the following function to load created bridge transactions:

getTransactions('active' | 'completed');

Configuration

Bridge settings for supported chains:

  • config.evm: EVM contracts.

  • config.btc: Multisig address and fee contract to retrieve service fees.

  • config.stx: Stacks contracts for bridging and loading fees.

Utilities

Load Service Fees After Authorization

Hook: useEvmFees

Gets fees for MERL or SEP chains.

  • loadFees(targetChain): Returns the minimum limit for BTC asset transfers and service fees for Runes and BTC.

  • loadMinFeesForRunes(runeId): Returns the minimum limit for a specified Rune.

Example:

const { loadFees, loadMinFeesForRunes } = useEvmFees(ChainType.MERL);

const fees = await loadFees(ChainType.BTC);
const minRunes = await loadMinFeesForRunes('runeId');

Hook: useFees Get fees for BTC and STX chains.

  • getFeesForBridge: Returns the minimum limit for BTC asset transfers and service fees for Runes and BTC.

    • sourceChain: 'BTC' | 'STX'

    • targetChain: ChainType

  • getMinRunes(runeId): Returns the minimum limit for a specified Rune.

    • sourceChain: 'BTC' | 'STX'

    • runeContractName: The Rune contract name.

    • runeContractAddress: The Rune contract address.

Example:

const runeContractAddress = 'ST3DGSTWQZ80CXTFBKE2RMC02MGXCXEPQCXY528VS';
const runeContractName = 'pontis-bridge-i-need-test-runes::bridge-token';

const { getFeesForBridge, getMinRunes } = useFees('testnet');

const fees = await getFeesForBridge(ChainType.BTC, ChainType.STX);
const minRune = await getMinRunes(ChainType.BTC, runeContractAddress, runeContractName);

Pending Transactions

Created Transactions Without Signed Messages

For Bitcoin, transactions without signed messages are stored in localStorage under the key: pending_transactions.


Hook: usePendingTransactions

  • Returns stored transactions.

  • Provides functions to handle the state of stored transaction data.

By default, stored data is managed within the library.


Signing Pending Transactions: signMessageForTx

Parameters:

  • txId: Transaction ID.

  • async doSignMessage(message: string): The message signing handler.

  • onFinish(claim: Claim): A callback triggered when the transaction is created on the backend.

Example:

const { txs, signMessageForTx } = usePendingTransactions();

{txs.length > 0 && (
  <div
    onClick={() => {
      signMessageForTx(
        txs[0].txId,
        async (message: string) => {
          return await signMessage(message) as string;
        },
        () => {
          navigate('history');
        }
      );
    }}
  >
    Pending
  </div>
)}

Last updated