@sodax/sdk 1.3.1-beta-rc1 → 1.3.1-beta-rc2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +921 -16
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +341 -7
- package/dist/index.d.ts +341 -7
- package/dist/index.mjs +909 -17
- package/dist/index.mjs.map +1 -1
- package/package.json +9 -5
package/dist/index.cjs
CHANGED
|
@@ -17,6 +17,8 @@ var coreProtoTs = require('@injectivelabs/core-proto-ts');
|
|
|
17
17
|
var rlp = require('rlp');
|
|
18
18
|
var anchor = require('@coral-xyz/anchor');
|
|
19
19
|
var BN = require('bn.js');
|
|
20
|
+
var bitcoin = require('bitcoinjs-lib');
|
|
21
|
+
var ecc = require('@bitcoinerlab/secp256k1');
|
|
20
22
|
|
|
21
23
|
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
22
24
|
|
|
@@ -44,6 +46,8 @@ var BigNumber4__default = /*#__PURE__*/_interopDefault(BigNumber4);
|
|
|
44
46
|
var rlp__namespace = /*#__PURE__*/_interopNamespace(rlp);
|
|
45
47
|
var anchor__namespace = /*#__PURE__*/_interopNamespace(anchor);
|
|
46
48
|
var BN__default = /*#__PURE__*/_interopDefault(BN);
|
|
49
|
+
var bitcoin__namespace = /*#__PURE__*/_interopNamespace(bitcoin);
|
|
50
|
+
var ecc__namespace = /*#__PURE__*/_interopNamespace(ecc);
|
|
47
51
|
|
|
48
52
|
// src/shared/abis/asset-manager.abi.ts
|
|
49
53
|
var assetManagerAbi = [
|
|
@@ -6855,7 +6859,7 @@ var stakingRouterAbi = [
|
|
|
6855
6859
|
];
|
|
6856
6860
|
|
|
6857
6861
|
// ../types/dist/constants/index.js
|
|
6858
|
-
var CONFIG_VERSION =
|
|
6862
|
+
var CONFIG_VERSION = 28;
|
|
6859
6863
|
var AVALANCHE_MAINNET_CHAIN_ID = "0xa86a.avax";
|
|
6860
6864
|
var ARBITRUM_MAINNET_CHAIN_ID = "0xa4b1.arbitrum";
|
|
6861
6865
|
var BASE_MAINNET_CHAIN_ID = "0x2105.base";
|
|
@@ -6872,6 +6876,7 @@ var HYPEREVM_MAINNET_CHAIN_ID = "hyper";
|
|
|
6872
6876
|
var LIGHTLINK_MAINNET_CHAIN_ID = "lightlink";
|
|
6873
6877
|
var NEAR_MAINNET_CHAIN_ID = "near";
|
|
6874
6878
|
var ETHEREUM_MAINNET_CHAIN_ID = "ethereum";
|
|
6879
|
+
var BITCOIN_MAINNET_CHAIN_ID = "bitcoin";
|
|
6875
6880
|
var REDBELLY_MAINNET_CHAIN_ID = "redbelly";
|
|
6876
6881
|
var KAIA_MAINNET_CHAIN_ID = "0x2019.kaia";
|
|
6877
6882
|
var HUB_CHAIN_IDS = [SONIC_MAINNET_CHAIN_ID];
|
|
@@ -6892,6 +6897,7 @@ var CHAIN_IDS = [
|
|
|
6892
6897
|
LIGHTLINK_MAINNET_CHAIN_ID,
|
|
6893
6898
|
NEAR_MAINNET_CHAIN_ID,
|
|
6894
6899
|
ETHEREUM_MAINNET_CHAIN_ID,
|
|
6900
|
+
BITCOIN_MAINNET_CHAIN_ID,
|
|
6895
6901
|
REDBELLY_MAINNET_CHAIN_ID,
|
|
6896
6902
|
KAIA_MAINNET_CHAIN_ID
|
|
6897
6903
|
];
|
|
@@ -7006,6 +7012,12 @@ var baseChainInfo = {
|
|
|
7006
7012
|
type: "EVM",
|
|
7007
7013
|
chainId: 1
|
|
7008
7014
|
},
|
|
7015
|
+
[BITCOIN_MAINNET_CHAIN_ID]: {
|
|
7016
|
+
name: "Bitcoin",
|
|
7017
|
+
id: BITCOIN_MAINNET_CHAIN_ID,
|
|
7018
|
+
type: "BITCOIN",
|
|
7019
|
+
chainId: "bitcoin"
|
|
7020
|
+
},
|
|
7009
7021
|
[REDBELLY_MAINNET_CHAIN_ID]: {
|
|
7010
7022
|
name: "Redbelly",
|
|
7011
7023
|
id: REDBELLY_MAINNET_CHAIN_ID,
|
|
@@ -7036,6 +7048,7 @@ var ChainIdToIntentRelayChainId = {
|
|
|
7036
7048
|
[LIGHTLINK_MAINNET_CHAIN_ID]: 27756n,
|
|
7037
7049
|
[NEAR_MAINNET_CHAIN_ID]: 15n,
|
|
7038
7050
|
[ETHEREUM_MAINNET_CHAIN_ID]: 2n,
|
|
7051
|
+
[BITCOIN_MAINNET_CHAIN_ID]: 627463n,
|
|
7039
7052
|
[REDBELLY_MAINNET_CHAIN_ID]: 726564n,
|
|
7040
7053
|
[KAIA_MAINNET_CHAIN_ID]: 27489n
|
|
7041
7054
|
};
|
|
@@ -7948,6 +7961,42 @@ var spokeChainConfig = {
|
|
|
7948
7961
|
rpcUrl: "https://injective-rpc.publicnode.com:443",
|
|
7949
7962
|
walletAddress: ""
|
|
7950
7963
|
},
|
|
7964
|
+
[BITCOIN_MAINNET_CHAIN_ID]: {
|
|
7965
|
+
addresses: {
|
|
7966
|
+
assetManager: "bc1p4z9555xw0266vhq2x5un4zdmm9dt9zyet32fs7wa7u5ckdxusd9qsw4xfx"
|
|
7967
|
+
},
|
|
7968
|
+
chain: baseChainInfo[BITCOIN_MAINNET_CHAIN_ID],
|
|
7969
|
+
bnUSD: "no",
|
|
7970
|
+
nativeToken: "BTC",
|
|
7971
|
+
supportedTokens: {
|
|
7972
|
+
BTC: {
|
|
7973
|
+
symbol: "BTC",
|
|
7974
|
+
name: "Bitcoin",
|
|
7975
|
+
decimals: 8,
|
|
7976
|
+
address: "0:0",
|
|
7977
|
+
xChainId: BITCOIN_MAINNET_CHAIN_ID
|
|
7978
|
+
},
|
|
7979
|
+
bnUSD: {
|
|
7980
|
+
symbol: "bnUSD",
|
|
7981
|
+
name: "bnUSD",
|
|
7982
|
+
decimals: 18,
|
|
7983
|
+
address: "0:0",
|
|
7984
|
+
xChainId: BITCOIN_MAINNET_CHAIN_ID
|
|
7985
|
+
},
|
|
7986
|
+
BUSD: {
|
|
7987
|
+
symbol: "BUSD",
|
|
7988
|
+
name: "BUSDSTABLECOIN",
|
|
7989
|
+
decimals: 6,
|
|
7990
|
+
address: "897442:43",
|
|
7991
|
+
xChainId: BITCOIN_MAINNET_CHAIN_ID
|
|
7992
|
+
}
|
|
7993
|
+
},
|
|
7994
|
+
radfiApiUrl: "https://staging.api.radfi.co/api",
|
|
7995
|
+
radfiApiKey: "",
|
|
7996
|
+
radfiUmsUrl: "https://staging.ums.radfi.co/api",
|
|
7997
|
+
network: "MAINNET",
|
|
7998
|
+
rpcUrl: "https://mempool.space/api"
|
|
7999
|
+
},
|
|
7951
8000
|
[STELLAR_MAINNET_CHAIN_ID]: {
|
|
7952
8001
|
addresses: {
|
|
7953
8002
|
connection: "CDFQDDPUPAM3XPGORHDOEFRNLMKOH3N3X6XTXNLSXJQXIU3RVCM3OPEP",
|
|
@@ -9444,6 +9493,22 @@ var hubAssets = {
|
|
|
9444
9493
|
name: "RedBelly POL",
|
|
9445
9494
|
vault: SodaTokens.sodaPOL.address
|
|
9446
9495
|
}
|
|
9496
|
+
},
|
|
9497
|
+
[BITCOIN_MAINNET_CHAIN_ID]: {
|
|
9498
|
+
[spokeChainConfig[BITCOIN_MAINNET_CHAIN_ID].supportedTokens.BTC.address]: {
|
|
9499
|
+
asset: "0xeb0393893b5bf98a50073d6740738b08e575058b",
|
|
9500
|
+
decimal: 8,
|
|
9501
|
+
symbol: "BTC",
|
|
9502
|
+
name: "Bitcoin",
|
|
9503
|
+
vault: "0x7A1A5555842Ad2D0eD274d09b5c4406a95799D5d"
|
|
9504
|
+
},
|
|
9505
|
+
[spokeChainConfig[BITCOIN_MAINNET_CHAIN_ID].supportedTokens.BUSD.address]: {
|
|
9506
|
+
asset: "0xdb41c7d09406026d4582bc2fc6d6319c323fe1bb",
|
|
9507
|
+
decimal: 6,
|
|
9508
|
+
symbol: "BUSD",
|
|
9509
|
+
name: "BUSD.BUSD.BUSD",
|
|
9510
|
+
vault: "0xE801CA34E19aBCbFeA12025378D19c4FBE250131"
|
|
9511
|
+
}
|
|
9447
9512
|
}
|
|
9448
9513
|
};
|
|
9449
9514
|
var solverConfig = {
|
|
@@ -9584,6 +9649,10 @@ var swapSupportedTokens = {
|
|
|
9584
9649
|
spokeChainConfig[NEAR_MAINNET_CHAIN_ID].supportedTokens.USDC,
|
|
9585
9650
|
spokeChainConfig[NEAR_MAINNET_CHAIN_ID].supportedTokens.USDT
|
|
9586
9651
|
],
|
|
9652
|
+
[BITCOIN_MAINNET_CHAIN_ID]: [
|
|
9653
|
+
spokeChainConfig[BITCOIN_MAINNET_CHAIN_ID].supportedTokens.BTC
|
|
9654
|
+
// spokeChainConfig[BITCOIN_MAINNET_CHAIN_ID].supportedTokens.BUSD, // TODO: re-enable when trading wallet balance is ready
|
|
9655
|
+
],
|
|
9587
9656
|
[ETHEREUM_MAINNET_CHAIN_ID]: [
|
|
9588
9657
|
spokeChainConfig[ETHEREUM_MAINNET_CHAIN_ID].supportedTokens.ETH,
|
|
9589
9658
|
spokeChainConfig[ETHEREUM_MAINNET_CHAIN_ID].supportedTokens.bnUSD,
|
|
@@ -9785,6 +9854,9 @@ var moneyMarketSupportedTokens = {
|
|
|
9785
9854
|
spokeChainConfig[KAIA_MAINNET_CHAIN_ID].supportedTokens.bnUSD,
|
|
9786
9855
|
spokeChainConfig[KAIA_MAINNET_CHAIN_ID].supportedTokens.USDT,
|
|
9787
9856
|
spokeChainConfig[KAIA_MAINNET_CHAIN_ID].supportedTokens.SODA
|
|
9857
|
+
],
|
|
9858
|
+
[BITCOIN_MAINNET_CHAIN_ID]: [
|
|
9859
|
+
spokeChainConfig[BITCOIN_MAINNET_CHAIN_ID].supportedTokens.BTC
|
|
9788
9860
|
]
|
|
9789
9861
|
};
|
|
9790
9862
|
var moneyMarketReserveAssets = [
|
|
@@ -9809,7 +9881,7 @@ var defaultSharedConfig = {
|
|
|
9809
9881
|
};
|
|
9810
9882
|
|
|
9811
9883
|
// ../types/dist/common/index.js
|
|
9812
|
-
var ChainTypeArr = ["ICON", "EVM", "INJECTIVE", "SUI", "STELLAR", "SOLANA", "NEAR"];
|
|
9884
|
+
var ChainTypeArr = ["ICON", "EVM", "INJECTIVE", "SUI", "STELLAR", "SOLANA", "NEAR", "BITCOIN"];
|
|
9813
9885
|
|
|
9814
9886
|
// ../types/dist/injective/index.js
|
|
9815
9887
|
var InjectiveExecuteResponse = class _InjectiveExecuteResponse {
|
|
@@ -9828,6 +9900,17 @@ var InjectiveExecuteResponse = class _InjectiveExecuteResponse {
|
|
|
9828
9900
|
return response;
|
|
9829
9901
|
}
|
|
9830
9902
|
};
|
|
9903
|
+
|
|
9904
|
+
// ../types/dist/btc/index.js
|
|
9905
|
+
function detectBitcoinAddressType(address) {
|
|
9906
|
+
if (address.startsWith("bc1p") || address.startsWith("tb1p"))
|
|
9907
|
+
return "P2TR";
|
|
9908
|
+
if (address.startsWith("bc1") || address.startsWith("tb1"))
|
|
9909
|
+
return "P2WPKH";
|
|
9910
|
+
if (address.startsWith("1") || address.startsWith("m") || address.startsWith("n"))
|
|
9911
|
+
return "P2PKH";
|
|
9912
|
+
throw new Error(`Unknown Bitcoin address type: ${address}`);
|
|
9913
|
+
}
|
|
9831
9914
|
var DEFAULT_MAX_RETRY = 3;
|
|
9832
9915
|
var DEFAULT_RELAY_TX_TIMEOUT = 12e4;
|
|
9833
9916
|
var DEFAULT_RETRY_DELAY_MS = 2e3;
|
|
@@ -21206,6 +21289,714 @@ var SolanaSpokeService = class _SolanaSpokeService {
|
|
|
21206
21289
|
}
|
|
21207
21290
|
}
|
|
21208
21291
|
};
|
|
21292
|
+
|
|
21293
|
+
// src/shared/entities/btc/RadfiProvider.ts
|
|
21294
|
+
var RadfiProvider = class {
|
|
21295
|
+
constructor(config) {
|
|
21296
|
+
this.config = config;
|
|
21297
|
+
}
|
|
21298
|
+
async authenticate(params) {
|
|
21299
|
+
const res = await this.request("/auth/authenticate", {
|
|
21300
|
+
method: "POST",
|
|
21301
|
+
body: JSON.stringify(params)
|
|
21302
|
+
});
|
|
21303
|
+
if (!res.ok) {
|
|
21304
|
+
const err = await res.json();
|
|
21305
|
+
throw new Error(err.message || "Radfi authentication failed");
|
|
21306
|
+
}
|
|
21307
|
+
return res.json().then((r) => ({
|
|
21308
|
+
accessToken: r.data?.accessToken ?? "",
|
|
21309
|
+
refreshToken: r.data?.refreshToken ?? "",
|
|
21310
|
+
tradingAddress: r.data?.tradingAddress ?? r.data?.wallet?.tradingAddress ?? ""
|
|
21311
|
+
}));
|
|
21312
|
+
}
|
|
21313
|
+
async refreshAccessToken(refreshToken) {
|
|
21314
|
+
const res = await this.request("/auth/refresh-token", {
|
|
21315
|
+
method: "POST",
|
|
21316
|
+
body: JSON.stringify({ refreshToken })
|
|
21317
|
+
});
|
|
21318
|
+
if (!res.ok) {
|
|
21319
|
+
const err = await res.json();
|
|
21320
|
+
throw new Error(err.message || "Token refresh failed");
|
|
21321
|
+
}
|
|
21322
|
+
return res.json().then((r) => ({
|
|
21323
|
+
accessToken: r.data?.accessToken ?? "",
|
|
21324
|
+
refreshToken: r.data?.refreshToken ?? refreshToken
|
|
21325
|
+
}));
|
|
21326
|
+
}
|
|
21327
|
+
async createTradingWallet(params, accessToken) {
|
|
21328
|
+
const res = await this.request("/wallets", {
|
|
21329
|
+
method: "POST",
|
|
21330
|
+
headers: {
|
|
21331
|
+
Authorization: `Bearer ${accessToken || this.config.apiKey}`
|
|
21332
|
+
},
|
|
21333
|
+
body: JSON.stringify(params)
|
|
21334
|
+
});
|
|
21335
|
+
if (!res.ok) {
|
|
21336
|
+
const err = await res.json();
|
|
21337
|
+
throw new Error(err.message || "Failed to create trading wallet");
|
|
21338
|
+
}
|
|
21339
|
+
return res.json().then((r) => r.data);
|
|
21340
|
+
}
|
|
21341
|
+
async getTradingWallet(userAddress, accessToken) {
|
|
21342
|
+
const res = await this.request(`/wallets/details/${userAddress}`, {
|
|
21343
|
+
method: "GET",
|
|
21344
|
+
headers: accessToken ? { Authorization: `Bearer ${accessToken}` } : {}
|
|
21345
|
+
});
|
|
21346
|
+
if (!res.ok) {
|
|
21347
|
+
throw new Error("Trading wallet not found");
|
|
21348
|
+
}
|
|
21349
|
+
const data = await res.json().then((r) => r.data);
|
|
21350
|
+
if (!data) throw new Error("Trading wallet not found");
|
|
21351
|
+
return data;
|
|
21352
|
+
}
|
|
21353
|
+
async getBalance(address) {
|
|
21354
|
+
if (!this.config.umsUrl) {
|
|
21355
|
+
throw new Error("RadfiConfig.umsUrl is required for getBalance");
|
|
21356
|
+
}
|
|
21357
|
+
const umsUrl = this.config.umsUrl;
|
|
21358
|
+
const res = await fetch(`${umsUrl}/wallets/balance?address=${address}`, {
|
|
21359
|
+
method: "GET",
|
|
21360
|
+
headers: { "Content-Type": "application/json" }
|
|
21361
|
+
});
|
|
21362
|
+
if (!res.ok) {
|
|
21363
|
+
throw new Error("Failed to fetch wallet balance");
|
|
21364
|
+
}
|
|
21365
|
+
const { data } = await res.json();
|
|
21366
|
+
return {
|
|
21367
|
+
btcSatoshi: BigInt(data.btcSatoshi ?? "0"),
|
|
21368
|
+
pendingSatoshi: BigInt(data.pendingSatoshi ?? "0"),
|
|
21369
|
+
externalPendingSatoshi: BigInt(data.externalPendingSatoshi ?? "0"),
|
|
21370
|
+
totalUtxos: Number(data.totalUtxos ?? 0)
|
|
21371
|
+
};
|
|
21372
|
+
}
|
|
21373
|
+
async checkIfTradingWalletExists(userAddress) {
|
|
21374
|
+
try {
|
|
21375
|
+
await this.getTradingWallet(userAddress);
|
|
21376
|
+
return true;
|
|
21377
|
+
} catch (error) {
|
|
21378
|
+
return false;
|
|
21379
|
+
}
|
|
21380
|
+
}
|
|
21381
|
+
async createWithdrawTransaction(params, accessToken) {
|
|
21382
|
+
const res = await this.request("/sodax/transaction", {
|
|
21383
|
+
method: "POST",
|
|
21384
|
+
headers: {
|
|
21385
|
+
Authorization: `Bearer ${accessToken ?? this.config.apiKey}`
|
|
21386
|
+
},
|
|
21387
|
+
body: JSON.stringify({
|
|
21388
|
+
type: "sodax-withdraw",
|
|
21389
|
+
params: {
|
|
21390
|
+
amount: params.amount.toString(),
|
|
21391
|
+
tokenId: params.token,
|
|
21392
|
+
sodaxData: params.data
|
|
21393
|
+
}
|
|
21394
|
+
})
|
|
21395
|
+
});
|
|
21396
|
+
if (!res.ok) {
|
|
21397
|
+
const err = await res.json();
|
|
21398
|
+
throw new Error(err.message || "Radfi transaction request failed");
|
|
21399
|
+
}
|
|
21400
|
+
return res.json().then((r) => r.data);
|
|
21401
|
+
}
|
|
21402
|
+
async requestRadfiSignature(params, accessToken) {
|
|
21403
|
+
const res = await this.request("/sodax/transaction/sign", {
|
|
21404
|
+
method: "POST",
|
|
21405
|
+
headers: {
|
|
21406
|
+
Authorization: `Bearer ${accessToken ?? this.config.apiKey}`
|
|
21407
|
+
},
|
|
21408
|
+
body: JSON.stringify({
|
|
21409
|
+
type: "sodax-withdraw",
|
|
21410
|
+
params
|
|
21411
|
+
})
|
|
21412
|
+
});
|
|
21413
|
+
if (!res.ok) {
|
|
21414
|
+
const err = await res.json();
|
|
21415
|
+
throw new Error(err.message || "Radfi signature request failed");
|
|
21416
|
+
}
|
|
21417
|
+
return res.json().then((r) => r.data.txId);
|
|
21418
|
+
}
|
|
21419
|
+
/**
|
|
21420
|
+
* Fetch expired (or near-expiry) UTXOs for a trading wallet address from UMS API.
|
|
21421
|
+
*/
|
|
21422
|
+
async getExpiredUtxos(tradingAddress, params) {
|
|
21423
|
+
if (!this.config.umsUrl) {
|
|
21424
|
+
throw new Error("RadfiConfig.umsUrl is required for getExpiredUtxos");
|
|
21425
|
+
}
|
|
21426
|
+
const page = params?.page ?? 1;
|
|
21427
|
+
const pageSize = params?.pageSize ?? 100;
|
|
21428
|
+
const url = `${this.config.umsUrl}/utxos?address_eq=${tradingAddress}&isSpent_eq=false&isExpired_eq=true&page=${page}&pageSize=${pageSize}`;
|
|
21429
|
+
const res = await fetch(url, {
|
|
21430
|
+
method: "GET",
|
|
21431
|
+
headers: { "Content-Type": "application/json" }
|
|
21432
|
+
});
|
|
21433
|
+
if (!res.ok) {
|
|
21434
|
+
throw new Error("Failed to fetch expired UTXOs");
|
|
21435
|
+
}
|
|
21436
|
+
return res.json();
|
|
21437
|
+
}
|
|
21438
|
+
/**
|
|
21439
|
+
* Build a renew-utxo transaction via the Radfi API.
|
|
21440
|
+
* Returns a PSBT that needs to be signed by the user.
|
|
21441
|
+
*/
|
|
21442
|
+
async buildRenewUtxoTransaction(params, accessToken) {
|
|
21443
|
+
const res = await this.request("/transactions", {
|
|
21444
|
+
method: "POST",
|
|
21445
|
+
headers: {
|
|
21446
|
+
Authorization: `Bearer ${accessToken}`
|
|
21447
|
+
},
|
|
21448
|
+
body: JSON.stringify({
|
|
21449
|
+
type: "renew-utxo",
|
|
21450
|
+
params: {
|
|
21451
|
+
userAddress: params.userAddress,
|
|
21452
|
+
txIdVouts: params.txIdVouts
|
|
21453
|
+
}
|
|
21454
|
+
})
|
|
21455
|
+
});
|
|
21456
|
+
if (!res.ok) {
|
|
21457
|
+
const err = await res.json();
|
|
21458
|
+
throw new Error(err.message || "Failed to build renew-utxo transaction");
|
|
21459
|
+
}
|
|
21460
|
+
return res.json().then((r) => r.data);
|
|
21461
|
+
}
|
|
21462
|
+
/**
|
|
21463
|
+
* Sign and broadcast a renew-utxo transaction via the Radfi API.
|
|
21464
|
+
* The user signs the PSBT first, then Radfi co-signs and broadcasts.
|
|
21465
|
+
*/
|
|
21466
|
+
async signAndBroadcastRenewUtxo(params, accessToken) {
|
|
21467
|
+
const res = await this.request("/transactions/sign", {
|
|
21468
|
+
method: "POST",
|
|
21469
|
+
headers: {
|
|
21470
|
+
Authorization: `Bearer ${accessToken}`
|
|
21471
|
+
},
|
|
21472
|
+
body: JSON.stringify({
|
|
21473
|
+
type: "renew-utxo",
|
|
21474
|
+
params
|
|
21475
|
+
})
|
|
21476
|
+
});
|
|
21477
|
+
if (!res.ok) {
|
|
21478
|
+
const err = await res.json();
|
|
21479
|
+
throw new Error(err.message || "Failed to sign and broadcast renew-utxo transaction");
|
|
21480
|
+
}
|
|
21481
|
+
return res.json().then((r) => r.data.txId);
|
|
21482
|
+
}
|
|
21483
|
+
async request(endpoint, options) {
|
|
21484
|
+
return fetch(`${this.config.url}${endpoint}`, {
|
|
21485
|
+
...options,
|
|
21486
|
+
headers: {
|
|
21487
|
+
"Content-Type": "application/json",
|
|
21488
|
+
...options?.headers || {}
|
|
21489
|
+
}
|
|
21490
|
+
});
|
|
21491
|
+
}
|
|
21492
|
+
};
|
|
21493
|
+
bitcoin__namespace.initEccLib(ecc__namespace);
|
|
21494
|
+
var BITCOIN_DEFAULT_FEE_RATE = 3;
|
|
21495
|
+
var DUST_THRESHOLD = 546;
|
|
21496
|
+
function normalizePsbtToBase64(signedPsbt) {
|
|
21497
|
+
const isHex = /^[0-9a-fA-F]+$/.test(signedPsbt);
|
|
21498
|
+
return isHex ? Buffer.from(signedPsbt, "hex").toString("base64") : signedPsbt;
|
|
21499
|
+
}
|
|
21500
|
+
var BitcoinBaseSpokeProvider = class _BitcoinBaseSpokeProvider {
|
|
21501
|
+
rpcUrl;
|
|
21502
|
+
network;
|
|
21503
|
+
chainConfig;
|
|
21504
|
+
radfi;
|
|
21505
|
+
walletMode;
|
|
21506
|
+
radfiAccessToken = "";
|
|
21507
|
+
constructor(config, radfiConfig, walletMode = "USER", rpcURL) {
|
|
21508
|
+
this.chainConfig = config;
|
|
21509
|
+
this.rpcUrl = rpcURL ?? config.rpcUrl;
|
|
21510
|
+
this.network = config.network === "TESTNET" ? bitcoin__namespace.networks.testnet : bitcoin__namespace.networks.bitcoin;
|
|
21511
|
+
this.radfi = new RadfiProvider(radfiConfig);
|
|
21512
|
+
this.walletMode = walletMode;
|
|
21513
|
+
}
|
|
21514
|
+
setRadfiAccessToken(token) {
|
|
21515
|
+
this.radfiAccessToken = token;
|
|
21516
|
+
}
|
|
21517
|
+
/**
|
|
21518
|
+
* Get current fee estimates
|
|
21519
|
+
*/
|
|
21520
|
+
async getFeeEstimate(targetBlocks = 6) {
|
|
21521
|
+
try {
|
|
21522
|
+
const response = await fetch(`${this.rpcUrl}/fee-estimates`);
|
|
21523
|
+
if (!response.ok) {
|
|
21524
|
+
return BITCOIN_DEFAULT_FEE_RATE;
|
|
21525
|
+
}
|
|
21526
|
+
const feeEstimates = await response.json();
|
|
21527
|
+
return feeEstimates[targetBlocks] ?? BITCOIN_DEFAULT_FEE_RATE;
|
|
21528
|
+
} catch {
|
|
21529
|
+
return BITCOIN_DEFAULT_FEE_RATE;
|
|
21530
|
+
}
|
|
21531
|
+
}
|
|
21532
|
+
static async getBalance(tokenAddress, provider) {
|
|
21533
|
+
const walletAddress = await provider.walletProvider.getWalletAddress();
|
|
21534
|
+
if (!tokenAddress || tokenAddress === "0x" || tokenAddress === "BTC") {
|
|
21535
|
+
const utxos = await provider.fetchUTXOs(walletAddress);
|
|
21536
|
+
const totalBalance = utxos.reduce((sum, utxo) => sum + utxo.value, 0);
|
|
21537
|
+
return BigInt(totalBalance);
|
|
21538
|
+
}
|
|
21539
|
+
throw new Error("Token balance queries not yet implemented for non-BTC assets");
|
|
21540
|
+
}
|
|
21541
|
+
async fetchScriptPubKey(utxo, provider) {
|
|
21542
|
+
const txHex = await provider.fetchRawTransaction(utxo.txid);
|
|
21543
|
+
const tx = bitcoin__namespace.Transaction.fromHex(txHex);
|
|
21544
|
+
const out = tx.outs[utxo.vout];
|
|
21545
|
+
if (!out) {
|
|
21546
|
+
throw new Error(`UTXO not found: ${utxo.txid}:${utxo.vout}`);
|
|
21547
|
+
}
|
|
21548
|
+
return out.script.toString("hex");
|
|
21549
|
+
}
|
|
21550
|
+
/**
|
|
21551
|
+
* Build a priority Bitcoin transaction with proper fee calculation
|
|
21552
|
+
*/
|
|
21553
|
+
static async buildBitcoinTransaction(utxos, outputs, changeAddress, provider, feeRate) {
|
|
21554
|
+
const psbt = new bitcoin__namespace.Psbt({ network: provider.network });
|
|
21555
|
+
const effectiveFeeRate = feeRate ?? await provider.getFeeEstimate();
|
|
21556
|
+
let inputSum = 0;
|
|
21557
|
+
const outputSum = outputs.reduce((sum, o) => sum + o.value, 0);
|
|
21558
|
+
for (const utxo of utxos) {
|
|
21559
|
+
if (!utxo.status.confirmed) continue;
|
|
21560
|
+
const scriptPubKey = await provider.fetchScriptPubKey(utxo, provider);
|
|
21561
|
+
const isTaproot = scriptPubKey.startsWith("51");
|
|
21562
|
+
const isSegwitV0 = scriptPubKey.startsWith("00");
|
|
21563
|
+
if (isTaproot) {
|
|
21564
|
+
if (!provider.walletProvider.getPublicKey) {
|
|
21565
|
+
throw new Error("Missing public key for P2TR input");
|
|
21566
|
+
}
|
|
21567
|
+
const tapInternalKey = await provider.walletProvider.getPublicKey();
|
|
21568
|
+
psbt.addInput({
|
|
21569
|
+
hash: utxo.txid,
|
|
21570
|
+
index: utxo.vout,
|
|
21571
|
+
witnessUtxo: {
|
|
21572
|
+
script: Buffer.from(scriptPubKey, "hex"),
|
|
21573
|
+
value: utxo.value
|
|
21574
|
+
},
|
|
21575
|
+
tapInternalKey: Buffer.from(tapInternalKey, "hex")
|
|
21576
|
+
});
|
|
21577
|
+
} else if (isSegwitV0) {
|
|
21578
|
+
psbt.addInput({
|
|
21579
|
+
hash: utxo.txid,
|
|
21580
|
+
index: utxo.vout,
|
|
21581
|
+
witnessUtxo: {
|
|
21582
|
+
script: Buffer.from(scriptPubKey, "hex"),
|
|
21583
|
+
value: utxo.value
|
|
21584
|
+
}
|
|
21585
|
+
});
|
|
21586
|
+
} else {
|
|
21587
|
+
const txHex = await provider.fetchRawTransaction(utxo.txid);
|
|
21588
|
+
psbt.addInput({
|
|
21589
|
+
hash: utxo.txid,
|
|
21590
|
+
index: utxo.vout,
|
|
21591
|
+
nonWitnessUtxo: Buffer.from(txHex, "hex")
|
|
21592
|
+
});
|
|
21593
|
+
}
|
|
21594
|
+
inputSum += utxo.value;
|
|
21595
|
+
const estimatedSize = provider.estimateTxSize(psbt.inputCount, outputs.length);
|
|
21596
|
+
const estimatedFee = Math.ceil(effectiveFeeRate * estimatedSize);
|
|
21597
|
+
if (inputSum >= outputSum + estimatedFee + DUST_THRESHOLD) {
|
|
21598
|
+
break;
|
|
21599
|
+
}
|
|
21600
|
+
}
|
|
21601
|
+
for (const output of outputs) {
|
|
21602
|
+
psbt.addOutput({
|
|
21603
|
+
address: output.address,
|
|
21604
|
+
value: output.value
|
|
21605
|
+
});
|
|
21606
|
+
}
|
|
21607
|
+
const sizeWithChange = provider.estimateTxSize(psbt.inputCount, outputs.length + 1);
|
|
21608
|
+
const sizeWithoutChange = provider.estimateTxSize(psbt.inputCount, outputs.length);
|
|
21609
|
+
const feeWithChange = Math.ceil(effectiveFeeRate * sizeWithChange);
|
|
21610
|
+
const feeWithoutChange = Math.ceil(effectiveFeeRate * sizeWithoutChange);
|
|
21611
|
+
let change = inputSum - outputSum - feeWithChange;
|
|
21612
|
+
if (change < 0) {
|
|
21613
|
+
const confirmedCount = utxos.filter((u) => u.status.confirmed).length;
|
|
21614
|
+
const unconfirmedCount = utxos.length - confirmedCount;
|
|
21615
|
+
const hint = unconfirmedCount > 0 ? ` (${unconfirmedCount} unconfirmed UTXO(s) skipped \u2014 wait for confirmation)` : "";
|
|
21616
|
+
throw new Error(`Insufficient funds. Need ${outputSum + feeWithChange} satoshis, have ${inputSum}${hint}`);
|
|
21617
|
+
}
|
|
21618
|
+
if (change > DUST_THRESHOLD) {
|
|
21619
|
+
psbt.addOutput({
|
|
21620
|
+
address: changeAddress,
|
|
21621
|
+
value: change
|
|
21622
|
+
});
|
|
21623
|
+
} else {
|
|
21624
|
+
const finalFee = feeWithoutChange;
|
|
21625
|
+
change = inputSum - outputSum - finalFee;
|
|
21626
|
+
if (change < 0) {
|
|
21627
|
+
throw new Error(`Insufficient funds after dust handling. Need ${outputSum + finalFee}`);
|
|
21628
|
+
}
|
|
21629
|
+
}
|
|
21630
|
+
return psbt;
|
|
21631
|
+
}
|
|
21632
|
+
/**
|
|
21633
|
+
* Deposit operation - transfer BTC to the asset manager
|
|
21634
|
+
*/
|
|
21635
|
+
static async deposit(token, amount, data, provider, raw, accessToken = "") {
|
|
21636
|
+
try {
|
|
21637
|
+
const walletAddress = await provider.walletProvider.getWalletAddress();
|
|
21638
|
+
const returnRawTx = (psbtBase64) => ({
|
|
21639
|
+
from: walletAddress,
|
|
21640
|
+
to: provider.chainConfig.addresses.assetManager,
|
|
21641
|
+
value: amount,
|
|
21642
|
+
data: psbtBase64
|
|
21643
|
+
});
|
|
21644
|
+
if (provider.walletMode === "TRADING") {
|
|
21645
|
+
const tokenId = Object.values(provider.chainConfig.supportedTokens).find((t) => t.address === token)?.address;
|
|
21646
|
+
if (!tokenId) {
|
|
21647
|
+
throw new Error(`Unsupported token: ${token}`);
|
|
21648
|
+
}
|
|
21649
|
+
data = data.startsWith("0x") ? data.slice(2) : data;
|
|
21650
|
+
data = data.length === 64 ? data : viem.keccak256(`0x${data}`).slice(2);
|
|
21651
|
+
accessToken = accessToken || provider.radfiAccessToken;
|
|
21652
|
+
const withdrawTx = await provider.radfi.createWithdrawTransaction(
|
|
21653
|
+
{
|
|
21654
|
+
token: tokenId,
|
|
21655
|
+
amount,
|
|
21656
|
+
recipient: provider.chainConfig.addresses.assetManager,
|
|
21657
|
+
userAddress: walletAddress,
|
|
21658
|
+
data
|
|
21659
|
+
},
|
|
21660
|
+
accessToken
|
|
21661
|
+
);
|
|
21662
|
+
if (raw || isBitcoinRawSpokeProvider(provider)) {
|
|
21663
|
+
return returnRawTx(withdrawTx.base64Psbt);
|
|
21664
|
+
}
|
|
21665
|
+
const signedTx = await provider.walletProvider.signTransaction(withdrawTx.base64Psbt, false);
|
|
21666
|
+
const signedBase64Tx = normalizePsbtToBase64(signedTx);
|
|
21667
|
+
return await provider.radfi.requestRadfiSignature(
|
|
21668
|
+
{
|
|
21669
|
+
userAddress: walletAddress,
|
|
21670
|
+
signedBase64Tx
|
|
21671
|
+
},
|
|
21672
|
+
accessToken
|
|
21673
|
+
);
|
|
21674
|
+
}
|
|
21675
|
+
const utxos = await provider.fetchUTXOs(walletAddress);
|
|
21676
|
+
if (!utxos?.length) {
|
|
21677
|
+
throw new Error("No UTXOs available for deposit");
|
|
21678
|
+
}
|
|
21679
|
+
const depositPsbt = await _BitcoinBaseSpokeProvider.buildDepositPsbt(
|
|
21680
|
+
walletAddress,
|
|
21681
|
+
token,
|
|
21682
|
+
amount,
|
|
21683
|
+
data,
|
|
21684
|
+
utxos,
|
|
21685
|
+
provider
|
|
21686
|
+
);
|
|
21687
|
+
if (raw || isBitcoinRawSpokeProvider(provider)) {
|
|
21688
|
+
return returnRawTx(depositPsbt.toBase64());
|
|
21689
|
+
}
|
|
21690
|
+
return await provider.signAndBroadcastTransaction(depositPsbt);
|
|
21691
|
+
} catch (error) {
|
|
21692
|
+
console.error("Error during deposit:", error);
|
|
21693
|
+
throw error;
|
|
21694
|
+
}
|
|
21695
|
+
}
|
|
21696
|
+
/**
|
|
21697
|
+
* Build deposit PSBT with embedded cross-chain data
|
|
21698
|
+
*/
|
|
21699
|
+
static async buildDepositPsbt(walletAddress, token, amount, data, utxos, provider) {
|
|
21700
|
+
const assetManagerAddress = provider.chainConfig.addresses.assetManager;
|
|
21701
|
+
if (token.toLocaleLowerCase() === "btc") {
|
|
21702
|
+
const outputs = [
|
|
21703
|
+
{
|
|
21704
|
+
address: assetManagerAddress,
|
|
21705
|
+
value: Number(amount)
|
|
21706
|
+
}
|
|
21707
|
+
];
|
|
21708
|
+
const psbt = await _BitcoinBaseSpokeProvider.buildBitcoinTransaction(utxos, outputs, walletAddress, provider);
|
|
21709
|
+
const OP_RADFI_SODAX_DATA = 49;
|
|
21710
|
+
const payload = Buffer.concat([Buffer.from([OP_RADFI_SODAX_DATA]), Buffer.from(data.slice(2), "hex")]);
|
|
21711
|
+
const OP_RETURN = bitcoin__namespace.opcodes.OP_RETURN;
|
|
21712
|
+
const OP_12 = bitcoin__namespace.opcodes.OP_12;
|
|
21713
|
+
if (OP_RETURN === void 0 || OP_12 === void 0) {
|
|
21714
|
+
throw new Error("bitcoinjs-lib opcodes OP_RETURN or OP_12 are undefined");
|
|
21715
|
+
}
|
|
21716
|
+
const script2 = bitcoin__namespace.script.compile([OP_RETURN, OP_12, payload]);
|
|
21717
|
+
psbt.addOutput({
|
|
21718
|
+
script: script2,
|
|
21719
|
+
value: 0
|
|
21720
|
+
});
|
|
21721
|
+
return psbt;
|
|
21722
|
+
}
|
|
21723
|
+
throw new Error(`Non-BTC token deposits not yet implemented (token: ${token})`);
|
|
21724
|
+
}
|
|
21725
|
+
/**
|
|
21726
|
+
* Fetch UTXOs for an address
|
|
21727
|
+
*/
|
|
21728
|
+
async fetchUTXOs(address) {
|
|
21729
|
+
const response = await fetch(`${this.rpcUrl}/address/${address}/utxo`);
|
|
21730
|
+
if (!response.ok) {
|
|
21731
|
+
throw new Error(`Failed to fetch UTXOs: ${response.statusText}`);
|
|
21732
|
+
}
|
|
21733
|
+
return await response.json();
|
|
21734
|
+
}
|
|
21735
|
+
/**
|
|
21736
|
+
* Fetch raw transaction hex
|
|
21737
|
+
*/
|
|
21738
|
+
async fetchRawTransaction(txid) {
|
|
21739
|
+
const response = await fetch(`${this.rpcUrl}/tx/${txid}/hex`);
|
|
21740
|
+
if (!response.ok) {
|
|
21741
|
+
throw new Error(`Failed to fetch transaction: ${response.statusText}`);
|
|
21742
|
+
}
|
|
21743
|
+
return await response.text();
|
|
21744
|
+
}
|
|
21745
|
+
/**
|
|
21746
|
+
* Estimate transaction size in vbytes
|
|
21747
|
+
*/
|
|
21748
|
+
estimateTxSize(inputCount, outputCount) {
|
|
21749
|
+
return Math.ceil(10.5 + 44 + inputCount * 68 + outputCount * 31);
|
|
21750
|
+
}
|
|
21751
|
+
getAddressType(address) {
|
|
21752
|
+
return detectBitcoinAddressType(address);
|
|
21753
|
+
}
|
|
21754
|
+
encodePayloadToBytes(payload) {
|
|
21755
|
+
const ordered = {
|
|
21756
|
+
src_address: payload.src_address.toLowerCase(),
|
|
21757
|
+
data: payload.data.toLowerCase(),
|
|
21758
|
+
src_chain_id: payload.src_chain_id,
|
|
21759
|
+
dst_chain_id: payload.dst_chain_id,
|
|
21760
|
+
wallet_used: payload.wallet_used,
|
|
21761
|
+
timestamp: payload.timestamp,
|
|
21762
|
+
address_type: payload.address_type
|
|
21763
|
+
};
|
|
21764
|
+
const json = JSON.stringify(ordered);
|
|
21765
|
+
return json;
|
|
21766
|
+
}
|
|
21767
|
+
static async encodeWithdrawalData(dstChainId, data, provider, raw) {
|
|
21768
|
+
let srcAddress = await provider.walletProvider.getWalletAddress();
|
|
21769
|
+
const addressType = provider.getAddressType(srcAddress);
|
|
21770
|
+
if (provider.walletMode === "TRADING") {
|
|
21771
|
+
srcAddress = await provider.radfi.getTradingWallet(srcAddress).then((res) => res.tradingAddress).catch(() => srcAddress);
|
|
21772
|
+
}
|
|
21773
|
+
const payload = {
|
|
21774
|
+
src_address: srcAddress,
|
|
21775
|
+
data,
|
|
21776
|
+
src_chain_id: Number(getIntentRelayChainId(provider.chainConfig.chain.id)),
|
|
21777
|
+
dst_chain_id: Number(getIntentRelayChainId(dstChainId)),
|
|
21778
|
+
wallet_used: provider.walletMode,
|
|
21779
|
+
timestamp: Date.now(),
|
|
21780
|
+
address_type: addressType
|
|
21781
|
+
};
|
|
21782
|
+
const orderedPayload = provider.encodePayloadToBytes(payload);
|
|
21783
|
+
const onDemandWithdraw = {
|
|
21784
|
+
payload_hex: Buffer.from(orderedPayload).toString("hex"),
|
|
21785
|
+
signature: void 0
|
|
21786
|
+
};
|
|
21787
|
+
if (raw || isBitcoinRawSpokeProvider(provider)) {
|
|
21788
|
+
return JSON.stringify(onDemandWithdraw);
|
|
21789
|
+
}
|
|
21790
|
+
const signature = await provider.walletProvider.signEcdsaMessage(orderedPayload);
|
|
21791
|
+
onDemandWithdraw.signature = signature;
|
|
21792
|
+
return JSON.stringify(onDemandWithdraw);
|
|
21793
|
+
}
|
|
21794
|
+
};
|
|
21795
|
+
var BitcoinRawSpokeProvider = class extends BitcoinBaseSpokeProvider {
|
|
21796
|
+
walletProvider;
|
|
21797
|
+
raw = true;
|
|
21798
|
+
constructor(walletAddress, publicKey, chainConfig, radfiConfig, walletMode = "USER", rpcUrl) {
|
|
21799
|
+
super(chainConfig, radfiConfig, walletMode, rpcUrl);
|
|
21800
|
+
this.walletProvider = {
|
|
21801
|
+
getWalletAddress: async () => walletAddress,
|
|
21802
|
+
getPublicKey: async () => publicKey
|
|
21803
|
+
};
|
|
21804
|
+
}
|
|
21805
|
+
};
|
|
21806
|
+
var BitcoinSpokeProvider = class extends BitcoinBaseSpokeProvider {
|
|
21807
|
+
walletProvider;
|
|
21808
|
+
constructor(walletProvider, chainConfig, radfiConfig, walletMode = "USER", rpcUrl) {
|
|
21809
|
+
super(chainConfig, radfiConfig, walletMode, rpcUrl);
|
|
21810
|
+
this.walletProvider = walletProvider;
|
|
21811
|
+
}
|
|
21812
|
+
/**
|
|
21813
|
+
* Authenticate with Radfi: BIP322-sign a login message, then call the Radfi API.
|
|
21814
|
+
* Returns accessToken, refreshToken, and tradingAddress.
|
|
21815
|
+
*/
|
|
21816
|
+
async authenticateWithWallet(cachedPublicKey) {
|
|
21817
|
+
const address = await this.walletProvider.getWalletAddress();
|
|
21818
|
+
let publicKey = cachedPublicKey;
|
|
21819
|
+
if (!publicKey) {
|
|
21820
|
+
if (!this.walletProvider.getPublicKey) {
|
|
21821
|
+
throw new Error("Wallet provider does not support getPublicKey");
|
|
21822
|
+
}
|
|
21823
|
+
publicKey = await this.walletProvider.getPublicKey();
|
|
21824
|
+
}
|
|
21825
|
+
if (!publicKey) {
|
|
21826
|
+
throw new Error("Failed to retrieve public key from wallet. Please unlock your wallet and try again.");
|
|
21827
|
+
}
|
|
21828
|
+
const message = `Login to Radfi via Sodax: ${Date.now()}`;
|
|
21829
|
+
const signature = await this.walletProvider.signBip322Message(message);
|
|
21830
|
+
const result = await this.radfi.authenticate({ message, signature, address, publicKey });
|
|
21831
|
+
this.setRadfiAccessToken(result.accessToken);
|
|
21832
|
+
return { ...result, publicKey };
|
|
21833
|
+
}
|
|
21834
|
+
/**
|
|
21835
|
+
* Ensure a valid Radfi access token is set on this provider.
|
|
21836
|
+
* No-op if a token is already present.
|
|
21837
|
+
*/
|
|
21838
|
+
async ensureRadfiAccessToken() {
|
|
21839
|
+
if (this.radfiAccessToken) return;
|
|
21840
|
+
await this.authenticateWithWallet();
|
|
21841
|
+
}
|
|
21842
|
+
/**
|
|
21843
|
+
* Sign and broadcast a Bitcoin transaction
|
|
21844
|
+
*/
|
|
21845
|
+
async signAndBroadcastTransaction(psbt) {
|
|
21846
|
+
const psbtBase64 = typeof psbt === "string" ? psbt : psbt.toBase64();
|
|
21847
|
+
const signedPsbtHex = await this.walletProvider.signTransaction(psbtBase64);
|
|
21848
|
+
const txHash = await this.broadcastTransaction(signedPsbtHex);
|
|
21849
|
+
return txHash;
|
|
21850
|
+
}
|
|
21851
|
+
/**
|
|
21852
|
+
* Broadcast a signed transaction
|
|
21853
|
+
*/
|
|
21854
|
+
async broadcastTransaction(txHex) {
|
|
21855
|
+
const response = await fetch(`${this.rpcUrl}/tx`, {
|
|
21856
|
+
method: "POST",
|
|
21857
|
+
body: txHex
|
|
21858
|
+
});
|
|
21859
|
+
if (!response.ok) {
|
|
21860
|
+
const errorText = await response.text();
|
|
21861
|
+
throw new Error(`Failed to broadcast transaction: ${errorText}`);
|
|
21862
|
+
}
|
|
21863
|
+
return await response.text();
|
|
21864
|
+
}
|
|
21865
|
+
};
|
|
21866
|
+
|
|
21867
|
+
// src/shared/services/spoke/BitcoinSpokeService.ts
|
|
21868
|
+
var BitcoinSpokeService = class _BitcoinSpokeService {
|
|
21869
|
+
constructor() {
|
|
21870
|
+
}
|
|
21871
|
+
/**
|
|
21872
|
+
* Estimate transaction fee for a Bitcoin transaction
|
|
21873
|
+
*
|
|
21874
|
+
* @param {Hex} rawTx - The raw transaction parameters
|
|
21875
|
+
* @param {BitcoinSpokeProviderType} spokeProvider - The Bitcoin spoke provider
|
|
21876
|
+
* @returns {Promise<bigint>} Estimated fee in satoshis
|
|
21877
|
+
*/
|
|
21878
|
+
static async estimateGas(rawTx, spokeProvider) {
|
|
21879
|
+
const txBytes = Buffer.from(rawTx, "hex");
|
|
21880
|
+
const vsize = Math.ceil(txBytes.length);
|
|
21881
|
+
const feeRate = await spokeProvider.getFeeEstimate();
|
|
21882
|
+
const feeRateBigInt = typeof feeRate === "bigint" ? feeRate : BigInt(Math.ceil(feeRate));
|
|
21883
|
+
return BigInt(vsize) * feeRateBigInt;
|
|
21884
|
+
}
|
|
21885
|
+
/**
|
|
21886
|
+
* Deposit tokens to the spoke chain and bridge to hub
|
|
21887
|
+
*
|
|
21888
|
+
* @param {BitcoinSpokeDepositParams} params - Deposit parameters
|
|
21889
|
+
* @param {BitcoinSpokeProviderType} spokeProvider - The Bitcoin spoke provider
|
|
21890
|
+
* @param {EvmHubProvider} EvmHubProvider - The hub chain provider
|
|
21891
|
+
* @param {boolean} raw - Whether to return raw PSBT or transaction hash
|
|
21892
|
+
* @returns {Promise<TxReturnType<BitcoinSpokeProviderType, R>>} Transaction hash or raw PSBT
|
|
21893
|
+
*/
|
|
21894
|
+
static async deposit(params, spokeProvider, raw) {
|
|
21895
|
+
return _BitcoinSpokeService.transfer(
|
|
21896
|
+
{
|
|
21897
|
+
token: params.token,
|
|
21898
|
+
amount: params.amount,
|
|
21899
|
+
data: params.data ?? "0x",
|
|
21900
|
+
accessToken: params.accessToken
|
|
21901
|
+
},
|
|
21902
|
+
spokeProvider,
|
|
21903
|
+
raw
|
|
21904
|
+
);
|
|
21905
|
+
}
|
|
21906
|
+
/**
|
|
21907
|
+
* Get the balance of deposited tokens in the asset manager
|
|
21908
|
+
*
|
|
21909
|
+
* @param {string} token - Token identifier ('BTC' for native Bitcoin)
|
|
21910
|
+
* @param {BitcoinSpokeProviderType} spokeProvider - The Bitcoin spoke provider
|
|
21911
|
+
* @returns {Promise<bigint>} Balance in satoshis
|
|
21912
|
+
*/
|
|
21913
|
+
static async getDeposit(token, spokeProvider) {
|
|
21914
|
+
const assetManagerAddress = spokeProvider.chainConfig.addresses.assetManager;
|
|
21915
|
+
const utxos = await spokeProvider.fetchUTXOs(assetManagerAddress);
|
|
21916
|
+
const totalBalance = utxos.reduce((sum, utxo) => sum + utxo.value, 0);
|
|
21917
|
+
return BigInt(totalBalance);
|
|
21918
|
+
}
|
|
21919
|
+
/**
|
|
21920
|
+
* Generate simulation parameters for deposit
|
|
21921
|
+
*
|
|
21922
|
+
* @param {BitcoinSpokeDepositParams} params - Deposit parameters
|
|
21923
|
+
* @param {BitcoinSpokeProviderType} spokeProvider - The Bitcoin spoke provider
|
|
21924
|
+
* @param {EvmHubProvider} EvmHubProvider - The hub chain provider
|
|
21925
|
+
* @returns {Promise<DepositSimulationParams>} Simulation parameters
|
|
21926
|
+
*/
|
|
21927
|
+
static async getSimulateDepositParams(params, spokeProvider, EvmHubProvider2) {
|
|
21928
|
+
const to = params.to ?? await EvmWalletAbstraction.getUserHubWalletAddress(
|
|
21929
|
+
spokeProvider.chainConfig.chain.id,
|
|
21930
|
+
encodeAddress(spokeProvider.chainConfig.chain.id, params.from),
|
|
21931
|
+
EvmHubProvider2
|
|
21932
|
+
);
|
|
21933
|
+
const tokenEntry = Object.values(spokeProvider.chainConfig.supportedTokens).find((t) => t.address === params.token);
|
|
21934
|
+
const token = tokenEntry?.address ?? params.token;
|
|
21935
|
+
return {
|
|
21936
|
+
spokeChainID: spokeProvider.chainConfig.chain.id,
|
|
21937
|
+
token: encodeAddress(spokeProvider.chainConfig.chain.id, token),
|
|
21938
|
+
from: encodeAddress(spokeProvider.chainConfig.chain.id, params.from),
|
|
21939
|
+
to,
|
|
21940
|
+
amount: params.amount,
|
|
21941
|
+
data: params.data,
|
|
21942
|
+
srcAddress: encodeAddress(spokeProvider.chainConfig.chain.id, spokeProvider.chainConfig.addresses.assetManager)
|
|
21943
|
+
};
|
|
21944
|
+
}
|
|
21945
|
+
/**
|
|
21946
|
+
* Fund the Radfi trading wallet by sending BTC from the user's personal wallet
|
|
21947
|
+
*
|
|
21948
|
+
* @param {bigint} amount - Amount in satoshis to send
|
|
21949
|
+
* @param {BitcoinSpokeProvider} spokeProvider - The Bitcoin spoke provider (must have signing capability)
|
|
21950
|
+
* @returns {Promise<string>} Transaction ID of the funding transaction
|
|
21951
|
+
*/
|
|
21952
|
+
static async fundTradingWallet(amount, spokeProvider) {
|
|
21953
|
+
const walletAddress = await spokeProvider.walletProvider.getWalletAddress();
|
|
21954
|
+
const { tradingAddress } = await spokeProvider.radfi.getTradingWallet(walletAddress);
|
|
21955
|
+
return spokeProvider.walletProvider.sendBitcoin(tradingAddress, amount);
|
|
21956
|
+
}
|
|
21957
|
+
/**
|
|
21958
|
+
* Call a contract on the hub chain from Bitcoin spoke
|
|
21959
|
+
*
|
|
21960
|
+
* @param {HubAddress} from - The hub wallet address
|
|
21961
|
+
* @param {Hex} payload - The payload to send
|
|
21962
|
+
* @param {BitcoinSpokeProviderType} spokeProvider - The Bitcoin spoke provider
|
|
21963
|
+
* @param {EvmHubProvider} EvmHubProvider - The hub chain provider
|
|
21964
|
+
* @param {boolean} raw - Whether to return raw PSBT or transaction hash
|
|
21965
|
+
* @returns {Promise<TxReturnType<BitcoinSpokeProviderType, R>>} Stringified JSON for payload and signature
|
|
21966
|
+
*/
|
|
21967
|
+
static async callWallet(from, payload, spokeProvider, EvmHubProvider2, raw) {
|
|
21968
|
+
return _BitcoinSpokeService.call(EvmHubProvider2.chainConfig.chain.id, from, payload, spokeProvider, raw);
|
|
21969
|
+
}
|
|
21970
|
+
/**
|
|
21971
|
+
* Transfer tokens to the hub chain
|
|
21972
|
+
*
|
|
21973
|
+
* @param {BitcoinTransferToHubParams} params - Transfer parameters
|
|
21974
|
+
* @param {BitcoinSpokeProviderType} spokeProvider - The Bitcoin spoke provider
|
|
21975
|
+
* @param {boolean} raw - Whether to return raw PSBT or transaction hash
|
|
21976
|
+
* @returns {Promise<TxReturnType<BitcoinSpokeProviderType, R>>} Transaction hash or raw PSBT
|
|
21977
|
+
*/
|
|
21978
|
+
static async transfer({ token, amount, data = "0x", accessToken }, spokeProvider, raw) {
|
|
21979
|
+
return await BitcoinBaseSpokeProvider.deposit(token, amount, data, spokeProvider, raw, accessToken);
|
|
21980
|
+
}
|
|
21981
|
+
/**
|
|
21982
|
+
* Send a message to the hub chain
|
|
21983
|
+
*
|
|
21984
|
+
* @param {HubChainId} dstChainId - Destination chain ID
|
|
21985
|
+
* @param {HubAddress} dstAddress - Destination address on hub
|
|
21986
|
+
* @param {Hex} payload - Message payload
|
|
21987
|
+
* @param {BitcoinSpokeProviderType} spokeProvider - The Bitcoin spoke provider
|
|
21988
|
+
* @param {boolean} raw - Whether to return raw PSBT or transaction hash
|
|
21989
|
+
* @returns {Promise<TxReturnType<BitcoinSpokeProviderType, R>>} Transaction hash or raw PSBT
|
|
21990
|
+
*/
|
|
21991
|
+
static async call(dstChainId, dstAddress, payload, spokeProvider, raw) {
|
|
21992
|
+
return await BitcoinBaseSpokeProvider.encodeWithdrawalData(
|
|
21993
|
+
dstChainId,
|
|
21994
|
+
payload,
|
|
21995
|
+
spokeProvider,
|
|
21996
|
+
raw
|
|
21997
|
+
);
|
|
21998
|
+
}
|
|
21999
|
+
};
|
|
21209
22000
|
var NearSpokeService = class _NearSpokeService {
|
|
21210
22001
|
constructor() {
|
|
21211
22002
|
}
|
|
@@ -21564,6 +22355,14 @@ var SpokeService = class _SpokeService {
|
|
|
21564
22355
|
raw
|
|
21565
22356
|
);
|
|
21566
22357
|
}
|
|
22358
|
+
if (isBitcoinSpokeProviderType(spokeProvider)) {
|
|
22359
|
+
await _SpokeService.verifyDepositSimulation(params, spokeProvider, hubProvider, skipSimulation);
|
|
22360
|
+
return BitcoinSpokeService.deposit(
|
|
22361
|
+
params,
|
|
22362
|
+
spokeProvider,
|
|
22363
|
+
raw
|
|
22364
|
+
);
|
|
22365
|
+
}
|
|
21567
22366
|
if (isNearSpokeProviderType(spokeProvider)) {
|
|
21568
22367
|
await _SpokeService.verifyDepositSimulation(params, spokeProvider, hubProvider, skipSimulation);
|
|
21569
22368
|
return NearSpokeService.deposit(
|
|
@@ -21618,6 +22417,13 @@ var SpokeService = class _SpokeService {
|
|
|
21618
22417
|
hubProvider
|
|
21619
22418
|
);
|
|
21620
22419
|
}
|
|
22420
|
+
if (isBitcoinSpokeProviderType(spokeProvider)) {
|
|
22421
|
+
return BitcoinSpokeService.getSimulateDepositParams(
|
|
22422
|
+
params,
|
|
22423
|
+
spokeProvider,
|
|
22424
|
+
hubProvider
|
|
22425
|
+
);
|
|
22426
|
+
}
|
|
21621
22427
|
if (isNearSpokeProviderType(spokeProvider)) {
|
|
21622
22428
|
return NearSpokeService.getSimulateDepositParams(
|
|
21623
22429
|
params,
|
|
@@ -21664,6 +22470,9 @@ var SpokeService = class _SpokeService {
|
|
|
21664
22470
|
if (isSonicSpokeProviderType(spokeProvider)) {
|
|
21665
22471
|
return SonicSpokeService.getDeposit(token, spokeProvider);
|
|
21666
22472
|
}
|
|
22473
|
+
if (isBitcoinSpokeProviderType(spokeProvider)) {
|
|
22474
|
+
return BitcoinSpokeService.getDeposit(token, spokeProvider);
|
|
22475
|
+
}
|
|
21667
22476
|
if (isNearSpokeProviderType(spokeProvider)) {
|
|
21668
22477
|
return NearSpokeService.getDeposit(token, spokeProvider);
|
|
21669
22478
|
}
|
|
@@ -21681,15 +22490,24 @@ var SpokeService = class _SpokeService {
|
|
|
21681
22490
|
if (isSonicSpokeProviderType(spokeProvider)) {
|
|
21682
22491
|
return await SonicSpokeService.callWallet(payload, spokeProvider, raw);
|
|
21683
22492
|
}
|
|
22493
|
+
let srcAddress = encodeAddress(
|
|
22494
|
+
spokeProvider.chainConfig.chain.id,
|
|
22495
|
+
await spokeProvider.walletProvider.getWalletAddress()
|
|
22496
|
+
);
|
|
22497
|
+
if (isBitcoinSpokeProvider(spokeProvider)) {
|
|
22498
|
+
if (spokeProvider.walletMode === "TRADING") {
|
|
22499
|
+
const tradingWalletAddress = await spokeProvider.radfi.getTradingWallet(
|
|
22500
|
+
await spokeProvider.walletProvider.getWalletAddress()
|
|
22501
|
+
);
|
|
22502
|
+
srcAddress = encodeAddress(spokeProvider.chainConfig.chain.id, tradingWalletAddress.tradingAddress);
|
|
22503
|
+
}
|
|
22504
|
+
}
|
|
21684
22505
|
if (!skipSimulation) {
|
|
21685
22506
|
const result = await _SpokeService.simulateRecvMessage(
|
|
21686
22507
|
{
|
|
21687
22508
|
target: from,
|
|
21688
22509
|
srcChainId: getIntentRelayChainId(spokeProvider.chainConfig.chain.id),
|
|
21689
|
-
srcAddress
|
|
21690
|
-
spokeProvider.chainConfig.chain.id,
|
|
21691
|
-
await spokeProvider.walletProvider.getWalletAddress()
|
|
21692
|
-
),
|
|
22510
|
+
srcAddress,
|
|
21693
22511
|
payload
|
|
21694
22512
|
},
|
|
21695
22513
|
hubProvider
|
|
@@ -21740,6 +22558,16 @@ var SpokeService = class _SpokeService {
|
|
|
21740
22558
|
raw
|
|
21741
22559
|
);
|
|
21742
22560
|
}
|
|
22561
|
+
if (isBitcoinSpokeProviderType(spokeProvider)) {
|
|
22562
|
+
await _SpokeService.verifySimulation(from, payload, spokeProvider, hubProvider, skipSimulation);
|
|
22563
|
+
return await BitcoinSpokeService.callWallet(
|
|
22564
|
+
from,
|
|
22565
|
+
payload,
|
|
22566
|
+
spokeProvider,
|
|
22567
|
+
hubProvider,
|
|
22568
|
+
raw
|
|
22569
|
+
);
|
|
22570
|
+
}
|
|
21743
22571
|
if (isNearSpokeProviderType(spokeProvider)) {
|
|
21744
22572
|
await _SpokeService.verifySimulation(from, payload, spokeProvider, hubProvider, skipSimulation);
|
|
21745
22573
|
return await NearSpokeService.callWallet(from, payload, spokeProvider, hubProvider, raw);
|
|
@@ -21748,14 +22576,26 @@ var SpokeService = class _SpokeService {
|
|
|
21748
22576
|
}
|
|
21749
22577
|
static async verifySimulation(from, payload, spokeProvider, hubProvider, skipSimulation) {
|
|
21750
22578
|
if (!skipSimulation) {
|
|
22579
|
+
let srcAddress = encodeAddress(
|
|
22580
|
+
spokeProvider.chainConfig.chain.id,
|
|
22581
|
+
await spokeProvider.walletProvider.getWalletAddress()
|
|
22582
|
+
);
|
|
22583
|
+
if (isBitcoinSpokeProvider(spokeProvider)) {
|
|
22584
|
+
if (spokeProvider.walletMode === "TRADING") {
|
|
22585
|
+
const tradingWalletAddress = await spokeProvider.radfi.getTradingWallet(
|
|
22586
|
+
await spokeProvider.walletProvider.getWalletAddress()
|
|
22587
|
+
);
|
|
22588
|
+
srcAddress = encodeAddress(
|
|
22589
|
+
spokeProvider.chainConfig.chain.id,
|
|
22590
|
+
tradingWalletAddress.tradingAddress
|
|
22591
|
+
);
|
|
22592
|
+
}
|
|
22593
|
+
}
|
|
21751
22594
|
const result = await _SpokeService.simulateRecvMessage(
|
|
21752
22595
|
{
|
|
21753
22596
|
target: from,
|
|
21754
22597
|
srcChainId: getIntentRelayChainId(spokeProvider.chainConfig.chain.id),
|
|
21755
|
-
srcAddress
|
|
21756
|
-
spokeProvider.chainConfig.chain.id,
|
|
21757
|
-
await spokeProvider.walletProvider.getWalletAddress()
|
|
21758
|
-
),
|
|
22598
|
+
srcAddress,
|
|
21759
22599
|
payload
|
|
21760
22600
|
},
|
|
21761
22601
|
hubProvider
|
|
@@ -22189,7 +23029,7 @@ var SwapService = class {
|
|
|
22189
23029
|
let dstIntentTxHash;
|
|
22190
23030
|
if (spokeProvider.chainConfig.chain.id !== this.hubProvider.chainConfig.chain.id) {
|
|
22191
23031
|
const intentRelayChainId = getIntentRelayChainId(params.srcChain).toString();
|
|
22192
|
-
const submitPayload = params.srcChain === SOLANA_MAINNET_CHAIN_ID && data ? {
|
|
23032
|
+
const submitPayload = (params.srcChain === SOLANA_MAINNET_CHAIN_ID || params.srcChain === BITCOIN_MAINNET_CHAIN_ID) && data ? {
|
|
22193
23033
|
action: "submit",
|
|
22194
23034
|
params: {
|
|
22195
23035
|
chain_id: intentRelayChainId,
|
|
@@ -22514,17 +23354,51 @@ var SwapService = class {
|
|
|
22514
23354
|
this.configService.isValidSpokeChainId(params.dstChain),
|
|
22515
23355
|
`Invalid spoke chain (params.dstChain): ${params.dstChain}`
|
|
22516
23356
|
);
|
|
23357
|
+
if (params.dstChain === BITCOIN_MAINNET_CHAIN_ID && params.outputToken === "BTC") {
|
|
23358
|
+
invariant6__default.default(
|
|
23359
|
+
params.minOutputAmount >= 546n,
|
|
23360
|
+
`Invalid minOutputAmount (params.minOutputAmount): ${params.minOutputAmount}`
|
|
23361
|
+
);
|
|
23362
|
+
}
|
|
22517
23363
|
try {
|
|
22518
|
-
|
|
23364
|
+
console.log("[SwapService.createIntent] start", {
|
|
23365
|
+
srcChain: params.srcChain,
|
|
23366
|
+
dstChain: params.dstChain,
|
|
23367
|
+
inputToken: params.inputToken,
|
|
23368
|
+
inputAmount: params.inputAmount.toString()
|
|
23369
|
+
});
|
|
23370
|
+
let walletAddress = await spokeProvider.walletProvider.getWalletAddress();
|
|
23371
|
+
console.log("[SwapService.createIntent] walletAddress", walletAddress, "srcAddress", params.srcAddress);
|
|
22519
23372
|
invariant6__default.default(
|
|
22520
23373
|
params.srcAddress.toLowerCase() === walletAddress.toLowerCase(),
|
|
22521
23374
|
"srcAddress must be the same as wallet address"
|
|
22522
23375
|
);
|
|
23376
|
+
if (isBitcoinSpokeProvider(spokeProvider)) {
|
|
23377
|
+
console.log(
|
|
23378
|
+
"[SwapService.createIntent] Bitcoin detected, walletMode:",
|
|
23379
|
+
spokeProvider.walletMode,
|
|
23380
|
+
"hasToken:",
|
|
23381
|
+
!!spokeProvider.radfiAccessToken
|
|
23382
|
+
);
|
|
23383
|
+
await spokeProvider.ensureRadfiAccessToken();
|
|
23384
|
+
console.log(
|
|
23385
|
+
"[SwapService.createIntent] ensureRadfiAccessToken done, hasToken:",
|
|
23386
|
+
!!spokeProvider.radfiAccessToken
|
|
23387
|
+
);
|
|
23388
|
+
if (spokeProvider.walletMode === "TRADING") {
|
|
23389
|
+
const tradingWalletAddress = await spokeProvider.radfi.getTradingWallet(
|
|
23390
|
+
await spokeProvider.walletProvider.getWalletAddress()
|
|
23391
|
+
);
|
|
23392
|
+
console.log("[SwapService.createIntent] tradingWalletAddress", tradingWalletAddress);
|
|
23393
|
+
walletAddress = tradingWalletAddress.tradingAddress;
|
|
23394
|
+
}
|
|
23395
|
+
}
|
|
22523
23396
|
const creatorHubWalletAddress = await deriveUserWalletAddress(
|
|
22524
23397
|
this.hubProvider,
|
|
22525
23398
|
spokeProvider.chainConfig.chain.id,
|
|
22526
23399
|
walletAddress
|
|
22527
23400
|
);
|
|
23401
|
+
console.log("[SwapService.createIntent] creatorHubWalletAddress", creatorHubWalletAddress);
|
|
22528
23402
|
if (spokeProvider.chainConfig.chain.id === this.hubProvider.chainConfig.chain.id && isSonicSpokeProviderType(spokeProvider)) {
|
|
22529
23403
|
const [txResult, intent, feeAmount, data] = await SonicSpokeService.createSwapIntent(
|
|
22530
23404
|
params,
|
|
@@ -22555,6 +23429,11 @@ var SwapService = class {
|
|
|
22555
23429
|
this.configService,
|
|
22556
23430
|
fee
|
|
22557
23431
|
);
|
|
23432
|
+
console.log("[SwapService.createIntent] intent data constructed", {
|
|
23433
|
+
data,
|
|
23434
|
+
intentId: intent.intentId?.toString()
|
|
23435
|
+
});
|
|
23436
|
+
console.log("[SwapService.createIntent] calling SpokeService.deposit...");
|
|
22558
23437
|
const txResult = await SpokeService.deposit(
|
|
22559
23438
|
{
|
|
22560
23439
|
from: walletAddress,
|
|
@@ -22568,12 +23447,14 @@ var SwapService = class {
|
|
|
22568
23447
|
raw,
|
|
22569
23448
|
skipSimulation
|
|
22570
23449
|
);
|
|
23450
|
+
console.log("[SwapService.createIntent] SpokeService.deposit done, txResult:", txResult);
|
|
22571
23451
|
return {
|
|
22572
23452
|
ok: true,
|
|
22573
23453
|
value: [txResult, { ...intent, feeAmount }, data]
|
|
22574
23454
|
};
|
|
22575
23455
|
}
|
|
22576
23456
|
} catch (error) {
|
|
23457
|
+
console.error("[SwapService.createIntent] FAILED", error);
|
|
22577
23458
|
return {
|
|
22578
23459
|
ok: false,
|
|
22579
23460
|
error: {
|
|
@@ -25632,9 +26513,15 @@ function isNearSpokeProvider(value) {
|
|
|
25632
26513
|
function isStellarSpokeProviderType(value) {
|
|
25633
26514
|
return typeof value === "object" && value !== null && (isStellarSpokeProvider(value) || isStellarRawSpokeProvider(value));
|
|
25634
26515
|
}
|
|
26516
|
+
function isBitcoinSpokeProviderType(value) {
|
|
26517
|
+
return typeof value === "object" && value !== null && (isBitcoinSpokeProvider(value) || isBitcoinRawSpokeProvider(value));
|
|
26518
|
+
}
|
|
25635
26519
|
function isStellarSpokeProvider(value) {
|
|
25636
26520
|
return typeof value === "object" && value !== null && value instanceof StellarSpokeProvider && !("raw" in value) && value.chainConfig.chain.type === "STELLAR";
|
|
25637
26521
|
}
|
|
26522
|
+
function isBitcoinSpokeProvider(value) {
|
|
26523
|
+
return typeof value === "object" && value !== null && value instanceof BitcoinSpokeProvider && !("raw" in value) && value.chainConfig.chain.type === "BITCOIN";
|
|
26524
|
+
}
|
|
25638
26525
|
function isNearSpokeProviderType(value) {
|
|
25639
26526
|
return typeof value === "object" && value !== null && (isNearSpokeProvider(value) || isNearRawSpokeProvider(value));
|
|
25640
26527
|
}
|
|
@@ -25731,6 +26618,9 @@ function isSolanaRawSpokeProvider(value) {
|
|
|
25731
26618
|
function isStellarRawSpokeProvider(value) {
|
|
25732
26619
|
return isRawSpokeProvider(value) && value.chainConfig.chain.type === "STELLAR";
|
|
25733
26620
|
}
|
|
26621
|
+
function isBitcoinRawSpokeProvider(value) {
|
|
26622
|
+
return isRawSpokeProvider(value) && value.chainConfig.chain.type === "BITCOIN";
|
|
26623
|
+
}
|
|
25734
26624
|
function isIconRawSpokeProvider(value) {
|
|
25735
26625
|
return isRawSpokeProvider(value) && value.chainConfig.chain.type === "ICON";
|
|
25736
26626
|
}
|
|
@@ -25839,8 +26729,6 @@ function encodeAddress(spokeChainId, address) {
|
|
|
25839
26729
|
case "0xa4b1.arbitrum":
|
|
25840
26730
|
case "sonic":
|
|
25841
26731
|
return address;
|
|
25842
|
-
case "injective-1":
|
|
25843
|
-
return viem.toHex(Buffer.from(address, "utf-8"));
|
|
25844
26732
|
case "0x1.icon":
|
|
25845
26733
|
return viem.toHex(Buffer.from(address.replace("cx", "01").replace("hx", "00") ?? "f8", "hex"));
|
|
25846
26734
|
case "sui":
|
|
@@ -25849,7 +26737,9 @@ function encodeAddress(spokeChainId, address) {
|
|
|
25849
26737
|
return viem.toHex(Buffer.from(new web3_js.PublicKey(address).toBytes()));
|
|
25850
26738
|
case "stellar":
|
|
25851
26739
|
return `0x${stellarSdk.Address.fromString(address).toScVal().toXDR("hex")}`;
|
|
26740
|
+
case "bitcoin":
|
|
25852
26741
|
case "near":
|
|
26742
|
+
case "injective-1":
|
|
25853
26743
|
return viem.toHex(Buffer.from(address, "utf-8"));
|
|
25854
26744
|
default:
|
|
25855
26745
|
return address;
|
|
@@ -26473,7 +27363,7 @@ var BridgeService = class {
|
|
|
26473
27363
|
}
|
|
26474
27364
|
const packetResult = await relayTxAndWaitPacket(
|
|
26475
27365
|
txResult.value,
|
|
26476
|
-
spokeProvider instanceof SolanaSpokeProvider ? txResult.data : void 0,
|
|
27366
|
+
spokeProvider instanceof SolanaSpokeProvider || spokeProvider instanceof BitcoinSpokeProvider ? txResult.data : void 0,
|
|
26477
27367
|
spokeProvider,
|
|
26478
27368
|
this.relayerApiEndpoint,
|
|
26479
27369
|
timeout
|
|
@@ -26546,7 +27436,11 @@ var BridgeService = class {
|
|
|
26546
27436
|
const dstAssetInfo = this.configService.getHubAssetInfo(params.dstChainId, params.dstAsset);
|
|
26547
27437
|
invariant6__default.default(srcAssetInfo, `Unsupported spoke chain (${params.srcChainId}) token: ${params.srcAsset}`);
|
|
26548
27438
|
invariant6__default.default(dstAssetInfo, `Unsupported spoke chain (${params.dstChainId}) token: ${params.dstAsset}`);
|
|
26549
|
-
|
|
27439
|
+
let walletAddress = await spokeProvider.walletProvider.getWalletAddress();
|
|
27440
|
+
if (spokeProvider instanceof BitcoinSpokeProvider && spokeProvider.walletMode === "TRADING") {
|
|
27441
|
+
const tradingWallet = await spokeProvider.radfi.getTradingWallet(walletAddress);
|
|
27442
|
+
walletAddress = tradingWallet.tradingAddress;
|
|
27443
|
+
}
|
|
26550
27444
|
const hubWallet = await WalletAbstractionService.getUserAbstractedWalletAddress(
|
|
26551
27445
|
walletAddress,
|
|
26552
27446
|
spokeProvider,
|
|
@@ -30080,11 +30974,16 @@ var BalnSwapService = class {
|
|
|
30080
30974
|
exports.ARBITRUM_MAINNET_CHAIN_ID = ARBITRUM_MAINNET_CHAIN_ID;
|
|
30081
30975
|
exports.AVALANCHE_MAINNET_CHAIN_ID = AVALANCHE_MAINNET_CHAIN_ID;
|
|
30082
30976
|
exports.BASE_MAINNET_CHAIN_ID = BASE_MAINNET_CHAIN_ID;
|
|
30977
|
+
exports.BITCOIN_MAINNET_CHAIN_ID = BITCOIN_MAINNET_CHAIN_ID;
|
|
30083
30978
|
exports.BSC_MAINNET_CHAIN_ID = BSC_MAINNET_CHAIN_ID;
|
|
30084
30979
|
exports.BackendApiService = BackendApiService;
|
|
30085
30980
|
exports.BalnSwapService = BalnSwapService;
|
|
30086
30981
|
exports.BigIntToHex = BigIntToHex;
|
|
30087
30982
|
exports.BigNumberZeroDecimal = BigNumberZeroDecimal;
|
|
30983
|
+
exports.BitcoinBaseSpokeProvider = BitcoinBaseSpokeProvider;
|
|
30984
|
+
exports.BitcoinRawSpokeProvider = BitcoinRawSpokeProvider;
|
|
30985
|
+
exports.BitcoinSpokeProvider = BitcoinSpokeProvider;
|
|
30986
|
+
exports.BitcoinSpokeService = BitcoinSpokeService;
|
|
30088
30987
|
exports.BnUSDMigrationService = BnUSDMigrationService;
|
|
30089
30988
|
exports.BridgeService = BridgeService;
|
|
30090
30989
|
exports.CHAIN_IDS = CHAIN_IDS;
|
|
@@ -30161,6 +31060,7 @@ exports.ProtocolIntentsAbi = ProtocolIntentsAbi;
|
|
|
30161
31060
|
exports.RAY = RAY;
|
|
30162
31061
|
exports.RAY_DECIMALS = RAY_DECIMALS;
|
|
30163
31062
|
exports.REDBELLY_MAINNET_CHAIN_ID = REDBELLY_MAINNET_CHAIN_ID;
|
|
31063
|
+
exports.RadfiProvider = RadfiProvider;
|
|
30164
31064
|
exports.SECONDS_PER_YEAR = SECONDS_PER_YEAR;
|
|
30165
31065
|
exports.SOLANA_MAINNET_CHAIN_ID = SOLANA_MAINNET_CHAIN_ID;
|
|
30166
31066
|
exports.SONIC_MAINNET_CHAIN_ID = SONIC_MAINNET_CHAIN_ID;
|
|
@@ -30226,6 +31126,7 @@ exports.convertTransactionInstructionToRaw = convertTransactionInstructionToRaw;
|
|
|
30226
31126
|
exports.defaultSharedConfig = defaultSharedConfig;
|
|
30227
31127
|
exports.defaultSodaxConfig = defaultSodaxConfig;
|
|
30228
31128
|
exports.deriveUserWalletAddress = deriveUserWalletAddress;
|
|
31129
|
+
exports.detectBitcoinAddressType = detectBitcoinAddressType;
|
|
30229
31130
|
exports.encodeAddress = encodeAddress;
|
|
30230
31131
|
exports.encodeContractCalls = encodeContractCalls;
|
|
30231
31132
|
exports.erc20Abi = erc20Abi;
|
|
@@ -30264,6 +31165,9 @@ exports.hubChainConfig = hubChainConfig;
|
|
|
30264
31165
|
exports.hyper = hyper;
|
|
30265
31166
|
exports.isAddressString = isAddressString;
|
|
30266
31167
|
exports.isBalnMigrateParams = isBalnMigrateParams;
|
|
31168
|
+
exports.isBitcoinRawSpokeProvider = isBitcoinRawSpokeProvider;
|
|
31169
|
+
exports.isBitcoinSpokeProvider = isBitcoinSpokeProvider;
|
|
31170
|
+
exports.isBitcoinSpokeProviderType = isBitcoinSpokeProviderType;
|
|
30267
31171
|
exports.isConfiguredMoneyMarketConfig = isConfiguredMoneyMarketConfig;
|
|
30268
31172
|
exports.isConfiguredSolverConfig = isConfiguredSolverConfig;
|
|
30269
31173
|
exports.isCreateIntentAutoSwapError = isCreateIntentAutoSwapError;
|
|
@@ -30345,6 +31249,7 @@ exports.nativeToUSD = nativeToUSD;
|
|
|
30345
31249
|
exports.newbnUSDSpokeChainIds = newbnUSDSpokeChainIds;
|
|
30346
31250
|
exports.normalize = normalize;
|
|
30347
31251
|
exports.normalizeBN = normalizeBN;
|
|
31252
|
+
exports.normalizePsbtToBase64 = normalizePsbtToBase64;
|
|
30348
31253
|
exports.normalizedToUsd = normalizedToUsd;
|
|
30349
31254
|
exports.parseToStroops = parseToStroops;
|
|
30350
31255
|
exports.parseTokenArrayFromJson = parseTokenArrayFromJson;
|