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-sdkSupported 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)addresssignature: 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
useBitcoinBlockchainActions1. 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:
The bridge transaction is created.
The message with the
txIdand destination parameters is signed by the sender's wallet.
Unsigned transactions are stored in
localStorageunder the key:pending_transactions.
Hook: usePendingTransactions
usePendingTransactionsThis 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
signMessageForTxParameters:
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
useStxBlockchainActionsSupported Properties
whitelistedRunes: A list of Supported Runes.unlockBtcUnsignedCall
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 generatedStacksTransaction. ReturnstxId.
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
useEvmBlockchainActionsIf 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) orMERL(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
pontisAxiosInstanceThis is an Axios instance used to interact with the Pontis API.
Authorization
Functions:
evmLoginRequeststacksLoginRequestbitcoinLoginRequest
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