swaply-sdk-ts 0.0.1

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.
@@ -0,0 +1,139 @@
1
+ import tsPlugin from '@typescript-eslint/eslint-plugin';
2
+ import prettier from 'eslint-plugin-prettier';
3
+ import simpleImportSort from 'eslint-plugin-simple-import-sort';
4
+ import unicorn from 'eslint-plugin-unicorn';
5
+ import unusedImports from 'eslint-plugin-unused-imports';
6
+ import globals from 'globals';
7
+ import tseslint from 'typescript-eslint';
8
+
9
+ export default tseslint.config(
10
+ {
11
+ ignores: ['dist', 'node_modules', 'src/tests'],
12
+ },
13
+ {
14
+ files: ['**/*.{ts,tsx}'],
15
+ languageOptions: {
16
+ ecmaVersion: 2020,
17
+ sourceType: 'module',
18
+ parser: tseslint.parser,
19
+ parserOptions: {
20
+ project: './tsconfig.json',
21
+ },
22
+ globals: globals.browser,
23
+ },
24
+ plugins: {
25
+ '@typescript-eslint': tsPlugin,
26
+ prettier,
27
+ unicorn,
28
+ 'simple-import-sort': simpleImportSort,
29
+ 'unused-imports': unusedImports,
30
+ },
31
+ rules: {
32
+ ...tsPlugin.configs.recommended.rules,
33
+ ...unicorn.configs.recommended.rules,
34
+ 'prettier/prettier': ['warn', { tabWidth: 4, singleQuote: true }],
35
+ 'import/order': 'off',
36
+ 'sort-imports': 'off',
37
+ 'simple-import-sort/imports': [
38
+ 'error',
39
+ {
40
+ groups: [
41
+ [String.raw`^\u0000`], // side effects
42
+ ['^node:'],
43
+ [String.raw`^@?(?!app|api|components|static|store|images)[\w-]`], // external
44
+ ['^@components/', '^@app/', '^@api/', '^@store/', '^@/'], // internal
45
+ ['^@static/', '^@images/'], // assets
46
+ [
47
+ String.raw`^\.\.(?!/?$)`,
48
+ String.raw`^\./(?=.*/)`,
49
+ String.raw`^\.(?!/?$)`,
50
+ String.raw`^\./?$`,
51
+ ], // local
52
+ [String.raw`^.+\.s?css$`], // styles
53
+ ],
54
+ },
55
+ ],
56
+ 'simple-import-sort/exports': 'error',
57
+ 'unused-imports/no-unused-imports': 'error',
58
+ 'unused-imports/no-unused-vars': [
59
+ 'warn',
60
+ {
61
+ vars: 'all',
62
+ varsIgnorePattern: '^_',
63
+ args: 'after-used',
64
+ argsIgnorePattern: '^_',
65
+ },
66
+ ],
67
+ '@typescript-eslint/naming-convention': [
68
+ 'warn',
69
+ {
70
+ selector: 'variable',
71
+ format: ['camelCase', 'PascalCase', 'UPPER_CASE'],
72
+ leadingUnderscore: 'allow',
73
+ },
74
+ {
75
+ selector: 'function',
76
+ format: ['camelCase', 'PascalCase'],
77
+ },
78
+ ],
79
+ semi: ['warn', 'always'],
80
+ 'no-console': 'error',
81
+ 'padding-line-between-statements': [
82
+ 'warn',
83
+ { blankLine: 'always', prev: '*', next: 'return' },
84
+ ],
85
+ 'spaced-comment': ['error', 'always', { markers: ['/'] }],
86
+ '@typescript-eslint/no-misused-new': 'error',
87
+ 'consistent-return': 'off',
88
+ 'guard-for-in': 'error',
89
+ 'no-constructor-return': 'error',
90
+ 'no-else-return': 'error',
91
+ 'no-eval': 'error',
92
+ 'no-extend-native': 'error',
93
+ 'no-extra-bind': 'error',
94
+ 'no-floating-decimal': 'error',
95
+ 'no-implicit-globals': 'error',
96
+ 'no-new': 'error',
97
+ 'no-script-url': 'error',
98
+ 'max-depth': ['error', 3],
99
+ 'max-nested-callbacks': ['error', 3],
100
+ 'new-cap': 'error',
101
+ 'no-multi-assign': 'error',
102
+ 'no-multiple-empty-lines': 'error',
103
+ 'no-nested-ternary': 'error',
104
+ 'no-trailing-spaces': 'error',
105
+ 'no-underscore-dangle': 'error',
106
+ 'no-whitespace-before-property': 'error',
107
+ 'object-curly-spacing': ['error', 'always'],
108
+ 'operator-assignment': ['error', 'always'],
109
+ 'padded-blocks': ['error', 'never'],
110
+ 'semi-spacing': 'error',
111
+ 'semi-style': ['error', 'last'],
112
+ 'space-before-blocks': 'error',
113
+ 'space-in-parens': ['error', 'never'],
114
+ 'space-unary-ops': 'error',
115
+ 'switch-colon-spacing': 'error',
116
+ 'array-bracket-spacing': ['error', 'never'],
117
+ 'block-spacing': 'error',
118
+ camelcase: 'off',
119
+ 'unicorn/prefer-switch': ['error', { minimumCases: 3 }],
120
+ 'unicorn/filename-case': 'off',
121
+ 'unicorn/prefer-query-selector': 'off',
122
+ 'unicorn/prevent-abbreviations': 'off',
123
+ 'unicorn/no-null': 'off',
124
+ 'unicorn/consistent-function-scoping': 'off',
125
+ 'unicorn/prefer-logical-operator-over-ternary': 'off',
126
+ 'unicorn/no-static-only-class': 'off',
127
+ 'unicorn/prefer-ternary': 'off',
128
+ 'unicorn/prefer-global-this': 'off',
129
+ 'unicorn/no-negated-condition': 'off',
130
+ 'unicorn/prefer-spread': 'off',
131
+ '@typescript-eslint/no-unused-expressions': 'off',
132
+ '@typescript-eslint/no-explicit-any': 'off',
133
+ 'unicorn/prefer-string-replace-all': 'off',
134
+ '@typescript-eslint/no-duplicate-enum-values': 'off',
135
+ '@typescript-eslint/no-unused-vars': 'off',
136
+ 'react-hooks/exhaustive-deps': 'off',
137
+ },
138
+ },
139
+ );
package/package.json ADDED
@@ -0,0 +1,29 @@
1
+ {
2
+ "name": "swaply-sdk-ts",
3
+ "version": "0.0.1",
4
+ "type": "module",
5
+ "module": "src/index.ts",
6
+ "dependencies": {
7
+ "axios": "^1.13.4",
8
+ "viem": "^2.45.0"
9
+ },
10
+ "devDependencies": {
11
+ "@eslint/js": "9.25.1",
12
+ "@types/bun": "latest",
13
+ "@types/node": "22.15.16",
14
+ "@types/react": "19.0.10",
15
+ "@types/react-dom": "19.0.4",
16
+ "@typescript-eslint/eslint-plugin": "8.31.0",
17
+ "@typescript-eslint/parser": "8.31.0",
18
+ "@vitejs/plugin-react": "4.3.4",
19
+ "eslint": "9.25.1",
20
+ "eslint-plugin-prettier": "5.2.6",
21
+ "eslint-plugin-simple-import-sort": "12.1.1",
22
+ "eslint-plugin-unicorn": "58.0.0",
23
+ "eslint-plugin-unused-imports": "4.1.4",
24
+ "typescript-eslint": "8.26.1"
25
+ },
26
+ "peerDependencies": {
27
+ "typescript": "^5.0.0"
28
+ }
29
+ }
@@ -0,0 +1,123 @@
1
+ import axios from 'axios';
2
+ import type { AxiosInstance, AxiosRequestConfig, AxiosResponse } from 'axios';
3
+ import type {
4
+ Quote,
5
+ CreateIntentData,
6
+ IntentStatus,
7
+ PublicSwapWithAdditionalInfo,
8
+ PaginatedResponse,
9
+ Network,
10
+ Token,
11
+ SwapType,
12
+ SignedApproval,
13
+ } from './types';
14
+
15
+ export class SwaplyApiClient {
16
+ private client: AxiosInstance;
17
+ private apiUrl: string;
18
+
19
+ constructor(apiUrl: string, apiKey: string, config?: AxiosRequestConfig) {
20
+ this.apiUrl = apiUrl;
21
+ this.client = axios.create({
22
+ baseURL: apiUrl,
23
+ headers: {
24
+ 'x-api-key': apiKey,
25
+ },
26
+ ...config,
27
+ });
28
+ }
29
+
30
+ async getQuote(
31
+ sourceChain: number,
32
+ sourceToken: string,
33
+ destChain: number,
34
+ destToken: string,
35
+ amount: number,
36
+ slippageBps: bigint,
37
+ swapType: SwapType,
38
+ retailUserId: string | null = null,
39
+ ): Promise<Quote> {
40
+ const response: AxiosResponse<Quote> = await this.client.post('/quotes/best', {
41
+ source_chain: sourceChain,
42
+ source_token: sourceToken,
43
+ dest_chain: destChain,
44
+ dest_token: destToken,
45
+ amount,
46
+ slippage_bps: slippageBps.toString(),
47
+ swap_type: swapType,
48
+ retail_user_id: retailUserId,
49
+ });
50
+ return response.data;
51
+ }
52
+
53
+ async createIntent(
54
+ quoteId: string,
55
+ userSourcePublicKey: string,
56
+ userSourceAddress: string,
57
+ userDestinationAddress: string,
58
+ refundAddress: string,
59
+ ): Promise<CreateIntentData> {
60
+ const response: AxiosResponse<CreateIntentData> = await this.client.post(
61
+ '/intents/create',
62
+ {
63
+ quote_id: quoteId,
64
+ user_source_public_key: userSourcePublicKey,
65
+ user_source_address: userSourceAddress,
66
+ user_destination_address: userDestinationAddress,
67
+ refund_address: refundAddress,
68
+ },
69
+ );
70
+ return response.data;
71
+ }
72
+
73
+ async addApproval(signedData: SignedApproval, intentId: string): Promise<void> {
74
+ await this.client.post(`/intents/${intentId}/approvals`, signedData);
75
+ }
76
+
77
+ async getIntentStatus(intentId: string): Promise<IntentStatus> {
78
+ const response: AxiosResponse<{ status: IntentStatus }> = await this.client.get(
79
+ `/intents/${intentId}/status`,
80
+ );
81
+ return response.data.status;
82
+ }
83
+
84
+ async listRetailUserHistory(
85
+ walletAddressOrRetailId: string,
86
+ ): Promise<PaginatedResponse<PublicSwapWithAdditionalInfo>> {
87
+ const response: AxiosResponse<PaginatedResponse<PublicSwapWithAdditionalInfo>> =
88
+ await this.client.get(`/history/${walletAddressOrRetailId}`);
89
+ return response.data;
90
+ }
91
+
92
+ async getSwapByIntentId(intentId: string): Promise<PublicSwapWithAdditionalInfo> {
93
+ const response: AxiosResponse<PublicSwapWithAdditionalInfo> = await this.client.get(
94
+ `/swaps/intents/${intentId}`,
95
+ );
96
+ return response.data;
97
+ }
98
+
99
+ async listNetworks(token?: string): Promise<Network[]> {
100
+ const endpoint = token ? `/networks?token=${token}` : '/networks';
101
+ const response: AxiosResponse<Network[]> = await this.client.get(endpoint);
102
+ return response.data;
103
+ }
104
+
105
+ async listTokens(
106
+ limit: number = 20,
107
+ offset: number = 0,
108
+ q?: string,
109
+ networkId?: number,
110
+ ): Promise<PaginatedResponse<Token>> {
111
+ let endpoint = `/tokens?limit=${limit}&offset=${offset}`;
112
+ if (q) {
113
+ endpoint += `&q=${q}`;
114
+ }
115
+ if (networkId) {
116
+ endpoint += `&network_id=${networkId}`;
117
+ }
118
+ const response: AxiosResponse<PaginatedResponse<Token>> = await this.client.get(endpoint);
119
+ return response.data;
120
+ }
121
+ }
122
+
123
+ export default SwaplyApiClient;
@@ -0,0 +1,38 @@
1
+ import { SwapType, type Permit2ApprovalToSign, type Quote } from './types';
2
+
3
+ export const signPermit2Approval = async (
4
+ permit2Approval: Permit2ApprovalToSign,
5
+ quote: Quote,
6
+ userAddress: string,
7
+ signTypedData: (typedData: any) => Promise<string>,
8
+ ) => {
9
+ const permit2Data = permit2Approval.additional_data;
10
+ const domain = {
11
+ name: permit2Data.domain.name,
12
+ chainId: permit2Data.domain.chain_id,
13
+ verifyingContract: permit2Data.domain.verifying_contract,
14
+ };
15
+
16
+ const witness = permit2Data.witness;
17
+
18
+ const message = {
19
+ permitted: {
20
+ token: quote.source_token,
21
+ amount: BigInt(quote.source_amount_lots),
22
+ },
23
+ spender: permit2Approval.escrow_contract_address,
24
+ nonce: permit2Approval.nonce,
25
+ deadline: permit2Approval.deadline,
26
+ witness,
27
+ };
28
+
29
+ const signature = await signTypedData({
30
+ domain,
31
+ types: permit2Data.types,
32
+ primaryType: 'PermitWitnessTransferFrom',
33
+ message,
34
+ account: userAddress,
35
+ });
36
+
37
+ return signature;
38
+ };
package/src/index.ts ADDED
@@ -0,0 +1,3 @@
1
+ export * from './apiClient';
2
+ export * from './approvals';
3
+ export * from './types';
package/src/types.ts ADDED
@@ -0,0 +1,154 @@
1
+ export enum SwapType {
2
+ Standard = 'Standard',
3
+ Optimized = 'Optimized',
4
+ }
5
+
6
+ export enum IntentStatus {
7
+ Initiated = 'Initiated',
8
+ ApprovalAdded = 'ApprovalAdded',
9
+ Accepted = 'Accepted',
10
+ Declined = 'Declined',
11
+ DeclinedDueToKytCheck = 'DeclinedDueToKytCheck',
12
+ UserDeposited = 'UserDeposited',
13
+ KycRequested = 'KycRequested',
14
+ Fulfilled = 'Fulfilled',
15
+ Expired = 'Expired',
16
+ RefundRequested = 'RefundRequested',
17
+ Refunded = 'Refunded',
18
+ }
19
+
20
+ export enum NetworkType {
21
+ EVM = 'EVM',
22
+ TRON = 'TRON',
23
+ BITCOIN = 'BITCOIN',
24
+ SOLANA = 'SOLANA',
25
+ }
26
+
27
+ export interface Quote {
28
+ id: string;
29
+ resolver_id: string;
30
+ source_chain: number;
31
+ source_token: string;
32
+ dest_chain: number;
33
+ dest_token: string;
34
+ intermediate_token: string | null;
35
+ intermediate_token_amount_min: string | null;
36
+ intermediate_token_amount_max: string | null;
37
+ intermediate_token_decimals: number | null;
38
+ source_amount_lots: string;
39
+ source_amount_decimals: number;
40
+ min_dest_amount_lots: string;
41
+ max_dest_amount_lots: string;
42
+ dest_amount_decimals: number;
43
+ slippage_bps: string;
44
+ expiry: number;
45
+ swap_type: SwapType;
46
+ }
47
+
48
+ export interface CreateIntentData {
49
+ intent_id: string;
50
+ deadline_secs: number;
51
+ secret_hash: `0x${string}`;
52
+ data: ApprovalToSign;
53
+ }
54
+
55
+ export interface ApprovalToSign {
56
+ approval_mechanism: string;
57
+ params_to_sign: Permit2ApprovalToSign | HtlcApprovalToSign | CosignApprovalToSign;
58
+ }
59
+
60
+ export interface SignedApproval {
61
+ type: 'Permit2' | 'Htlc' | 'Cosign';
62
+ signed_data: string | Record<string, string>;
63
+ }
64
+
65
+ export interface Permit2ApprovalToSign {
66
+ escrow_contract_address: string;
67
+ permit2_contract_address: string;
68
+ resolver_deposit_address: string;
69
+ nonce: number;
70
+ deadline: number;
71
+ additional_data: {
72
+ domain: {
73
+ name: string;
74
+ chain_id: number;
75
+ verifying_contract: string;
76
+ };
77
+ types: Record<string, { name: string; typ: string }>;
78
+ witness: Record<string, unknown>;
79
+ witness_type_string: string;
80
+ witness_hash: `0x${string}`;
81
+ };
82
+ }
83
+
84
+ export interface HtlcApprovalToSign {
85
+ psbt: string;
86
+ inputs: number[];
87
+ }
88
+
89
+ export interface CosignApprovalToSign {
90
+ transaction: string;
91
+ }
92
+
93
+ export interface IntentStatusResponse {
94
+ status: IntentStatus;
95
+ }
96
+
97
+ export interface PublicSwapWithAdditionalInfo {
98
+ intent_id: string;
99
+ status: IntentStatus;
100
+ kyc_link: string | null;
101
+ swap_metadata: SwapMetadata | null;
102
+ source_amount_decimals: number;
103
+ source_amount_lots: string;
104
+ source_chain: number;
105
+ source_token: string;
106
+ dest_amount_decimals: number;
107
+ dest_chain: number;
108
+ dest_token: string;
109
+ min_dest_amount_lots: string;
110
+ max_dest_amount_lots: string;
111
+ }
112
+
113
+ export interface SwapMetadata {
114
+ id: string;
115
+ proxy_address: string;
116
+ user_deposit_tx: string | null;
117
+ fulfill_tx: string | null;
118
+ swap_tx: string | null;
119
+ created_at: Date;
120
+ user_deposited_at: Date | null;
121
+ kyc_requested_at: Date | null;
122
+ fulfilled_at: Date | null;
123
+ withdrawn_at: Date | null;
124
+ swapped_at: Date | null;
125
+ refunded_at: Date | null;
126
+ }
127
+
128
+ export interface PaginatedResponse<T> {
129
+ pagination: {
130
+ total: number;
131
+ limit: number;
132
+ offset: number;
133
+ pages: number;
134
+ };
135
+ data: T[];
136
+ }
137
+
138
+ export interface Network {
139
+ id: number;
140
+ name: string;
141
+ type: NetworkType;
142
+ supports_optimized_swap: boolean;
143
+ icon_url: string;
144
+ supports_custom_tokens: boolean;
145
+ }
146
+
147
+ export interface Token {
148
+ network_id: string;
149
+ name: string;
150
+ contract_address: string;
151
+ symbol: string;
152
+ icon_url: string;
153
+ wrapped_token_address: string | null;
154
+ }
package/tsconfig.json ADDED
@@ -0,0 +1,28 @@
1
+ {
2
+ "compilerOptions": {
3
+ // Enable latest features
4
+ "lib": ["ESNext", "DOM"],
5
+ "target": "ESNext",
6
+ "module": "ESNext",
7
+ "moduleDetection": "force",
8
+ "jsx": "react-jsx",
9
+ "allowJs": true,
10
+
11
+ // Bundler mode
12
+ "moduleResolution": "bundler",
13
+ "allowImportingTsExtensions": true,
14
+ "verbatimModuleSyntax": true,
15
+ "noEmit": true,
16
+
17
+ // Best practices
18
+ "strict": true,
19
+ "skipLibCheck": true,
20
+ "noFallthroughCasesInSwitch": true,
21
+
22
+ // Some stricter flags (disabled by default)
23
+ "noUnusedLocals": false,
24
+ "noUnusedParameters": false,
25
+ "noPropertyAccessFromIndexSignature": false,
26
+ },
27
+ "include": ["src", "eslint.config.ts"],
28
+ }