@renegade-fi/renegade-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/LICENSE +21 -0
- package/README.md +31 -0
- package/examples/basic.ts +121 -0
- package/index.ts +30 -0
- package/package.json +42 -0
- package/scripts/update-version.sh +30 -0
- package/src/client.ts +371 -0
- package/src/http.ts +238 -0
- package/src/types.ts +112 -0
- package/src/version.ts +7 -0
- package/tsconfig.build.json +17 -0
- package/tsconfig.json +28 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Renegade
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# Renegade External Match Client
|
|
2
|
+
|
|
3
|
+
A TypeScript client for interacting with the Renegade Darkpool's External Match API.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
# Using npm
|
|
9
|
+
npm install renegade-sdk
|
|
10
|
+
|
|
11
|
+
# Using yarn
|
|
12
|
+
yarn add renegade-sdk
|
|
13
|
+
|
|
14
|
+
# Using bun
|
|
15
|
+
bun add renegade-sdk
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
## Usage
|
|
19
|
+
|
|
20
|
+
See the [examples](examples) for usage examples.
|
|
21
|
+
|
|
22
|
+
## Documentation
|
|
23
|
+
|
|
24
|
+
See the following resources for more information:
|
|
25
|
+
- [Examples From the Existing SDK](https://github.com/renegade-fi/typescript-sdk/tree/main/examples)
|
|
26
|
+
- [Renegade Docs](https://docs.renegade.fi/technical-reference/typescript-sdk#external-atomic-matching)
|
|
27
|
+
- [OpenAPI spec](https://github.com/renegade-fi/renegade-docs/blob/main/api-specs/external-match-openapi.yaml)
|
|
28
|
+
|
|
29
|
+
## License
|
|
30
|
+
|
|
31
|
+
MIT
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Basic example of using the Renegade External Match Client
|
|
3
|
+
*
|
|
4
|
+
* This example demonstrates how to create a client, request a quote, assemble a match, and submit the transaction on-chain.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import {
|
|
8
|
+
ExternalMatchClient,
|
|
9
|
+
OrderSide,
|
|
10
|
+
} from '../index';
|
|
11
|
+
import type { ExternalOrder } from '../index';
|
|
12
|
+
import { stringifyBigJSON } from '../src/http';
|
|
13
|
+
|
|
14
|
+
// Viem imports for on-chain transactions
|
|
15
|
+
import { http, createWalletClient } from 'viem';
|
|
16
|
+
import { privateKeyToAccount } from 'viem/accounts';
|
|
17
|
+
import { arbitrumSepolia } from 'viem/chains';
|
|
18
|
+
|
|
19
|
+
// Get API credentials from environment variables
|
|
20
|
+
const API_KEY = process.env.EXTERNAL_MATCH_KEY || '';
|
|
21
|
+
const API_SECRET = process.env.EXTERNAL_MATCH_SECRET || '';
|
|
22
|
+
const PRIVATE_KEY = process.env.PKEY || '';
|
|
23
|
+
const RPC_URL = process.env.RPC_URL || 'https://sepolia-rollup.arbitrum.io/rpc';
|
|
24
|
+
|
|
25
|
+
// Validate API credentials
|
|
26
|
+
if (!API_KEY || !API_SECRET) {
|
|
27
|
+
console.error('Error: Missing API credentials');
|
|
28
|
+
console.error('Please set EXTERNAL_MATCH_KEY and EXTERNAL_MATCH_SECRET environment variables');
|
|
29
|
+
process.exit(1);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// Validate wallet private key
|
|
33
|
+
if (!PRIVATE_KEY) {
|
|
34
|
+
console.error('Error: Missing private key');
|
|
35
|
+
console.error('Please set PRIVATE_KEY environment variable');
|
|
36
|
+
process.exit(1);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// Set up wallet client for blockchain transactions
|
|
40
|
+
const privateKey = PRIVATE_KEY.startsWith('0x') ? PRIVATE_KEY : `0x${PRIVATE_KEY}`;
|
|
41
|
+
const walletClient = createWalletClient({
|
|
42
|
+
account: privateKeyToAccount(privateKey as `0x${string}`),
|
|
43
|
+
chain: arbitrumSepolia,
|
|
44
|
+
transport: http(RPC_URL),
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
// Create the external match client
|
|
48
|
+
console.log('API KEY', API_KEY);
|
|
49
|
+
const client = ExternalMatchClient.newSepoliaClient(API_KEY, API_SECRET);
|
|
50
|
+
|
|
51
|
+
// Example order for USDC/WETH pair
|
|
52
|
+
const order: ExternalOrder = {
|
|
53
|
+
quote_mint: '0xdf8d259c04020562717557f2b5a3cf28e92707d1', // USDC
|
|
54
|
+
base_mint: '0xc3414a7ef14aaaa9c4522dfc00a4e66e74e9c25a', // WETH
|
|
55
|
+
side: OrderSide.BUY,
|
|
56
|
+
quote_amount: BigInt(20_000_000), // 20 USDC
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Submit a transaction to the chain
|
|
61
|
+
* @param settlementTx The settlement transaction
|
|
62
|
+
* @returns The transaction hash
|
|
63
|
+
*/
|
|
64
|
+
async function submitTransaction(settlementTx: any): Promise<`0x${string}`> {
|
|
65
|
+
console.log('Submitting transaction...');
|
|
66
|
+
|
|
67
|
+
const tx = await walletClient.sendTransaction({
|
|
68
|
+
to: settlementTx.to as `0x${string}`,
|
|
69
|
+
data: settlementTx.data as `0x${string}`,
|
|
70
|
+
value: settlementTx.value ? BigInt(settlementTx.value) : BigInt(0),
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
return tx;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// Full example with on-chain submission
|
|
77
|
+
async function fullExample() {
|
|
78
|
+
try {
|
|
79
|
+
// Step 1: Request a quote
|
|
80
|
+
console.log('Requesting quote...');
|
|
81
|
+
const quote = await client.requestQuote(order);
|
|
82
|
+
|
|
83
|
+
if (!quote) {
|
|
84
|
+
console.log('No quote available');
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
console.log('Quote received!');
|
|
89
|
+
|
|
90
|
+
// Step 2: Assemble the quote into a match bundle
|
|
91
|
+
console.log('Assembling match...');
|
|
92
|
+
const bundle = await client.assembleQuote(quote);
|
|
93
|
+
|
|
94
|
+
if (!bundle) {
|
|
95
|
+
console.log('No match available');
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
console.log('Match assembled!');
|
|
100
|
+
|
|
101
|
+
// Step 3: Submit the transaction on-chain
|
|
102
|
+
const txHash = await submitTransaction(bundle.match_bundle.settlement_tx);
|
|
103
|
+
console.log(
|
|
104
|
+
'Transaction submitted:',
|
|
105
|
+
`${walletClient.chain.blockExplorers?.default.url}/tx/${txHash}`
|
|
106
|
+
);
|
|
107
|
+
} catch (error) {
|
|
108
|
+
console.error('Error:', error);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
// Run the examples
|
|
113
|
+
async function main() {
|
|
114
|
+
console.log('Running full example with on-chain submission...');
|
|
115
|
+
await fullExample();
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// Only run if this file is being executed directly
|
|
119
|
+
if (require.main === module) {
|
|
120
|
+
main().catch(console.error);
|
|
121
|
+
}
|
package/index.ts
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Renegade External Match Client
|
|
3
|
+
* A TypeScript client for interacting with the Renegade Darkpool API.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
// Export main client
|
|
7
|
+
export { ExternalMatchClient, ExternalMatchClientError, RequestQuoteOptions, AssembleExternalMatchOptions } from './src/client';
|
|
8
|
+
|
|
9
|
+
// Export types
|
|
10
|
+
export type {
|
|
11
|
+
ApiExternalAssetTransfer,
|
|
12
|
+
ApiTimestampedPrice,
|
|
13
|
+
ApiExternalMatchResult,
|
|
14
|
+
FeeTake,
|
|
15
|
+
ExternalOrder,
|
|
16
|
+
ApiExternalQuote,
|
|
17
|
+
ApiSignedExternalQuote,
|
|
18
|
+
GasSponsorshipInfo,
|
|
19
|
+
SignedGasSponsorshipInfo,
|
|
20
|
+
SignedExternalQuote,
|
|
21
|
+
SettlementTransaction,
|
|
22
|
+
AtomicMatchApiBundle,
|
|
23
|
+
ExternalQuoteRequest,
|
|
24
|
+
ExternalQuoteResponse,
|
|
25
|
+
AssembleExternalMatchRequest,
|
|
26
|
+
ExternalMatchResponse
|
|
27
|
+
} from './src/types';
|
|
28
|
+
|
|
29
|
+
// Export enums
|
|
30
|
+
export { OrderSide } from './src/types';
|
package/package.json
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@renegade-fi/renegade-sdk",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "A TypeScript client for interacting with the Renegade Darkpool API",
|
|
5
|
+
"module": "index.ts",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"main": "dist/index.js",
|
|
8
|
+
"types": "dist/index.d.ts",
|
|
9
|
+
"scripts": {
|
|
10
|
+
"build": "tsc -p tsconfig.build.json",
|
|
11
|
+
"update-version": "bash scripts/update-version.sh",
|
|
12
|
+
"prepublishOnly": "npm run update-version && npm run build"
|
|
13
|
+
},
|
|
14
|
+
"keywords": [
|
|
15
|
+
"renegade",
|
|
16
|
+
"darkpool",
|
|
17
|
+
"trading",
|
|
18
|
+
"api",
|
|
19
|
+
"client",
|
|
20
|
+
"cryptocurrency",
|
|
21
|
+
"defi"
|
|
22
|
+
],
|
|
23
|
+
"author": "Renegade",
|
|
24
|
+
"license": "MIT",
|
|
25
|
+
"dependencies": {
|
|
26
|
+
"@noble/hashes": "^1.7.1",
|
|
27
|
+
"json-bigint": "^1.0.0"
|
|
28
|
+
},
|
|
29
|
+
"devDependencies": {
|
|
30
|
+
"@types/bun": "latest",
|
|
31
|
+
"@types/json-bigint": "^1.0.4",
|
|
32
|
+
"typescript": "^5",
|
|
33
|
+
"viem": "^2.23.15"
|
|
34
|
+
},
|
|
35
|
+
"repository": {
|
|
36
|
+
"type": "git",
|
|
37
|
+
"url": "https://github.com/renegade-fi/typescript-external-match-client"
|
|
38
|
+
},
|
|
39
|
+
"engines": {
|
|
40
|
+
"node": ">=18"
|
|
41
|
+
}
|
|
42
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
|
|
3
|
+
# Script to update the SDK version in the version.ts file
|
|
4
|
+
# This should be run as part of the prepublishOnly npm script
|
|
5
|
+
|
|
6
|
+
set -e
|
|
7
|
+
|
|
8
|
+
# Get the package version from package.json using jq
|
|
9
|
+
VERSION=$(jq -r '.version' package.json)
|
|
10
|
+
|
|
11
|
+
if [ -z "$VERSION" ]; then
|
|
12
|
+
echo "Error: Could not find version in package.json"
|
|
13
|
+
exit 1
|
|
14
|
+
fi
|
|
15
|
+
|
|
16
|
+
# Path to version.ts file
|
|
17
|
+
VERSION_FILE="src/version.ts"
|
|
18
|
+
|
|
19
|
+
# Generate version file content
|
|
20
|
+
cat > $VERSION_FILE << EOF
|
|
21
|
+
/**
|
|
22
|
+
* SDK version information
|
|
23
|
+
* This file is automatically updated during the build process
|
|
24
|
+
* Last updated: $(date -u +"%Y-%m-%dT%H:%M:%SZ")
|
|
25
|
+
*/
|
|
26
|
+
|
|
27
|
+
export const VERSION = '$VERSION';
|
|
28
|
+
EOF
|
|
29
|
+
|
|
30
|
+
echo "Successfully updated version to $VERSION in $VERSION_FILE"
|
package/src/client.ts
ADDED
|
@@ -0,0 +1,371 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Client for interacting with the Renegade external matching API.
|
|
3
|
+
*
|
|
4
|
+
* This client handles authentication and provides methods for requesting quotes,
|
|
5
|
+
* assembling matches, and executing trades.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { RelayerHttpClient, RENEGADE_HEADER_PREFIX } from './http';
|
|
9
|
+
import { VERSION } from './version';
|
|
10
|
+
import type {
|
|
11
|
+
ExternalOrder,
|
|
12
|
+
SignedExternalQuote,
|
|
13
|
+
ExternalQuoteRequest,
|
|
14
|
+
ExternalQuoteResponse,
|
|
15
|
+
AssembleExternalMatchRequest,
|
|
16
|
+
ExternalMatchResponse,
|
|
17
|
+
ApiSignedExternalQuote,
|
|
18
|
+
AtomicMatchApiBundle
|
|
19
|
+
} from './types';
|
|
20
|
+
|
|
21
|
+
// Constants for API URLs
|
|
22
|
+
const SEPOLIA_BASE_URL = "https://testnet.auth-server.renegade.fi";
|
|
23
|
+
const MAINNET_BASE_URL = "https://mainnet.auth-server.renegade.fi";
|
|
24
|
+
|
|
25
|
+
// Header constants
|
|
26
|
+
const RENEGADE_API_KEY_HEADER = "x-renegade-api-key";
|
|
27
|
+
const RENEGADE_SDK_VERSION_HEADER = "x-renegade-sdk-version";
|
|
28
|
+
|
|
29
|
+
// API Routes
|
|
30
|
+
const REQUEST_EXTERNAL_QUOTE_ROUTE = "/v0/matching-engine/quote";
|
|
31
|
+
const ASSEMBLE_EXTERNAL_MATCH_ROUTE = "/v0/matching-engine/assemble-external-match";
|
|
32
|
+
|
|
33
|
+
// Query Parameters
|
|
34
|
+
const DISABLE_GAS_SPONSORSHIP_QUERY_PARAM = "disable_gas_sponsorship";
|
|
35
|
+
const GAS_REFUND_ADDRESS_QUERY_PARAM = "refund_address";
|
|
36
|
+
const REFUND_NATIVE_ETH_QUERY_PARAM = "refund_native_eth";
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Get the SDK version string.
|
|
40
|
+
*
|
|
41
|
+
* @returns The SDK version prefixed with "typescript-v"
|
|
42
|
+
*/
|
|
43
|
+
function getSdkVersion(): string {
|
|
44
|
+
return `typescript-v${VERSION}`;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Options for requesting a quote.
|
|
49
|
+
*/
|
|
50
|
+
export class RequestQuoteOptions {
|
|
51
|
+
disableGasSponsorship: boolean = false;
|
|
52
|
+
gasRefundAddress?: string;
|
|
53
|
+
refundNativeEth: boolean = false;
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Create a new instance of RequestQuoteOptions.
|
|
57
|
+
*/
|
|
58
|
+
static new(): RequestQuoteOptions {
|
|
59
|
+
return new RequestQuoteOptions();
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Set whether gas sponsorship should be disabled.
|
|
64
|
+
*/
|
|
65
|
+
withGasSponsorshipDisabled(disableGasSponsorship: boolean): RequestQuoteOptions {
|
|
66
|
+
this.disableGasSponsorship = disableGasSponsorship;
|
|
67
|
+
return this;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Set the gas refund address.
|
|
72
|
+
*/
|
|
73
|
+
withGasRefundAddress(gasRefundAddress: string): RequestQuoteOptions {
|
|
74
|
+
this.gasRefundAddress = gasRefundAddress;
|
|
75
|
+
return this;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Set whether to refund in native ETH.
|
|
80
|
+
*/
|
|
81
|
+
withRefundNativeEth(refundNativeEth: boolean): RequestQuoteOptions {
|
|
82
|
+
this.refundNativeEth = refundNativeEth;
|
|
83
|
+
return this;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Build the request path with query parameters.
|
|
88
|
+
*/
|
|
89
|
+
buildRequestPath(): string {
|
|
90
|
+
const params = new URLSearchParams();
|
|
91
|
+
params.set(DISABLE_GAS_SPONSORSHIP_QUERY_PARAM, this.disableGasSponsorship.toString());
|
|
92
|
+
if (this.gasRefundAddress) {
|
|
93
|
+
params.set(GAS_REFUND_ADDRESS_QUERY_PARAM, this.gasRefundAddress);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
if (this.refundNativeEth) {
|
|
97
|
+
params.set(REFUND_NATIVE_ETH_QUERY_PARAM, this.refundNativeEth.toString());
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
return `${REQUEST_EXTERNAL_QUOTE_ROUTE}?${params.toString()}`;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Options for assembling an external match.
|
|
106
|
+
*/
|
|
107
|
+
export class AssembleExternalMatchOptions {
|
|
108
|
+
doGasEstimation: boolean = false;
|
|
109
|
+
receiverAddress?: string;
|
|
110
|
+
updatedOrder?: ExternalOrder;
|
|
111
|
+
requestGasSponsorship: boolean = false;
|
|
112
|
+
gasRefundAddress?: string;
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Create a new instance of AssembleExternalMatchOptions.
|
|
116
|
+
*/
|
|
117
|
+
static new(): AssembleExternalMatchOptions {
|
|
118
|
+
return new AssembleExternalMatchOptions();
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* Set whether to do gas estimation.
|
|
123
|
+
*/
|
|
124
|
+
withGasEstimation(doGasEstimation: boolean): AssembleExternalMatchOptions {
|
|
125
|
+
this.doGasEstimation = doGasEstimation;
|
|
126
|
+
return this;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* Set the receiver address.
|
|
131
|
+
*/
|
|
132
|
+
withReceiverAddress(receiverAddress: string): AssembleExternalMatchOptions {
|
|
133
|
+
this.receiverAddress = receiverAddress;
|
|
134
|
+
return this;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* Set the updated order.
|
|
139
|
+
*/
|
|
140
|
+
withUpdatedOrder(updatedOrder: ExternalOrder): AssembleExternalMatchOptions {
|
|
141
|
+
this.updatedOrder = updatedOrder;
|
|
142
|
+
return this;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* Set whether to request gas sponsorship.
|
|
147
|
+
* @deprecated Request gas sponsorship when requesting a quote instead
|
|
148
|
+
*/
|
|
149
|
+
withGasSponsorship(requestGasSponsorship: boolean): AssembleExternalMatchOptions {
|
|
150
|
+
this.requestGasSponsorship = requestGasSponsorship;
|
|
151
|
+
return this;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* Set the gas refund address.
|
|
156
|
+
* @deprecated Request gas sponsorship when requesting a quote instead
|
|
157
|
+
*/
|
|
158
|
+
withGasRefundAddress(gasRefundAddress: string): AssembleExternalMatchOptions {
|
|
159
|
+
this.gasRefundAddress = gasRefundAddress;
|
|
160
|
+
return this;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
/**
|
|
164
|
+
* Build the request path with query parameters.
|
|
165
|
+
*/
|
|
166
|
+
buildRequestPath(): string {
|
|
167
|
+
// If no query parameters are needed, return the base path
|
|
168
|
+
if (!this.requestGasSponsorship && !this.gasRefundAddress) {
|
|
169
|
+
return ASSEMBLE_EXTERNAL_MATCH_ROUTE;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
const params = new URLSearchParams();
|
|
173
|
+
if (this.requestGasSponsorship) {
|
|
174
|
+
// We only write this query parameter if it was explicitly set
|
|
175
|
+
params.set(DISABLE_GAS_SPONSORSHIP_QUERY_PARAM, (!this.requestGasSponsorship).toString());
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
if (this.gasRefundAddress) {
|
|
179
|
+
params.set(GAS_REFUND_ADDRESS_QUERY_PARAM, this.gasRefundAddress);
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
return `${ASSEMBLE_EXTERNAL_MATCH_ROUTE}?${params.toString()}`;
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
/**
|
|
187
|
+
* Error thrown by the ExternalMatchClient.
|
|
188
|
+
*/
|
|
189
|
+
export class ExternalMatchClientError extends Error {
|
|
190
|
+
statusCode?: number;
|
|
191
|
+
|
|
192
|
+
constructor(message: string, statusCode?: number) {
|
|
193
|
+
super(message);
|
|
194
|
+
this.name = 'ExternalMatchClientError';
|
|
195
|
+
this.statusCode = statusCode;
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
/**
|
|
200
|
+
* Client for interacting with the Renegade external matching API.
|
|
201
|
+
*/
|
|
202
|
+
export class ExternalMatchClient {
|
|
203
|
+
private apiKey: string;
|
|
204
|
+
private httpClient: RelayerHttpClient;
|
|
205
|
+
|
|
206
|
+
/**
|
|
207
|
+
* Initialize a new ExternalMatchClient.
|
|
208
|
+
*
|
|
209
|
+
* @param apiKey The API key for authentication
|
|
210
|
+
* @param apiSecret The API secret for request signing
|
|
211
|
+
* @param baseUrl The base URL of the Renegade API
|
|
212
|
+
*/
|
|
213
|
+
constructor(apiKey: string, apiSecret: string, baseUrl: string) {
|
|
214
|
+
this.apiKey = apiKey;
|
|
215
|
+
this.httpClient = new RelayerHttpClient(baseUrl, apiSecret);
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
/**
|
|
219
|
+
* Create a new client configured for the Sepolia testnet.
|
|
220
|
+
*
|
|
221
|
+
* @param apiKey The API key for authentication
|
|
222
|
+
* @param apiSecret The API secret for request signing
|
|
223
|
+
* @returns A new ExternalMatchClient configured for Sepolia
|
|
224
|
+
*/
|
|
225
|
+
static newSepoliaClient(apiKey: string, apiSecret: string): ExternalMatchClient {
|
|
226
|
+
return new ExternalMatchClient(apiKey, apiSecret, SEPOLIA_BASE_URL);
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
/**
|
|
230
|
+
* Create a new client configured for mainnet.
|
|
231
|
+
*
|
|
232
|
+
* @param apiKey The API key for authentication
|
|
233
|
+
* @param apiSecret The API secret for request signing
|
|
234
|
+
* @returns A new ExternalMatchClient configured for mainnet
|
|
235
|
+
*/
|
|
236
|
+
static newMainnetClient(apiKey: string, apiSecret: string): ExternalMatchClient {
|
|
237
|
+
return new ExternalMatchClient(apiKey, apiSecret, MAINNET_BASE_URL);
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
/**
|
|
241
|
+
* Request a quote for the given order.
|
|
242
|
+
*
|
|
243
|
+
* @param order The order to request a quote for
|
|
244
|
+
* @returns A promise that resolves to a signed quote if one is available, null otherwise
|
|
245
|
+
* @throws ExternalMatchClientError if the request fails
|
|
246
|
+
*/
|
|
247
|
+
async requestQuote(order: ExternalOrder): Promise<SignedExternalQuote | null> {
|
|
248
|
+
return this.requestQuoteWithOptions(order, RequestQuoteOptions.new());
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
/**
|
|
252
|
+
* Request a quote for the given order with custom options.
|
|
253
|
+
*
|
|
254
|
+
* @param order The order to request a quote for
|
|
255
|
+
* @param options Custom options for the quote request
|
|
256
|
+
* @returns A promise that resolves to a signed quote if one is available, null otherwise
|
|
257
|
+
* @throws ExternalMatchClientError if the request fails
|
|
258
|
+
*/
|
|
259
|
+
async requestQuoteWithOptions(
|
|
260
|
+
order: ExternalOrder,
|
|
261
|
+
options: RequestQuoteOptions
|
|
262
|
+
): Promise<SignedExternalQuote | null> {
|
|
263
|
+
const request: ExternalQuoteRequest = {
|
|
264
|
+
external_order: order
|
|
265
|
+
};
|
|
266
|
+
|
|
267
|
+
const path = options.buildRequestPath();
|
|
268
|
+
const headers = this.getHeaders();
|
|
269
|
+
|
|
270
|
+
try {
|
|
271
|
+
const response = await this.httpClient.post<ExternalQuoteResponse>(path, request, headers);
|
|
272
|
+
|
|
273
|
+
// Handle 204 No Content (no quotes available)
|
|
274
|
+
if (response.status === 204 || !response.data) {
|
|
275
|
+
return null;
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
const quoteResp = response.data;
|
|
279
|
+
const signedQuote: SignedExternalQuote = {
|
|
280
|
+
quote: quoteResp.signed_quote.quote,
|
|
281
|
+
signature: quoteResp.signed_quote.signature,
|
|
282
|
+
gas_sponsorship_info: quoteResp.gas_sponsorship_info
|
|
283
|
+
};
|
|
284
|
+
|
|
285
|
+
return signedQuote;
|
|
286
|
+
} catch (error: any) {
|
|
287
|
+
// Handle HTTP-related errors from fetch implementation
|
|
288
|
+
if (error.status === 204) {
|
|
289
|
+
return null;
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
throw new ExternalMatchClientError(
|
|
293
|
+
error.message || 'Failed to request quote',
|
|
294
|
+
error.status
|
|
295
|
+
);
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
/**
|
|
300
|
+
* Assemble a quote into a match bundle with default options.
|
|
301
|
+
*
|
|
302
|
+
* @param quote The signed quote to assemble
|
|
303
|
+
* @returns A promise that resolves to a match response if assembly succeeds, null otherwise
|
|
304
|
+
* @throws ExternalMatchClientError if the request fails
|
|
305
|
+
*/
|
|
306
|
+
async assembleQuote(quote: SignedExternalQuote): Promise<ExternalMatchResponse | null> {
|
|
307
|
+
return this.assembleQuoteWithOptions(quote, AssembleExternalMatchOptions.new());
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
/**
|
|
311
|
+
* Assemble a quote into a match bundle with custom options.
|
|
312
|
+
*
|
|
313
|
+
* @param quote The signed quote to assemble
|
|
314
|
+
* @param options Custom options for quote assembly
|
|
315
|
+
* @returns A promise that resolves to a match response if assembly succeeds, null otherwise
|
|
316
|
+
* @throws ExternalMatchClientError if the request fails
|
|
317
|
+
*/
|
|
318
|
+
async assembleQuoteWithOptions(
|
|
319
|
+
quote: SignedExternalQuote,
|
|
320
|
+
options: AssembleExternalMatchOptions
|
|
321
|
+
): Promise<ExternalMatchResponse | null> {
|
|
322
|
+
const signedQuote: ApiSignedExternalQuote = {
|
|
323
|
+
quote: quote.quote,
|
|
324
|
+
signature: quote.signature,
|
|
325
|
+
};
|
|
326
|
+
|
|
327
|
+
const request: AssembleExternalMatchRequest = {
|
|
328
|
+
do_gas_estimation: options.doGasEstimation,
|
|
329
|
+
receiver_address: options.receiverAddress,
|
|
330
|
+
signed_quote: signedQuote,
|
|
331
|
+
updated_order: options.updatedOrder,
|
|
332
|
+
gas_sponsorship_info: quote.gas_sponsorship_info,
|
|
333
|
+
};
|
|
334
|
+
|
|
335
|
+
const path = options.buildRequestPath();
|
|
336
|
+
const headers = this.getHeaders();
|
|
337
|
+
|
|
338
|
+
try {
|
|
339
|
+
const response = await this.httpClient.post<ExternalMatchResponse>(path, request, headers);
|
|
340
|
+
|
|
341
|
+
// Handle 204 No Content
|
|
342
|
+
if (response.status === 204 || !response.data) {
|
|
343
|
+
return null;
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
return response.data;
|
|
347
|
+
} catch (error: any) {
|
|
348
|
+
// Handle HTTP-related errors from fetch implementation
|
|
349
|
+
if (error.status === 204) {
|
|
350
|
+
return null;
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
throw new ExternalMatchClientError(
|
|
354
|
+
error.message || 'Failed to assemble quote',
|
|
355
|
+
error.status
|
|
356
|
+
);
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
/**
|
|
361
|
+
* Get the headers required for API requests.
|
|
362
|
+
*
|
|
363
|
+
* @returns Headers containing the API key and SDK version
|
|
364
|
+
*/
|
|
365
|
+
private getHeaders(): Record<string, string> {
|
|
366
|
+
return {
|
|
367
|
+
[RENEGADE_API_KEY_HEADER]: this.apiKey,
|
|
368
|
+
[RENEGADE_SDK_VERSION_HEADER]: getSdkVersion(),
|
|
369
|
+
};
|
|
370
|
+
}
|
|
371
|
+
}
|
package/src/http.ts
ADDED
|
@@ -0,0 +1,238 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* HTTP client for making authenticated requests to the Renegade relayer API.
|
|
3
|
+
* This client handles request signing and authentication using HMAC-SHA256.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { sha256 } from '@noble/hashes/sha256';
|
|
7
|
+
import { hmac } from '@noble/hashes/hmac';
|
|
8
|
+
import { bytesToHex } from '@noble/hashes/utils';
|
|
9
|
+
import JSONBigInt from 'json-bigint';
|
|
10
|
+
|
|
11
|
+
// Constants for authentication
|
|
12
|
+
export const RENEGADE_HEADER_PREFIX = 'x-renegade';
|
|
13
|
+
export const RENEGADE_AUTH_HEADER = 'x-renegade-auth';
|
|
14
|
+
export const RENEGADE_AUTH_EXPIRATION_HEADER = 'x-renegade-auth-expiration';
|
|
15
|
+
|
|
16
|
+
// Authentication constants
|
|
17
|
+
const REQUEST_SIGNATURE_DURATION_MS = 10 * 1000; // 10 seconds in milliseconds
|
|
18
|
+
|
|
19
|
+
// Configure JSON-BigInt for parsing and stringifying
|
|
20
|
+
const jsonProcessor = JSONBigInt({
|
|
21
|
+
alwaysParseAsBig: true,
|
|
22
|
+
useNativeBigInt: true,
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Parse JSON string that may contain BigInt values
|
|
27
|
+
*/
|
|
28
|
+
export const parseBigJSON = (data: string) => {
|
|
29
|
+
try {
|
|
30
|
+
return jsonProcessor.parse(data);
|
|
31
|
+
} catch (error) {
|
|
32
|
+
// If parsing fails, return original data
|
|
33
|
+
console.error('Failed to parse JSON with BigInt', error);
|
|
34
|
+
return data;
|
|
35
|
+
}
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Stringify object that may contain BigInt values
|
|
40
|
+
*/
|
|
41
|
+
export const stringifyBigJSON = (data: any) => {
|
|
42
|
+
return jsonProcessor.stringify(data);
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
// Define interface for HTTP response similar to Axios response
|
|
46
|
+
export interface HttpResponse<T = any> {
|
|
47
|
+
data: T;
|
|
48
|
+
status: number;
|
|
49
|
+
statusText: string;
|
|
50
|
+
headers: Record<string, string>;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* HTTP client for making authenticated requests to the Renegade relayer API.
|
|
55
|
+
*/
|
|
56
|
+
export class RelayerHttpClient {
|
|
57
|
+
private baseUrl: string;
|
|
58
|
+
private authKey: Uint8Array;
|
|
59
|
+
private defaultHeaders: Record<string, string>;
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Initialize a new RelayerHttpClient.
|
|
63
|
+
*
|
|
64
|
+
* @param baseUrl The base URL of the relayer API
|
|
65
|
+
* @param authKey The base64-encoded authentication key for request signing
|
|
66
|
+
*/
|
|
67
|
+
constructor(baseUrl: string, authKey: string) {
|
|
68
|
+
this.baseUrl = baseUrl.endsWith('/') ? baseUrl.slice(0, -1) : baseUrl;
|
|
69
|
+
this.authKey = this.decodeBase64(authKey);
|
|
70
|
+
this.defaultHeaders = {
|
|
71
|
+
'Content-Type': 'application/json'
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Make a GET request with custom headers.
|
|
77
|
+
*
|
|
78
|
+
* @param path The API endpoint path
|
|
79
|
+
* @param headers Additional headers to include
|
|
80
|
+
* @returns The API response
|
|
81
|
+
*/
|
|
82
|
+
public async get<T>(path: string, headers: Record<string, string> = {}): Promise<HttpResponse<T>> {
|
|
83
|
+
return this.request<T>('GET', path, undefined, headers);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Make a POST request with custom headers.
|
|
88
|
+
*
|
|
89
|
+
* @param path The API endpoint path
|
|
90
|
+
* @param data The request body to send
|
|
91
|
+
* @param headers Additional headers to include
|
|
92
|
+
* @returns The API response
|
|
93
|
+
*/
|
|
94
|
+
public async post<T, D = any>(path: string, data: D, headers: Record<string, string> = {}): Promise<HttpResponse<T>> {
|
|
95
|
+
return this.request<T>('POST', path, data, headers);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Make an HTTP request with authentication.
|
|
100
|
+
*
|
|
101
|
+
* @param method The HTTP method
|
|
102
|
+
* @param path The API endpoint path
|
|
103
|
+
* @param data The request body data
|
|
104
|
+
* @param customHeaders Additional headers to include
|
|
105
|
+
* @returns The API response
|
|
106
|
+
*/
|
|
107
|
+
private async request<T>(
|
|
108
|
+
method: string,
|
|
109
|
+
path: string,
|
|
110
|
+
data?: any,
|
|
111
|
+
customHeaders: Record<string, string> = {}
|
|
112
|
+
): Promise<HttpResponse<T>> {
|
|
113
|
+
const urlPath = path.startsWith('/') ? path.slice(1) : path;
|
|
114
|
+
const url = new URL(urlPath, this.baseUrl);
|
|
115
|
+
|
|
116
|
+
// Prepare headers, and add authentication headers
|
|
117
|
+
const headers = { ...this.defaultHeaders, ...customHeaders };
|
|
118
|
+
const fullHeaders = this.addAuthHeaders(
|
|
119
|
+
url.pathname + url.search,
|
|
120
|
+
headers,
|
|
121
|
+
data
|
|
122
|
+
);
|
|
123
|
+
|
|
124
|
+
// Prepare request body
|
|
125
|
+
let body: string | undefined;
|
|
126
|
+
if (data) {
|
|
127
|
+
body = typeof data === 'string' ? data : stringifyBigJSON(data);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
// Make the fetch request
|
|
131
|
+
const response = await fetch(url.toString(), {
|
|
132
|
+
method,
|
|
133
|
+
headers: fullHeaders,
|
|
134
|
+
body
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
// Read the response body
|
|
138
|
+
let responseData: any;
|
|
139
|
+
const contentType = response.headers.get('content-type') || '';
|
|
140
|
+
if (contentType.includes('application/json')) {
|
|
141
|
+
const text = await response.text();
|
|
142
|
+
responseData = parseBigJSON(text);
|
|
143
|
+
} else {
|
|
144
|
+
responseData = await response.text();
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
// Convert headers to a simple object
|
|
148
|
+
const responseHeaders: Record<string, string> = {};
|
|
149
|
+
response.headers.forEach((value, key) => {
|
|
150
|
+
responseHeaders[key] = value;
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
// Return a response object similar to Axios response
|
|
154
|
+
return {
|
|
155
|
+
data: responseData,
|
|
156
|
+
status: response.status,
|
|
157
|
+
statusText: response.statusText,
|
|
158
|
+
headers: responseHeaders
|
|
159
|
+
};
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* Add authentication headers to a request.
|
|
164
|
+
*/
|
|
165
|
+
private addAuthHeaders(
|
|
166
|
+
path: string,
|
|
167
|
+
headers: Record<string, string>,
|
|
168
|
+
data?: any
|
|
169
|
+
): Record<string, string> {
|
|
170
|
+
// Add timestamp and expiry
|
|
171
|
+
const timestamp = Date.now();
|
|
172
|
+
const expiry = timestamp + REQUEST_SIGNATURE_DURATION_MS;
|
|
173
|
+
headers[RENEGADE_AUTH_EXPIRATION_HEADER] = expiry.toString();
|
|
174
|
+
|
|
175
|
+
// Compute the MAC signature and
|
|
176
|
+
const macDigest = this.computeRequestMac(path, headers, data);
|
|
177
|
+
headers[RENEGADE_AUTH_HEADER] = this.encodeBase64(Buffer.from(macDigest));
|
|
178
|
+
return headers;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
/**
|
|
182
|
+
* Compute the HMAC-SHA256 MAC for a request.
|
|
183
|
+
*
|
|
184
|
+
* @param path The API endpoint path with query parameters
|
|
185
|
+
* @param headers The request headers
|
|
186
|
+
* @param data The request body data
|
|
187
|
+
* @returns The computed MAC digest
|
|
188
|
+
*/
|
|
189
|
+
private computeRequestMac(
|
|
190
|
+
path: string,
|
|
191
|
+
headers: Record<string, string>,
|
|
192
|
+
data?: any
|
|
193
|
+
): Uint8Array {
|
|
194
|
+
// Initialize MAC with auth key
|
|
195
|
+
const mac = hmac.create(sha256, this.authKey);
|
|
196
|
+
|
|
197
|
+
// Add path to signature
|
|
198
|
+
const pathBytes = new TextEncoder().encode(path);
|
|
199
|
+
mac.update(pathBytes);
|
|
200
|
+
|
|
201
|
+
// Add Renegade headers to signature
|
|
202
|
+
const renegadeHeaders = Object.entries(headers)
|
|
203
|
+
.filter(([key]) => key.toLowerCase().startsWith(RENEGADE_HEADER_PREFIX))
|
|
204
|
+
.filter(([key]) => key.toLowerCase() !== RENEGADE_AUTH_HEADER.toLowerCase())
|
|
205
|
+
.sort(([a], [b]) => a.localeCompare(b));
|
|
206
|
+
|
|
207
|
+
for (const [key, value] of renegadeHeaders) {
|
|
208
|
+
mac.update(new TextEncoder().encode(key));
|
|
209
|
+
mac.update(new TextEncoder().encode(value.toString()));
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
// Add body to signature
|
|
213
|
+
let body = '';
|
|
214
|
+
if (data) {
|
|
215
|
+
body = typeof data === 'string'
|
|
216
|
+
? data
|
|
217
|
+
: stringifyBigJSON(data);
|
|
218
|
+
}
|
|
219
|
+
mac.update(new TextEncoder().encode(body));
|
|
220
|
+
|
|
221
|
+
// Return the digest
|
|
222
|
+
return mac.digest();
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
/**
|
|
226
|
+
* Decode a base64 string to a Uint8Array.
|
|
227
|
+
*/
|
|
228
|
+
private decodeBase64(base64: string): Uint8Array {
|
|
229
|
+
return Buffer.from(base64, 'base64');
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
/**
|
|
233
|
+
* Encode a Uint8Array or Buffer to a base64 string.
|
|
234
|
+
*/
|
|
235
|
+
private encodeBase64(data: Uint8Array | Buffer): string {
|
|
236
|
+
return Buffer.from(data).toString('base64').replace(/=+$/, '');
|
|
237
|
+
}
|
|
238
|
+
}
|
package/src/types.ts
ADDED
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Type definitions for the Renegade Darkpool API.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
export enum OrderSide {
|
|
6
|
+
BUY = "Buy",
|
|
7
|
+
SELL = "Sell",
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export interface ApiExternalAssetTransfer {
|
|
11
|
+
mint: string;
|
|
12
|
+
amount: bigint;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export interface ApiTimestampedPrice {
|
|
16
|
+
price: string;
|
|
17
|
+
timestamp: bigint;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export interface ApiExternalMatchResult {
|
|
21
|
+
quote_mint: string;
|
|
22
|
+
base_mint: string;
|
|
23
|
+
quote_amount: bigint;
|
|
24
|
+
base_amount: bigint;
|
|
25
|
+
direction: OrderSide;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export interface FeeTake {
|
|
29
|
+
relayer_fee: bigint;
|
|
30
|
+
protocol_fee: bigint;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export interface ExternalOrder {
|
|
34
|
+
quote_mint: string;
|
|
35
|
+
base_mint: string;
|
|
36
|
+
side: OrderSide;
|
|
37
|
+
base_amount?: bigint;
|
|
38
|
+
quote_amount?: bigint;
|
|
39
|
+
exact_base_output?: bigint;
|
|
40
|
+
exact_quote_output?: bigint;
|
|
41
|
+
min_fill_size?: bigint;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export interface ApiExternalQuote {
|
|
45
|
+
order: ExternalOrder;
|
|
46
|
+
match_result: ApiExternalMatchResult;
|
|
47
|
+
fees: FeeTake;
|
|
48
|
+
send: ApiExternalAssetTransfer;
|
|
49
|
+
receive: ApiExternalAssetTransfer;
|
|
50
|
+
price: ApiTimestampedPrice;
|
|
51
|
+
timestamp: bigint;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export interface ApiSignedExternalQuote {
|
|
55
|
+
quote: ApiExternalQuote;
|
|
56
|
+
signature: string;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export interface GasSponsorshipInfo {
|
|
60
|
+
refund_amount: bigint;
|
|
61
|
+
refund_native_eth: boolean;
|
|
62
|
+
refund_address?: string;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export interface SignedGasSponsorshipInfo {
|
|
66
|
+
gas_sponsorship_info: GasSponsorshipInfo;
|
|
67
|
+
signature: string;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export interface SignedExternalQuote {
|
|
71
|
+
quote: ApiExternalQuote;
|
|
72
|
+
signature: string;
|
|
73
|
+
gas_sponsorship_info?: SignedGasSponsorshipInfo;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
export interface SettlementTransaction {
|
|
77
|
+
tx_type: string;
|
|
78
|
+
to: string;
|
|
79
|
+
data: string;
|
|
80
|
+
value: string;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
export interface AtomicMatchApiBundle {
|
|
84
|
+
match_result: ApiExternalMatchResult;
|
|
85
|
+
fees: FeeTake;
|
|
86
|
+
receive: ApiExternalAssetTransfer;
|
|
87
|
+
send: ApiExternalAssetTransfer;
|
|
88
|
+
settlement_tx: SettlementTransaction;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
export interface ExternalQuoteRequest {
|
|
92
|
+
external_order: ExternalOrder;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
export interface ExternalQuoteResponse {
|
|
96
|
+
signed_quote: ApiSignedExternalQuote;
|
|
97
|
+
gas_sponsorship_info?: SignedGasSponsorshipInfo;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
export interface AssembleExternalMatchRequest {
|
|
101
|
+
do_gas_estimation?: boolean;
|
|
102
|
+
receiver_address?: string;
|
|
103
|
+
signed_quote: ApiSignedExternalQuote;
|
|
104
|
+
updated_order?: ExternalOrder;
|
|
105
|
+
gas_sponsorship_info?: SignedGasSponsorshipInfo;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
export interface ExternalMatchResponse {
|
|
109
|
+
match_bundle: AtomicMatchApiBundle;
|
|
110
|
+
gas_sponsored: boolean;
|
|
111
|
+
gas_sponsorship_info?: GasSponsorshipInfo;
|
|
112
|
+
}
|
package/src/version.ts
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
{
|
|
2
|
+
"extends": "./tsconfig.json",
|
|
3
|
+
"compilerOptions": {
|
|
4
|
+
"outDir": "dist",
|
|
5
|
+
"declaration": true,
|
|
6
|
+
"noEmit": false,
|
|
7
|
+
"allowImportingTsExtensions": false
|
|
8
|
+
},
|
|
9
|
+
"include": [
|
|
10
|
+
"index.ts",
|
|
11
|
+
"src/**/*.ts"
|
|
12
|
+
],
|
|
13
|
+
"exclude": [
|
|
14
|
+
"node_modules",
|
|
15
|
+
"**/*.test.ts"
|
|
16
|
+
]
|
|
17
|
+
}
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
// Environment setup & latest features
|
|
4
|
+
"lib": ["esnext"],
|
|
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
|
+
"noUncheckedIndexedAccess": true,
|
|
22
|
+
|
|
23
|
+
// Some stricter flags (disabled by default)
|
|
24
|
+
"noUnusedLocals": false,
|
|
25
|
+
"noUnusedParameters": false,
|
|
26
|
+
"noPropertyAccessFromIndexSignature": false
|
|
27
|
+
}
|
|
28
|
+
}
|