Skip to content

Commit f1a1d38

Browse files
nakul1010slavastartsevgregdhill
authored
feat: onramp signet (#520)
* fix: add token + esplora and ordinals url * fix: logo url * fix: logo url * fix: change testnet to signnet * fix: change testnet to signnet * chore: bump version * fix: add back testnet urls * fix: add signet url for mempool * fix: build * fix: update comment * fix: estimate the fee test case * fix: test cases * fix: remove double imported types * chore: bump bitcoin-address-validation (#568) Signed-off-by: Gregory Hill <gregorydhill@outlook.com> * chore: fix imports * chore: revert `package.json` formatting --------- Signed-off-by: Gregory Hill <gregorydhill@outlook.com> Co-authored-by: Slava <slava@interlay.io> Co-authored-by: Greg Hill <gregorydhill@outlook.com>
1 parent 80ff847 commit f1a1d38

File tree

5 files changed

+54
-17
lines changed

5 files changed

+54
-17
lines changed

sdk/src/esplora.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,11 @@ export const TESTNET_ESPLORA_BASE_PATH = 'https://btc-testnet.gobob.xyz';
1313
* @default "http://localhost:3003"
1414
*/
1515
export const REGTEST_ESPLORA_BASE_PATH = 'http://localhost:3003';
16+
/**
17+
* Base path for the signet Esplora API.
18+
* @default "https://btc-signet.gobob.xyz"
19+
*/
20+
export const SIGNET_ESPLORA_BASE_PATH = 'https://btc-signet.gobob.xyz';
1621

1722
/**
1823
* @ignore
@@ -170,6 +175,9 @@ export class EsploraClient {
170175
case 'mainnet':
171176
this.basePath = MAINNET_ESPLORA_BASE_PATH;
172177
break;
178+
case 'signet':
179+
this.basePath = SIGNET_ESPLORA_BASE_PATH;
180+
break;
173181
case 'testnet':
174182
this.basePath = TESTNET_ESPLORA_BASE_PATH;
175183
break;

sdk/src/gateway/client.ts

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,9 @@ import {
2727
OfframpOrderStatus,
2828
EnrichedToken,
2929
} from './types';
30+
import { createBitcoinPsbt, getAddressInfo } from '../wallet';
3031
import { SYMBOL_LOOKUP, ADDRESS_LOOKUP, getTokenDecimals } from './tokens';
31-
import { createBitcoinPsbt } from '../wallet';
32-
import { AddressType, getAddressInfo, Network } from 'bitcoin-address-validation';
32+
import { AddressType, Network } from 'bitcoin-address-validation';
3333
import { EsploraClient } from '../esplora';
3434
import {
3535
claimDelayAbi,
@@ -78,6 +78,7 @@ export class GatewayApiClient {
7878
private chain: Chain.BOB | Chain.BOB_SEPOLIA;
7979
private baseUrl: string;
8080
private strategy: StrategyClient;
81+
private isSignet: boolean = false;
8182

8283
/**
8384
* @constructor
@@ -100,6 +101,7 @@ export class GatewayApiClient {
100101
this.chain = Chain.BOB_SEPOLIA; // Same chain as testnet
101102
this.baseUrl = SIGNET_GATEWAY_BASE_URL;
102103
this.strategy = new StrategyClient(bobSepolia, options?.rpcUrl);
104+
this.isSignet = true;
103105
break;
104106
default:
105107
throw new Error('Invalid chain');
@@ -294,7 +296,7 @@ export class GatewayApiClient {
294296
bitcoinNetwork = bitcoin.networks.testnet;
295297
}
296298

297-
if (getAddressInfo(params.bitcoinUserAddress).type === AddressType.p2tr) {
299+
if (getAddressInfo(params.bitcoinUserAddress, this.isSignet).type === AddressType.p2tr) {
298300
throw new Error('Only following bitcoin address types are supported P2PKH, P2WPKH, P2SH or P2WSH.');
299301
}
300302
const receiverAddress = toHexScriptPubKey(params.bitcoinUserAddress, bitcoinNetwork);
@@ -576,7 +578,8 @@ export class GatewayApiClient {
576578
params.fromUserPublicKey,
577579
data.opReturnHash,
578580
params.feeRate,
579-
gatewayQuote.txProofDifficultyFactor
581+
gatewayQuote.txProofDifficultyFactor,
582+
this.isSignet
580583
);
581584
}
582585

sdk/src/mempool.ts

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,18 @@
11
/**
22
* Base path for the mainnet Memopool API.
3-
* @default "https://btc-mainnet.gobob.xyz"
3+
* @default "https://mempool.space/api/v1"
44
*/
55
export const MAINNET_MEMPOOL_BASE_PATH = 'https://mempool.space/api/v1';
66
/**
77
* Base path for the testnet Memopool API.
8-
* @default "https://btc-testnet.gobob.xyz"
8+
* @default "https://mempool.space/testnet4/api/v1"
99
*/
1010
export const TESTNET_MEMPOOL_BASE_PATH = 'https://mempool.space/testnet4/api/v1';
11+
/**
12+
* Base path for the signet Memopool API.
13+
* @default "https://mempool.space/signet/api/v1"
14+
*/
15+
export const SIGNET_MEMPOOL_BASE_PATH = 'https://mempool.space/signet/api/v1';
1116
/**
1217
* Base path for the regtest Memopool API.
1318
* @default "http://localhost:3003"
@@ -49,6 +54,9 @@ export class MempoolClient {
4954
case 'mainnet':
5055
this.basePath = MAINNET_MEMPOOL_BASE_PATH;
5156
break;
57+
case 'signet':
58+
this.basePath = SIGNET_MEMPOOL_BASE_PATH;
59+
break;
5260
case 'testnet':
5361
this.basePath = TESTNET_MEMPOOL_BASE_PATH;
5462
break;

sdk/src/ordinal-api/index.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,12 @@ export const MAINNET_ORD_BASE_PATH = 'https://ordinals-mainnet.gobob.xyz';
1616
*/
1717
export const TESTNET_ORD_BASE_PATH = 'https://ordinals-testnet.gobob.xyz';
1818

19+
/**
20+
* Base path for Ordinals signet Explorer.
21+
* @default "https://ordinals-signet.gobob.xyz"
22+
*/
23+
export const SIGNET_ORD_BASE_PATH = 'https://ordinals-signet.gobob.xyz';
24+
1925
// https://github.com/ordinals/ord/blob/e39031a46531696e5dd0c853146f8bfab5b7582c/src/inscription_id.rs#L4-L7
2026
export type InscriptionId = {
2127
txid: string;
@@ -368,6 +374,9 @@ export class OrdinalsClient {
368374
case 'mainnet':
369375
this.basePath = MAINNET_ORD_BASE_PATH;
370376
break;
377+
case 'signet':
378+
this.basePath = SIGNET_ORD_BASE_PATH;
379+
break;
371380
case 'testnet':
372381
this.basePath = TESTNET_ORD_BASE_PATH;
373382
break;

sdk/src/wallet/utxo.ts

Lines changed: 20 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import * as bitcoin from 'bitcoinjs-lib';
22
import { Transaction, Script, selectUTXO, TEST_NETWORK, NETWORK, p2wpkh, p2sh, p2tr } from '@scure/btc-signer';
33
import { hex, base64 } from '@scure/base';
4-
import { AddressType, getAddressInfo, Network } from 'bitcoin-address-validation';
4+
import { AddressType, getAddressInfo as getAddressInfoRaw, Network, AddressInfo } from 'bitcoin-address-validation';
55
import { EsploraClient, UTXO } from '../esplora';
66
import { OrdinalsClient, OutPoint, OutputJson } from '../ordinal-api';
77
import { parseInscriptions } from '../inscription';
@@ -19,6 +19,10 @@ export const getBtcNetwork = (name: BitcoinNetworkName) => {
1919
return bitcoinNetworks[name];
2020
};
2121

22+
export const getAddressInfo = (address: string, isSignet: boolean): AddressInfo => {
23+
return getAddressInfoRaw(address, isSignet ? { castTestnetTo: Network.signet } : undefined);
24+
};
25+
2226
type Output = { address: string; amount: bigint } | { script: Uint8Array; amount: bigint };
2327

2428
const isCardinalOutput = (output: OutputJson) =>
@@ -101,8 +105,8 @@ const getSafeUtxos = async (
101105
return findSafeUtxos(utxos, cardinalOutputsSet, esploraClient, ordinalsClient);
102106
};
103107

104-
const collectPossibleInputs = async (fromAddress: string, publicKey: string) => {
105-
const addressInfo = getAddressInfo(fromAddress);
108+
const collectPossibleInputs = async (fromAddress: string, publicKey: string, isSignet: boolean) => {
109+
const addressInfo = getAddressInfo(fromAddress, isSignet);
106110

107111
const esploraClient = new EsploraClient(addressInfo.network);
108112
const ordinalsClient = new OrdinalsClient(addressInfo.network);
@@ -155,6 +159,7 @@ export interface Input {
155159
* @param opReturnData Optional OP_RETURN data to include in an output.
156160
* @param feeRate Optional fee rate in satoshis per byte.
157161
* @param confirmationTarget The number of blocks to include this tx (for fee estimation).
162+
* @param isSignet True if using Bitcoin Signet.
158163
* @returns {Promise<string>} The Base64 encoded PSBT.
159164
*
160165
* @example
@@ -179,9 +184,10 @@ export async function createBitcoinPsbt(
179184
publicKey?: string,
180185
opReturnData?: string,
181186
feeRate?: number,
182-
confirmationTarget: number = 3
187+
confirmationTarget: number = 3,
188+
isSignet: boolean = false
183189
): Promise<string> {
184-
const addressInfo = getAddressInfo(fromAddress);
190+
const addressInfo = getAddressInfo(fromAddress, isSignet);
185191

186192
// TODO: possibly, allow other strategies to be passed to this function
187193
const utxoSelectionStrategy: 'all' | 'default' = 'default';
@@ -206,7 +212,7 @@ export async function createBitcoinPsbt(
206212
let possibleInputs: Input[] = [];
207213
const esploraClient = new EsploraClient(addressInfo.network);
208214
[possibleInputs, feeRate] = await Promise.all([
209-
collectPossibleInputs(fromAddress, publicKey),
215+
collectPossibleInputs(fromAddress, publicKey, isSignet),
210216
feeRate === undefined ? esploraClient.getFeeEstimate(confirmationTarget) : feeRate,
211217
]);
212218

@@ -321,6 +327,7 @@ export function getInputFromUtxoAndTx(
321327
* @param opReturnData Optional OP_RETURN data to include in an output.
322328
* @param feeRate Optional fee rate in satoshis per byte.
323329
* @param confirmationTarget The number of blocks to include this tx (for fee estimation).
330+
* @param isSignet True if using Bitcoin Signet
324331
* @returns {Promise<bigint>} The fee amount for estimated transaction inclusion in satoshis.
325332
*
326333
* @example
@@ -355,9 +362,10 @@ export async function estimateTxFee(
355362
publicKey?: string,
356363
opReturnData?: string,
357364
feeRate?: number,
358-
confirmationTarget: number = 3
365+
confirmationTarget: number = 3,
366+
isSignet: boolean = false
359367
): Promise<bigint> {
360-
const addressInfo = getAddressInfo(fromAddress);
368+
const addressInfo = getAddressInfo(fromAddress, isSignet);
361369

362370
if (addressInfo.network === 'regtest') {
363371
throw new Error('Bitcoin regtest not supported');
@@ -382,7 +390,7 @@ export async function estimateTxFee(
382390
let possibleInputs: Input[] = [];
383391
const esploraClient = new EsploraClient(addressInfo.network);
384392
[possibleInputs, feeRate] = await Promise.all([
385-
collectPossibleInputs(fromAddress, publicKey),
393+
collectPossibleInputs(fromAddress, publicKey, isSignet),
386394
feeRate === undefined ? esploraClient.getFeeEstimate(confirmationTarget) : feeRate,
387395
]);
388396

@@ -445,6 +453,7 @@ export async function estimateTxFee(
445453
* @typedef { {confirmed: BigInt, unconfirmed: BigInt, total: bigint} } Balance
446454
*
447455
* @param {string} [address] The Bitcoin address. If no address specified returning object will contain zeros.
456+
* @param isSignet True if using Bitcoin Signet.
448457
* @returns {Promise<Balance>} The balance object of provided address in satoshis.
449458
*
450459
* @example
@@ -457,12 +466,12 @@ export async function estimateTxFee(
457466
*
458467
* @dev UTXOs that contain inscriptions or runes will not be used to calculate balance.
459468
*/
460-
export async function getBalance(address?: string) {
469+
export async function getBalance(address?: string, isSignet: boolean = false) {
461470
if (!address) {
462471
return { confirmed: BigInt(0), unconfirmed: BigInt(0), total: BigInt(0) };
463472
}
464473

465-
const addressInfo = getAddressInfo(address);
474+
const addressInfo = getAddressInfo(address, isSignet);
466475

467476
const esploraClient = new EsploraClient(addressInfo.network);
468477
const ordinalsClient = new OrdinalsClient(addressInfo.network);

0 commit comments

Comments
 (0)