@silentswap/sdk 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.
- package/README.md +6 -0
- package/dist/caip19.d.ts +29 -0
- package/dist/caip19.js +31 -0
- package/dist/client.d.ts +69 -0
- package/dist/client.js +168 -0
- package/dist/constants.d.ts +14 -0
- package/dist/constants.js +19 -0
- package/dist/facilitator-account.d.ts +50 -0
- package/dist/facilitator-account.js +108 -0
- package/dist/gateway-abi.d.ts +588 -0
- package/dist/gateway-abi.js +766 -0
- package/dist/hd-facilitator-group.d.ts +34 -0
- package/dist/hd-facilitator-group.js +115 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.js +3 -0
- package/dist/order.d.ts +277 -0
- package/dist/order.js +111 -0
- package/dist/sdk.d.ts +161 -0
- package/dist/sdk.js +57 -0
- package/dist/signer-adapters/viem.d.ts +16 -0
- package/dist/signer-adapters/viem.js +30 -0
- package/dist/types/api.d.ts +145 -0
- package/dist/types/api.js +1 -0
- package/dist/types/authorization.d.ts +245 -0
- package/dist/types/authorization.js +1 -0
- package/dist/types/core.d.ts +50 -0
- package/dist/types/core.js +1 -0
- package/dist/types/sdk.d.ts +33 -0
- package/dist/types/sdk.js +1 -0
- package/dist/util.d.ts +13 -0
- package/dist/util.js +55 -0
- package/package.json +36 -0
package/README.md
ADDED
package/dist/caip19.d.ts
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { Caip19, IntStr } from './types/core.js';
|
|
2
|
+
import type { Hex } from 'viem';
|
|
3
|
+
export declare enum Caip19Namespace {
|
|
4
|
+
BIP122 = "bip122",
|
|
5
|
+
EIP155 = "eip155",
|
|
6
|
+
COSMOS = "cosmos",
|
|
7
|
+
SOLANA = "solana",
|
|
8
|
+
SUI = "sui",
|
|
9
|
+
STELLAR = "stellar"
|
|
10
|
+
}
|
|
11
|
+
export interface Caip19Parts<N extends Caip19Namespace> {
|
|
12
|
+
chainNamespace: N;
|
|
13
|
+
chainId: N extends Caip19Namespace.EIP155 ? number | bigint | IntStr : N extends Caip19Namespace.SUI ? 'mainnet' | 'testnet' | 'devnet' : string;
|
|
14
|
+
assetNamespace: N extends Caip19Namespace.EIP155 ? 'erc20' : N extends Caip19Namespace.SOLANA ? 'token' : N extends Caip19Namespace.COSMOS ? 'ics20' : N extends Caip19Namespace.SUI ? 'slip44' : string;
|
|
15
|
+
assetReference: N extends Caip19Namespace.EIP155 ? Hex : N extends Caip19Namespace.SUI ? string : bigint | IntStr;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Helper function makes a CAIP-19 string from parts
|
|
19
|
+
* @param parts CAIP-19 parts
|
|
20
|
+
* @returns CAIP-19 string
|
|
21
|
+
*/
|
|
22
|
+
export declare function caip19FromParts<N extends Caip19Namespace>(parts: Caip19Parts<N>): Caip19;
|
|
23
|
+
/**
|
|
24
|
+
* Helper function makes a CAIP-19 string for an EVM fungible token
|
|
25
|
+
* @param chainId EVM chain ID
|
|
26
|
+
* @param tokenAddress EVM token address
|
|
27
|
+
* @returns CAIP-19 string
|
|
28
|
+
*/
|
|
29
|
+
export declare function caip19FungibleEvmToken(chainId: number, tokenAddress: Hex): Caip19;
|
package/dist/caip19.js
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
export var Caip19Namespace;
|
|
2
|
+
(function (Caip19Namespace) {
|
|
3
|
+
Caip19Namespace["BIP122"] = "bip122";
|
|
4
|
+
Caip19Namespace["EIP155"] = "eip155";
|
|
5
|
+
Caip19Namespace["COSMOS"] = "cosmos";
|
|
6
|
+
Caip19Namespace["SOLANA"] = "solana";
|
|
7
|
+
Caip19Namespace["SUI"] = "sui";
|
|
8
|
+
Caip19Namespace["STELLAR"] = "stellar";
|
|
9
|
+
})(Caip19Namespace || (Caip19Namespace = {}));
|
|
10
|
+
/**
|
|
11
|
+
* Helper function makes a CAIP-19 string from parts
|
|
12
|
+
* @param parts CAIP-19 parts
|
|
13
|
+
* @returns CAIP-19 string
|
|
14
|
+
*/
|
|
15
|
+
export function caip19FromParts(parts) {
|
|
16
|
+
return `${parts.chainNamespace}:${parts.chainId}/${parts.assetNamespace}:${parts.assetReference}`;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Helper function makes a CAIP-19 string for an EVM fungible token
|
|
20
|
+
* @param chainId EVM chain ID
|
|
21
|
+
* @param tokenAddress EVM token address
|
|
22
|
+
* @returns CAIP-19 string
|
|
23
|
+
*/
|
|
24
|
+
export function caip19FungibleEvmToken(chainId, tokenAddress) {
|
|
25
|
+
return caip19FromParts({
|
|
26
|
+
chainNamespace: Caip19Namespace.EIP155,
|
|
27
|
+
chainId,
|
|
28
|
+
assetNamespace: 'erc20',
|
|
29
|
+
assetReference: tokenAddress,
|
|
30
|
+
});
|
|
31
|
+
}
|
package/dist/client.d.ts
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { ENVIRONMENT } from './constants.js';
|
|
2
|
+
import type { AuthRequest, AuthResponse, NonceResponse, OrderRequest, OrderResponse, QuoteRequest, QuoteResponse } from './types/api.js';
|
|
3
|
+
import type { ResponseWrapper } from './types/sdk.js';
|
|
4
|
+
import type { Hex } from 'viem';
|
|
5
|
+
export type SilentSwapClientConfig = {
|
|
6
|
+
/**
|
|
7
|
+
* API key for authentication
|
|
8
|
+
*/
|
|
9
|
+
apiKey: string;
|
|
10
|
+
/**
|
|
11
|
+
* Chain environment
|
|
12
|
+
*/
|
|
13
|
+
environment: ENVIRONMENT;
|
|
14
|
+
/**
|
|
15
|
+
* Base URL to override the default
|
|
16
|
+
*/
|
|
17
|
+
baseUrl?: string;
|
|
18
|
+
};
|
|
19
|
+
/**
|
|
20
|
+
* SilentSwap client
|
|
21
|
+
*/
|
|
22
|
+
declare class SilentSwapClient {
|
|
23
|
+
#private;
|
|
24
|
+
protected config: SilentSwapClientConfig;
|
|
25
|
+
constructor(config: SilentSwapClientConfig);
|
|
26
|
+
/**
|
|
27
|
+
* Returns the gateway address for the current environment
|
|
28
|
+
*/
|
|
29
|
+
get gatewayAddress(): Hex;
|
|
30
|
+
/**
|
|
31
|
+
* Returns the proxy public key for the current environment
|
|
32
|
+
*/
|
|
33
|
+
get proxyPublicKey(): Hex;
|
|
34
|
+
/**
|
|
35
|
+
* Fetches a signed nonce from the backend for the given signer address
|
|
36
|
+
* @param addr - signer address
|
|
37
|
+
* @param init - request initialization options
|
|
38
|
+
* @returns a {@link ResponseWrapper `ResponseWrapper`}{@link NonceResponse `<NonceResponse>`}
|
|
39
|
+
*/
|
|
40
|
+
nonce(addr: Hex, init?: RequestInit): Promise<ResponseWrapper<NonceResponse>>;
|
|
41
|
+
/**
|
|
42
|
+
* Authenticates a signer with the backend
|
|
43
|
+
* @param auth - authentication request
|
|
44
|
+
* @param init - request initialization options
|
|
45
|
+
* @returns a {@link ResponseWrapper `ResponseWrapper`}{@link AuthResponse `<AuthResponse>`}
|
|
46
|
+
*/
|
|
47
|
+
authenticate(auth: AuthRequest, init?: RequestInit): Promise<ResponseWrapper<AuthResponse>>;
|
|
48
|
+
/**
|
|
49
|
+
* Fetches a signed quote from the backend
|
|
50
|
+
* @param quote - quote request
|
|
51
|
+
* @param init - request initialization options
|
|
52
|
+
* @returns a {@link ResponseWrapper `ResponseWrapper`}{@link QuoteResponse `<QuoteResponse>`}
|
|
53
|
+
*/
|
|
54
|
+
quote(quote: QuoteRequest, init?: RequestInit): Promise<ResponseWrapper<QuoteResponse>>;
|
|
55
|
+
/**
|
|
56
|
+
* Creates a SilentSwap order, a prerequisite to depositing funds into the Gateway contract
|
|
57
|
+
* @param order - order request
|
|
58
|
+
* @param init - request initialization options
|
|
59
|
+
* @returns a {@link ResponseWrapper `ResponseWrapper`}{@link OrderResponse `<OrderResponse>`}
|
|
60
|
+
*/
|
|
61
|
+
order(order: OrderRequest, init?: RequestInit): Promise<ResponseWrapper<OrderResponse>>;
|
|
62
|
+
}
|
|
63
|
+
export type { SilentSwapClient };
|
|
64
|
+
/**
|
|
65
|
+
* Creates a new SilentSwap client
|
|
66
|
+
* @param gc_client - client configuration
|
|
67
|
+
* @returns a new {@link SilentSwapClient}
|
|
68
|
+
*/
|
|
69
|
+
export declare function createSilentSwapClient(gc_client: SilentSwapClientConfig): SilentSwapClient;
|
package/dist/client.js
ADDED
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
import { ENVIRONMENT, MAINNET_GATEWAY_ADDRESS, MAINNET_GATEWAY_PUBLIC_KEY, MAINNET_SILENTSWAP_API } from './constants.js';
|
|
2
|
+
const ENVIRONMENT_CONFIGS = {
|
|
3
|
+
[ENVIRONMENT.MAINNET]: {
|
|
4
|
+
gatewayAddress: MAINNET_GATEWAY_ADDRESS,
|
|
5
|
+
proxyPublicKey: MAINNET_GATEWAY_PUBLIC_KEY,
|
|
6
|
+
},
|
|
7
|
+
};
|
|
8
|
+
/**
|
|
9
|
+
* SilentSwap client
|
|
10
|
+
*/
|
|
11
|
+
class SilentSwapClient {
|
|
12
|
+
config;
|
|
13
|
+
constructor(config) {
|
|
14
|
+
this.config = config;
|
|
15
|
+
// unsupported environment
|
|
16
|
+
if (!['MAINNET'].includes(this.config.environment)) {
|
|
17
|
+
throw new Error(`Unsupported environment: ${this.config.environment}`);
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Performs a GET request to the backend API
|
|
22
|
+
* @param path - path to request
|
|
23
|
+
* @param params - query parameters
|
|
24
|
+
* @param init - request initialization options
|
|
25
|
+
* @returns a {@link ResponseWrapper `<ResponseWrapper>`}`<Data>`
|
|
26
|
+
*/
|
|
27
|
+
async #get(path, params = {}, init = {}) {
|
|
28
|
+
const { config } = this;
|
|
29
|
+
// submit GET request
|
|
30
|
+
const res = await fetch(`${(config.baseUrl ?? MAINNET_SILENTSWAP_API) + path}?${new URLSearchParams(params).toString()}`, {
|
|
31
|
+
...init || {},
|
|
32
|
+
method: 'GET',
|
|
33
|
+
headers: {
|
|
34
|
+
...init?.headers
|
|
35
|
+
? Object === init.headers.constructor
|
|
36
|
+
? init.headers
|
|
37
|
+
: () => { throw new Error('.headers value must be a plain object'); }
|
|
38
|
+
: {},
|
|
39
|
+
authorization: config.apiKey,
|
|
40
|
+
accept: 'application/json',
|
|
41
|
+
},
|
|
42
|
+
});
|
|
43
|
+
// read body
|
|
44
|
+
const resBody = await res.text();
|
|
45
|
+
// attempt to parse response body JSON
|
|
46
|
+
try {
|
|
47
|
+
const resJson = JSON.parse(resBody);
|
|
48
|
+
// OK respose
|
|
49
|
+
if (res.ok) {
|
|
50
|
+
return [void 0, resJson];
|
|
51
|
+
}
|
|
52
|
+
// not OK
|
|
53
|
+
else {
|
|
54
|
+
return [resJson, void 0];
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
catch (_err) {
|
|
58
|
+
return [{
|
|
59
|
+
type: 'SERVER_ERROR',
|
|
60
|
+
error: `Failed to parse server response:\n${resBody}`,
|
|
61
|
+
}, void 0];
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Performs a POST request to the backend API
|
|
66
|
+
* @param path - path to request
|
|
67
|
+
* @param reqBody - request body JSON object
|
|
68
|
+
* @param init - request initialization options
|
|
69
|
+
* @returns a {@link ResponseWrapper `ResponseWrapper`}`<Data>`
|
|
70
|
+
*/
|
|
71
|
+
async #post(path, reqBody, init = {}) {
|
|
72
|
+
const { config } = this;
|
|
73
|
+
// submit POST request
|
|
74
|
+
const res = await fetch((config.baseUrl ?? MAINNET_SILENTSWAP_API) + path, {
|
|
75
|
+
...init || {},
|
|
76
|
+
method: 'POST',
|
|
77
|
+
headers: {
|
|
78
|
+
...init?.headers
|
|
79
|
+
? Object === init.headers.constructor
|
|
80
|
+
? init.headers
|
|
81
|
+
: () => { throw new Error('.headers value must be a plain object'); }
|
|
82
|
+
: {},
|
|
83
|
+
'authorization': config.apiKey,
|
|
84
|
+
'accept': 'application/json',
|
|
85
|
+
'content-type': 'application/json',
|
|
86
|
+
},
|
|
87
|
+
body: JSON.stringify(reqBody),
|
|
88
|
+
});
|
|
89
|
+
// read body
|
|
90
|
+
const resBody = await res.text();
|
|
91
|
+
// attempt to parse response body JSON
|
|
92
|
+
try {
|
|
93
|
+
const resJson = JSON.parse(resBody);
|
|
94
|
+
// OK respose
|
|
95
|
+
if (res.ok) {
|
|
96
|
+
return [void 0, resJson];
|
|
97
|
+
}
|
|
98
|
+
// not OK
|
|
99
|
+
else {
|
|
100
|
+
return [resJson, void 0];
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
catch (_err) {
|
|
104
|
+
return [{
|
|
105
|
+
type: 'SERVER_ERROR',
|
|
106
|
+
error: `Failed to parse server response:\n${resBody}`,
|
|
107
|
+
}, void 0];
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Returns the gateway address for the current environment
|
|
112
|
+
*/
|
|
113
|
+
get gatewayAddress() {
|
|
114
|
+
return ENVIRONMENT_CONFIGS[this.config.environment].gatewayAddress;
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Returns the proxy public key for the current environment
|
|
118
|
+
*/
|
|
119
|
+
get proxyPublicKey() {
|
|
120
|
+
return ENVIRONMENT_CONFIGS[this.config.environment].proxyPublicKey;
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* Fetches a signed nonce from the backend for the given signer address
|
|
124
|
+
* @param addr - signer address
|
|
125
|
+
* @param init - request initialization options
|
|
126
|
+
* @returns a {@link ResponseWrapper `ResponseWrapper`}{@link NonceResponse `<NonceResponse>`}
|
|
127
|
+
*/
|
|
128
|
+
async nonce(addr, init = {}) {
|
|
129
|
+
return await this.#get('/nonce', {
|
|
130
|
+
address: addr,
|
|
131
|
+
}, init);
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* Authenticates a signer with the backend
|
|
135
|
+
* @param auth - authentication request
|
|
136
|
+
* @param init - request initialization options
|
|
137
|
+
* @returns a {@link ResponseWrapper `ResponseWrapper`}{@link AuthResponse `<AuthResponse>`}
|
|
138
|
+
*/
|
|
139
|
+
async authenticate(auth, init = {}) {
|
|
140
|
+
return await this.#post('/authenticate', auth, init);
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* Fetches a signed quote from the backend
|
|
144
|
+
* @param quote - quote request
|
|
145
|
+
* @param init - request initialization options
|
|
146
|
+
* @returns a {@link ResponseWrapper `ResponseWrapper`}{@link QuoteResponse `<QuoteResponse>`}
|
|
147
|
+
*/
|
|
148
|
+
async quote(quote, init = {}) {
|
|
149
|
+
return await this.#post('/quote', quote, init);
|
|
150
|
+
}
|
|
151
|
+
/**
|
|
152
|
+
* Creates a SilentSwap order, a prerequisite to depositing funds into the Gateway contract
|
|
153
|
+
* @param order - order request
|
|
154
|
+
* @param init - request initialization options
|
|
155
|
+
* @returns a {@link ResponseWrapper `ResponseWrapper`}{@link OrderResponse `<OrderResponse>`}
|
|
156
|
+
*/
|
|
157
|
+
async order(order, init = {}) {
|
|
158
|
+
return await this.#post('/order', order, init);
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
/**
|
|
162
|
+
* Creates a new SilentSwap client
|
|
163
|
+
* @param gc_client - client configuration
|
|
164
|
+
* @returns a new {@link SilentSwapClient}
|
|
165
|
+
*/
|
|
166
|
+
export function createSilentSwapClient(gc_client) {
|
|
167
|
+
return new SilentSwapClient(gc_client);
|
|
168
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { type Hex } from 'viem';
|
|
2
|
+
export declare const EVM_PHONY_ADDRESS: Hex;
|
|
3
|
+
export declare const EVM_NATIVE_ADDRESS: Hex;
|
|
4
|
+
export declare const MAINNET_SILENTSWAP_API = "https://api.silentswap.com/v2";
|
|
5
|
+
export declare const MAINNET_GATEWAY_ADDRESS = "0xA798d4D04faad17C309127C2B9B99Cc459635eDC";
|
|
6
|
+
export declare const MAINNET_GATEWAY_PUBLIC_KEY = "0x0494913354a94d40604cd453d2a654489aa78472daf953c63cae4ceaaa40740d682905847e99618c34b360d8ef4645a954cc9686619995465dfdba6da34f35642f";
|
|
7
|
+
export declare const COIN_TYPES: {
|
|
8
|
+
readonly ETH: "60";
|
|
9
|
+
readonly ATOM: "118";
|
|
10
|
+
readonly SCRT: "529";
|
|
11
|
+
};
|
|
12
|
+
export declare enum ENVIRONMENT {
|
|
13
|
+
MAINNET = "MAINNET"
|
|
14
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
// EVM addresses
|
|
2
|
+
export const EVM_PHONY_ADDRESS = '0x1111111111111111111111111111111111111111';
|
|
3
|
+
export const EVM_NATIVE_ADDRESS = '0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE';
|
|
4
|
+
// Mainnet constants
|
|
5
|
+
export const MAINNET_SILENTSWAP_API = 'https://api.silentswap.com/v2';
|
|
6
|
+
export const MAINNET_GATEWAY_ADDRESS = '0xA798d4D04faad17C309127C2B9B99Cc459635eDC';
|
|
7
|
+
export const MAINNET_GATEWAY_PUBLIC_KEY = '0x0494913354a94d40604cd453d2a654489aa78472daf953c63cae4ceaaa40740d682905847e99618c34b360d8ef4645a954cc9686619995465dfdba6da34f35642f';
|
|
8
|
+
// Coin types
|
|
9
|
+
export const COIN_TYPES = {
|
|
10
|
+
ETH: '60',
|
|
11
|
+
ATOM: '118',
|
|
12
|
+
SCRT: '529',
|
|
13
|
+
};
|
|
14
|
+
// Environments
|
|
15
|
+
export var ENVIRONMENT;
|
|
16
|
+
(function (ENVIRONMENT) {
|
|
17
|
+
ENVIRONMENT["MAINNET"] = "MAINNET";
|
|
18
|
+
})(ENVIRONMENT || (ENVIRONMENT = {}));
|
|
19
|
+
;
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { Account, Hex } from 'viem';
|
|
2
|
+
import { OfflineAminoSigner } from '@cosmjs/amino';
|
|
3
|
+
import { FacilitatorKeyType, type FacilitatorPublicKey } from './order.js';
|
|
4
|
+
import type { EncryptSecretKeyArgs, ExportedFacilitator } from './types/sdk.js';
|
|
5
|
+
import type { CoinTypeStr } from './types/core.js';
|
|
6
|
+
import type { ProxyAuthInstruction } from './types/authorization.js';
|
|
7
|
+
export declare const SECP256K1: import("@solar-republic/wasm-secp256k1").Secp256k1;
|
|
8
|
+
export declare class FacilitatorAccount {
|
|
9
|
+
#private;
|
|
10
|
+
/**
|
|
11
|
+
* Creates a facilitator account
|
|
12
|
+
* @param secretKeyBytes optional secret key bytes
|
|
13
|
+
*/
|
|
14
|
+
constructor(secretKeyBytes?: Uint8Array<ArrayBuffer>);
|
|
15
|
+
/**
|
|
16
|
+
* Exports the secret key
|
|
17
|
+
* @returns A copy of the secret key
|
|
18
|
+
*/
|
|
19
|
+
exportSecretKey(): Uint8Array;
|
|
20
|
+
/**
|
|
21
|
+
* Exports the public key for the given coin type and key type
|
|
22
|
+
* @param coinType coin type
|
|
23
|
+
* @param keyType key type
|
|
24
|
+
* @returns the public key
|
|
25
|
+
*/
|
|
26
|
+
exportPublicKey(coinType: CoinTypeStr, keyType: FacilitatorKeyType): FacilitatorPublicKey;
|
|
27
|
+
/**
|
|
28
|
+
* Returns a Viem {@link Account} instance for signing EVM transactions from this account
|
|
29
|
+
* @returns A Promise that resolves to the signer
|
|
30
|
+
*/
|
|
31
|
+
evmSigner(): Promise<Account>;
|
|
32
|
+
/**
|
|
33
|
+
* Returns a CosmJS {@link OfflineAminoSigner} instance for signing Cosmos transactions from this account
|
|
34
|
+
* @param bech32Prefix - the bech32 prefix for the desired chain
|
|
35
|
+
* @returns A Promise that resolves to the signer
|
|
36
|
+
*/
|
|
37
|
+
cosmosSigner(bech32Prefix: string): Promise<OfflineAminoSigner>;
|
|
38
|
+
/**
|
|
39
|
+
* Signs a proxy authorization instruction
|
|
40
|
+
* @param authorization the proxy authorization instruction to sign
|
|
41
|
+
* @returns the signature
|
|
42
|
+
*/
|
|
43
|
+
signProxyAuthorization(authorization: ProxyAuthInstruction): Promise<Hex>;
|
|
44
|
+
/**
|
|
45
|
+
* Encrypts the secret key with the given public key
|
|
46
|
+
* @param args encryption arguments
|
|
47
|
+
* @returns the encrypted secret key
|
|
48
|
+
*/
|
|
49
|
+
encryptSecretKeyForProxy(args: EncryptSecretKeyArgs): Promise<ExportedFacilitator>;
|
|
50
|
+
}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import { bytesToHex, stringToBytes } from 'viem';
|
|
2
|
+
import { toBase64 } from '@cosmjs/encoding';
|
|
3
|
+
import { initWasmSecp256k1 } from '@solar-republic/wasm-secp256k1';
|
|
4
|
+
import { privateKeyToAccount } from 'viem/accounts';
|
|
5
|
+
import { Secp256k1Wallet } from '@cosmjs/amino';
|
|
6
|
+
import { normalizeBytesish, normalizeJson } from './util.js';
|
|
7
|
+
import { FacilitatorKeyType } from './order.js';
|
|
8
|
+
// wasm-secp256k1 instance
|
|
9
|
+
export const SECP256K1 = await initWasmSecp256k1();
|
|
10
|
+
export class FacilitatorAccount {
|
|
11
|
+
#secretKey;
|
|
12
|
+
/**
|
|
13
|
+
* Creates a facilitator account
|
|
14
|
+
* @param secretKeyBytes optional secret key bytes
|
|
15
|
+
*/
|
|
16
|
+
constructor(secretKeyBytes) {
|
|
17
|
+
// if secret was given, copy its bytes into a new section of memory so parent can zeroize original
|
|
18
|
+
this.#secretKey = secretKeyBytes ? secretKeyBytes.slice() : SECP256K1.gen_sk();
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Exports the secret key
|
|
22
|
+
* @returns A copy of the secret key
|
|
23
|
+
*/
|
|
24
|
+
exportSecretKey() {
|
|
25
|
+
return this.#secretKey.slice();
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Exports the public key for the given coin type and key type
|
|
29
|
+
* @param coinType coin type
|
|
30
|
+
* @param keyType key type
|
|
31
|
+
* @returns the public key
|
|
32
|
+
*/
|
|
33
|
+
exportPublicKey(coinType, keyType) {
|
|
34
|
+
let publicKeyBytes;
|
|
35
|
+
switch (keyType) {
|
|
36
|
+
case FacilitatorKeyType.SECP256K1:
|
|
37
|
+
publicKeyBytes = SECP256K1.sk_to_pk(this.#secretKey, true);
|
|
38
|
+
break;
|
|
39
|
+
// case FacilitatorKeyType.ED25519:
|
|
40
|
+
// publicKeyBytes =
|
|
41
|
+
// break;
|
|
42
|
+
default:
|
|
43
|
+
throw new Error('Invalid key type');
|
|
44
|
+
}
|
|
45
|
+
return {
|
|
46
|
+
coinType,
|
|
47
|
+
keyType,
|
|
48
|
+
publicKeyBytes: bytesToHex(publicKeyBytes),
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Returns a Viem {@link Account} instance for signing EVM transactions from this account
|
|
53
|
+
* @returns A Promise that resolves to the signer
|
|
54
|
+
*/
|
|
55
|
+
evmSigner() {
|
|
56
|
+
return Promise.resolve(privateKeyToAccount(bytesToHex(this.#secretKey)));
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Returns a CosmJS {@link OfflineAminoSigner} instance for signing Cosmos transactions from this account
|
|
60
|
+
* @param bech32Prefix - the bech32 prefix for the desired chain
|
|
61
|
+
* @returns A Promise that resolves to the signer
|
|
62
|
+
*/
|
|
63
|
+
async cosmosSigner(bech32Prefix) {
|
|
64
|
+
return await Secp256k1Wallet.fromKey(this.#secretKey, bech32Prefix);
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Signs a proxy authorization instruction
|
|
68
|
+
* @param authorization the proxy authorization instruction to sign
|
|
69
|
+
* @returns the signature
|
|
70
|
+
*/
|
|
71
|
+
async signProxyAuthorization(authorization) {
|
|
72
|
+
// create local account
|
|
73
|
+
const account = privateKeyToAccount(bytesToHex(this.#secretKey));
|
|
74
|
+
// sign message
|
|
75
|
+
return await account.signMessage({
|
|
76
|
+
message: bytesToHex(stringToBytes(JSON.stringify(normalizeJson(authorization.content)))),
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Encrypts the secret key with the given public key
|
|
81
|
+
* @param args encryption arguments
|
|
82
|
+
* @returns the encrypted secret key
|
|
83
|
+
*/
|
|
84
|
+
async encryptSecretKeyForProxy(args) {
|
|
85
|
+
// import secret key
|
|
86
|
+
const privKey = await crypto.subtle.importKey('raw', this.#secretKey, { name: 'AES-GCM' }, true, ['encrypt']);
|
|
87
|
+
// normalize public key
|
|
88
|
+
const proxyPubKey = normalizeBytesish(args.proxyPublicKey);
|
|
89
|
+
// generate key pair for encryption
|
|
90
|
+
const encPrivKey = SECP256K1.gen_sk();
|
|
91
|
+
const encPubKey = SECP256K1.sk_to_pk(encPrivKey);
|
|
92
|
+
// derive shared secret
|
|
93
|
+
const sharedSecret = SECP256K1.ecdh(encPrivKey, proxyPubKey);
|
|
94
|
+
// zeroize secret key bytes
|
|
95
|
+
encPrivKey.fill(0);
|
|
96
|
+
// import secret as wrapping key
|
|
97
|
+
const ecdhPrivKey = await crypto.subtle.importKey('raw', sharedSecret, 'AES-KW', false, ['wrapKey']);
|
|
98
|
+
// zeroize shared secret bytes
|
|
99
|
+
sharedSecret.fill(0);
|
|
100
|
+
// encrypt secret key
|
|
101
|
+
const wrappedKey = await crypto.subtle.wrapKey('raw', privKey, ecdhPrivKey, 'AES-KW');
|
|
102
|
+
// export
|
|
103
|
+
return {
|
|
104
|
+
wrappedKey: toBase64(new Uint8Array(wrappedKey)),
|
|
105
|
+
encryptionPublicKey: toBase64(encPubKey),
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
}
|