@harukit/sdk 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,221 @@
1
+ /**
2
+ * ConfigManager - Validate and test configs against the Haru API
3
+ *
4
+ * @example
5
+ * ```typescript
6
+ * const result = await ConfigManager.validate(
7
+ * { chains: ['arbitrum'] },
8
+ * { apiKey: 'haru_live_demo123' }
9
+ * );
10
+ *
11
+ * if (result.valid) {
12
+ * console.log('Config is valid!');
13
+ * }
14
+ * ```
15
+ */
16
+ export class ConfigManager {
17
+ static getBaseUrl(options) {
18
+ return options.baseUrl || 'https://api.haruapi.com';
19
+ }
20
+ static getHeaders(options) {
21
+ return {
22
+ 'Content-Type': 'application/json',
23
+ 'X-API-Key': options.apiKey,
24
+ };
25
+ }
26
+ /**
27
+ * Validate a config against the API
28
+ * Checks if chains are allowed, tokens can be hydrated, etc.
29
+ */
30
+ static async validate(config, options) {
31
+ const baseUrl = this.getBaseUrl(options);
32
+ try {
33
+ const response = await fetch(`${baseUrl}/v1/config/verify`, {
34
+ method: 'POST',
35
+ headers: this.getHeaders(options),
36
+ body: JSON.stringify({ config }),
37
+ });
38
+ if (!response.ok) {
39
+ const error = await response.json().catch(() => ({ error: 'Unknown error' }));
40
+ return {
41
+ valid: false,
42
+ errors: [error.error || `HTTP ${response.status}`],
43
+ };
44
+ }
45
+ const result = await response.json();
46
+ return {
47
+ valid: result.verified === true,
48
+ errors: result.error ? [result.error] : [],
49
+ config: result.config,
50
+ hydratedTokens: result.hydratedTokens,
51
+ };
52
+ }
53
+ catch (e) {
54
+ return {
55
+ valid: false,
56
+ errors: [e.message || 'Network error'],
57
+ };
58
+ }
59
+ }
60
+ /**
61
+ * Test a config by making dry-run calls to all endpoints
62
+ * This validates that the config works for all features
63
+ */
64
+ static async test(config, options) {
65
+ const baseUrl = this.getBaseUrl(options);
66
+ const headers = {
67
+ 'X-API-Key': options.apiKey,
68
+ 'X-Haru-Config': JSON.stringify(config),
69
+ };
70
+ const results = {
71
+ tokens: { success: false },
72
+ balances: { success: false },
73
+ swaps: { success: false },
74
+ transfers: { success: false },
75
+ yield: { success: false },
76
+ relay: { success: false },
77
+ };
78
+ // Test tokens
79
+ try {
80
+ const response = await fetch(`${baseUrl}/v1/tokens/defaults`, { headers });
81
+ results.tokens.success = response.ok;
82
+ if (!response.ok) {
83
+ const error = await response.json().catch(() => ({}));
84
+ results.tokens.error = error.error;
85
+ }
86
+ }
87
+ catch (e) {
88
+ results.tokens.error = e.message;
89
+ }
90
+ // Test balances (requires userAddress - skip if no chains)
91
+ if (config.chains?.length > 0) {
92
+ try {
93
+ // Use a dummy address for testing
94
+ const dummyAddress = '0x0000000000000000000000000000000000000000';
95
+ const response = await fetch(`${baseUrl}/v1/balances/${dummyAddress}`, { headers });
96
+ // 400 is expected for dummy address, but API should respond
97
+ results.balances.success = response.status === 400 || response.ok;
98
+ if (!response.ok && response.status !== 400) {
99
+ const error = await response.json().catch(() => ({}));
100
+ results.balances.error = error.error;
101
+ }
102
+ else {
103
+ results.balances.success = true;
104
+ }
105
+ }
106
+ catch (e) {
107
+ results.balances.error = e.message;
108
+ }
109
+ }
110
+ // Test swaps
111
+ try {
112
+ const response = await fetch(`${baseUrl}/v1/swaps/quote-by-usd`, {
113
+ method: 'POST',
114
+ headers: { ...headers, 'Content-Type': 'application/json' },
115
+ body: JSON.stringify({
116
+ userAddress: '0x0000000000000000000000000000000000000000',
117
+ fromSymbol: 'USDC',
118
+ toSymbol: 'WETH',
119
+ usdValue: '100',
120
+ }),
121
+ });
122
+ // 400 is expected for dummy data, but API should respond
123
+ results.swaps.success = response.status === 400 || response.ok;
124
+ if (!response.ok && response.status !== 400) {
125
+ const error = await response.json().catch(() => ({}));
126
+ results.swaps.error = error.error;
127
+ }
128
+ else {
129
+ results.swaps.success = true;
130
+ }
131
+ }
132
+ catch (e) {
133
+ results.swaps.error = e.message;
134
+ }
135
+ // Test transfers
136
+ try {
137
+ const response = await fetch(`${baseUrl}/v1/transfers/by-usd`, {
138
+ method: 'POST',
139
+ headers: { ...headers, 'Content-Type': 'application/json' },
140
+ body: JSON.stringify({
141
+ fromUser: '0x0000000000000000000000000000000000000000',
142
+ toUser: '0x0000000000000000000000000000000000000001',
143
+ tokenSymbol: 'USDC',
144
+ usdValue: '100',
145
+ }),
146
+ });
147
+ results.transfers.success = response.status === 400 || response.ok;
148
+ if (!response.ok && response.status !== 400) {
149
+ const error = await response.json().catch(() => ({}));
150
+ results.transfers.error = error.error;
151
+ }
152
+ else {
153
+ results.transfers.success = true;
154
+ }
155
+ }
156
+ catch (e) {
157
+ results.transfers.error = e.message;
158
+ }
159
+ // Test yield
160
+ try {
161
+ const response = await fetch(`${baseUrl}/v1/yield/rates`, { headers });
162
+ results.yield.success = response.ok;
163
+ if (!response.ok) {
164
+ const error = await response.json().catch(() => ({}));
165
+ results.yield.error = error.error;
166
+ }
167
+ }
168
+ catch (e) {
169
+ results.yield.error = e.message;
170
+ }
171
+ // Test relay
172
+ try {
173
+ const response = await fetch(`${baseUrl}/v1/relay/sponsor`, { headers });
174
+ results.relay.success = response.ok;
175
+ if (!response.ok) {
176
+ const error = await response.json().catch(() => ({}));
177
+ results.relay.error = error.error;
178
+ }
179
+ }
180
+ catch (e) {
181
+ results.relay.error = e.message;
182
+ }
183
+ return results;
184
+ }
185
+ /**
186
+ * Create a config from a template
187
+ * This is local-only, doesn't validate against API
188
+ */
189
+ static create(template) {
190
+ const now = Date.now();
191
+ const templates = {
192
+ minimal: {
193
+ chains: ['arbitrum'],
194
+ sig: '',
195
+ ts: now,
196
+ exp: now + 30 * 24 * 60 * 60 * 1000, // 30 days
197
+ },
198
+ default: {
199
+ chains: ['arbitrum', 'base'],
200
+ tokens: ['USDC', 'WETH'],
201
+ primaryUsd: ['USDC'],
202
+ sig: '',
203
+ ts: now,
204
+ exp: now + 30 * 24 * 60 * 60 * 1000,
205
+ },
206
+ full: {
207
+ chains: ['arbitrum', 'base', 'optimism', 'ethereum'],
208
+ tokens: ['USDC', 'USDT', 'WETH', 'WBTC'],
209
+ primaryUsd: ['USDC', 'USDT'],
210
+ yield: {
211
+ enabled: true,
212
+ allowList: ['USDC', 'USDT'],
213
+ },
214
+ sig: '',
215
+ ts: now,
216
+ exp: now + 30 * 24 * 60 * 60 * 1000,
217
+ },
218
+ };
219
+ return templates[template || 'default'];
220
+ }
221
+ }
@@ -0,0 +1,85 @@
1
+ import { type Address } from 'viem';
2
+ import type { CleanSwapQuote, CleanTransfer, EIP7702Call, ChainCallBundle, SignedBatch, SimulationResult, TxStatus, NonceMetadata, SponsorTxResponse, PrivySignRawHash, Haru7702Options as Haru7702OptionsType, MultiInputSwapQuote } from '@harukit/types';
3
+ export type { Haru7702Options } from '@harukit/types';
4
+ /**
5
+ * Haru7702 — EIP-7702 batch transaction client with gas sponsorship.
6
+ *
7
+ * @example Single-chain swap (one-shot)
8
+ * ```ts
9
+ * const haru = new Haru7702({ apiKey: '...' }); // defaultChain = 'arbitrum'
10
+ * await haru.executeSwap({ quote, wallet, signAuthorization });
11
+ * ```
12
+ *
13
+ * @example Multi-chain swap (automatic parallel execution)
14
+ * ```ts
15
+ * const haru = new Haru7702({ apiKey: '...' });
16
+ * const batches = haru.buildCalls(quote); // Map { 'arbitrum' → ChainCallBundle, 'base' → ChainCallBundle }
17
+ * await haru.executeSwap({ quote, wallet, signAuthorization }); // handles multi-chain automatically
18
+ * ```
19
+ *
20
+ * @example Transfer
21
+ * ```ts
22
+ * await haru.executeTransfer({ transfer, wallet, signAuthorization });
23
+ * ```
24
+ */
25
+ export declare class Haru7702 {
26
+ private defaultChain;
27
+ private apiBaseUrl;
28
+ private apiKey;
29
+ constructor(options?: Haru7702OptionsType);
30
+ private getHeaders;
31
+ private serializeWithBigInt;
32
+ createSignRawHash(wallet: any): Promise<PrivySignRawHash>;
33
+ signAuthorization(signAuthorization: any, walletAddress: string, chain?: string): Promise<string>;
34
+ signBatchCall(calls: EIP7702Call[], nonce: bigint, deadline: bigint, sponsor: Address, signRawHash: PrivySignRawHash, walletAddress: string, chain?: string): Promise<string>;
35
+ /**
36
+ * Build execution calls from a swap quote or transfer.
37
+ * Always returns calls grouped by chain as Map<chain, ChainCallBundle>.
38
+ * Works for both single-chain and multi-chain operations.
39
+ */
40
+ buildCalls(quote: CleanSwapQuote | MultiInputSwapQuote | CleanTransfer): Map<string, ChainCallBundle>;
41
+ /**
42
+ * Execute a swap in one call. Handles multi-chain automatically.
43
+ * Returns immediately with transaction hashes (does not wait for confirmation).
44
+ */
45
+ executeSwap(params: {
46
+ quote: CleanSwapQuote | MultiInputSwapQuote;
47
+ wallet: any;
48
+ signAuthorization: any;
49
+ deadline?: bigint;
50
+ }): Promise<Map<string, SponsorTxResponse>>;
51
+ /**
52
+ * Execute a transfer in one call.
53
+ * Returns immediately with transaction hash (does not wait for confirmation).
54
+ */
55
+ executeTransfer(params: {
56
+ transfer: CleanTransfer;
57
+ wallet: any;
58
+ signAuthorization: any;
59
+ deadline?: bigint;
60
+ }): Promise<Map<string, SponsorTxResponse>>;
61
+ /**
62
+ * Execute a pre-built bundle (from buildCalls) in one call.
63
+ * Useful when you've combined multiple quotes into a single bundle.
64
+ * Returns immediately with transaction hash (does not wait for confirmation).
65
+ */
66
+ executeBatch(params: {
67
+ bundle: ChainCallBundle;
68
+ wallet: any;
69
+ signAuthorization: any;
70
+ deadline?: bigint;
71
+ }): Promise<Map<string, SponsorTxResponse>>;
72
+ /**
73
+ * Get the contract address for a specific chain.
74
+ * Fetches from the dedicated contract-address endpoint.
75
+ */
76
+ getContractAddress(chainId: number): Promise<Address>;
77
+ getSponsorAddress(): Promise<Address>;
78
+ getNonce(userAddress: Address, chain?: string): Promise<bigint>;
79
+ getNonceMetadata(userAddress: Address, chainId?: number): Promise<NonceMetadata>;
80
+ simulateTx(authorization: string, signedBatch: SignedBatch, userEOA: Address, chain?: string): Promise<SimulationResult>;
81
+ sponsorTx(signedBatch: SignedBatch, authorization: string, userEOA: Address, chain?: string): Promise<SponsorTxResponse>;
82
+ waitForTx(txHash: string, chain?: string): Promise<TxStatus>;
83
+ getTxStatus(txHash: string, chain?: string): Promise<TxStatus>;
84
+ }
85
+ //# sourceMappingURL=haru-7702.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"haru-7702.d.ts","sourceRoot":"","sources":["../src/haru-7702.ts"],"names":[],"mappings":"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"}