@gobob/bob-sdk 4.4.10-rc9 → 4.4.11-rc1
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/README.md +10 -2
- package/dist/assets/tokenlist.json +99 -3
- package/dist/gateway/abi.d.ts +1 -220
- package/dist/gateway/abi.js +2 -146
- package/dist/gateway/abi.js.map +1 -1
- package/dist/gateway/client.d.ts +13 -30
- package/dist/gateway/client.js +68 -738
- package/dist/gateway/client.js.map +1 -1
- package/dist/gateway/generated-client/apis/DefaultApi.d.ts +46 -0
- package/dist/gateway/generated-client/apis/DefaultApi.js +253 -0
- package/dist/gateway/generated-client/apis/DefaultApi.js.map +1 -0
- package/dist/gateway/generated-client/apis/index.d.ts +1 -0
- package/dist/gateway/generated-client/apis/index.js +18 -0
- package/dist/gateway/generated-client/apis/index.js.map +1 -0
- package/dist/gateway/generated-client/index.d.ts +3 -0
- package/dist/gateway/generated-client/index.js +20 -0
- package/dist/gateway/generated-client/index.js.map +1 -0
- package/dist/gateway/generated-client/models/ChainDetails.d.ts +10 -0
- package/dist/gateway/generated-client/models/ChainDetails.js +41 -0
- package/dist/gateway/generated-client/models/ChainDetails.js.map +1 -0
- package/dist/gateway/generated-client/models/GatewayChain.d.ts +23 -0
- package/dist/gateway/generated-client/models/GatewayChain.js +48 -0
- package/dist/gateway/generated-client/models/GatewayChain.js.map +1 -0
- package/dist/gateway/generated-client/models/GatewayCreateOnramp.d.ts +11 -0
- package/dist/gateway/generated-client/models/GatewayCreateOnramp.js +45 -0
- package/dist/gateway/generated-client/models/GatewayCreateOnramp.js.map +1 -0
- package/dist/gateway/generated-client/models/GatewayLayerZeroQuote.d.ts +12 -0
- package/dist/gateway/generated-client/models/GatewayLayerZeroQuote.js +48 -0
- package/dist/gateway/generated-client/models/GatewayLayerZeroQuote.js.map +1 -0
- package/dist/gateway/generated-client/models/GatewayOfframpFeeBreakdown.d.ts +12 -0
- package/dist/gateway/generated-client/models/GatewayOfframpFeeBreakdown.js +51 -0
- package/dist/gateway/generated-client/models/GatewayOfframpFeeBreakdown.js.map +1 -0
- package/dist/gateway/generated-client/models/GatewayOfframpQuote.d.ts +15 -0
- package/dist/gateway/generated-client/models/GatewayOfframpQuote.js +57 -0
- package/dist/gateway/generated-client/models/GatewayOfframpQuote.js.map +1 -0
- package/dist/gateway/generated-client/models/GatewayOnrampFeeBreakdown.d.ts +12 -0
- package/dist/gateway/generated-client/models/GatewayOnrampFeeBreakdown.js +51 -0
- package/dist/gateway/generated-client/models/GatewayOnrampFeeBreakdown.js.map +1 -0
- package/dist/gateway/generated-client/models/GatewayOnrampQuote.d.ts +20 -0
- package/dist/gateway/generated-client/models/GatewayOnrampQuote.js +74 -0
- package/dist/gateway/generated-client/models/GatewayOnrampQuote.js.map +1 -0
- package/dist/gateway/generated-client/models/GatewayOrderInfo.d.ts +8 -0
- package/dist/gateway/generated-client/models/GatewayOrderInfo.js +52 -0
- package/dist/gateway/generated-client/models/GatewayOrderInfo.js.map +1 -0
- package/dist/gateway/generated-client/models/GatewayOrderInfoOneOf.d.ts +9 -0
- package/dist/gateway/generated-client/models/GatewayOrderInfoOneOf.js +36 -0
- package/dist/gateway/generated-client/models/GatewayOrderInfoOneOf.js.map +1 -0
- package/dist/gateway/generated-client/models/GatewayOrderInfoOneOf1.d.ts +9 -0
- package/dist/gateway/generated-client/models/GatewayOrderInfoOneOf1.js +36 -0
- package/dist/gateway/generated-client/models/GatewayOrderInfoOneOf1.js.map +1 -0
- package/dist/gateway/generated-client/models/GatewayOrderInfoOneOf1Offramp.d.ts +24 -0
- package/dist/gateway/generated-client/models/GatewayOrderInfoOneOf1Offramp.js +80 -0
- package/dist/gateway/generated-client/models/GatewayOrderInfoOneOf1Offramp.js.map +1 -0
- package/dist/gateway/generated-client/models/GatewayOrderInfoOneOf2.d.ts +9 -0
- package/dist/gateway/generated-client/models/GatewayOrderInfoOneOf2.js +36 -0
- package/dist/gateway/generated-client/models/GatewayOrderInfoOneOf2.js.map +1 -0
- package/dist/gateway/generated-client/models/GatewayOrderInfoOneOf2LayerZero.d.ts +16 -0
- package/dist/gateway/generated-client/models/GatewayOrderInfoOneOf2LayerZero.js +61 -0
- package/dist/gateway/generated-client/models/GatewayOrderInfoOneOf2LayerZero.js.map +1 -0
- package/dist/gateway/generated-client/models/GatewayOrderInfoOneOfOnramp.d.ts +22 -0
- package/dist/gateway/generated-client/models/GatewayOrderInfoOneOfOnramp.js +75 -0
- package/dist/gateway/generated-client/models/GatewayOrderInfoOneOfOnramp.js.map +1 -0
- package/dist/gateway/generated-client/models/GatewayQuote.d.ts +8 -0
- package/dist/gateway/generated-client/models/GatewayQuote.js +52 -0
- package/dist/gateway/generated-client/models/GatewayQuote.js.map +1 -0
- package/dist/gateway/generated-client/models/GatewayQuoteOneOf.d.ts +9 -0
- package/dist/gateway/generated-client/models/GatewayQuoteOneOf.js +36 -0
- package/dist/gateway/generated-client/models/GatewayQuoteOneOf.js.map +1 -0
- package/dist/gateway/generated-client/models/GatewayQuoteOneOf1.d.ts +9 -0
- package/dist/gateway/generated-client/models/GatewayQuoteOneOf1.js +36 -0
- package/dist/gateway/generated-client/models/GatewayQuoteOneOf1.js.map +1 -0
- package/dist/gateway/generated-client/models/GatewayQuoteOneOf2.d.ts +9 -0
- package/dist/gateway/generated-client/models/GatewayQuoteOneOf2.js +36 -0
- package/dist/gateway/generated-client/models/GatewayQuoteOneOf2.js.map +1 -0
- package/dist/gateway/generated-client/models/LayerZeroChainDetailsSchema.d.ts +10 -0
- package/dist/gateway/generated-client/models/LayerZeroChainDetailsSchema.js +43 -0
- package/dist/gateway/generated-client/models/LayerZeroChainDetailsSchema.js.map +1 -0
- package/dist/gateway/generated-client/models/LayerZeroOrderStatus.d.ts +14 -0
- package/dist/gateway/generated-client/models/LayerZeroOrderStatus.js +39 -0
- package/dist/gateway/generated-client/models/LayerZeroOrderStatus.js.map +1 -0
- package/dist/gateway/generated-client/models/OnrampStatus.d.ts +12 -0
- package/dist/gateway/generated-client/models/OnrampStatus.js +37 -0
- package/dist/gateway/generated-client/models/OnrampStatus.js.map +1 -0
- package/dist/gateway/generated-client/models/OrderStatus.d.ts +12 -0
- package/dist/gateway/generated-client/models/OrderStatus.js +37 -0
- package/dist/gateway/generated-client/models/OrderStatus.js.map +1 -0
- package/dist/gateway/generated-client/models/ReferralInfo.d.ts +11 -0
- package/dist/gateway/generated-client/models/ReferralInfo.js +47 -0
- package/dist/gateway/generated-client/models/ReferralInfo.js.map +1 -0
- package/dist/gateway/generated-client/models/RegisterBtcTx.d.ts +9 -0
- package/dist/gateway/generated-client/models/RegisterBtcTx.js +39 -0
- package/dist/gateway/generated-client/models/RegisterBtcTx.js.map +1 -0
- package/dist/gateway/generated-client/models/RouteInfo.d.ts +11 -0
- package/dist/gateway/generated-client/models/RouteInfo.js +47 -0
- package/dist/gateway/generated-client/models/RouteInfo.js.map +1 -0
- package/dist/gateway/generated-client/models/TxInfo.d.ts +10 -0
- package/dist/gateway/generated-client/models/TxInfo.js +43 -0
- package/dist/gateway/generated-client/models/TxInfo.js.map +1 -0
- package/dist/gateway/generated-client/models/index.d.ts +26 -0
- package/dist/gateway/generated-client/models/index.js +43 -0
- package/dist/gateway/generated-client/models/index.js.map +1 -0
- package/dist/gateway/generated-client/runtime.d.ts +156 -0
- package/dist/gateway/generated-client/runtime.js +316 -0
- package/dist/gateway/generated-client/runtime.js.map +1 -0
- package/dist/gateway/index.d.ts +2 -3
- package/dist/gateway/index.js +16 -7
- package/dist/gateway/index.js.map +1 -1
- package/dist/gateway/types/offramp.d.ts +0 -19
- package/dist/gateway/types/quote.d.ts +4 -7
- package/dist/gateway/types/strategy.d.ts +0 -51
- package/dist/gateway/types/swaps.d.ts +9 -0
- package/dist/gateway/utils/common.d.ts +12 -12
- package/dist/type-utils.d.ts +7 -0
- package/dist/type-utils.js +11 -0
- package/dist/type-utils.js.map +1 -0
- package/package.json +1 -1
- package/dist/gateway/cross-chain-swap.d.ts +0 -24
- package/dist/gateway/cross-chain-swap.js +0 -424
- package/dist/gateway/cross-chain-swap.js.map +0 -1
- package/dist/gateway/layerzero.d.ts +0 -44
- package/dist/gateway/layerzero.js +0 -762
- package/dist/gateway/layerzero.js.map +0 -1
- package/dist/gateway/swaps.d.ts +0 -12
- package/dist/gateway/swaps.js +0 -72
- package/dist/gateway/swaps.js.map +0 -1
package/dist/gateway/client.js
CHANGED
|
@@ -1,582 +1,110 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
-
if (k2 === undefined) k2 = k;
|
|
4
|
-
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
-
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
-
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
-
}
|
|
8
|
-
Object.defineProperty(o, k2, desc);
|
|
9
|
-
}) : (function(o, m, k, k2) {
|
|
10
|
-
if (k2 === undefined) k2 = k;
|
|
11
|
-
o[k2] = m[k];
|
|
12
|
-
}));
|
|
13
|
-
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
-
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
-
}) : function(o, v) {
|
|
16
|
-
o["default"] = v;
|
|
17
|
-
});
|
|
18
|
-
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
-
var ownKeys = function(o) {
|
|
20
|
-
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
-
var ar = [];
|
|
22
|
-
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
-
return ar;
|
|
24
|
-
};
|
|
25
|
-
return ownKeys(o);
|
|
26
|
-
};
|
|
27
|
-
return function (mod) {
|
|
28
|
-
if (mod && mod.__esModule) return mod;
|
|
29
|
-
var result = {};
|
|
30
|
-
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
-
__setModuleDefault(result, mod);
|
|
32
|
-
return result;
|
|
33
|
-
};
|
|
34
|
-
})();
|
|
35
2
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
36
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
37
4
|
};
|
|
38
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
-
exports.GatewayApiClient = exports.
|
|
40
|
-
const bitcoin_address_validation_1 = require("bitcoin-address-validation");
|
|
41
|
-
const bitcoin = __importStar(require("bitcoinjs-lib"));
|
|
6
|
+
exports.GatewayApiClient = exports.SIGNET_GATEWAY_BASE_URL = exports.MAINNET_GATEWAY_BASE_URL = exports.WBTC_OFT_ADDRESS = void 0;
|
|
42
7
|
const viem_1 = require("viem");
|
|
43
8
|
const chains_1 = require("viem/chains");
|
|
44
|
-
const esplora_1 = require("../esplora");
|
|
45
9
|
const utils_1 = require("../utils");
|
|
46
|
-
const wallet_1 = require("../wallet");
|
|
47
10
|
const abi_1 = require("./abi");
|
|
48
11
|
const base_client_1 = require("./base-client");
|
|
49
12
|
const strategy_1 = __importDefault(require("./strategy"));
|
|
13
|
+
const generated_client_1 = require("./generated-client");
|
|
50
14
|
const tokens_1 = require("./tokens");
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
exports.MAINNET_GATEWAY_BASE_URL = 'https://gateway-api-mainnet.gobob.xyz';
|
|
15
|
+
exports.WBTC_OFT_ADDRESS = '0x0555E30da8f98308EdB960aa94C0Db47230d2B9c';
|
|
16
|
+
exports.MAINNET_GATEWAY_BASE_URL = 'https://gateway-api-staging.gobob.xyz';
|
|
54
17
|
exports.SIGNET_GATEWAY_BASE_URL = 'https://gateway-api-signet.gobob.xyz';
|
|
55
|
-
exports.ORDER_DEADLINE_IN_SECONDS = 30 * 60;
|
|
56
18
|
class GatewayApiClient extends base_client_1.BaseClient {
|
|
57
19
|
chain;
|
|
58
20
|
strategy;
|
|
59
|
-
|
|
21
|
+
api;
|
|
60
22
|
constructor(chainId, options) {
|
|
61
23
|
super();
|
|
62
24
|
switch (chainId) {
|
|
63
25
|
case chains_1.bob.id:
|
|
64
26
|
this.chain = chains_1.bob;
|
|
65
27
|
this.strategy = new strategy_1.default(chains_1.bob, options?.rpcUrl);
|
|
28
|
+
this.api = new generated_client_1.DefaultApi(new generated_client_1.Configuration({
|
|
29
|
+
basePath: exports.MAINNET_GATEWAY_BASE_URL,
|
|
30
|
+
}));
|
|
66
31
|
break;
|
|
67
32
|
case chains_1.bobSepolia.id:
|
|
68
33
|
this.chain = chains_1.bobSepolia;
|
|
69
34
|
this.strategy = new strategy_1.default(chains_1.bobSepolia, options?.rpcUrl);
|
|
70
|
-
this.
|
|
35
|
+
this.api = new generated_client_1.DefaultApi(new generated_client_1.Configuration({
|
|
36
|
+
basePath: exports.SIGNET_GATEWAY_BASE_URL,
|
|
37
|
+
}));
|
|
71
38
|
break;
|
|
72
39
|
default:
|
|
73
40
|
throw new Error('Invalid chain');
|
|
74
41
|
}
|
|
75
42
|
}
|
|
76
|
-
get baseUrl() {
|
|
77
|
-
return this.chain.id === chains_1.bob.id ? exports.MAINNET_GATEWAY_BASE_URL : exports.SIGNET_GATEWAY_BASE_URL;
|
|
78
|
-
}
|
|
79
43
|
get chainId() {
|
|
80
44
|
return this.chain.id;
|
|
81
45
|
}
|
|
82
|
-
async mapRawOrderToOfframpOrder(order) {
|
|
83
|
-
const status = order.status;
|
|
84
|
-
const offrampRegistryAddress = order.offrampRegistryAddress;
|
|
85
|
-
const canOrderBeUnlocked = await this.canOrderBeUnlocked(status, Number(order.orderTimestamp), offrampRegistryAddress);
|
|
86
|
-
return {
|
|
87
|
-
orderId: (0, utils_2.safeBigInt)(order.orderId),
|
|
88
|
-
token: order.token,
|
|
89
|
-
satAmountLocked: (0, utils_2.safeBigInt)(order.satAmountLocked),
|
|
90
|
-
satSolverFeeMax: (0, utils_2.safeBigInt)(order.satFeesMax),
|
|
91
|
-
status,
|
|
92
|
-
orderTimestamp: (0, utils_2.safeNumber)(order.orderTimestamp),
|
|
93
|
-
submitOrderEvmTx: order.submitOrderEvmTx,
|
|
94
|
-
refundedEvmTx: order.refundedEvmTx,
|
|
95
|
-
btcTx: order.btcTx,
|
|
96
|
-
shouldFeesBeBumped: order.shouldFeesBeBumped,
|
|
97
|
-
canOrderBeUnlocked,
|
|
98
|
-
offrampRegistryAddress,
|
|
99
|
-
satAffiliateFee: (0, utils_2.safeBigInt)(order.satAffiliateFee),
|
|
100
|
-
affiliateFeeRecipient: order.affiliateFeeRecipient,
|
|
101
|
-
offrampRegistryVersion: (0, utils_2.safeNumber)(order.offrampRegistryVersion),
|
|
102
|
-
bumpFeeAmountInSats: order.bumpFeeAmountInSats !== null ? (0, utils_2.safeBigInt)(order.bumpFeeAmountInSats) : null,
|
|
103
|
-
userAddress: order.userAddress,
|
|
104
|
-
};
|
|
105
|
-
}
|
|
106
46
|
async getQuote(params) {
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
else if (params.toChain.toString().toLowerCase() === 'bitcoin') {
|
|
118
|
-
const data = await this.getOfframpQuote(params);
|
|
119
|
-
let createOrderGasCost = 0n;
|
|
120
|
-
try {
|
|
121
|
-
createOrderGasCost = await this.getOfframpCreateOrderGasCost(params, data);
|
|
122
|
-
}
|
|
123
|
-
catch (err) {
|
|
124
|
-
console.warn('Failed to get create order gas cost, defaulting to 0', err);
|
|
125
|
-
}
|
|
126
|
-
return {
|
|
127
|
-
type: types_1.GatewayOrderType.Offramp,
|
|
128
|
-
params,
|
|
129
|
-
finalOutputSats: data.amountReceiveInSat,
|
|
130
|
-
finalFeeSats: data.feeBreakdown.overallFeeSats + data.feeBreakdown.affiliateFeeSats,
|
|
131
|
-
data: {
|
|
132
|
-
...data,
|
|
133
|
-
feeBreakdown: {
|
|
134
|
-
...data.feeBreakdown,
|
|
135
|
-
gasFee: createOrderGasCost,
|
|
136
|
-
},
|
|
137
|
-
},
|
|
138
|
-
};
|
|
139
|
-
}
|
|
140
|
-
throw new Error('Invalid quote arguments');
|
|
141
|
-
}
|
|
142
|
-
async getOfframpCreateOrderGasCost(params, offrampQuote) {
|
|
143
|
-
const chain = (0, utils_2.getChainConfig)(params.l0ChainId ?? params.fromChain);
|
|
144
|
-
const publicClient = (0, utils_2.viemClient)(chain);
|
|
145
|
-
if (!params.toUserAddress) {
|
|
146
|
-
params.toUserAddress = this.isSignet
|
|
147
|
-
? 'tb1q0c2qnya702wrna5hqjp83jqqhx8zh5p9au2rqt'
|
|
148
|
-
: '14EvE4gm1yiYSzN8dYBtgYDppsaa1VVfud';
|
|
149
|
-
}
|
|
150
|
-
if (!params.fromUserAddress ||
|
|
151
|
-
((0, viem_1.isAddress)(params.fromUserAddress) && (0, viem_1.isAddressEqual)(params.fromUserAddress, viem_1.zeroAddress))) {
|
|
152
|
-
params.fromUserAddress = '0x1111111111111111111111111111111111111111';
|
|
153
|
-
}
|
|
154
|
-
const [offrampOrder, offrampRegistryAddress, feeValues, gasPrice] = await Promise.all([
|
|
155
|
-
this.createOfframpOrder(offrampQuote, params),
|
|
156
|
-
this.fetchOfframpRegistryAddress(),
|
|
157
|
-
publicClient.estimateFeesPerGas(),
|
|
158
|
-
publicClient.getGasPrice(),
|
|
159
|
-
]);
|
|
160
|
-
const fee = feeValues.maxFeePerGas ?? gasPrice;
|
|
161
|
-
const slots = (0, tokens_1.getTokenSlots)(offrampOrder.quote.token);
|
|
162
|
-
const user = params.fromUserAddress;
|
|
163
|
-
const allowanceSlot = (0, utils_2.computeAllowanceSlot)(user, offrampRegistryAddress, slots.allowanceSlot);
|
|
164
|
-
const balanceSlot = (0, utils_2.computeBalanceSlot)(user, slots.balanceSlot);
|
|
165
|
-
const args = [
|
|
166
|
-
{
|
|
167
|
-
...offrampOrder.offrampArgs[0],
|
|
168
|
-
owner: user,
|
|
169
|
-
},
|
|
170
|
-
];
|
|
171
|
-
const createOrderGasEstimate = await publicClient.estimateContractGas({
|
|
172
|
-
address: offrampRegistryAddress,
|
|
173
|
-
abi: offrampOrder.offrampABI,
|
|
174
|
-
functionName: offrampOrder.offrampFunctionName,
|
|
175
|
-
args,
|
|
176
|
-
account: user,
|
|
177
|
-
stateOverride: [
|
|
178
|
-
{
|
|
179
|
-
address: offrampOrder.quote.token,
|
|
180
|
-
stateDiff: [
|
|
181
|
-
{
|
|
182
|
-
slot: allowanceSlot,
|
|
183
|
-
value: (0, viem_1.toHex)(viem_1.maxUint256),
|
|
184
|
-
},
|
|
185
|
-
{
|
|
186
|
-
slot: balanceSlot,
|
|
187
|
-
value: (0, viem_1.toHex)(viem_1.maxUint256),
|
|
188
|
-
},
|
|
189
|
-
],
|
|
190
|
-
},
|
|
191
|
-
{
|
|
192
|
-
address: user,
|
|
193
|
-
balance: (0, viem_1.parseEther)('1'),
|
|
194
|
-
},
|
|
195
|
-
],
|
|
196
|
-
});
|
|
197
|
-
return createOrderGasEstimate * fee;
|
|
198
|
-
}
|
|
199
|
-
async getOnrampQuote(params) {
|
|
200
|
-
const isMainnet = params.toChain === chains_1.bob.id ||
|
|
201
|
-
(typeof params.toChain === 'string' && params.toChain.toLowerCase() === chains_1.bob.name.toLowerCase());
|
|
202
|
-
const isTestnet = params.toChain === chains_1.bobSepolia.id ||
|
|
203
|
-
(typeof params.toChain === 'string' && params.toChain.toLowerCase() === chains_1.bobSepolia.name.toLowerCase());
|
|
204
|
-
if ((!isMainnet && !isTestnet) ||
|
|
205
|
-
(isMainnet && this.chain.id !== chains_1.bob.id) ||
|
|
206
|
-
(isTestnet && this.chain.id !== chains_1.bobSepolia.id)) {
|
|
207
|
-
throw new Error('Invalid output chain');
|
|
208
|
-
}
|
|
209
|
-
const outputTokenAddress = (0, tokens_1.getTokenAddress)(this.chainId, params.toToken);
|
|
210
|
-
const strategyAddress = params.strategyAddress?.startsWith('0x') ? params.strategyAddress : undefined;
|
|
211
|
-
const url = new URL(`${this.baseUrl}/v4/quote/${outputTokenAddress}`);
|
|
212
|
-
url.searchParams.append('userAddress', `${params.toUserAddress}`);
|
|
213
|
-
if (strategyAddress)
|
|
214
|
-
url.searchParams.append('strategy', strategyAddress);
|
|
215
|
-
if (params.amount)
|
|
216
|
-
url.searchParams.append('satoshis', `${params.amount}`);
|
|
217
|
-
if (params.gasRefill)
|
|
218
|
-
url.searchParams.append('ethAmountToReceive', `${params.gasRefill}`);
|
|
219
|
-
if (params.message)
|
|
220
|
-
url.searchParams.append('strategyExtraData', `${params.message}`);
|
|
221
|
-
if (params.affiliateFeeRecipient && params.affiliateFeeSats) {
|
|
222
|
-
url.searchParams.append('affiliateFee', params.affiliateFeeSats.toString());
|
|
223
|
-
url.searchParams.append('affiliateRecipient', params.affiliateFeeRecipient.toString());
|
|
224
|
-
}
|
|
225
|
-
const response = await this.safeFetch(url, {
|
|
226
|
-
headers: {
|
|
227
|
-
'Content-Type': 'application/json',
|
|
228
|
-
Accept: 'application/json',
|
|
229
|
-
},
|
|
230
|
-
}, 'Failed to get onramp liquidity');
|
|
231
|
-
if (!response.ok) {
|
|
232
|
-
const errorData = await response.json().catch(() => null);
|
|
233
|
-
const errorMessage = errorData?.message || 'Failed to get onramp liquidity';
|
|
234
|
-
throw new Error(errorMessage);
|
|
235
|
-
}
|
|
236
|
-
const jsonResponse = await response.json();
|
|
237
|
-
if (!jsonResponse.orderDetails) {
|
|
238
|
-
const errorData = jsonResponse.errorData;
|
|
239
|
-
const apiMessage = errorData?.message;
|
|
240
|
-
const errorMessage = apiMessage || 'Failed to get onramp quote';
|
|
241
|
-
throw new Error(errorMessage);
|
|
242
|
-
}
|
|
243
|
-
const quote = {
|
|
244
|
-
...jsonResponse,
|
|
245
|
-
orderDetails: (0, utils_2.convertOrderDetailsRawToOrderDetails)(jsonResponse.orderDetails),
|
|
246
|
-
feeBreakdown: (0, utils_2.convertOnrampFeeBreakdown)(jsonResponse.feeBreakdown),
|
|
247
|
-
};
|
|
248
|
-
return {
|
|
249
|
-
...quote,
|
|
250
|
-
outputSatoshis: quote.satoshis - quote.feeBreakdown.overallFeeSats - quote.feeBreakdown.affiliateFeeSats,
|
|
251
|
-
baseToken: (0, tokens_1.getTokenDetails)(this.chainId, quote.baseTokenAddress),
|
|
252
|
-
outputToken: quote.strategyAddress ? (0, tokens_1.getTokenDetails)(this.chainId, outputTokenAddress) : undefined,
|
|
253
|
-
};
|
|
254
|
-
}
|
|
255
|
-
async getOfframpQuote(params) {
|
|
256
|
-
if (!params.fromToken) {
|
|
257
|
-
throw new Error('`fromToken` must be specified for offramp');
|
|
258
|
-
}
|
|
259
|
-
const tokenAddress = (0, tokens_1.getTokenAddress)(this.chainId, params.fromToken);
|
|
260
|
-
const quote = await this.fetchOfframpQuote(tokenAddress, BigInt(params.amount || 0), params.fromUserAddress, params.toUserAddress, params.affiliateFeeRecipient, params.affiliateFeeSats);
|
|
261
|
-
return quote;
|
|
262
|
-
}
|
|
263
|
-
async fetchOfframpRegistryAddress() {
|
|
264
|
-
const response = await this.safeFetch(`${this.baseUrl}/offramp-registry-address`, undefined, 'Failed to fetch offramp registry contract address');
|
|
265
|
-
if (!response.ok) {
|
|
266
|
-
const errorData = await response.json().catch(() => null);
|
|
267
|
-
const apiMessage = errorData?.message;
|
|
268
|
-
const errorMessage = apiMessage || 'Failed to fetch offramp registry contract';
|
|
269
|
-
throw new Error(errorMessage);
|
|
270
|
-
}
|
|
271
|
-
return response.text();
|
|
272
|
-
}
|
|
273
|
-
async fetchOfframpLiquidity(token, userAddress) {
|
|
274
|
-
const tokenAddress = (0, tokens_1.getTokenAddress)(this.chainId, token);
|
|
275
|
-
const finalUserAddress = userAddress ?? viem_1.zeroAddress;
|
|
276
|
-
const queryParams = new URLSearchParams({
|
|
277
|
-
tokenAddress: tokenAddress,
|
|
278
|
-
userAddress: finalUserAddress,
|
|
279
|
-
});
|
|
280
|
-
const requestUrl = `${this.baseUrl}/v2/offramp-liquidity?${queryParams}`;
|
|
281
|
-
const response = await this.safeFetch(requestUrl, undefined, 'Failed to get offramp v2 liquidity');
|
|
282
|
-
if (!response.ok) {
|
|
283
|
-
const errorData = await response.json().catch(() => null);
|
|
284
|
-
const errorMessage = errorData?.message || 'Failed to get offramp v2 liquidity';
|
|
285
|
-
throw new Error(errorMessage);
|
|
286
|
-
}
|
|
287
|
-
const rawLiquidity = await response.json();
|
|
288
|
-
return {
|
|
289
|
-
tokenAddress: rawLiquidity.tokenAddress,
|
|
290
|
-
maxOrderAmountInSats: BigInt(rawLiquidity.maxOrderAmountInSats),
|
|
291
|
-
totalOfframpLiquidityInSats: BigInt(rawLiquidity.totalOfframpLiquidityInSats),
|
|
292
|
-
minimumOfframpQuote: {
|
|
293
|
-
minimumAmountInSats: BigInt(rawLiquidity.minimumOfframpQuote.minimumAmountInSats),
|
|
294
|
-
calculatedForFeeRate: BigInt(rawLiquidity.minimumOfframpQuote.calculatedForFeeRate),
|
|
295
|
-
},
|
|
296
|
-
};
|
|
297
|
-
}
|
|
298
|
-
async fetchOnrampLiquidity(token, userAddress, gasRefill) {
|
|
299
|
-
const tokenAddress = (0, tokens_1.getTokenAddress)(this.chainId, token.toLowerCase());
|
|
300
|
-
const finalUserAddress = userAddress ?? viem_1.zeroAddress;
|
|
301
|
-
const queryParams = new URLSearchParams({
|
|
302
|
-
tokenAddress: tokenAddress,
|
|
303
|
-
userAddress: finalUserAddress,
|
|
304
|
-
});
|
|
305
|
-
if (gasRefill) {
|
|
306
|
-
queryParams.append('gasRefill', gasRefill.toString());
|
|
307
|
-
}
|
|
308
|
-
const requestUrl = `${this.baseUrl}/onramp-liquidity?${queryParams.toString()}`;
|
|
309
|
-
const response = await this.safeFetch(requestUrl, undefined, 'Failed to get onramp liquidity');
|
|
310
|
-
if (!response.ok) {
|
|
311
|
-
const errorData = await response.json().catch(() => null);
|
|
312
|
-
const errorMessage = errorData?.message || 'Failed to get onramp liquidity';
|
|
313
|
-
throw new Error(errorMessage);
|
|
314
|
-
}
|
|
315
|
-
const rawLiquidity = await response.json();
|
|
316
|
-
return {
|
|
317
|
-
tokenAddress: rawLiquidity.tokenAddress,
|
|
318
|
-
maxOrderAmountInSats: BigInt(rawLiquidity.maxOrderAmountInSats),
|
|
319
|
-
totalOnrampLiquidityInSats: BigInt(rawLiquidity.totalOnrampLiquidityInSats),
|
|
320
|
-
minSatsAmount: BigInt(rawLiquidity.minSatsAmount),
|
|
321
|
-
};
|
|
322
|
-
}
|
|
323
|
-
async fetchOfframpQuote(token, amountInToken, userAddress, toUserAddress, affiliateFeeRecipient, affiliateFeeSats) {
|
|
324
|
-
const queryParams = new URLSearchParams({
|
|
325
|
-
amountInWrappedToken: amountInToken.toString(),
|
|
326
|
-
token,
|
|
327
|
-
userAddress: userAddress,
|
|
328
|
-
});
|
|
329
|
-
if (toUserAddress) {
|
|
330
|
-
queryParams.append('userBtcAddress', toUserAddress);
|
|
331
|
-
}
|
|
332
|
-
if (affiliateFeeRecipient && affiliateFeeSats) {
|
|
333
|
-
queryParams.append('affiliateFee', affiliateFeeSats.toString());
|
|
334
|
-
queryParams.append('affiliateRecipient', affiliateFeeRecipient.toString());
|
|
335
|
-
}
|
|
336
|
-
const response = await this.safeFetch(`${this.baseUrl}/offramp-quote?${queryParams}`, undefined, 'Failed to get offramp quote');
|
|
337
|
-
if (!response.ok) {
|
|
338
|
-
const errorData = await response.json().catch(() => null);
|
|
339
|
-
const apiMessage = errorData?.message;
|
|
340
|
-
const errorMessage = apiMessage || `Failed to get offramp quote`;
|
|
341
|
-
throw new Error(`${errorMessage}`);
|
|
342
|
-
}
|
|
343
|
-
const rawQuote = await response.json();
|
|
344
|
-
const currentUnixTimeInSec = Math.floor(Date.now() / 1000);
|
|
345
|
-
const deadline = currentUnixTimeInSec + exports.ORDER_DEADLINE_IN_SECONDS;
|
|
346
|
-
const normalizedAffiliateFeeRecipient = affiliateFeeRecipient ?? viem_1.zeroAddress;
|
|
347
|
-
return {
|
|
348
|
-
amountLockInSat: rawQuote.amountLockInSat,
|
|
349
|
-
deadline: deadline,
|
|
350
|
-
token: token,
|
|
351
|
-
feeBreakdown: {
|
|
352
|
-
overallFeeSats: rawQuote.feeBreakdown.overallFeeSats,
|
|
353
|
-
inclusionFeeSats: rawQuote.feeBreakdown.inclusionFeeSats,
|
|
354
|
-
protocolFeeSats: rawQuote.feeBreakdown.protocolFeeSats,
|
|
355
|
-
affiliateFeeSats: rawQuote.feeBreakdown.affiliateFeeSats,
|
|
356
|
-
fastestFeeRate: rawQuote.feeBreakdown.fastestFeeRate,
|
|
357
|
-
},
|
|
358
|
-
amountReceiveInSat: rawQuote.amountLockInSat -
|
|
359
|
-
rawQuote.feeBreakdown.overallFeeSats -
|
|
360
|
-
rawQuote.feeBreakdown.affiliateFeeSats,
|
|
361
|
-
affiliateFeeRecipient: normalizedAffiliateFeeRecipient,
|
|
362
|
-
};
|
|
363
|
-
}
|
|
364
|
-
async createOfframpOrder(quote, params) {
|
|
365
|
-
let bitcoinNetwork = bitcoin.networks.regtest;
|
|
366
|
-
if (this.chain.id == chains_1.bob.id) {
|
|
367
|
-
bitcoinNetwork = bitcoin.networks.bitcoin;
|
|
368
|
-
}
|
|
369
|
-
else if (this.chain.id == chains_1.bobSepolia.id) {
|
|
370
|
-
bitcoinNetwork = bitcoin.networks.testnet;
|
|
371
|
-
}
|
|
372
|
-
const receiverAddress = (0, utils_2.toHexScriptPubKey)(params.toUserAddress, bitcoinNetwork);
|
|
373
|
-
return {
|
|
374
|
-
quote,
|
|
375
|
-
offrampABI: abi_1.offrampCallerV2,
|
|
376
|
-
feeBreakdown: quote.feeBreakdown,
|
|
377
|
-
offrampFunctionName: 'createOrderV2',
|
|
378
|
-
offrampArgs: [
|
|
379
|
-
{
|
|
380
|
-
satAmountToLock: BigInt(quote.amountLockInSat),
|
|
381
|
-
satSolverFeeMax: BigInt(quote.feeBreakdown.overallFeeSats),
|
|
382
|
-
satAffiliateFee: BigInt(quote.feeBreakdown.affiliateFeeSats),
|
|
383
|
-
affiliateFeeRecipient: quote.affiliateFeeRecipient,
|
|
384
|
-
creationDeadline: BigInt(quote.deadline),
|
|
385
|
-
outputScript: receiverAddress,
|
|
386
|
-
token: quote.token,
|
|
387
|
-
owner: params.fromUserAddress,
|
|
388
|
-
},
|
|
389
|
-
],
|
|
390
|
-
};
|
|
391
|
-
}
|
|
392
|
-
async bumpFeeForOfframpOrder({ orderId, offrampRegistryAddress, walletClient, publicClient, }) {
|
|
393
|
-
const orderDetails = await this.fetchOfframpOrder(orderId, offrampRegistryAddress);
|
|
394
|
-
if (orderDetails.status !== 'Active') {
|
|
395
|
-
throw new Error(`Offramp order needs to be Active for bumping fees`);
|
|
396
|
-
}
|
|
397
|
-
if (orderDetails.bumpFeeAmountInSats === null) {
|
|
398
|
-
throw new Error(`No need to bump fees, the current fees are sufficient`);
|
|
399
|
-
}
|
|
400
|
-
const { request } = await publicClient.simulateContract({
|
|
401
|
-
address: offrampRegistryAddress,
|
|
402
|
-
abi: abi_1.offrampCallerV2,
|
|
403
|
-
functionName: 'bumpFeeOfExistingOrder',
|
|
404
|
-
args: [orderId, BigInt(orderDetails.bumpFeeAmountInSats)],
|
|
405
|
-
account: walletClient.account,
|
|
406
|
-
});
|
|
407
|
-
const transactionHash = await walletClient.writeContract(request);
|
|
408
|
-
await publicClient.waitForTransactionReceipt({ hash: transactionHash });
|
|
409
|
-
return transactionHash;
|
|
410
|
-
}
|
|
411
|
-
async unlockOfframpOrder({ orderId, receiver, offrampRegistryAddress, walletClient, publicClient, }) {
|
|
412
|
-
const orderDetails = await this.fetchOfframpOrder(orderId, offrampRegistryAddress);
|
|
413
|
-
if (orderDetails.status == 'Processed' || orderDetails.status == 'Refunded') {
|
|
414
|
-
throw new Error(`Offramp order already processed / refunded`);
|
|
415
|
-
}
|
|
416
|
-
if (!(await this.canOrderBeUnlocked(orderDetails.status, orderDetails.orderTimestamp, offrampRegistryAddress))) {
|
|
417
|
-
throw new Error(`Offramp order is still within the 7-day claim delay and cannot be unlocked yet.`);
|
|
418
|
-
}
|
|
419
|
-
const { request } = await publicClient.simulateContract({
|
|
420
|
-
address: offrampRegistryAddress,
|
|
421
|
-
abi: abi_1.offrampCallerV2,
|
|
422
|
-
functionName: 'refundOrder',
|
|
423
|
-
args: [orderId, receiver],
|
|
424
|
-
account: walletClient.account,
|
|
47
|
+
return this.api.getQuote({
|
|
48
|
+
srcChain: params.fromChain.toString(),
|
|
49
|
+
dstChain: params.toChain.toString(),
|
|
50
|
+
sender: params.fromUserAddress?.toString() || '',
|
|
51
|
+
recipient: params.toUserAddress.toString(),
|
|
52
|
+
srcToken: params.fromToken.toString(),
|
|
53
|
+
dstToken: params.toToken.toString(),
|
|
54
|
+
amount: params.amount.toString(),
|
|
55
|
+
slippage: params.maxSlippage?.toString() || '0',
|
|
56
|
+
gasRefill: params.gasRefill?.toString(),
|
|
425
57
|
});
|
|
426
|
-
const transactionHash = await walletClient.writeContract(request);
|
|
427
|
-
await publicClient.waitForTransactionReceipt({ hash: transactionHash });
|
|
428
|
-
return transactionHash;
|
|
429
|
-
}
|
|
430
|
-
async getOfframpOrders(userAddress) {
|
|
431
|
-
const response = await this.safeFetch(`${this.baseUrl}/offramp-orders/${userAddress}`, undefined, 'Failed to fetch offramp orders');
|
|
432
|
-
const rawOrders = await response.json();
|
|
433
|
-
return Promise.all(rawOrders.map((order) => this.mapRawOrderToOfframpOrder(order)));
|
|
434
|
-
}
|
|
435
|
-
async canOrderBeUnlocked(status, orderTimestamp, offrampRegistryAddress) {
|
|
436
|
-
if (status === 'Active' && Math.floor(Date.now() / 1000) - orderTimestamp >= 60) {
|
|
437
|
-
return true;
|
|
438
|
-
}
|
|
439
|
-
if (status !== 'Accepted') {
|
|
440
|
-
return false;
|
|
441
|
-
}
|
|
442
|
-
const nowInSec = Math.floor(Date.now() / 1000);
|
|
443
|
-
const publicClient = (0, utils_2.viemClient)(this.chain);
|
|
444
|
-
const claimDelay = await publicClient.readContract({
|
|
445
|
-
address: offrampRegistryAddress,
|
|
446
|
-
abi: abi_1.claimDelayAbi,
|
|
447
|
-
functionName: 'CLAIM_DELAY',
|
|
448
|
-
});
|
|
449
|
-
return orderTimestamp + Number(claimDelay) <= nowInSec;
|
|
450
|
-
}
|
|
451
|
-
async fetchOfframpOrder(orderId, registryAddress) {
|
|
452
|
-
const queryParams = new URLSearchParams({
|
|
453
|
-
registryAddress: registryAddress.toString(),
|
|
454
|
-
orderId: orderId.toString(),
|
|
455
|
-
});
|
|
456
|
-
const response = await this.safeFetch(`${this.baseUrl}/offramp-order?${queryParams}`, undefined, 'Failed to fetch offramp order');
|
|
457
|
-
if (!response.ok) {
|
|
458
|
-
const errorData = await response.json().catch(() => null);
|
|
459
|
-
const apiMessage = errorData?.message;
|
|
460
|
-
const errorMessage = apiMessage || `Failed to get offramp order (status: ${response.status} ${response.statusText})`;
|
|
461
|
-
throw new Error(`${errorMessage}`);
|
|
462
|
-
}
|
|
463
|
-
const offrampRawOrder = await response.json();
|
|
464
|
-
return await this.mapRawOrderToOfframpOrder(offrampRawOrder);
|
|
465
|
-
}
|
|
466
|
-
async startOnrampOrder(gatewayQuote, params) {
|
|
467
|
-
if (!params.toUserAddress || !(0, viem_1.isAddress)(params.toUserAddress)) {
|
|
468
|
-
throw new Error('Invalid user address');
|
|
469
|
-
}
|
|
470
|
-
const request = {
|
|
471
|
-
gatewayAddress: gatewayQuote.gatewayAddress,
|
|
472
|
-
strategyAddress: gatewayQuote.strategyAddress,
|
|
473
|
-
userAddress: params.toUserAddress,
|
|
474
|
-
gatewayExtraData: undefined,
|
|
475
|
-
strategyExtraData: params.message,
|
|
476
|
-
satoshis: gatewayQuote.satoshis,
|
|
477
|
-
campaignId: params.campaignId,
|
|
478
|
-
orderDetails: (0, utils_2.convertOrderDetailsToRaw)(gatewayQuote.orderDetails),
|
|
479
|
-
};
|
|
480
|
-
const response = await this.safeFetch(`${this.baseUrl}/v4/order`, {
|
|
481
|
-
method: 'POST',
|
|
482
|
-
headers: {
|
|
483
|
-
'Content-Type': 'application/json',
|
|
484
|
-
Accept: 'application/json',
|
|
485
|
-
},
|
|
486
|
-
body: JSON.stringify(request),
|
|
487
|
-
}, 'Failed to create order');
|
|
488
|
-
if (!response.ok) {
|
|
489
|
-
const errorData = await response.json().catch(() => null);
|
|
490
|
-
const apiMessage = errorData?.message;
|
|
491
|
-
const errorMessage = apiMessage || 'Failed to create order';
|
|
492
|
-
throw new Error(errorMessage);
|
|
493
|
-
}
|
|
494
|
-
const data = await response.json();
|
|
495
|
-
let psbtBase64 = '';
|
|
496
|
-
if (params.fromUserAddress &&
|
|
497
|
-
typeof params.fromChain === 'string' &&
|
|
498
|
-
params.fromChain.toLowerCase() === 'bitcoin') {
|
|
499
|
-
psbtBase64 = await (0, wallet_1.createBitcoinPsbt)(params.fromUserAddress, gatewayQuote.bitcoinAddress, gatewayQuote.satoshis, params.fromUserPublicKey, data.opReturnHash, params.feeRate, gatewayQuote.txProofDifficultyFactor, this.isSignet);
|
|
500
|
-
return {
|
|
501
|
-
uuid: data.uuid,
|
|
502
|
-
opReturnHash: data.opReturnHash,
|
|
503
|
-
bitcoinAddress: gatewayQuote.bitcoinAddress,
|
|
504
|
-
satoshis: gatewayQuote.satoshis,
|
|
505
|
-
psbtBase64,
|
|
506
|
-
};
|
|
507
|
-
}
|
|
508
|
-
throw new Error('Failed to create bitcoin psbt due to an unexpected error.');
|
|
509
58
|
}
|
|
510
59
|
async executeQuote({ quote, walletClient, publicClient, btcSigner, }) {
|
|
511
|
-
if (
|
|
512
|
-
const { params, data } = quote;
|
|
513
|
-
const esploraClient = new esplora_1.EsploraClient(this.chain.id === chains_1.bob.id ? bitcoin_address_validation_1.Network.mainnet : bitcoin_address_validation_1.Network.signet);
|
|
514
|
-
const availableBtcBalance = await esploraClient.getBalance(params.fromUserAddress);
|
|
515
|
-
if (availableBtcBalance.total < BigInt(data.satoshis)) {
|
|
516
|
-
throw new Error(`Insufficient BTC balance in address ${data.bitcoinAddress}. Required: ${(0, utils_2.formatBtc)(BigInt(data.satoshis))}, Got: ${(0, utils_2.formatBtc)(BigInt(availableBtcBalance.total))}`);
|
|
517
|
-
}
|
|
518
|
-
const { uuid, psbtBase64, bitcoinAddress, satoshis, opReturnHash } = await this.startOnrampOrder(data, params);
|
|
60
|
+
if ((0, generated_client_1.instanceOfGatewayQuoteOneOf)(quote)) {
|
|
519
61
|
if (!btcSigner) {
|
|
520
62
|
throw new Error(`btcSigner is required for onramp order`);
|
|
521
63
|
}
|
|
64
|
+
const { id, psbt } = await this.api.startOnramp({ gatewayOnrampQuote: quote.onramp });
|
|
522
65
|
let bitcoinTxHex;
|
|
523
66
|
if (btcSigner.sendBitcoin) {
|
|
524
|
-
bitcoinTxHex =
|
|
525
|
-
from: params.fromUserAddress,
|
|
526
|
-
to: bitcoinAddress,
|
|
527
|
-
value: (0, utils_2.formatBtc)(BigInt(satoshis)),
|
|
528
|
-
opReturn: opReturnHash,
|
|
529
|
-
isSignet: this.isSignet,
|
|
530
|
-
});
|
|
67
|
+
bitcoinTxHex = '';
|
|
531
68
|
}
|
|
532
69
|
else if (btcSigner.signAllInputs) {
|
|
533
|
-
bitcoinTxHex = await btcSigner.signAllInputs(
|
|
70
|
+
bitcoinTxHex = await btcSigner.signAllInputs(psbt);
|
|
534
71
|
}
|
|
535
72
|
else {
|
|
536
73
|
throw new Error('btcSigner must implement either sendBitcoin or signAllInputs method');
|
|
537
74
|
}
|
|
538
75
|
if (!bitcoinTxHex)
|
|
539
76
|
throw new Error('Failed to get signed transaction');
|
|
540
|
-
const txId = await this.
|
|
77
|
+
const txId = await this.api.registerBtcTx({ registerBtcTx: { bitcoinTx: bitcoinTxHex, id } });
|
|
541
78
|
return txId;
|
|
542
79
|
}
|
|
543
|
-
else if (
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
const
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
{
|
|
567
|
-
address: tokenAddress,
|
|
568
|
-
abi: viem_1.erc20Abi,
|
|
569
|
-
functionName: 'decimals',
|
|
570
|
-
},
|
|
571
|
-
],
|
|
572
|
-
}),
|
|
573
|
-
]);
|
|
574
|
-
const fee = feeValues.maxFeePerGas ?? gasPrice;
|
|
80
|
+
else if ((0, generated_client_1.instanceOfGatewayQuoteOneOf1)(quote)) {
|
|
81
|
+
if (!walletClient.account) {
|
|
82
|
+
throw new Error(`walletClient is required for offramp order`);
|
|
83
|
+
}
|
|
84
|
+
const accountAddress = walletClient.account.address;
|
|
85
|
+
const tokenAddress = exports.WBTC_OFT_ADDRESS;
|
|
86
|
+
const spenderAddress = quote.offramp.tx.to;
|
|
87
|
+
const [allowance, decimals] = await publicClient.multicall({
|
|
88
|
+
allowFailure: false,
|
|
89
|
+
contracts: [
|
|
90
|
+
{
|
|
91
|
+
address: tokenAddress,
|
|
92
|
+
abi: viem_1.erc20Abi,
|
|
93
|
+
functionName: 'allowance',
|
|
94
|
+
args: [accountAddress, spenderAddress],
|
|
95
|
+
},
|
|
96
|
+
{
|
|
97
|
+
address: tokenAddress,
|
|
98
|
+
abi: viem_1.erc20Abi,
|
|
99
|
+
functionName: 'decimals',
|
|
100
|
+
},
|
|
101
|
+
],
|
|
102
|
+
});
|
|
575
103
|
if (decimals < 8) {
|
|
576
104
|
throw new Error('Tokens with less than 8 decimals are not supported');
|
|
577
105
|
}
|
|
578
106
|
const multiplier = 10n ** BigInt(decimals - 8);
|
|
579
|
-
const requiredAmount = BigInt(
|
|
107
|
+
const requiredAmount = BigInt(quote.offramp.inputAmount) * multiplier;
|
|
580
108
|
const needsApproval = requiredAmount > allowance;
|
|
581
109
|
if (needsApproval) {
|
|
582
110
|
const { request } = await publicClient.simulateContract({
|
|
@@ -584,36 +112,22 @@ class GatewayApiClient extends base_client_1.BaseClient {
|
|
|
584
112
|
address: tokenAddress,
|
|
585
113
|
abi: viem_1.erc20Abi,
|
|
586
114
|
functionName: 'approve',
|
|
587
|
-
args: [
|
|
115
|
+
args: [spenderAddress, viem_1.maxUint256],
|
|
588
116
|
});
|
|
589
117
|
const approveTxHash = await walletClient.writeContract(request);
|
|
590
118
|
await publicClient.waitForTransactionReceipt({ hash: approveTxHash });
|
|
591
119
|
}
|
|
592
|
-
const
|
|
593
|
-
? await publicClient.getBalance({ address: accountAddress })
|
|
594
|
-
: ethBalance;
|
|
595
|
-
const createOrderGasEstimate = await publicClient.estimateContractGas({
|
|
596
|
-
address: offrampRegistryAddress,
|
|
597
|
-
abi: offrampOrder.offrampABI,
|
|
598
|
-
functionName: offrampOrder.offrampFunctionName,
|
|
599
|
-
args: offrampOrder.offrampArgs,
|
|
600
|
-
account: walletClient.account,
|
|
601
|
-
});
|
|
602
|
-
const createOrderGasCost = createOrderGasEstimate * fee;
|
|
603
|
-
if (balanceForCreate < createOrderGasCost) {
|
|
604
|
-
throw new Error(`Insufficient ETH balance for gas fees. Required: ${createOrderGasCost} wei, Available: ${ethBalance} wei`);
|
|
605
|
-
}
|
|
606
|
-
const { request } = await publicClient.simulateContract({
|
|
120
|
+
const transactionHash = await walletClient.sendTransaction({
|
|
607
121
|
account: walletClient.account,
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
args: offrampOrder.offrampArgs,
|
|
122
|
+
data: quote.offramp.tx.data,
|
|
123
|
+
to: spenderAddress,
|
|
124
|
+
value: BigInt(quote.offramp.tx.value || 0),
|
|
612
125
|
});
|
|
613
|
-
const transactionHash = await walletClient.writeContract(request);
|
|
614
126
|
await publicClient?.waitForTransactionReceipt({ hash: transactionHash });
|
|
615
127
|
return transactionHash;
|
|
616
128
|
}
|
|
129
|
+
else if ((0, generated_client_1.instanceOfGatewayQuoteOneOf2)(quote)) {
|
|
130
|
+
}
|
|
617
131
|
throw new Error('Invalid quote type');
|
|
618
132
|
}
|
|
619
133
|
async executeStrategy({ walletClient, publicClient, ...params }) {
|
|
@@ -645,191 +159,8 @@ class GatewayApiClient extends base_client_1.BaseClient {
|
|
|
645
159
|
await publicClient?.waitForTransactionReceipt({ hash: transactionHash });
|
|
646
160
|
return transactionHash;
|
|
647
161
|
}
|
|
648
|
-
async
|
|
649
|
-
|
|
650
|
-
let bitcoinTxHex;
|
|
651
|
-
if (bitcoinTxOrId.length === 64) {
|
|
652
|
-
const esploraClient = new esplora_1.EsploraClient(this.chain.id === chains_1.bob.id ? bitcoin_address_validation_1.Network.mainnet : bitcoin_address_validation_1.Network.signet);
|
|
653
|
-
bitcoinTxHex = await esploraClient.getTransactionHex(bitcoinTxOrId);
|
|
654
|
-
}
|
|
655
|
-
else {
|
|
656
|
-
bitcoinTxHex = bitcoinTxOrId;
|
|
657
|
-
}
|
|
658
|
-
const response = await this.safeFetch(`${this.baseUrl}/order/${uuid}`, {
|
|
659
|
-
method: 'PATCH',
|
|
660
|
-
headers: {
|
|
661
|
-
'Content-Type': 'application/json',
|
|
662
|
-
Accept: 'application/json',
|
|
663
|
-
},
|
|
664
|
-
body: JSON.stringify({ bitcoinTx: bitcoinTxHex }),
|
|
665
|
-
}, 'Failed to update order');
|
|
666
|
-
if (!response.ok) {
|
|
667
|
-
const errorData = await response.json().catch(() => null);
|
|
668
|
-
const apiMessage = errorData?.message;
|
|
669
|
-
const errorMessage = apiMessage || `Failed to update order`;
|
|
670
|
-
throw new Error(errorMessage);
|
|
671
|
-
}
|
|
672
|
-
return response.json();
|
|
673
|
-
}
|
|
674
|
-
async getOnrampOrders(userAddress) {
|
|
675
|
-
const chainId = this.chainId;
|
|
676
|
-
const response = await this.safeFetch(`${this.baseUrl}/orders/${userAddress}`, undefined, 'Failed to fetch onramp orders');
|
|
677
|
-
const orders = await response.json();
|
|
678
|
-
return orders.map((order) => {
|
|
679
|
-
const outputTokenAddress = order.outputTokenAddress ?? order.tokensReceived?.[0]?.tokenAddress ?? null;
|
|
680
|
-
const outputTokenAmount = order.outputTokenAmount ?? order.tokensReceived?.[0]?.amount ?? null;
|
|
681
|
-
function getFinal(base, output) {
|
|
682
|
-
return order.status
|
|
683
|
-
? order.strategyAddress
|
|
684
|
-
? output
|
|
685
|
-
? output
|
|
686
|
-
: base
|
|
687
|
-
: base
|
|
688
|
-
: order.strategyAddress
|
|
689
|
-
? output
|
|
690
|
-
: base;
|
|
691
|
-
}
|
|
692
|
-
const getTokenAddress = () => {
|
|
693
|
-
return getFinal(order.baseTokenAddress, outputTokenAddress);
|
|
694
|
-
};
|
|
695
|
-
const getTokenAmount = () => {
|
|
696
|
-
let amount = order.satoshis - order.fee;
|
|
697
|
-
const token = getToken();
|
|
698
|
-
if (token && !outputTokenAmount) {
|
|
699
|
-
amount *= Math.pow(10, token.decimals - 8);
|
|
700
|
-
}
|
|
701
|
-
return getFinal(amount, outputTokenAmount);
|
|
702
|
-
};
|
|
703
|
-
const getToken = () => {
|
|
704
|
-
return (0, tokens_1.getTokenDetails)(chainId, getTokenAddress());
|
|
705
|
-
};
|
|
706
|
-
const getConfirmations = async (esploraClient, latestHeight) => {
|
|
707
|
-
const txStatus = await esploraClient.getTransactionStatus(order.txid);
|
|
708
|
-
if (!latestHeight) {
|
|
709
|
-
latestHeight = await esploraClient.getLatestHeight();
|
|
710
|
-
}
|
|
711
|
-
return txStatus.confirmed ? latestHeight - txStatus.block_height + 1 : 0;
|
|
712
|
-
};
|
|
713
|
-
const orderDetails = order.orderDetails
|
|
714
|
-
? (0, utils_2.convertOrderDetailsRawToOrderDetails)(order.orderDetails)
|
|
715
|
-
: undefined;
|
|
716
|
-
const getOutputTokens = () => {
|
|
717
|
-
const tokens = order.tokensReceived
|
|
718
|
-
? order.tokensReceived
|
|
719
|
-
: outputTokenAmount && outputTokenAddress
|
|
720
|
-
? [{ amount: outputTokenAmount, tokenAddress: outputTokenAddress }]
|
|
721
|
-
: [];
|
|
722
|
-
return tokens
|
|
723
|
-
.map(({ amount, tokenAddress }) => ({
|
|
724
|
-
amount: amount,
|
|
725
|
-
token: (0, tokens_1.getTokenDetails)(chainId, tokenAddress),
|
|
726
|
-
}))
|
|
727
|
-
.filter((x) => x.token);
|
|
728
|
-
};
|
|
729
|
-
const getTokens = () => {
|
|
730
|
-
const tokens = order.tokensReceived
|
|
731
|
-
? order.tokensReceived
|
|
732
|
-
: [{ amount: getTokenAmount(), tokenAddress: getTokenAddress() }];
|
|
733
|
-
return tokens.map(({ amount, tokenAddress }) => ({
|
|
734
|
-
amount: amount,
|
|
735
|
-
token: (0, tokens_1.getTokenDetails)(chainId, tokenAddress),
|
|
736
|
-
}));
|
|
737
|
-
};
|
|
738
|
-
return {
|
|
739
|
-
...order,
|
|
740
|
-
orderDetails,
|
|
741
|
-
gasRefill: order.satsToConvertToEth,
|
|
742
|
-
baseToken: (0, tokens_1.getTokenDetails)(chainId, order.baseTokenAddress),
|
|
743
|
-
outputToken: order.outputTokenAddress ? (0, tokens_1.getTokenDetails)(chainId, order.outputTokenAddress) : undefined,
|
|
744
|
-
getTokenAddress,
|
|
745
|
-
getToken,
|
|
746
|
-
getTokenAmount,
|
|
747
|
-
getTokens,
|
|
748
|
-
getOutputTokens,
|
|
749
|
-
getConfirmations,
|
|
750
|
-
async getStatus(esploraClient, latestHeight) {
|
|
751
|
-
const confirmations = await getConfirmations(esploraClient, latestHeight);
|
|
752
|
-
const hasEnoughConfirmations = confirmations >= order.txProofDifficultyFactor;
|
|
753
|
-
const data = { confirmations };
|
|
754
|
-
if (!hasEnoughConfirmations) {
|
|
755
|
-
return { confirmed: false, data };
|
|
756
|
-
}
|
|
757
|
-
return {
|
|
758
|
-
success: !(order.strategyAddress && order.strategyFailed === true),
|
|
759
|
-
data,
|
|
760
|
-
};
|
|
761
|
-
},
|
|
762
|
-
};
|
|
763
|
-
});
|
|
764
|
-
}
|
|
765
|
-
async getStrategies() {
|
|
766
|
-
const response = await this.safeFetch(`${this.baseUrl}/strategies`, undefined, 'Failed to fetch gateway strategies');
|
|
767
|
-
const chainName = this.chain.name;
|
|
768
|
-
const chainId = this.chainId;
|
|
769
|
-
const strategies = await response.json();
|
|
770
|
-
return strategies.map((strategy) => {
|
|
771
|
-
const strategySlug = (0, utils_2.slugify)(strategy.strategyName);
|
|
772
|
-
const inputToken = (0, tokens_1.getTokenDetails)(chainId, strategy.inputTokenAddress);
|
|
773
|
-
if (!inputToken) {
|
|
774
|
-
throw new Error(`Token not found: ${strategy.inputTokenAddress} on chain ${chainId}`);
|
|
775
|
-
}
|
|
776
|
-
const outputToken = strategy.outputTokenAddress
|
|
777
|
-
? (0, tokens_1.getTokenDetails)(chainId, strategy.outputTokenAddress)
|
|
778
|
-
: undefined;
|
|
779
|
-
return {
|
|
780
|
-
id: strategySlug,
|
|
781
|
-
type: 'deposit',
|
|
782
|
-
address: strategy.strategyAddress,
|
|
783
|
-
method: '',
|
|
784
|
-
chain: {
|
|
785
|
-
id: '',
|
|
786
|
-
chainId: chainId,
|
|
787
|
-
slug: chainName,
|
|
788
|
-
name: chainName,
|
|
789
|
-
logo: '',
|
|
790
|
-
type: 'evm',
|
|
791
|
-
singleChainSwap: true,
|
|
792
|
-
singleChainStaking: true,
|
|
793
|
-
},
|
|
794
|
-
integration: {
|
|
795
|
-
type: strategy.strategyType,
|
|
796
|
-
slug: strategySlug,
|
|
797
|
-
name: strategy.strategyName,
|
|
798
|
-
logo: strategy.projectLogo || outputToken?.logoURI || '',
|
|
799
|
-
monetization: false,
|
|
800
|
-
},
|
|
801
|
-
inputToken: {
|
|
802
|
-
symbol: inputToken.symbol,
|
|
803
|
-
address: inputToken.address,
|
|
804
|
-
logo: inputToken.logoURI,
|
|
805
|
-
decimals: inputToken.decimals,
|
|
806
|
-
chain: chainName,
|
|
807
|
-
},
|
|
808
|
-
outputToken: outputToken
|
|
809
|
-
? {
|
|
810
|
-
symbol: outputToken.symbol,
|
|
811
|
-
address: outputToken.address,
|
|
812
|
-
logo: outputToken.logoURI,
|
|
813
|
-
decimals: outputToken.decimals,
|
|
814
|
-
chain: chainName,
|
|
815
|
-
}
|
|
816
|
-
: null,
|
|
817
|
-
};
|
|
818
|
-
});
|
|
819
|
-
}
|
|
820
|
-
async getTokenAddresses(includeStrategies = true) {
|
|
821
|
-
const response = await this.safeFetch(`${this.baseUrl}/tokens?includeStrategies=${includeStrategies}`, undefined, 'Failed to fetch supported token addresses');
|
|
822
|
-
if (!response.ok) {
|
|
823
|
-
const errorData = await response.json().catch(() => null);
|
|
824
|
-
const apiMessage = errorData?.message;
|
|
825
|
-
const errorMessage = apiMessage || 'Failed to fetch supported token addresses';
|
|
826
|
-
throw new Error(errorMessage);
|
|
827
|
-
}
|
|
828
|
-
return response.json();
|
|
829
|
-
}
|
|
830
|
-
async getTokens(includeStrategies = true) {
|
|
831
|
-
const tokens = await this.getTokenAddresses(includeStrategies);
|
|
832
|
-
return tokens.map((token) => (0, tokens_1.getTokenDetails)(this.chainId, token)).filter((token) => token !== undefined);
|
|
162
|
+
async getTokens() {
|
|
163
|
+
return this.api.getTokens();
|
|
833
164
|
}
|
|
834
165
|
async getPrices() {
|
|
835
166
|
const response = await this.safeFetch('https://fusion-api.gobob.xyz/pricefeed', undefined, 'Failed to fetch prices from Fusion API');
|
|
@@ -840,8 +171,8 @@ class GatewayApiClient extends base_client_1.BaseClient {
|
|
|
840
171
|
const list = await response.json();
|
|
841
172
|
return new Map(list.map((x) => [x.token_address.toLowerCase(), Number(x.price)]));
|
|
842
173
|
}
|
|
843
|
-
async getEnrichedTokens(
|
|
844
|
-
const [tokens, prices] = await Promise.all([this.
|
|
174
|
+
async getEnrichedTokens() {
|
|
175
|
+
const [tokens, prices] = await Promise.all([this.getTokens(), this.getPrices()]);
|
|
845
176
|
const tokensIncentives = await this.strategy.getTokensIncentives(tokens);
|
|
846
177
|
return Promise.all(tokens.map(async (address, i) => {
|
|
847
178
|
const token = (0, tokens_1.getTokenDetails)(this.chainId, address);
|
|
@@ -874,14 +205,13 @@ class GatewayApiClient extends base_client_1.BaseClient {
|
|
|
874
205
|
}));
|
|
875
206
|
}
|
|
876
207
|
async getOrders(userAddress) {
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
];
|
|
208
|
+
return this.api.getOrders({ userAddress: userAddress.toString() });
|
|
209
|
+
}
|
|
210
|
+
async getChains() {
|
|
211
|
+
return this.api.getChains();
|
|
212
|
+
}
|
|
213
|
+
async getRoutes() {
|
|
214
|
+
return this.api.getRoutes();
|
|
885
215
|
}
|
|
886
216
|
}
|
|
887
217
|
exports.GatewayApiClient = GatewayApiClient;
|