@vultisig/rujira 1.0.0
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/CHANGELOG.md +23 -0
- package/README.md +254 -0
- package/dist/assets/amount.d.ts +80 -0
- package/dist/assets/amount.d.ts.map +1 -0
- package/dist/assets/amount.js +186 -0
- package/dist/assets/asset.d.ts +43 -0
- package/dist/assets/asset.d.ts.map +1 -0
- package/dist/assets/asset.js +1 -0
- package/dist/assets/formats.d.ts +54 -0
- package/dist/assets/formats.d.ts.map +1 -0
- package/dist/assets/formats.js +164 -0
- package/dist/assets/index.d.ts +27 -0
- package/dist/assets/index.d.ts.map +1 -0
- package/dist/assets/index.js +45 -0
- package/dist/assets/registry.d.ts +37 -0
- package/dist/assets/registry.d.ts.map +1 -0
- package/dist/assets/registry.js +487 -0
- package/dist/assets/router.d.ts +44 -0
- package/dist/assets/router.d.ts.map +1 -0
- package/dist/assets/router.js +142 -0
- package/dist/client.d.ts +70 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +250 -0
- package/dist/config/constants.d.ts +25 -0
- package/dist/config/constants.d.ts.map +1 -0
- package/dist/config/constants.js +36 -0
- package/dist/config.d.ts +41 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +72 -0
- package/dist/discovery/discovery.d.ts +39 -0
- package/dist/discovery/discovery.d.ts.map +1 -0
- package/dist/discovery/discovery.js +250 -0
- package/dist/discovery/graphql-client.d.ts +46 -0
- package/dist/discovery/graphql-client.d.ts.map +1 -0
- package/dist/discovery/graphql-client.js +137 -0
- package/dist/discovery/index.d.ts +9 -0
- package/dist/discovery/index.d.ts.map +1 -0
- package/dist/discovery/index.js +7 -0
- package/dist/discovery/types.d.ts +62 -0
- package/dist/discovery/types.d.ts.map +1 -0
- package/dist/discovery/types.js +5 -0
- package/dist/easy-routes.d.ts +216 -0
- package/dist/easy-routes.d.ts.map +1 -0
- package/dist/easy-routes.js +241 -0
- package/dist/errors.d.ts +65 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +184 -0
- package/dist/index.d.ts +46 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +46 -0
- package/dist/modules/assets.d.ts +68 -0
- package/dist/modules/assets.d.ts.map +1 -0
- package/dist/modules/assets.js +127 -0
- package/dist/modules/deposit.d.ts +152 -0
- package/dist/modules/deposit.d.ts.map +1 -0
- package/dist/modules/deposit.js +233 -0
- package/dist/modules/index.d.ts +12 -0
- package/dist/modules/index.d.ts.map +1 -0
- package/dist/modules/index.js +9 -0
- package/dist/modules/orderbook.d.ts +80 -0
- package/dist/modules/orderbook.d.ts.map +1 -0
- package/dist/modules/orderbook.js +320 -0
- package/dist/modules/swap.d.ts +48 -0
- package/dist/modules/swap.d.ts.map +1 -0
- package/dist/modules/swap.js +318 -0
- package/dist/modules/withdraw.d.ts +46 -0
- package/dist/modules/withdraw.d.ts.map +1 -0
- package/dist/modules/withdraw.js +218 -0
- package/dist/services/fee-estimator.d.ts +14 -0
- package/dist/services/fee-estimator.d.ts.map +1 -0
- package/dist/services/fee-estimator.js +89 -0
- package/dist/services/price-impact.d.ts +11 -0
- package/dist/services/price-impact.d.ts.map +1 -0
- package/dist/services/price-impact.js +58 -0
- package/dist/signer/index.d.ts +3 -0
- package/dist/signer/index.d.ts.map +1 -0
- package/dist/signer/index.js +1 -0
- package/dist/signer/keysign-builder.d.ts +21 -0
- package/dist/signer/keysign-builder.d.ts.map +1 -0
- package/dist/signer/keysign-builder.js +106 -0
- package/dist/signer/types.d.ts +81 -0
- package/dist/signer/types.d.ts.map +1 -0
- package/dist/signer/types.js +8 -0
- package/dist/signer/vultisig-provider.d.ts +33 -0
- package/dist/signer/vultisig-provider.d.ts.map +1 -0
- package/dist/signer/vultisig-provider.js +242 -0
- package/dist/types.d.ts +375 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +18 -0
- package/dist/utils/cache.d.ts +87 -0
- package/dist/utils/cache.d.ts.map +1 -0
- package/dist/utils/cache.js +124 -0
- package/dist/utils/denom-conversion.d.ts +47 -0
- package/dist/utils/denom-conversion.d.ts.map +1 -0
- package/dist/utils/denom-conversion.js +105 -0
- package/dist/utils/encoding.d.ts +17 -0
- package/dist/utils/encoding.d.ts.map +1 -0
- package/dist/utils/encoding.js +55 -0
- package/dist/utils/format.d.ts +108 -0
- package/dist/utils/format.d.ts.map +1 -0
- package/dist/utils/format.js +213 -0
- package/dist/utils/index.d.ts +10 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/utils/index.js +9 -0
- package/dist/utils/memo.d.ts +107 -0
- package/dist/utils/memo.d.ts.map +1 -0
- package/dist/utils/memo.js +190 -0
- package/dist/utils/rate-limiter.d.ts +38 -0
- package/dist/utils/rate-limiter.d.ts.map +1 -0
- package/dist/utils/rate-limiter.js +67 -0
- package/dist/utils/type-guards.d.ts +22 -0
- package/dist/utils/type-guards.d.ts.map +1 -0
- package/dist/utils/type-guards.js +27 -0
- package/dist/validation/address-validator.d.ts +15 -0
- package/dist/validation/address-validator.d.ts.map +1 -0
- package/dist/validation/address-validator.js +75 -0
- package/package.json +98 -0
- package/src/__tests__/live/README.md +47 -0
package/dist/client.d.ts
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { ExecuteResult } from '@cosmjs/cosmwasm-stargate';
|
|
2
|
+
import { Coin } from '@cosmjs/proto-signing';
|
|
3
|
+
import { type RujiraConfig } from './config.js';
|
|
4
|
+
import { RujiraDiscovery } from './discovery/discovery.js';
|
|
5
|
+
import { RujiraAssets } from './modules/assets.js';
|
|
6
|
+
import { RujiraDeposit } from './modules/deposit.js';
|
|
7
|
+
import { RujiraOrderbook } from './modules/orderbook.js';
|
|
8
|
+
import { RujiraSwap, type RujiraSwapOptions } from './modules/swap.js';
|
|
9
|
+
import { RujiraWithdraw } from './modules/withdraw.js';
|
|
10
|
+
import type { RujiraSigner } from './signer/types.js';
|
|
11
|
+
import type { BookResponse, SimulationResponse } from './types.js';
|
|
12
|
+
export type RujiraClientOptions = {
|
|
13
|
+
config?: Partial<RujiraConfig>;
|
|
14
|
+
signer?: RujiraSigner;
|
|
15
|
+
rpcEndpoint?: string;
|
|
16
|
+
contractCache?: {
|
|
17
|
+
load?: () => Promise<Record<string, string>> | Record<string, string>;
|
|
18
|
+
save?: (finContracts: Record<string, string>) => Promise<void> | void;
|
|
19
|
+
};
|
|
20
|
+
debug?: boolean;
|
|
21
|
+
swapOptions?: RujiraSwapOptions;
|
|
22
|
+
};
|
|
23
|
+
export declare class RujiraClient {
|
|
24
|
+
readonly config: RujiraConfig;
|
|
25
|
+
readonly swap: RujiraSwap;
|
|
26
|
+
readonly orderbook: RujiraOrderbook;
|
|
27
|
+
readonly assets: RujiraAssets;
|
|
28
|
+
readonly deposit: RujiraDeposit;
|
|
29
|
+
readonly withdraw: RujiraWithdraw;
|
|
30
|
+
readonly discovery: RujiraDiscovery;
|
|
31
|
+
private queryClient;
|
|
32
|
+
private stargateClient;
|
|
33
|
+
private signingClient;
|
|
34
|
+
private signer;
|
|
35
|
+
private contractCache?;
|
|
36
|
+
private debug;
|
|
37
|
+
constructor(options?: RujiraClientOptions);
|
|
38
|
+
connect(): Promise<void>;
|
|
39
|
+
disconnect(): void;
|
|
40
|
+
isConnected(): boolean;
|
|
41
|
+
canSign(): boolean;
|
|
42
|
+
getAddress(): Promise<string>;
|
|
43
|
+
getBalance(address: string, denom: string): Promise<Coin>;
|
|
44
|
+
getAllBalances(address: string): Promise<readonly Coin[]>;
|
|
45
|
+
persistFinContracts(): Promise<void>;
|
|
46
|
+
queryContract<T>(contractAddress: string, query: object): Promise<T>;
|
|
47
|
+
private queryContractViaRest;
|
|
48
|
+
/**
|
|
49
|
+
* Execute an arbitrary CosmWasm contract.
|
|
50
|
+
*
|
|
51
|
+
* **Trust model**: This method does NOT validate the contract address.
|
|
52
|
+
* Callers are responsible for ensuring the address is trustworthy.
|
|
53
|
+
* The higher-level modules (swap, deposit, withdraw) use dynamically
|
|
54
|
+
* discovered contracts from THORNode and are safe by default.
|
|
55
|
+
*/
|
|
56
|
+
executeContract(contractAddress: string, msg: object, funds?: Coin[], memo?: string): Promise<ExecuteResult>;
|
|
57
|
+
simulateSwap(contractAddress: string, denom: string, amount: string): Promise<SimulationResponse>;
|
|
58
|
+
getOrderBook(contractAddress: string, limit?: number, offset?: number): Promise<BookResponse>;
|
|
59
|
+
waitForTransaction(txHash: string, timeoutMs?: number): Promise<{
|
|
60
|
+
code: number;
|
|
61
|
+
height: number;
|
|
62
|
+
rawLog?: string;
|
|
63
|
+
}>;
|
|
64
|
+
getBlockHeight(): Promise<number>;
|
|
65
|
+
private validateContractConfig;
|
|
66
|
+
private ensureConnected;
|
|
67
|
+
private ensureSigner;
|
|
68
|
+
private log;
|
|
69
|
+
}
|
|
70
|
+
//# sourceMappingURL=client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
|
package/dist/client.js
ADDED
|
@@ -0,0 +1,250 @@
|
|
|
1
|
+
import { CosmWasmClient, SigningCosmWasmClient } from '@cosmjs/cosmwasm-stargate';
|
|
2
|
+
import { GasPrice, StargateClient } from '@cosmjs/stargate';
|
|
3
|
+
import { MAINNET_CONFIG } from './config.js';
|
|
4
|
+
import { DEFAULT_TIMEOUT_MS } from './config/constants.js';
|
|
5
|
+
import { RujiraDiscovery } from './discovery/discovery.js';
|
|
6
|
+
import { RujiraError, RujiraErrorCode, wrapError } from './errors.js';
|
|
7
|
+
import { RujiraAssets } from './modules/assets.js';
|
|
8
|
+
import { RujiraDeposit } from './modules/deposit.js';
|
|
9
|
+
import { RujiraOrderbook } from './modules/orderbook.js';
|
|
10
|
+
import { RujiraSwap } from './modules/swap.js';
|
|
11
|
+
import { RujiraWithdraw } from './modules/withdraw.js';
|
|
12
|
+
import { base64Encode } from './utils/encoding.js';
|
|
13
|
+
import { thornodeRateLimiter } from './utils/rate-limiter.js';
|
|
14
|
+
export class RujiraClient {
|
|
15
|
+
constructor(options = {}) {
|
|
16
|
+
this.queryClient = null;
|
|
17
|
+
this.stargateClient = null;
|
|
18
|
+
this.signingClient = null;
|
|
19
|
+
this.signer = null;
|
|
20
|
+
const networkConfig = MAINNET_CONFIG;
|
|
21
|
+
this.config = {
|
|
22
|
+
...networkConfig,
|
|
23
|
+
...options.config,
|
|
24
|
+
contracts: {
|
|
25
|
+
...networkConfig.contracts,
|
|
26
|
+
...options.config?.contracts,
|
|
27
|
+
},
|
|
28
|
+
};
|
|
29
|
+
if (options.rpcEndpoint) {
|
|
30
|
+
this.config.rpcEndpoint = options.rpcEndpoint;
|
|
31
|
+
}
|
|
32
|
+
this.signer = options.signer || null;
|
|
33
|
+
this.contractCache = options.contractCache;
|
|
34
|
+
this.debug = options.debug || false;
|
|
35
|
+
this.swap = new RujiraSwap(this, options.swapOptions);
|
|
36
|
+
this.orderbook = new RujiraOrderbook(this);
|
|
37
|
+
this.assets = new RujiraAssets(this);
|
|
38
|
+
this.deposit = new RujiraDeposit(this);
|
|
39
|
+
this.withdraw = new RujiraWithdraw(this);
|
|
40
|
+
this.discovery = new RujiraDiscovery({
|
|
41
|
+
rpcEndpoint: this.config.rpcEndpoint,
|
|
42
|
+
debug: this.debug,
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
async connect() {
|
|
46
|
+
try {
|
|
47
|
+
this.log('Connecting to', this.config.rpcEndpoint);
|
|
48
|
+
if (this.contractCache?.load) {
|
|
49
|
+
try {
|
|
50
|
+
const loaded = await this.contractCache.load();
|
|
51
|
+
this.config.contracts.finContracts = {
|
|
52
|
+
...this.config.contracts.finContracts,
|
|
53
|
+
...(loaded ?? {}),
|
|
54
|
+
};
|
|
55
|
+
this.log('Loaded persisted FIN contracts:', Object.keys(loaded ?? {}).length);
|
|
56
|
+
}
|
|
57
|
+
catch (e) {
|
|
58
|
+
this.log('Failed to load persisted FIN contracts (continuing):', e);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
this.queryClient = await CosmWasmClient.connect(this.config.rpcEndpoint);
|
|
62
|
+
this.log('CosmWasm query client connected');
|
|
63
|
+
this.stargateClient = await StargateClient.connect(this.config.rpcEndpoint);
|
|
64
|
+
this.log('Stargate client connected');
|
|
65
|
+
this.validateContractConfig().catch(err => {
|
|
66
|
+
this.log('Contract config validation failed (non-blocking):', err);
|
|
67
|
+
});
|
|
68
|
+
if (this.signer) {
|
|
69
|
+
this.signingClient = await SigningCosmWasmClient.connectWithSigner(this.config.rpcEndpoint, this.signer, {
|
|
70
|
+
gasPrice: GasPrice.fromString(this.config.gasPrice),
|
|
71
|
+
});
|
|
72
|
+
this.log('Signing client connected');
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
catch (error) {
|
|
76
|
+
throw wrapError(error, RujiraErrorCode.NETWORK_ERROR);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
disconnect() {
|
|
80
|
+
this.queryClient?.disconnect();
|
|
81
|
+
this.queryClient = null;
|
|
82
|
+
this.stargateClient?.disconnect();
|
|
83
|
+
this.stargateClient = null;
|
|
84
|
+
this.signingClient?.disconnect();
|
|
85
|
+
this.signingClient = null;
|
|
86
|
+
this.log('Disconnected');
|
|
87
|
+
}
|
|
88
|
+
isConnected() {
|
|
89
|
+
return this.queryClient !== null;
|
|
90
|
+
}
|
|
91
|
+
canSign() {
|
|
92
|
+
return this.signingClient !== null;
|
|
93
|
+
}
|
|
94
|
+
async getAddress() {
|
|
95
|
+
if (!this.signer) {
|
|
96
|
+
throw new RujiraError(RujiraErrorCode.MISSING_SIGNER, 'No signer provided');
|
|
97
|
+
}
|
|
98
|
+
const accounts = await this.signer.getAccounts();
|
|
99
|
+
if (!accounts.length) {
|
|
100
|
+
throw new RujiraError(RujiraErrorCode.MISSING_SIGNER, 'Signer returned no accounts');
|
|
101
|
+
}
|
|
102
|
+
return accounts[0].address;
|
|
103
|
+
}
|
|
104
|
+
async getBalance(address, denom) {
|
|
105
|
+
this.ensureConnected();
|
|
106
|
+
if (this.stargateClient) {
|
|
107
|
+
return this.stargateClient.getBalance(address, denom);
|
|
108
|
+
}
|
|
109
|
+
return this.queryClient.getBalance(address, denom);
|
|
110
|
+
}
|
|
111
|
+
async getAllBalances(address) {
|
|
112
|
+
this.ensureConnected();
|
|
113
|
+
if (!this.stargateClient) {
|
|
114
|
+
throw new RujiraError(RujiraErrorCode.NOT_CONNECTED, 'Stargate client not available. Call connect() first.');
|
|
115
|
+
}
|
|
116
|
+
return this.stargateClient.getAllBalances(address);
|
|
117
|
+
}
|
|
118
|
+
async persistFinContracts() {
|
|
119
|
+
if (!this.contractCache?.save)
|
|
120
|
+
return;
|
|
121
|
+
await this.contractCache.save(this.config.contracts.finContracts);
|
|
122
|
+
}
|
|
123
|
+
async queryContract(contractAddress, query) {
|
|
124
|
+
this.ensureConnected();
|
|
125
|
+
this.log('Query contract:', contractAddress, query);
|
|
126
|
+
try {
|
|
127
|
+
const result = await this.queryClient.queryContractSmart(contractAddress, query);
|
|
128
|
+
this.log('Query result:', result);
|
|
129
|
+
return result;
|
|
130
|
+
}
|
|
131
|
+
catch (error) {
|
|
132
|
+
const msg = error instanceof Error ? error.message : String(error);
|
|
133
|
+
if (msg.toLowerCase().includes('out of gas')) {
|
|
134
|
+
try {
|
|
135
|
+
const result = await this.queryContractViaRest(contractAddress, query);
|
|
136
|
+
this.log('Query result (REST fallback):', result);
|
|
137
|
+
return result;
|
|
138
|
+
}
|
|
139
|
+
catch (fallbackError) {
|
|
140
|
+
throw wrapError(fallbackError, RujiraErrorCode.CONTRACT_ERROR);
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
throw wrapError(error, RujiraErrorCode.CONTRACT_ERROR);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
async queryContractViaRest(contractAddress, query) {
|
|
147
|
+
const encoded = base64Encode(JSON.stringify(query));
|
|
148
|
+
const base = this.config.restEndpoint.replace(/\/$/, '');
|
|
149
|
+
const url = `${base}/cosmwasm/wasm/v1/contract/${contractAddress}/smart/${encoded}?gas_limit=${this.config.wasmQueryGasLimit}`;
|
|
150
|
+
this.log('Query contract (REST):', url);
|
|
151
|
+
const res = await thornodeRateLimiter.fetch(url);
|
|
152
|
+
if (!res.ok) {
|
|
153
|
+
const text = await res.text().catch(() => '');
|
|
154
|
+
throw new Error(`REST smart query failed (${res.status}): ${text || res.statusText}`);
|
|
155
|
+
}
|
|
156
|
+
const data = (await res.json());
|
|
157
|
+
return data.data;
|
|
158
|
+
}
|
|
159
|
+
/**
|
|
160
|
+
* Execute an arbitrary CosmWasm contract.
|
|
161
|
+
*
|
|
162
|
+
* **Trust model**: This method does NOT validate the contract address.
|
|
163
|
+
* Callers are responsible for ensuring the address is trustworthy.
|
|
164
|
+
* The higher-level modules (swap, deposit, withdraw) use dynamically
|
|
165
|
+
* discovered contracts from THORNode and are safe by default.
|
|
166
|
+
*/
|
|
167
|
+
async executeContract(contractAddress, msg, funds = [], memo) {
|
|
168
|
+
this.ensureSigner();
|
|
169
|
+
const address = await this.getAddress();
|
|
170
|
+
try {
|
|
171
|
+
this.log('Execute contract:', contractAddress, msg, funds);
|
|
172
|
+
const result = await this.signingClient.execute(address, contractAddress, msg, 'auto', memo, funds);
|
|
173
|
+
this.log('Execute result:', result.transactionHash);
|
|
174
|
+
return result;
|
|
175
|
+
}
|
|
176
|
+
catch (error) {
|
|
177
|
+
throw wrapError(error, RujiraErrorCode.CONTRACT_ERROR);
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
async simulateSwap(contractAddress, denom, amount) {
|
|
181
|
+
const query = {
|
|
182
|
+
simulate: { denom, amount },
|
|
183
|
+
};
|
|
184
|
+
return this.queryContract(contractAddress, query);
|
|
185
|
+
}
|
|
186
|
+
async getOrderBook(contractAddress, limit = 10, offset = 0) {
|
|
187
|
+
const query = {
|
|
188
|
+
book: { limit, offset },
|
|
189
|
+
};
|
|
190
|
+
return this.queryContract(contractAddress, query);
|
|
191
|
+
}
|
|
192
|
+
async waitForTransaction(txHash, timeoutMs = DEFAULT_TIMEOUT_MS) {
|
|
193
|
+
this.ensureConnected();
|
|
194
|
+
const start = Date.now();
|
|
195
|
+
while (Date.now() - start < timeoutMs) {
|
|
196
|
+
try {
|
|
197
|
+
const tx = await this.queryClient.getTx(txHash);
|
|
198
|
+
if (tx) {
|
|
199
|
+
return {
|
|
200
|
+
code: tx.code,
|
|
201
|
+
height: tx.height,
|
|
202
|
+
rawLog: tx.rawLog,
|
|
203
|
+
};
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
catch {
|
|
207
|
+
// keep polling
|
|
208
|
+
}
|
|
209
|
+
await new Promise(resolve => setTimeout(resolve, 2000));
|
|
210
|
+
}
|
|
211
|
+
throw new RujiraError(RujiraErrorCode.TIMEOUT, `Transaction ${txHash} not found within ${timeoutMs}ms`);
|
|
212
|
+
}
|
|
213
|
+
async getBlockHeight() {
|
|
214
|
+
this.ensureConnected();
|
|
215
|
+
return this.queryClient.getHeight();
|
|
216
|
+
}
|
|
217
|
+
async validateContractConfig() {
|
|
218
|
+
try {
|
|
219
|
+
const base = this.config.restEndpoint.replace(/\/$/, '');
|
|
220
|
+
const url = `${base}/cosmwasm/wasm/v1/code/${this.config.contracts.finCodeId}/contracts?pagination.limit=1`;
|
|
221
|
+
const res = await thornodeRateLimiter.fetch(url);
|
|
222
|
+
if (!res.ok)
|
|
223
|
+
return;
|
|
224
|
+
const data = (await res.json());
|
|
225
|
+
if (!data.contracts || data.contracts.length === 0) {
|
|
226
|
+
console.warn(`[RujiraClient] WARNING: FIN code ID ${this.config.contracts.finCodeId} returned no contracts. ` +
|
|
227
|
+
'Contract may have been upgraded on-chain. Update SDK or config.');
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
catch {
|
|
231
|
+
// Non-blocking: validation failure doesn't prevent operation
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
ensureConnected() {
|
|
235
|
+
if (!this.queryClient || !this.stargateClient) {
|
|
236
|
+
throw new RujiraError(RujiraErrorCode.NOT_CONNECTED, 'Client not connected. Call connect() first.');
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
ensureSigner() {
|
|
240
|
+
this.ensureConnected();
|
|
241
|
+
if (!this.signingClient) {
|
|
242
|
+
throw new RujiraError(RujiraErrorCode.MISSING_SIGNER, 'No signer provided. Initialize client with a signer for transactions.');
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
log(...args) {
|
|
246
|
+
if (this.debug) {
|
|
247
|
+
console.log('[RujiraClient]', ...args);
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Named constants replacing magic values throughout the Rujira SDK.
|
|
3
|
+
* @module config/constants
|
|
4
|
+
*/
|
|
5
|
+
/** Swap amounts at or above this are considered "large" for price impact estimation. */
|
|
6
|
+
export declare const LARGE_SWAP_THRESHOLD: bigint;
|
|
7
|
+
/** Default THORChain native transaction fee (in base units, 8 decimals). */
|
|
8
|
+
export declare const DEFAULT_THORCHAIN_FEE = 2000000n;
|
|
9
|
+
/** Default gas price for THORChain transactions. */
|
|
10
|
+
export declare const DEFAULT_GAS_PRICE = "0.025rune";
|
|
11
|
+
/** Default timeout for waiting on transaction confirmation (ms). */
|
|
12
|
+
export declare const DEFAULT_TIMEOUT_MS = 60000;
|
|
13
|
+
/** Default taker fee for FIN orderbook contracts. */
|
|
14
|
+
export declare const DEFAULT_TAKER_FEE = "0.0015";
|
|
15
|
+
/** Default maker fee for FIN orderbook contracts. */
|
|
16
|
+
export declare const DEFAULT_MAKER_FEE = "0.00075";
|
|
17
|
+
/**
|
|
18
|
+
* Fallback outbound fees per chain (base units, 8 decimals for most chains).
|
|
19
|
+
* Captured from THORNode on 2026-02-08 — only used when THORNode API is unreachable.
|
|
20
|
+
* Run LIVE_TESTS=1 to verify against current THORNode values.
|
|
21
|
+
*/
|
|
22
|
+
export declare const FALLBACK_OUTBOUND_FEES: Record<string, string>;
|
|
23
|
+
/** THORChain decimal precision (8 decimals). */
|
|
24
|
+
export declare const THORCHAIN_DECIMALS = 8;
|
|
25
|
+
//# sourceMappingURL=constants.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../src/config/constants.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,wFAAwF;AACxF,eAAO,MAAM,oBAAoB,QAA0B,CAAC;AAE5D,4EAA4E;AAC5E,eAAO,MAAM,qBAAqB,WAAW,CAAC;AAE9C,oDAAoD;AACpD,eAAO,MAAM,iBAAiB,cAAc,CAAC;AAE7C,oEAAoE;AACpE,eAAO,MAAM,kBAAkB,QAAQ,CAAC;AAExC,qDAAqD;AACrD,eAAO,MAAM,iBAAiB,WAAW,CAAC;AAE1C,qDAAqD;AACrD,eAAO,MAAM,iBAAiB,YAAY,CAAC;AAE3C;;;;GAIG;AACH,eAAO,MAAM,sBAAsB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAYzD,CAAC;AAEF,gDAAgD;AAChD,eAAO,MAAM,kBAAkB,IAAI,CAAC"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Named constants replacing magic values throughout the Rujira SDK.
|
|
3
|
+
* @module config/constants
|
|
4
|
+
*/
|
|
5
|
+
/** Swap amounts at or above this are considered "large" for price impact estimation. */
|
|
6
|
+
export const LARGE_SWAP_THRESHOLD = BigInt('1000000000000'); // 10,000 RUNE (8 dec)
|
|
7
|
+
/** Default THORChain native transaction fee (in base units, 8 decimals). */
|
|
8
|
+
export const DEFAULT_THORCHAIN_FEE = 2000000n; // 0.02 RUNE
|
|
9
|
+
/** Default gas price for THORChain transactions. */
|
|
10
|
+
export const DEFAULT_GAS_PRICE = '0.025rune';
|
|
11
|
+
/** Default timeout for waiting on transaction confirmation (ms). */
|
|
12
|
+
export const DEFAULT_TIMEOUT_MS = 60000;
|
|
13
|
+
/** Default taker fee for FIN orderbook contracts. */
|
|
14
|
+
export const DEFAULT_TAKER_FEE = '0.0015'; // 0.15%
|
|
15
|
+
/** Default maker fee for FIN orderbook contracts. */
|
|
16
|
+
export const DEFAULT_MAKER_FEE = '0.00075'; // 0.075%
|
|
17
|
+
/**
|
|
18
|
+
* Fallback outbound fees per chain (base units, 8 decimals for most chains).
|
|
19
|
+
* Captured from THORNode on 2026-02-08 — only used when THORNode API is unreachable.
|
|
20
|
+
* Run LIVE_TESTS=1 to verify against current THORNode values.
|
|
21
|
+
*/
|
|
22
|
+
export const FALLBACK_OUTBOUND_FEES = {
|
|
23
|
+
BTC: '1572',
|
|
24
|
+
ETH: '12319',
|
|
25
|
+
BSC: '40318',
|
|
26
|
+
AVAX: '2845482',
|
|
27
|
+
GAIA: '13088900',
|
|
28
|
+
DOGE: '267956702',
|
|
29
|
+
LTC: '473869',
|
|
30
|
+
BCH: '48635',
|
|
31
|
+
BASE: '12324',
|
|
32
|
+
TRON: '94966900',
|
|
33
|
+
XRP: '18038300',
|
|
34
|
+
};
|
|
35
|
+
/** THORChain decimal precision (8 decimals). */
|
|
36
|
+
export const THORCHAIN_DECIMALS = 8;
|
package/dist/config.d.ts
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Rujira SDK is mainnet-only.
|
|
3
|
+
*/
|
|
4
|
+
export type NetworkType = 'mainnet';
|
|
5
|
+
export type NetworkConfig = {
|
|
6
|
+
network: NetworkType;
|
|
7
|
+
chainId: string;
|
|
8
|
+
rpcEndpoint: string;
|
|
9
|
+
restEndpoint: string;
|
|
10
|
+
midgardEndpoint: string;
|
|
11
|
+
graphqlWsEndpoint?: string;
|
|
12
|
+
gasPrice: string;
|
|
13
|
+
gasLimit: number;
|
|
14
|
+
wasmQueryGasLimit: number;
|
|
15
|
+
addressPrefix: string;
|
|
16
|
+
};
|
|
17
|
+
export type ContractRegistry = {
|
|
18
|
+
finCodeId: number;
|
|
19
|
+
finCodeHash: string;
|
|
20
|
+
bowCodeHash: string;
|
|
21
|
+
affiliateCodeHash: string;
|
|
22
|
+
finContracts: Record<string, string>;
|
|
23
|
+
};
|
|
24
|
+
export type RujiraConfig = {
|
|
25
|
+
contracts: ContractRegistry;
|
|
26
|
+
defaultSlippageBps: number;
|
|
27
|
+
affiliateAddress?: string;
|
|
28
|
+
affiliateFeeBps?: number;
|
|
29
|
+
} & NetworkConfig;
|
|
30
|
+
export declare const MAINNET_CONFIG: RujiraConfig;
|
|
31
|
+
/** Maps THORChain chain identifiers to SDK chain names */
|
|
32
|
+
export declare const THORCHAIN_TO_SDK_CHAIN: Record<string, string>;
|
|
33
|
+
/** Estimated processing times per chain in minutes (deposit/withdrawal) */
|
|
34
|
+
export declare const CHAIN_PROCESSING_TIMES: Record<string, number>;
|
|
35
|
+
export declare function getNetworkConfig(_network?: NetworkType): RujiraConfig;
|
|
36
|
+
export declare function getAssetMetadata(denom: string): {
|
|
37
|
+
decimals: number;
|
|
38
|
+
chainDecimals: number;
|
|
39
|
+
ticker: string;
|
|
40
|
+
};
|
|
41
|
+
//# sourceMappingURL=config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAIA;;GAEG;AACH,MAAM,MAAM,WAAW,GAAG,SAAS,CAAA;AAEnC,MAAM,MAAM,aAAa,GAAG;IAC1B,OAAO,EAAE,WAAW,CAAA;IACpB,OAAO,EAAE,MAAM,CAAA;IACf,WAAW,EAAE,MAAM,CAAA;IACnB,YAAY,EAAE,MAAM,CAAA;IACpB,eAAe,EAAE,MAAM,CAAA;IACvB,iBAAiB,CAAC,EAAE,MAAM,CAAA;IAC1B,QAAQ,EAAE,MAAM,CAAA;IAChB,QAAQ,EAAE,MAAM,CAAA;IAChB,iBAAiB,EAAE,MAAM,CAAA;IACzB,aAAa,EAAE,MAAM,CAAA;CACtB,CAAA;AAED,MAAM,MAAM,gBAAgB,GAAG;IAC7B,SAAS,EAAE,MAAM,CAAA;IACjB,WAAW,EAAE,MAAM,CAAA;IACnB,WAAW,EAAE,MAAM,CAAA;IACnB,iBAAiB,EAAE,MAAM,CAAA;IACzB,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CACrC,CAAA;AAED,MAAM,MAAM,YAAY,GAAG;IACzB,SAAS,EAAE,gBAAgB,CAAA;IAC3B,kBAAkB,EAAE,MAAM,CAAA;IAC1B,gBAAgB,CAAC,EAAE,MAAM,CAAA;IACzB,eAAe,CAAC,EAAE,MAAM,CAAA;CACzB,GAAG,aAAa,CAAA;AAEjB,eAAO,MAAM,cAAc,EAAE,YAmB5B,CAAA;AAED,0DAA0D;AAC1D,eAAO,MAAM,sBAAsB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAmBzD,CAAA;AAED,2EAA2E;AAC3E,eAAO,MAAM,sBAAsB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAUzD,CAAA;AAED,wBAAgB,gBAAgB,CAAC,QAAQ,GAAE,WAAuB,GAAG,YAAY,CAEhF;AAED,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,GAAG;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,aAAa,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAc3G"}
|
package/dist/config.js
ADDED
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { findAssetByFormat } from './assets/index.js';
|
|
2
|
+
import { DEFAULT_GAS_PRICE } from './config/constants.js';
|
|
3
|
+
import { denomToTicker } from './utils/denom-conversion.js';
|
|
4
|
+
export const MAINNET_CONFIG = {
|
|
5
|
+
network: 'mainnet',
|
|
6
|
+
chainId: 'thorchain-1',
|
|
7
|
+
rpcEndpoint: 'https://rpc.ninerealms.com',
|
|
8
|
+
restEndpoint: 'https://thornode.ninerealms.com',
|
|
9
|
+
midgardEndpoint: 'https://midgard.ninerealms.com/v2',
|
|
10
|
+
graphqlWsEndpoint: 'wss://api.rujira.network/socket',
|
|
11
|
+
gasPrice: DEFAULT_GAS_PRICE,
|
|
12
|
+
gasLimit: 500000,
|
|
13
|
+
wasmQueryGasLimit: 5_000_000,
|
|
14
|
+
addressPrefix: 'thor',
|
|
15
|
+
contracts: {
|
|
16
|
+
finCodeId: 73,
|
|
17
|
+
finCodeHash: '240a0994d37b7eb80bf2273c4224c736194160353ba6ccd9ae893eeab88794b9',
|
|
18
|
+
bowCodeHash: 'd77de081ae6440fd46cb4620d5fc9e285f2343f972edc0f70685a4b5f9f49536',
|
|
19
|
+
affiliateCodeHash: '223ea20a4463696fe32b23f845e9f90ae5c83ef0175894a4b0cec114b7dd4b26',
|
|
20
|
+
finContracts: {},
|
|
21
|
+
},
|
|
22
|
+
defaultSlippageBps: 100,
|
|
23
|
+
};
|
|
24
|
+
/** Maps THORChain chain identifiers to SDK chain names */
|
|
25
|
+
export const THORCHAIN_TO_SDK_CHAIN = {
|
|
26
|
+
ETH: 'Ethereum',
|
|
27
|
+
BTC: 'Bitcoin',
|
|
28
|
+
BCH: 'BitcoinCash',
|
|
29
|
+
DOGE: 'Dogecoin',
|
|
30
|
+
LTC: 'Litecoin',
|
|
31
|
+
AVAX: 'Avalanche',
|
|
32
|
+
BSC: 'BSC',
|
|
33
|
+
GAIA: 'Cosmos',
|
|
34
|
+
THOR: 'THORChain',
|
|
35
|
+
MAYA: 'MayaChain',
|
|
36
|
+
KUJI: 'Kujira',
|
|
37
|
+
DASH: 'Dash',
|
|
38
|
+
ARB: 'Arbitrum',
|
|
39
|
+
ZEC: 'Zcash',
|
|
40
|
+
XRP: 'Ripple',
|
|
41
|
+
BASE: 'Base',
|
|
42
|
+
TRON: 'Tron',
|
|
43
|
+
NOBLE: 'Noble',
|
|
44
|
+
};
|
|
45
|
+
/** Estimated processing times per chain in minutes (deposit/withdrawal) */
|
|
46
|
+
export const CHAIN_PROCESSING_TIMES = {
|
|
47
|
+
BTC: 30, // ~3 confirmations
|
|
48
|
+
ETH: 5, // ~12 confirmations
|
|
49
|
+
BSC: 2, // Fast finality
|
|
50
|
+
AVAX: 1, // Sub-second finality
|
|
51
|
+
GAIA: 2, // Cosmos ~6 seconds
|
|
52
|
+
DOGE: 20, // ~3 confirmations
|
|
53
|
+
LTC: 15, // ~3 confirmations
|
|
54
|
+
BCH: 20, // ~3 confirmations
|
|
55
|
+
THOR: 0, // Native, instant
|
|
56
|
+
};
|
|
57
|
+
export function getNetworkConfig(_network = 'mainnet') {
|
|
58
|
+
return MAINNET_CONFIG;
|
|
59
|
+
}
|
|
60
|
+
export function getAssetMetadata(denom) {
|
|
61
|
+
const normalized = denom.toLowerCase();
|
|
62
|
+
const asset = findAssetByFormat(normalized);
|
|
63
|
+
if (asset) {
|
|
64
|
+
return {
|
|
65
|
+
decimals: asset.decimals.fin,
|
|
66
|
+
chainDecimals: asset.decimals.thorchain,
|
|
67
|
+
ticker: asset.id.toUpperCase(),
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
const ticker = denomToTicker(denom);
|
|
71
|
+
return { decimals: 6, chainDecimals: 8, ticker };
|
|
72
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { type GraphQLClientOptions } from './graphql-client.js';
|
|
2
|
+
import type { DiscoveredContracts, Market } from './types.js';
|
|
3
|
+
export type DiscoveryOptions = {
|
|
4
|
+
graphql?: GraphQLClientOptions;
|
|
5
|
+
rpcEndpoint?: string;
|
|
6
|
+
cacheTtl?: number;
|
|
7
|
+
debug?: boolean;
|
|
8
|
+
};
|
|
9
|
+
export declare class RujiraDiscovery {
|
|
10
|
+
private graphql;
|
|
11
|
+
private rpcEndpoint;
|
|
12
|
+
private cacheTtl;
|
|
13
|
+
private debug;
|
|
14
|
+
private finCodeId;
|
|
15
|
+
private cache;
|
|
16
|
+
private pendingDiscovery;
|
|
17
|
+
constructor(options?: DiscoveryOptions);
|
|
18
|
+
discoverContracts(forceRefresh?: boolean): Promise<DiscoveredContracts>;
|
|
19
|
+
private performDiscovery;
|
|
20
|
+
private shouldFallbackToChain;
|
|
21
|
+
findMarket(baseAsset: string, quoteAsset: string): Promise<Market | null>;
|
|
22
|
+
getContractAddress(baseAsset: string, quoteAsset: string): Promise<string | null>;
|
|
23
|
+
listMarkets(): Promise<Market[]>;
|
|
24
|
+
clearCache(): void;
|
|
25
|
+
getCacheTtl(): number;
|
|
26
|
+
getCacheStatus(): {
|
|
27
|
+
cached: boolean;
|
|
28
|
+
age?: number;
|
|
29
|
+
valid: boolean;
|
|
30
|
+
ttl: number;
|
|
31
|
+
};
|
|
32
|
+
private discoverViaGraphQL;
|
|
33
|
+
private discoverViaChain;
|
|
34
|
+
private normalizeDenom;
|
|
35
|
+
private transformMarket;
|
|
36
|
+
private isCacheValid;
|
|
37
|
+
private log;
|
|
38
|
+
}
|
|
39
|
+
//# sourceMappingURL=discovery.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"discovery.d.ts","sourceRoot":"","sources":["../../src/discovery/discovery.ts"],"names":[],"mappings":"AAGA,OAAO,EAAiB,KAAK,oBAAoB,EAAE,MAAM,qBAAqB,CAAA;AAC9E,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,EAAE,MAAM,YAAY,CAAA;AAE7D,MAAM,MAAM,gBAAgB,GAAG;IAC7B,OAAO,CAAC,EAAE,oBAAoB,CAAA;IAC9B,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,KAAK,CAAC,EAAE,OAAO,CAAA;CAChB,CAAA;AAED,qBAAa,eAAe;IAC1B,OAAO,CAAC,OAAO,CAAe;IAC9B,OAAO,CAAC,WAAW,CAAQ;IAC3B,OAAO,CAAC,QAAQ,CAAQ;IACxB,OAAO,CAAC,KAAK,CAAS;IACtB,OAAO,CAAC,SAAS,CAAQ;IACzB,OAAO,CAAC,KAAK,CAAmC;IAChD,OAAO,CAAC,gBAAgB,CAA4C;gBAExD,OAAO,GAAE,gBAAqB;IAgBpC,iBAAiB,CAAC,YAAY,UAAQ,GAAG,OAAO,CAAC,mBAAmB,CAAC;YAqB7D,gBAAgB;IAoC9B,OAAO,CAAC,qBAAqB;IAavB,UAAU,CAAC,SAAS,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAyCzE,kBAAkB,CAAC,SAAS,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAKjF,WAAW,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;IAUtC,UAAU,IAAI,IAAI;IAIlB,WAAW,IAAI,MAAM;IAIrB,cAAc,IAAI;QAAE,MAAM,EAAE,OAAO,CAAC;QAAC,GAAG,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,OAAO,CAAC;QAAC,GAAG,EAAE,MAAM,CAAA;KAAE;YAalE,kBAAkB;YAiBlB,gBAAgB;IAsF9B,OAAO,CAAC,cAAc;IAItB,OAAO,CAAC,eAAe;IAqBvB,OAAO,CAAC,YAAY;IAMpB,OAAO,CAAC,GAAG;CAKZ"}
|