@make-software/cspr-trade-mcp-sdk 0.1.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/README.md +257 -0
- package/dist/assets/proxy_caller.wasm +0 -0
- package/dist/index.d.ts +362 -0
- package/dist/index.js +1003 -0
- package/package.json +32 -0
- package/src/api/currencies.ts +11 -0
- package/src/api/http.ts +57 -0
- package/src/api/index.ts +9 -0
- package/src/api/liquidity.ts +22 -0
- package/src/api/pairs.ts +77 -0
- package/src/api/quotes.ts +23 -0
- package/src/api/rates.ts +33 -0
- package/src/api/submission.ts +42 -0
- package/src/api/swaps.ts +24 -0
- package/src/api/tokens.ts +57 -0
- package/src/assets/index.ts +21 -0
- package/src/assets/proxy_caller.wasm +0 -0
- package/src/client.ts +587 -0
- package/src/config.ts +60 -0
- package/src/index.ts +4 -0
- package/src/resolver/currency-resolver.ts +19 -0
- package/src/resolver/index.ts +2 -0
- package/src/resolver/token-resolver.ts +43 -0
- package/src/transactions/approve.ts +14 -0
- package/src/transactions/index.ts +5 -0
- package/src/transactions/liquidity.ts +92 -0
- package/src/transactions/proxy-wasm.ts +33 -0
- package/src/transactions/swap.ts +76 -0
- package/src/transactions/transaction-builder.ts +44 -0
- package/src/types/api.ts +32 -0
- package/src/types/index.ts +6 -0
- package/src/types/liquidity.ts +72 -0
- package/src/types/pair.ts +29 -0
- package/src/types/quote.ts +41 -0
- package/src/types/token.ts +48 -0
- package/src/types/transaction.ts +72 -0
- package/src/utils/amounts.ts +30 -0
- package/tests/integration/api.integration.test.ts +64 -0
- package/tests/unit/api/http.test.ts +68 -0
- package/tests/unit/api/liquidity.test.ts +40 -0
- package/tests/unit/api/pairs.test.ts +53 -0
- package/tests/unit/api/quotes.test.ts +59 -0
- package/tests/unit/api/rates.test.ts +27 -0
- package/tests/unit/api/tokens.test.ts +100 -0
- package/tests/unit/assets/proxy-caller.test.ts +21 -0
- package/tests/unit/client.test.ts +73 -0
- package/tests/unit/config.test.ts +23 -0
- package/tests/unit/resolver/currency-resolver.test.ts +32 -0
- package/tests/unit/resolver/token-resolver.test.ts +51 -0
- package/tests/unit/transactions/approve.test.ts +13 -0
- package/tests/unit/transactions/liquidity.test.ts +59 -0
- package/tests/unit/transactions/proxy-wasm.test.ts +50 -0
- package/tests/unit/transactions/swap.test.ts +77 -0
- package/tests/unit/utils/amounts.test.ts +44 -0
- package/tsconfig.json +9 -0
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import type { Token } from '../types/index.js';
|
|
2
|
+
|
|
3
|
+
export class TokenResolver {
|
|
4
|
+
private cache: Token[] | null = null;
|
|
5
|
+
private cacheTimestamp = 0;
|
|
6
|
+
private readonly cacheTtlMs = 30_000; // 30 seconds
|
|
7
|
+
|
|
8
|
+
constructor(private readonly fetchTokens: () => Promise<Token[]>) {}
|
|
9
|
+
|
|
10
|
+
async resolve(identifier: string): Promise<Token> {
|
|
11
|
+
const tokens = await this.getTokens();
|
|
12
|
+
const id = identifier.trim();
|
|
13
|
+
|
|
14
|
+
// 1. Match by symbol (case-insensitive)
|
|
15
|
+
const bySymbol = tokens.find(t => t.symbol.toLowerCase() === id.toLowerCase());
|
|
16
|
+
if (bySymbol) return bySymbol;
|
|
17
|
+
|
|
18
|
+
// 2. Match by contract package hash
|
|
19
|
+
const byHash = tokens.find(t => t.packageHash.toLowerCase() === id.toLowerCase());
|
|
20
|
+
if (byHash) return byHash;
|
|
21
|
+
|
|
22
|
+
// 3. Match by name (case-insensitive)
|
|
23
|
+
const byName = tokens.find(t => t.name.toLowerCase() === id.toLowerCase());
|
|
24
|
+
if (byName) return byName;
|
|
25
|
+
|
|
26
|
+
throw new Error(`Token not found: "${identifier}". Use a token symbol (e.g., "CSPR"), name, or contract package hash.`);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
async getTokens(): Promise<Token[]> {
|
|
30
|
+
const now = Date.now();
|
|
31
|
+
if (this.cache && now - this.cacheTimestamp < this.cacheTtlMs) {
|
|
32
|
+
return this.cache;
|
|
33
|
+
}
|
|
34
|
+
this.cache = await this.fetchTokens();
|
|
35
|
+
this.cacheTimestamp = now;
|
|
36
|
+
return this.cache;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
invalidateCache(): void {
|
|
40
|
+
this.cache = null;
|
|
41
|
+
this.cacheTimestamp = 0;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import casperSdk from 'casper-js-sdk';
|
|
2
|
+
const { Args, CLValue, Key } = casperSdk;
|
|
3
|
+
|
|
4
|
+
export interface ApproveArgsParams {
|
|
5
|
+
spenderPackageHash: string;
|
|
6
|
+
amount: string;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export function buildApproveArgs(params: ApproveArgsParams): Args {
|
|
10
|
+
return Args.fromMap({
|
|
11
|
+
spender: CLValue.newCLKey(Key.newKey(params.spenderPackageHash)),
|
|
12
|
+
amount: CLValue.newCLUInt256(params.amount),
|
|
13
|
+
});
|
|
14
|
+
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export { buildProxyWasmArgs, serializeInnerArgs } from './proxy-wasm.js';
|
|
2
|
+
export { getSwapEntryPoint, buildSwapInnerArgs, getSwapAttachedValue } from './swap.js';
|
|
3
|
+
export { buildAddLiquidityInnerArgs, buildRemoveLiquidityInnerArgs } from './liquidity.js';
|
|
4
|
+
export { buildApproveArgs } from './approve.js';
|
|
5
|
+
export { buildWasmTransaction, buildContractCallTransaction } from './transaction-builder.js';
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import casperSdk from 'casper-js-sdk';
|
|
2
|
+
const { Args, CLValue, Key } = casperSdk;
|
|
3
|
+
|
|
4
|
+
export type AddLiquidityInnerArgsParams =
|
|
5
|
+
| {
|
|
6
|
+
isCSPRPair: false;
|
|
7
|
+
tokenAHash: string;
|
|
8
|
+
tokenBHash: string;
|
|
9
|
+
amountADesired: string;
|
|
10
|
+
amountBDesired: string;
|
|
11
|
+
amountAMin: string;
|
|
12
|
+
amountBMin: string;
|
|
13
|
+
accountHash: string;
|
|
14
|
+
deadline: number;
|
|
15
|
+
}
|
|
16
|
+
| {
|
|
17
|
+
isCSPRPair: true;
|
|
18
|
+
tokenHash: string;
|
|
19
|
+
amountTokenDesired: string;
|
|
20
|
+
amountTokenMin: string;
|
|
21
|
+
amountCSPRMin: string;
|
|
22
|
+
accountHash: string;
|
|
23
|
+
deadline: number;
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
export function buildAddLiquidityInnerArgs(params: AddLiquidityInnerArgsParams): Args {
|
|
27
|
+
if (params.isCSPRPair) {
|
|
28
|
+
return Args.fromMap({
|
|
29
|
+
token: CLValue.newCLKey(Key.newKey(params.tokenHash)),
|
|
30
|
+
amount_token_desired: CLValue.newCLUInt256(params.amountTokenDesired),
|
|
31
|
+
amount_token_min: CLValue.newCLUInt256(params.amountTokenMin),
|
|
32
|
+
amount_cspr_min: CLValue.newCLUInt256(params.amountCSPRMin),
|
|
33
|
+
to: CLValue.newCLKey(Key.newKey(params.accountHash)),
|
|
34
|
+
deadline: CLValue.newCLUint64(params.deadline),
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
return Args.fromMap({
|
|
39
|
+
token_a: CLValue.newCLKey(Key.newKey(params.tokenAHash)),
|
|
40
|
+
token_b: CLValue.newCLKey(Key.newKey(params.tokenBHash)),
|
|
41
|
+
amount_a_desired: CLValue.newCLUInt256(params.amountADesired),
|
|
42
|
+
amount_b_desired: CLValue.newCLUInt256(params.amountBDesired),
|
|
43
|
+
amount_a_min: CLValue.newCLUInt256(params.amountAMin),
|
|
44
|
+
amount_b_min: CLValue.newCLUInt256(params.amountBMin),
|
|
45
|
+
to: CLValue.newCLKey(Key.newKey(params.accountHash)),
|
|
46
|
+
deadline: CLValue.newCLUint64(params.deadline),
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export type RemoveLiquidityInnerArgsParams =
|
|
51
|
+
| {
|
|
52
|
+
isCSPRPair: false;
|
|
53
|
+
tokenAHash: string;
|
|
54
|
+
tokenBHash: string;
|
|
55
|
+
liquidity: string;
|
|
56
|
+
amountAMin: string;
|
|
57
|
+
amountBMin: string;
|
|
58
|
+
accountHash: string;
|
|
59
|
+
deadline: number;
|
|
60
|
+
}
|
|
61
|
+
| {
|
|
62
|
+
isCSPRPair: true;
|
|
63
|
+
tokenHash: string;
|
|
64
|
+
liquidity: string;
|
|
65
|
+
amountTokenMin: string;
|
|
66
|
+
amountCSPRMin: string;
|
|
67
|
+
accountHash: string;
|
|
68
|
+
deadline: number;
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
export function buildRemoveLiquidityInnerArgs(params: RemoveLiquidityInnerArgsParams): Args {
|
|
72
|
+
if (params.isCSPRPair) {
|
|
73
|
+
return Args.fromMap({
|
|
74
|
+
token: CLValue.newCLKey(Key.newKey(params.tokenHash)),
|
|
75
|
+
liquidity: CLValue.newCLUInt256(params.liquidity),
|
|
76
|
+
amount_token_min: CLValue.newCLUInt256(params.amountTokenMin),
|
|
77
|
+
amount_cspr_min: CLValue.newCLUInt256(params.amountCSPRMin),
|
|
78
|
+
to: CLValue.newCLKey(Key.newKey(params.accountHash)),
|
|
79
|
+
deadline: CLValue.newCLUint64(params.deadline),
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
return Args.fromMap({
|
|
84
|
+
token_a: CLValue.newCLKey(Key.newKey(params.tokenAHash)),
|
|
85
|
+
token_b: CLValue.newCLKey(Key.newKey(params.tokenBHash)),
|
|
86
|
+
liquidity: CLValue.newCLUInt256(params.liquidity),
|
|
87
|
+
amount_a_min: CLValue.newCLUInt256(params.amountAMin),
|
|
88
|
+
amount_b_min: CLValue.newCLUInt256(params.amountBMin),
|
|
89
|
+
to: CLValue.newCLKey(Key.newKey(params.accountHash)),
|
|
90
|
+
deadline: CLValue.newCLUint64(params.deadline),
|
|
91
|
+
});
|
|
92
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { hexToBytes } from '@noble/hashes/utils';
|
|
2
|
+
import casperSdk from 'casper-js-sdk';
|
|
3
|
+
const { Args, CLTypeUInt8, CLValue } = casperSdk;
|
|
4
|
+
|
|
5
|
+
export interface ProxyWasmArgsParams {
|
|
6
|
+
routerPackageHash: string; // hex without 'hash-' prefix
|
|
7
|
+
entryPoint: string;
|
|
8
|
+
innerArgs: Args;
|
|
9
|
+
attachedValue: string; // motes as string
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export function serializeInnerArgs(args: Args): Uint8Array {
|
|
13
|
+
return args.toBytes();
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export function buildProxyWasmArgs(params: ProxyWasmArgsParams): Args {
|
|
17
|
+
const { routerPackageHash, entryPoint, innerArgs, attachedValue } = params;
|
|
18
|
+
|
|
19
|
+
const rawArgsBytes = serializeInnerArgs(innerArgs);
|
|
20
|
+
|
|
21
|
+
const argsBytes: CLValue[] = [];
|
|
22
|
+
for (let i = 0; i < rawArgsBytes.length; i++) {
|
|
23
|
+
argsBytes.push(CLValue.newCLUint8(rawArgsBytes[i]));
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
return Args.fromMap({
|
|
27
|
+
package_hash: CLValue.newCLByteArray(hexToBytes(routerPackageHash)),
|
|
28
|
+
entry_point: CLValue.newCLString(entryPoint),
|
|
29
|
+
args: CLValue.newCLList(CLTypeUInt8, argsBytes),
|
|
30
|
+
attached_value: CLValue.newCLUInt512(attachedValue),
|
|
31
|
+
amount: CLValue.newCLUInt512(attachedValue),
|
|
32
|
+
});
|
|
33
|
+
}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import casperSdk from 'casper-js-sdk';
|
|
2
|
+
const { Args, CLTypeKey, CLValue, Key } = casperSdk;
|
|
3
|
+
import type { QuoteType } from '../types/index.js';
|
|
4
|
+
|
|
5
|
+
export function getSwapEntryPoint(
|
|
6
|
+
isFirstTokenNative: boolean,
|
|
7
|
+
isSecondTokenNative: boolean,
|
|
8
|
+
quoteType: QuoteType,
|
|
9
|
+
): string {
|
|
10
|
+
if (isFirstTokenNative) {
|
|
11
|
+
return quoteType === 'exact_in' ? 'swap_exact_cspr_for_tokens' : 'swap_cspr_for_exact_tokens';
|
|
12
|
+
}
|
|
13
|
+
if (isSecondTokenNative) {
|
|
14
|
+
return quoteType === 'exact_in' ? 'swap_exact_tokens_for_cspr' : 'swap_tokens_for_exact_cspr';
|
|
15
|
+
}
|
|
16
|
+
return quoteType === 'exact_in' ? 'swap_exact_tokens_for_tokens' : 'swap_tokens_for_exact_tokens';
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export interface SwapInnerArgsParams {
|
|
20
|
+
isFirstTokenNative: boolean;
|
|
21
|
+
isSecondTokenNative: boolean;
|
|
22
|
+
quoteType: QuoteType;
|
|
23
|
+
path: string[];
|
|
24
|
+
accountHash: string;
|
|
25
|
+
deadline: number;
|
|
26
|
+
amountIn: string;
|
|
27
|
+
amountOut: string;
|
|
28
|
+
amountInMax: string;
|
|
29
|
+
amountOutMin: string;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export function buildSwapInnerArgs(params: SwapInnerArgsParams): Args {
|
|
33
|
+
const {
|
|
34
|
+
isFirstTokenNative, isSecondTokenNative, quoteType,
|
|
35
|
+
path, accountHash, deadline,
|
|
36
|
+
amountIn, amountOut, amountInMax, amountOutMin,
|
|
37
|
+
} = params;
|
|
38
|
+
|
|
39
|
+
const isBothNotNative = !isFirstTokenNative && !isSecondTokenNative;
|
|
40
|
+
|
|
41
|
+
const argsMap: Record<string, CLValue> = {
|
|
42
|
+
path: CLValue.newCLList(
|
|
43
|
+
CLTypeKey,
|
|
44
|
+
path.map(hash => CLValue.newCLKey(Key.newKey(hash))),
|
|
45
|
+
),
|
|
46
|
+
to: CLValue.newCLKey(Key.newKey(accountHash)),
|
|
47
|
+
deadline: CLValue.newCLUint64(deadline),
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
if (isFirstTokenNative && quoteType === 'exact_in') {
|
|
51
|
+
argsMap.amount_out_min = CLValue.newCLUInt256(amountOutMin);
|
|
52
|
+
}
|
|
53
|
+
if (isFirstTokenNative && quoteType === 'exact_out') {
|
|
54
|
+
argsMap.amount_out = CLValue.newCLUInt256(amountOut);
|
|
55
|
+
}
|
|
56
|
+
if ((isSecondTokenNative || isBothNotNative) && quoteType === 'exact_in') {
|
|
57
|
+
argsMap.amount_in = CLValue.newCLUInt256(amountIn);
|
|
58
|
+
argsMap.amount_out_min = CLValue.newCLUInt256(amountOutMin);
|
|
59
|
+
}
|
|
60
|
+
if ((isSecondTokenNative || isBothNotNative) && quoteType === 'exact_out') {
|
|
61
|
+
argsMap.amount_in_max = CLValue.newCLUInt256(amountInMax);
|
|
62
|
+
argsMap.amount_out = CLValue.newCLUInt256(amountOut);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
return Args.fromMap(argsMap);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export function getSwapAttachedValue(params: {
|
|
69
|
+
isFirstTokenNative: boolean;
|
|
70
|
+
quoteType: QuoteType;
|
|
71
|
+
amountIn: string;
|
|
72
|
+
amountInMax: string;
|
|
73
|
+
}): string {
|
|
74
|
+
if (!params.isFirstTokenNative) return '0';
|
|
75
|
+
return params.quoteType === 'exact_in' ? params.amountIn : params.amountInMax;
|
|
76
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import casperSdk from 'casper-js-sdk';
|
|
2
|
+
import type { Args, Transaction } from 'casper-js-sdk';
|
|
3
|
+
const { SessionBuilder, ContractCallBuilder, PublicKey } = casperSdk;
|
|
4
|
+
import type { NetworkConfig } from '../config.js';
|
|
5
|
+
|
|
6
|
+
export function buildWasmTransaction(params: {
|
|
7
|
+
publicKey: string;
|
|
8
|
+
paymentAmount: string;
|
|
9
|
+
wasmBinary: Uint8Array;
|
|
10
|
+
runtimeArgs: Args;
|
|
11
|
+
networkConfig: NetworkConfig;
|
|
12
|
+
}): Transaction {
|
|
13
|
+
const { publicKey, paymentAmount, wasmBinary, runtimeArgs, networkConfig } = params;
|
|
14
|
+
return new SessionBuilder()
|
|
15
|
+
.from(PublicKey.fromHex(publicKey))
|
|
16
|
+
.wasm(wasmBinary)
|
|
17
|
+
.installOrUpgrade()
|
|
18
|
+
.runtimeArgs(runtimeArgs)
|
|
19
|
+
.chainName(networkConfig.chainName)
|
|
20
|
+
.payment(Number(paymentAmount))
|
|
21
|
+
.ttl(networkConfig.ttl)
|
|
22
|
+
.build();
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export function buildContractCallTransaction(params: {
|
|
26
|
+
publicKey: string;
|
|
27
|
+
paymentAmount: string;
|
|
28
|
+
contractPackageHash: string;
|
|
29
|
+
entryPoint: string;
|
|
30
|
+
runtimeArgs: Args;
|
|
31
|
+
networkConfig: NetworkConfig;
|
|
32
|
+
}): Transaction {
|
|
33
|
+
const { publicKey, paymentAmount, contractPackageHash, entryPoint, runtimeArgs, networkConfig } = params;
|
|
34
|
+
const hash = contractPackageHash.replace('hash-', '');
|
|
35
|
+
return new ContractCallBuilder()
|
|
36
|
+
.from(PublicKey.fromHex(publicKey))
|
|
37
|
+
.byPackageHash(hash)
|
|
38
|
+
.entryPoint(entryPoint)
|
|
39
|
+
.runtimeArgs(runtimeArgs)
|
|
40
|
+
.chainName(networkConfig.chainName)
|
|
41
|
+
.payment(Number(paymentAmount))
|
|
42
|
+
.ttl(networkConfig.ttl)
|
|
43
|
+
.build();
|
|
44
|
+
}
|
package/src/types/api.ts
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/** Generic API success response */
|
|
2
|
+
export interface ApiResponse<T> {
|
|
3
|
+
data: T;
|
|
4
|
+
message?: string;
|
|
5
|
+
status?: string;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
/** Paginated API response */
|
|
9
|
+
export interface PaginatedApiResponse<T> {
|
|
10
|
+
data: T[];
|
|
11
|
+
item_count: number;
|
|
12
|
+
page_count: number;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/** API error */
|
|
16
|
+
export interface ApiError {
|
|
17
|
+
code: number;
|
|
18
|
+
message: string;
|
|
19
|
+
status?: number;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/** Pagination options */
|
|
23
|
+
export interface PaginationOptions {
|
|
24
|
+
page?: number;
|
|
25
|
+
page_size?: number;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/** Sort options */
|
|
29
|
+
export interface SortOptions {
|
|
30
|
+
order_by?: string;
|
|
31
|
+
order_direction?: 'asc' | 'desc';
|
|
32
|
+
}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import type { PairApiResponse } from './pair.js';
|
|
2
|
+
|
|
3
|
+
/** Liquidity position API response */
|
|
4
|
+
export interface LiquidityPositionApiResponse {
|
|
5
|
+
account_hash: string;
|
|
6
|
+
pair_contract_package_hash: string;
|
|
7
|
+
lp_token_balance: string;
|
|
8
|
+
pair: PairApiResponse;
|
|
9
|
+
pair_lp_tokens_total_supply: string;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
/** Liquidity position for SDK consumption */
|
|
13
|
+
export interface LiquidityPosition {
|
|
14
|
+
accountHash: string;
|
|
15
|
+
pairContractPackageHash: string;
|
|
16
|
+
lpTokenBalance: string;
|
|
17
|
+
lpTokenTotalSupply: string;
|
|
18
|
+
pair: {
|
|
19
|
+
token0Symbol: string;
|
|
20
|
+
token1Symbol: string;
|
|
21
|
+
token0PackageHash: string;
|
|
22
|
+
token1PackageHash: string;
|
|
23
|
+
reserve0: string;
|
|
24
|
+
reserve1: string;
|
|
25
|
+
decimals0: number;
|
|
26
|
+
decimals1: number;
|
|
27
|
+
};
|
|
28
|
+
/** User's share of the pool as percentage */
|
|
29
|
+
poolShare: string;
|
|
30
|
+
/** Estimated token0 amount based on pool share */
|
|
31
|
+
estimatedToken0Amount: string;
|
|
32
|
+
/** Estimated token1 amount based on pool share */
|
|
33
|
+
estimatedToken1Amount: string;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/** Impermanent loss response */
|
|
37
|
+
export interface ImpermanentLossApiResponse {
|
|
38
|
+
pair_contract_package_hash: string;
|
|
39
|
+
account_hash: string;
|
|
40
|
+
value: string;
|
|
41
|
+
timestamp: string;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export interface ImpermanentLoss {
|
|
45
|
+
pairContractPackageHash: string;
|
|
46
|
+
value: string;
|
|
47
|
+
timestamp: string;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/** Add liquidity parameters */
|
|
51
|
+
export interface AddLiquidityParams {
|
|
52
|
+
tokenA: string; // symbol, name, or hash
|
|
53
|
+
tokenB: string; // symbol, name, or hash
|
|
54
|
+
amountA: string; // human-readable
|
|
55
|
+
amountB: string; // human-readable
|
|
56
|
+
slippageBps?: number; // basis points (default 300 = 3%)
|
|
57
|
+
deadlineMinutes?: number; // default 20
|
|
58
|
+
senderPublicKey: string; // hex public key
|
|
59
|
+
/** Raw token A balance for approval amount. Falls back to amountA in motes. */
|
|
60
|
+
tokenABalance?: string;
|
|
61
|
+
/** Raw token B balance for approval amount. Falls back to amountB in motes. */
|
|
62
|
+
tokenBBalance?: string;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/** Remove liquidity parameters */
|
|
66
|
+
export interface RemoveLiquidityParams {
|
|
67
|
+
pairContractPackageHash: string;
|
|
68
|
+
percentage: number; // 1-100
|
|
69
|
+
slippageBps?: number;
|
|
70
|
+
deadlineMinutes?: number;
|
|
71
|
+
senderPublicKey: string;
|
|
72
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { ContractPackage } from './token.js';
|
|
2
|
+
|
|
3
|
+
/** Pair as returned by API */
|
|
4
|
+
export interface PairApiResponse {
|
|
5
|
+
contract_package_hash: string;
|
|
6
|
+
token0_contract_package_hash: string;
|
|
7
|
+
token1_contract_package_hash: string;
|
|
8
|
+
decimals0: number;
|
|
9
|
+
decimals1: number;
|
|
10
|
+
reserve0: string;
|
|
11
|
+
reserve1: string;
|
|
12
|
+
timestamp: string;
|
|
13
|
+
latest_event_id: string;
|
|
14
|
+
contract_package: ContractPackage;
|
|
15
|
+
token0_contract_package: ContractPackage;
|
|
16
|
+
token1_contract_package: ContractPackage;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/** Pair for SDK consumption */
|
|
20
|
+
export interface Pair {
|
|
21
|
+
contractPackageHash: string;
|
|
22
|
+
token0: { packageHash: string; symbol: string; name: string; decimals: number; iconUrl: string | null };
|
|
23
|
+
token1: { packageHash: string; symbol: string; name: string; decimals: number; iconUrl: string | null };
|
|
24
|
+
reserve0: string;
|
|
25
|
+
reserve1: string;
|
|
26
|
+
timestamp: string;
|
|
27
|
+
fiatPrice0: number | null;
|
|
28
|
+
fiatPrice1: number | null;
|
|
29
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/** Quote API response */
|
|
2
|
+
export interface QuoteApiResponse {
|
|
3
|
+
amount_in: string;
|
|
4
|
+
amount_out: string;
|
|
5
|
+
execution_price: string;
|
|
6
|
+
mid_price: string;
|
|
7
|
+
path: string[];
|
|
8
|
+
price_impact: string;
|
|
9
|
+
recommended_slippage_bps: string;
|
|
10
|
+
type_id: 1 | 2;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/** Quote type enum */
|
|
14
|
+
export type QuoteType = 'exact_in' | 'exact_out';
|
|
15
|
+
|
|
16
|
+
/** Quote parameters */
|
|
17
|
+
export interface QuoteParams {
|
|
18
|
+
tokenIn: string; // symbol, name, or hash
|
|
19
|
+
tokenOut: string; // symbol, name, or hash
|
|
20
|
+
amount: string; // human-readable amount
|
|
21
|
+
type: QuoteType;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/** Resolved quote for SDK consumption */
|
|
25
|
+
export interface Quote {
|
|
26
|
+
amountIn: string; // raw amount
|
|
27
|
+
amountOut: string; // raw amount
|
|
28
|
+
amountInFormatted: string; // human-readable
|
|
29
|
+
amountOutFormatted: string; // human-readable
|
|
30
|
+
executionPrice: string;
|
|
31
|
+
midPrice: string;
|
|
32
|
+
path: string[]; // contract package hashes
|
|
33
|
+
pathSymbols: string[]; // token symbols for display
|
|
34
|
+
priceImpact: string; // percentage string
|
|
35
|
+
recommendedSlippageBps: string;
|
|
36
|
+
type: QuoteType;
|
|
37
|
+
tokenInSymbol: string;
|
|
38
|
+
tokenOutSymbol: string;
|
|
39
|
+
tokenInDecimals: number;
|
|
40
|
+
tokenOutDecimals: number;
|
|
41
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/** Contract package metadata from CSPR.cloud */
|
|
2
|
+
export interface ContractPackage {
|
|
3
|
+
contract_package_hash: string;
|
|
4
|
+
owner_public_key: string;
|
|
5
|
+
name: string;
|
|
6
|
+
description: string | null;
|
|
7
|
+
metadata: TokenMetadata;
|
|
8
|
+
icon_url: string | null;
|
|
9
|
+
website_url: string | null;
|
|
10
|
+
latest_version_contract_hash: string | null;
|
|
11
|
+
csprtrade_data: { price: number } | null;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export interface TokenMetadata {
|
|
15
|
+
balances_uref: string;
|
|
16
|
+
decimals: number;
|
|
17
|
+
name: string;
|
|
18
|
+
symbol: string;
|
|
19
|
+
total_supply_uref: string;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/** Token as returned by GET /tokens */
|
|
23
|
+
export interface TokenApiResponse {
|
|
24
|
+
contract_package_hash: string;
|
|
25
|
+
contract_package: ContractPackage;
|
|
26
|
+
listed_at: string;
|
|
27
|
+
sorting_order: number;
|
|
28
|
+
total_value_locked?: string;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/** Resolved token for SDK consumption */
|
|
32
|
+
export interface Token {
|
|
33
|
+
id: string;
|
|
34
|
+
name: string;
|
|
35
|
+
symbol: string;
|
|
36
|
+
decimals: number;
|
|
37
|
+
packageHash: string;
|
|
38
|
+
iconUrl: string | null;
|
|
39
|
+
fiatPrice: number | null;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/** Currency for fiat display */
|
|
43
|
+
export interface Currency {
|
|
44
|
+
id: number;
|
|
45
|
+
code: string;
|
|
46
|
+
name: string;
|
|
47
|
+
symbol: string;
|
|
48
|
+
}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
/** Swap parameters */
|
|
2
|
+
export interface SwapParams {
|
|
3
|
+
tokenIn: string; // symbol, name, or hash
|
|
4
|
+
tokenOut: string; // symbol, name, or hash
|
|
5
|
+
amount: string; // human-readable
|
|
6
|
+
type: 'exact_in' | 'exact_out';
|
|
7
|
+
slippageBps?: number; // basis points (default 300 = 3%)
|
|
8
|
+
deadlineMinutes?: number; // default 20
|
|
9
|
+
senderPublicKey: string; // hex public key
|
|
10
|
+
/** Raw token balance for approval amount (matching CSPR.trade pattern). Falls back to swap amount. */
|
|
11
|
+
tokenInBalance?: string;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/** Token approval parameters */
|
|
15
|
+
export interface ApprovalParams {
|
|
16
|
+
tokenContractPackageHash: string;
|
|
17
|
+
spenderPackageHash: string;
|
|
18
|
+
amount: string; // raw amount
|
|
19
|
+
senderPublicKey: string;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/** The result of building a transaction */
|
|
23
|
+
export interface TransactionBundle {
|
|
24
|
+
/** The unsigned transaction as JSON */
|
|
25
|
+
transactionJson: string;
|
|
26
|
+
/** Human-readable description of what this transaction does */
|
|
27
|
+
summary: string;
|
|
28
|
+
/** Gas cost in CSPR */
|
|
29
|
+
estimatedGasCost: string;
|
|
30
|
+
/** If token approvals are needed first, these contain those transactions (sign & submit each before the main tx) */
|
|
31
|
+
approvalsRequired?: TransactionBundle[];
|
|
32
|
+
/** Safety warnings (high price impact, high slippage, etc.) */
|
|
33
|
+
warnings: string[];
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/** Result of submitting a transaction */
|
|
37
|
+
export interface SubmitResult {
|
|
38
|
+
transactionHash: string;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/** Transaction status */
|
|
42
|
+
export interface TransactionStatus {
|
|
43
|
+
hash: string;
|
|
44
|
+
status: 'pending' | 'success' | 'failed' | 'expired';
|
|
45
|
+
errorMessage?: string;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/** Signer interface for pluggable signing */
|
|
49
|
+
export interface Signer {
|
|
50
|
+
sign(deployJson: string): Promise<string>;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/** Swap history entry */
|
|
54
|
+
export interface SwapHistoryEntry {
|
|
55
|
+
transactionHash: string;
|
|
56
|
+
timestamp: string;
|
|
57
|
+
token0ContractPackageHash: string;
|
|
58
|
+
token1ContractPackageHash: string;
|
|
59
|
+
amount0In: string;
|
|
60
|
+
amount1In: string;
|
|
61
|
+
amount0Out: string;
|
|
62
|
+
amount1Out: string;
|
|
63
|
+
senderAccountHash: string;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/** Swap history query params */
|
|
67
|
+
export interface SwapHistoryQuery {
|
|
68
|
+
publicKey?: string;
|
|
69
|
+
pairContractPackageHash?: string;
|
|
70
|
+
page?: number;
|
|
71
|
+
pageSize?: number;
|
|
72
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import Big from 'big.js';
|
|
2
|
+
|
|
3
|
+
export function toRawAmount(humanAmount: string, decimals: number): string {
|
|
4
|
+
const big = new Big(humanAmount);
|
|
5
|
+
const multiplier = new Big(10).pow(decimals);
|
|
6
|
+
return big.times(multiplier).toFixed(0);
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export function toFormattedAmount(rawAmount: string, decimals: number): string {
|
|
10
|
+
const big = new Big(rawAmount);
|
|
11
|
+
const divisor = new Big(10).pow(decimals);
|
|
12
|
+
const result = big.div(divisor);
|
|
13
|
+
const str = result.toFixed();
|
|
14
|
+
if (str.includes('.')) {
|
|
15
|
+
return str.replace(/\.?0+$/, '') || '0';
|
|
16
|
+
}
|
|
17
|
+
return str;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export function calculateMinWithSlippage(rawAmount: string, slippageBps: number): string {
|
|
21
|
+
const amount = new Big(rawAmount);
|
|
22
|
+
const factor = new Big(1).minus(new Big(slippageBps).div(10000));
|
|
23
|
+
return amount.times(factor).toFixed(0, Big.roundDown);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export function calculateMaxWithSlippage(rawAmount: string, slippageBps: number): string {
|
|
27
|
+
const amount = new Big(rawAmount);
|
|
28
|
+
const factor = new Big(1).plus(new Big(slippageBps).div(10000));
|
|
29
|
+
return amount.times(factor).toFixed(0, Big.roundUp);
|
|
30
|
+
}
|