@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
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Type guard to check if an object is a valid Asset with a secured FIN denom.
|
|
3
|
+
* Secured assets follow the `chain-symbol` pattern (e.g., `btc-btc`, `eth-usdc-0xa0b8...`).
|
|
4
|
+
* Native tokens (`rune`, `tcy`) and module tokens (`x/ruji`) are excluded.
|
|
5
|
+
* @internal
|
|
6
|
+
*/
|
|
7
|
+
export function isFinAsset(obj) {
|
|
8
|
+
if (!obj || typeof obj !== 'object')
|
|
9
|
+
return false;
|
|
10
|
+
const asset = obj;
|
|
11
|
+
return (typeof asset.formats === 'object' &&
|
|
12
|
+
asset.formats !== null &&
|
|
13
|
+
typeof asset.formats.fin === 'string' &&
|
|
14
|
+
asset.formats.fin.includes('-'));
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Parse a THORChain asset string into chain and symbol components.
|
|
18
|
+
* @param asset - Asset string (e.g., "BTC.BTC", "ETH.USDC-0xA0b8...")
|
|
19
|
+
* @internal
|
|
20
|
+
*/
|
|
21
|
+
export function parseAsset(asset) {
|
|
22
|
+
const parts = asset.split('.');
|
|
23
|
+
return {
|
|
24
|
+
chain: parts[0]?.toUpperCase() || '',
|
|
25
|
+
symbol: parts.slice(1).join('.') || '',
|
|
26
|
+
};
|
|
27
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Address validation for L1 chains and THORChain
|
|
3
|
+
* @module validation/address-validator
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* Validate an L1 chain address.
|
|
7
|
+
* Throws RujiraError if the address is invalid.
|
|
8
|
+
*/
|
|
9
|
+
export declare function validateL1Address(chain: string, address: string): void;
|
|
10
|
+
/**
|
|
11
|
+
* Validate a THORChain bech32 address (thor1...).
|
|
12
|
+
* Throws RujiraError if the address is invalid.
|
|
13
|
+
*/
|
|
14
|
+
export declare function validateThorAddress(address: string): void;
|
|
15
|
+
//# sourceMappingURL=address-validator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"address-validator.d.ts","sourceRoot":"","sources":["../../src/validation/address-validator.ts"],"names":[],"mappings":"AAAA;;;GAGG;AA6BH;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI,CAmBtE;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAwCzD"}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Address validation for L1 chains and THORChain
|
|
3
|
+
* @module validation/address-validator
|
|
4
|
+
*/
|
|
5
|
+
import { fromBech32 } from '@cosmjs/encoding';
|
|
6
|
+
import { RujiraError, RujiraErrorCode } from '../errors.js';
|
|
7
|
+
const evmValidator = (addr) => /^0x[a-fA-F0-9]{40}$/.test(addr);
|
|
8
|
+
const L1_ADDRESS_VALIDATORS = {
|
|
9
|
+
BTC: addr => /^(1|3)[a-km-zA-HJ-NP-Z1-9]{25,34}$/.test(addr) || /^bc1[a-z0-9]{39,87}$/.test(addr),
|
|
10
|
+
ETH: evmValidator,
|
|
11
|
+
BSC: evmValidator,
|
|
12
|
+
AVAX: evmValidator,
|
|
13
|
+
BASE: evmValidator,
|
|
14
|
+
ARB: evmValidator,
|
|
15
|
+
GAIA: addr => /^cosmos1[a-z0-9]{38}$/.test(addr),
|
|
16
|
+
NOBLE: addr => /^noble1[a-z0-9]{38}$/.test(addr),
|
|
17
|
+
DOGE: addr => /^D[a-km-zA-HJ-NP-Z1-9]{25,34}$/.test(addr),
|
|
18
|
+
DASH: addr => /^[X7][a-km-zA-HJ-NP-Z1-9]{25,34}$/.test(addr),
|
|
19
|
+
LTC: addr => /^[LM3][a-km-zA-HJ-NP-Z1-9]{25,34}$/.test(addr) || /^ltc1[a-z0-9]{39,87}$/.test(addr),
|
|
20
|
+
BCH: addr => /^(1|3)[a-km-zA-HJ-NP-Z1-9]{25,34}$/.test(addr) ||
|
|
21
|
+
/^bitcoincash:[qp][a-z0-9]{41}$/.test(addr) ||
|
|
22
|
+
/^[qp][a-z0-9]{41}$/.test(addr),
|
|
23
|
+
XRP: addr => /^r[1-9A-HJ-NP-Za-km-z]{24,34}$/.test(addr),
|
|
24
|
+
TRON: addr => /^T[a-zA-Z0-9]{33}$/.test(addr),
|
|
25
|
+
ZEC: addr => /^t1[a-km-zA-HJ-NP-Z1-9]{33}$/.test(addr) || /^t3[a-km-zA-HJ-NP-Z1-9]{33}$/.test(addr),
|
|
26
|
+
};
|
|
27
|
+
/**
|
|
28
|
+
* Validate an L1 chain address.
|
|
29
|
+
* Throws RujiraError if the address is invalid.
|
|
30
|
+
*/
|
|
31
|
+
export function validateL1Address(chain, address) {
|
|
32
|
+
if (!address || address.trim().length === 0) {
|
|
33
|
+
throw new RujiraError(RujiraErrorCode.INVALID_ADDRESS, `${chain} address is required`);
|
|
34
|
+
}
|
|
35
|
+
const validator = L1_ADDRESS_VALIDATORS[chain.toUpperCase()];
|
|
36
|
+
if (validator) {
|
|
37
|
+
if (!validator(address)) {
|
|
38
|
+
throw new RujiraError(RujiraErrorCode.INVALID_ADDRESS, `Invalid ${chain} address: ${address}`);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
else {
|
|
42
|
+
// Fallback: non-empty, reasonable length
|
|
43
|
+
if (address.length < 10 || address.length > 128) {
|
|
44
|
+
throw new RujiraError(RujiraErrorCode.INVALID_ADDRESS, `Invalid ${chain} address: expected 10-128 characters, got ${address.length}`);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Validate a THORChain bech32 address (thor1...).
|
|
50
|
+
* Throws RujiraError if the address is invalid.
|
|
51
|
+
*/
|
|
52
|
+
export function validateThorAddress(address) {
|
|
53
|
+
if (!address || typeof address !== 'string') {
|
|
54
|
+
throw new RujiraError(RujiraErrorCode.INVALID_ADDRESS, 'Destination address is required');
|
|
55
|
+
}
|
|
56
|
+
const trimmed = address.trim();
|
|
57
|
+
if (!trimmed.startsWith('thor1')) {
|
|
58
|
+
throw new RujiraError(RujiraErrorCode.INVALID_ADDRESS, `Invalid destination address format: must start with 'thor1'. Got: ${address.substring(0, 10)}...`);
|
|
59
|
+
}
|
|
60
|
+
try {
|
|
61
|
+
const decoded = fromBech32(trimmed);
|
|
62
|
+
if (decoded.prefix !== 'thor') {
|
|
63
|
+
throw new RujiraError(RujiraErrorCode.INVALID_ADDRESS, `Invalid address prefix: expected 'thor', got '${decoded.prefix}'`);
|
|
64
|
+
}
|
|
65
|
+
if (decoded.data.length !== 20 && decoded.data.length !== 32) {
|
|
66
|
+
throw new RujiraError(RujiraErrorCode.INVALID_ADDRESS, `Invalid address data length: expected 20 or 32 bytes, got ${decoded.data.length}`);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
catch (error) {
|
|
70
|
+
if (error instanceof RujiraError) {
|
|
71
|
+
throw error;
|
|
72
|
+
}
|
|
73
|
+
throw new RujiraError(RujiraErrorCode.INVALID_ADDRESS, `Invalid bech32 address: ${error instanceof Error ? error.message : 'checksum verification failed'}`);
|
|
74
|
+
}
|
|
75
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@vultisig/rujira",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"description": "Rujira DEX integration for Vultisig SDK - Modular TypeScript SDK for swaps and limit orders on THORChain",
|
|
6
|
+
"main": "./dist/index.js",
|
|
7
|
+
"types": "./dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"import": "./dist/index.js",
|
|
11
|
+
"types": "./dist/index.d.ts"
|
|
12
|
+
},
|
|
13
|
+
"./swap": {
|
|
14
|
+
"import": "./dist/modules/swap.js",
|
|
15
|
+
"types": "./dist/modules/swap.d.ts"
|
|
16
|
+
},
|
|
17
|
+
"./orderbook": {
|
|
18
|
+
"import": "./dist/modules/orderbook.js",
|
|
19
|
+
"types": "./dist/modules/orderbook.d.ts"
|
|
20
|
+
},
|
|
21
|
+
"./signer": {
|
|
22
|
+
"import": "./dist/signer/vultisig-provider.js",
|
|
23
|
+
"types": "./dist/signer/vultisig-provider.d.ts"
|
|
24
|
+
},
|
|
25
|
+
"./utils": {
|
|
26
|
+
"import": "./dist/utils/format.js",
|
|
27
|
+
"types": "./dist/utils/format.d.ts"
|
|
28
|
+
},
|
|
29
|
+
"./assets": {
|
|
30
|
+
"import": "./dist/assets/index.js",
|
|
31
|
+
"types": "./dist/assets/index.d.ts"
|
|
32
|
+
}
|
|
33
|
+
},
|
|
34
|
+
"files": [
|
|
35
|
+
"dist",
|
|
36
|
+
"README.md",
|
|
37
|
+
"LICENSE"
|
|
38
|
+
],
|
|
39
|
+
"scripts": {
|
|
40
|
+
"build": "tsc -b",
|
|
41
|
+
"clean": "rm -rf dist",
|
|
42
|
+
"dev": "tsc -w",
|
|
43
|
+
"test": "vitest run",
|
|
44
|
+
"test:watch": "vitest",
|
|
45
|
+
"typecheck": "tsc --noEmit"
|
|
46
|
+
},
|
|
47
|
+
"dependencies": {
|
|
48
|
+
"@bufbuild/protobuf": "^2.10.2",
|
|
49
|
+
"@cosmjs/cosmwasm-stargate": "^0.32.4",
|
|
50
|
+
"@cosmjs/proto-signing": "^0.32.4",
|
|
51
|
+
"@cosmjs/stargate": "^0.32.4",
|
|
52
|
+
"big.js": "^7.0.1",
|
|
53
|
+
"cosmjs-types": "^0.9.0"
|
|
54
|
+
},
|
|
55
|
+
"devDependencies": {
|
|
56
|
+
"@types/big.js": "^6.2.2",
|
|
57
|
+
"@types/node": "^22.13.10",
|
|
58
|
+
"@vultisig/sdk": "0.5.0",
|
|
59
|
+
"typescript": "^5.8.2",
|
|
60
|
+
"vitest": "^3.0.9"
|
|
61
|
+
},
|
|
62
|
+
"peerDependencies": {
|
|
63
|
+
"@vultisig/sdk": ">=0.5.0"
|
|
64
|
+
},
|
|
65
|
+
"peerDependenciesMeta": {
|
|
66
|
+
"@vultisig/sdk": {
|
|
67
|
+
"optional": true
|
|
68
|
+
}
|
|
69
|
+
},
|
|
70
|
+
"keywords": [
|
|
71
|
+
"vultisig",
|
|
72
|
+
"rujira",
|
|
73
|
+
"thorchain",
|
|
74
|
+
"dex",
|
|
75
|
+
"swap",
|
|
76
|
+
"defi",
|
|
77
|
+
"cosmwasm",
|
|
78
|
+
"cosmos",
|
|
79
|
+
"crypto",
|
|
80
|
+
"wallet"
|
|
81
|
+
],
|
|
82
|
+
"author": "Vultisig",
|
|
83
|
+
"license": "MIT",
|
|
84
|
+
"repository": {
|
|
85
|
+
"type": "git",
|
|
86
|
+
"url": "https://github.com/vultisig/vultisig-sdk.git",
|
|
87
|
+
"directory": "packages/rujira"
|
|
88
|
+
},
|
|
89
|
+
"bugs": {
|
|
90
|
+
"url": "https://github.com/vultisig/vultisig-sdk/issues"
|
|
91
|
+
},
|
|
92
|
+
"engines": {
|
|
93
|
+
"node": ">=20.0.0"
|
|
94
|
+
},
|
|
95
|
+
"publishConfig": {
|
|
96
|
+
"access": "public"
|
|
97
|
+
}
|
|
98
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# Live Verification Tests
|
|
2
|
+
|
|
3
|
+
Tests that query THORChain mainnet to verify SDK correctness against live data.
|
|
4
|
+
|
|
5
|
+
## Running Live Tests
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
# Run all live tests
|
|
9
|
+
LIVE_TESTS=1 yarn workspace @vultisig/rujira test
|
|
10
|
+
|
|
11
|
+
# Run specific live test file
|
|
12
|
+
LIVE_TESTS=1 yarn workspace @vultisig/rujira test src/__tests__/orderside-serialization.test.ts
|
|
13
|
+
LIVE_TESTS=1 yarn workspace @vultisig/rujira test src/__tests__/outbound-fee.test.ts
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
## Test Files
|
|
17
|
+
|
|
18
|
+
### `orderside-serialization.test.ts`
|
|
19
|
+
- Verifies FIN contract OrderSide format (base/quote vs buy/sell)
|
|
20
|
+
- Queries live FIN contracts to confirm book structure
|
|
21
|
+
- **Audit Item:** H1
|
|
22
|
+
|
|
23
|
+
### `outbound-fee.test.ts`
|
|
24
|
+
- Verifies hardcoded fallback fees against THORNode
|
|
25
|
+
- Checks all chain fees are within 3x tolerance
|
|
26
|
+
- **Audit Item:** L2
|
|
27
|
+
|
|
28
|
+
## When to Run
|
|
29
|
+
|
|
30
|
+
1. **After updating hardcoded values** - Verify they match mainnet
|
|
31
|
+
2. **Before releases** - Ensure no regression
|
|
32
|
+
3. **Periodically** - Detect stale configurations
|
|
33
|
+
|
|
34
|
+
## Adding New Live Tests
|
|
35
|
+
|
|
36
|
+
Use the `describe.skipIf(!process.env.LIVE_TESTS)` pattern:
|
|
37
|
+
|
|
38
|
+
```typescript
|
|
39
|
+
describe.skipIf(!process.env.LIVE_TESTS)('Live Test Name', () => {
|
|
40
|
+
it('queries mainnet', async () => {
|
|
41
|
+
const response = await fetch('https://thornode.ninerealms.com/...');
|
|
42
|
+
// assertions
|
|
43
|
+
});
|
|
44
|
+
});
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
This ensures tests are skipped in normal CI runs but can be enabled explicitly.
|