@elsoul/erpc-sdk 0.8.1 → 0.9.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/LICENSE CHANGED
@@ -2,6 +2,59 @@ MIT License
2
2
 
3
3
  Copyright (c) 2026 ELSOUL LABO B.V.
4
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.
22
+
23
+ -------------------------------------------------------------------------------
24
+ Third-party MIT notice: pinned Mayan source commit
25
+ c4c98031aaad9264d17630d7b4de0cb18688cf78
26
+ (source LICENSE SHA-256: a5b74ba954fd256feffa4c25251a0cbbfb7002af43278e3e4e6268a2e8208865)
27
+
28
+ The MIT License (MIT)
29
+ Copyright (c) 2022-2026 Mayan Finance
30
+
31
+
32
+ Permission is hereby granted, free of charge, to any person obtaining a copy
33
+ of this software and associated documentation files (the "Software"), to deal
34
+ in the Software without restriction, including without limitation the rights
35
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
36
+ copies of the Software, and to permit persons to whom the Software is
37
+ furnished to do so, subject to the following conditions:
38
+
39
+ The above copyright notice and this permission notice shall be included in all
40
+ copies or substantial portions of the Software.
41
+
42
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
43
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
44
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
45
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
46
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
47
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
48
+ SOFTWARE.
49
+
50
+ -------------------------------------------------------------------------------
51
+ Third-party MIT notice: npm oracle @mayanfinance/swap-sdk 15.2.2
52
+ (oracle LICENSE SHA-256: 3333053878e484331d629fb35ba704b0a635f26b9d81d9c5d51ab2d5817f4744)
53
+
54
+ The MIT License (MIT)
55
+ Copyright (c) 2019-2020 Hugo Di Francesco
56
+
57
+
5
58
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
59
  of this software and associated documentation files (the "Software"), to deal
7
60
  in the Software without restriction, including without limitation the rights
package/README.md CHANGED
@@ -1,20 +1,28 @@
1
1
  # `@elsoul/erpc-sdk`
2
2
 
3
3
  Official type-safe TypeScript client for [ERPC](https://erpc.global). Use one
4
- client and an API key for Solana, Ethereum, Avalanche C/P/X chains, price data,
5
- indexed data, leader and validator data, analytics, subscriptions, and account
6
- information. Caller-owned direct endpoints can be selected for Solana,
7
- Ethereum, and Avalanche C-Chain JSON-RPC.
4
+ client and an API key for Base, Solana, Ethereum, Avalanche C/P/X chains, price
5
+ data, indexed data, leader and validator data, analytics, subscriptions, and
6
+ account information. Base is exposed as a read-only JSON-RPC facade; caller-owned
7
+ direct endpoints can be selected for Base, Solana, Ethereum, and Avalanche
8
+ C-Chain JSON-RPC.
9
+
10
+ The Base facade documented below has been available since `0.9.0`. This
11
+ source/release cohort targets `0.9.1`; check the
12
+ [npm registry versions](https://registry.npmjs.org/%40elsoul%2Ferpc-sdk) for
13
+ current package availability.
8
14
 
9
15
  ## Install
10
16
 
11
17
  ```bash
12
- npm install @elsoul/erpc-sdk
13
- # or: pnpm add @elsoul/erpc-sdk
18
+ # After the npm registry lists 0.9.1:
19
+ npm install @elsoul/erpc-sdk@0.9.1
20
+ # or: pnpm add @elsoul/erpc-sdk@0.9.1
21
+ # For local validation, use the public 0.9.0 package or this source checkout.
14
22
  ```
15
23
 
16
- The package has no runtime dependencies and includes ESM, CommonJS, and
17
- TypeScript declarations. Node.js 20 or later is supported.
24
+ The package includes its ESM, CommonJS, and TypeScript declarations. Node.js 20
25
+ or later is supported.
18
26
 
19
27
  ## Quick start
20
28
 
@@ -29,8 +37,9 @@ const erpc = createErpcClient({ apiKey })
29
37
  const slot = await erpc.solana.rpc.getSlot().send()
30
38
  const chainId = await erpc.ethereum.rpc.eth_chainId().send()
31
39
  const avalancheChainId = await erpc.avalanche.rpc.eth_chainId().send()
40
+ const baseChainId = await erpc.base.rpc.eth_chainId().send()
32
41
 
33
- console.log({ slot, chainId, avalancheChainId })
42
+ console.log({ slot, chainId, avalancheChainId, baseChainId })
34
43
  erpc.close()
35
44
  ```
36
45
 
@@ -62,6 +71,10 @@ const chainId = await erpc.ethereum.rpc.eth_chainId().send()
62
71
  The configured HTTP URL is treated as the final target. Redirect responses are
63
72
  returned as HTTP errors, and no redirected request is made.
64
73
 
74
+ For direct HTTP transports, the public `endpoint` property is diagnostic
75
+ metadata containing only the origin/root. The private request target still
76
+ preserves the configured path, query order, and percent encoding exactly.
77
+
65
78
  Direct HTTP requests use `credentials: 'omit'`, so ambient browser cookies and
66
79
  authentication are not sent implicitly. Add authentication explicitly through
67
80
  the endpoint's scoped headers when needed.
@@ -84,12 +97,108 @@ const erpc = createErpcClient({
84
97
  })
85
98
  ```
86
99
 
87
- `solanaRpc`, `ethereumRpc`, and `avalancheCRpc` select direct Solana, Ethereum,
88
- and Avalanche C-Chain JSON-RPC transports. Without an API key, non-overridden
89
- chains and ERPC REST, native, and index services fail locally. The
100
+ `solanaRpc`, `ethereumRpc`, `avalancheCRpc`, and `baseRpc` select direct Solana,
101
+ Ethereum, Avalanche C-Chain, and Base JSON-RPC transports. `baseRpc` accepts
102
+ only an HTTP URL and scoped HTTP headers because the Base facade has no
103
+ WebSocket or subscription surface. Without an API key, non-overridden chains
104
+ and ERPC REST, native, and index services fail locally. The
90
105
  `RpcEndpointConfig.headers` field applies to direct HTTP requests only; those
91
106
  headers are never sent on WSS connections.
92
107
 
108
+ ## Base read-only RPC (available since `0.9.0`)
109
+
110
+ The `0.9.0` API-key client uses `https://base.erpc.global/` at the root JSON-RPC
111
+ path.
112
+ The first check for a Base connection should be `eth_chainId()` and must return
113
+ `0x2105` (Base mainnet). The following uses the catalog's Base EURC record and
114
+ formats the raw response with integer arithmetic:
115
+
116
+ ```ts
117
+ import {
118
+ createErpcClient,
119
+ getTokenDeployment,
120
+ tokens,
121
+ } from '@elsoul/erpc-sdk'
122
+
123
+ const erpc = createErpcClient({ apiKey: process.env.ERPC_API_KEY! })
124
+ const wallet = '0x7A5837f5bB52C53e08fcFf214c2Cd11daa8EF9EE'
125
+ const eurc = getTokenDeployment(tokens.base.EURC)
126
+ if (eurc?.address === null || eurc === undefined) {
127
+ throw new Error('Base EURC is missing from the catalog')
128
+ }
129
+
130
+ const chainId = await erpc.base.rpc.eth_chainId().send()
131
+ if (chainId !== '0x2105') throw new Error(`Unexpected Base chain: ${chainId}`)
132
+
133
+ const nativeWei = BigInt(
134
+ await erpc.base.rpc.eth_getBalance(wallet, '0x3167564').send(),
135
+ )
136
+ const calldata = `0x70a08231${wallet.slice(2).padStart(64, '0')}`
137
+ const eurcAtomic = BigInt(
138
+ await erpc.base.rpc.eth_call(
139
+ { to: eurc.address, data: calldata },
140
+ '0x3167564',
141
+ ).send(),
142
+ )
143
+
144
+ const formatUnits = (value: bigint, decimals: number): string => {
145
+ const scale = 10n ** BigInt(decimals)
146
+ const whole = value / scale
147
+ const fraction = (value % scale).toString().padStart(decimals, '0').replace(/0+$/u, '')
148
+ return fraction.length === 0 ? whole.toString() : `${whole}.${fraction}`
149
+ }
150
+
151
+ const eurcDisplay = formatUnits(eurcAtomic, eurc.decimals)
152
+ // Pinned review read: eurcAtomic === 5_500_000n and eurcDisplay === '5.5'.
153
+ console.log({ chainId, nativeWei, eurcAtomic, eurcDecimals: eurc.decimals, eurcDisplay })
154
+ erpc.close()
155
+ ```
156
+
157
+ For a keyless caller-owned endpoint, use `baseRpc`. Its URL path and query are
158
+ sent exactly as configured, and its headers stay scoped to Base:
159
+
160
+ ```ts
161
+ const erpc = createErpcClient({
162
+ baseRpc: {
163
+ httpUrl: process.env.ERPC_BASE_RPC_URL!,
164
+ headers: { authorization: 'Bearer node-token' },
165
+ },
166
+ })
167
+
168
+ const chainId = await erpc.base.rpc.eth_chainId().send()
169
+ ```
170
+
171
+ The Base client exposes only `rpc`; the inner read-only facade has exactly
172
+ `endpoint`, `eth_chainId`, `eth_getBalance`, and `eth_call`. It does not provide
173
+ raw, batch, subscription, signing, or broadcast methods. `baseEndpoint` forwards
174
+ the main API key and global headers, so use it only for a caller-trusted,
175
+ eRPC-compatible host. `baseRpc` takes precedence over it and over global
176
+ headers; it sends only credentials explicitly scoped inside the direct override.
177
+
178
+ ## Wallets, signing, and broadcast
179
+
180
+ `ErpcClient` has no wallet, private-key, or signer configuration. Swap
181
+ preparation and Mayan `buildUnsigned` return unsigned transaction envelopes;
182
+ the caller owns account selection, allowance changes, nonce and fee policy,
183
+ transaction review, key custody, signing, broadcast, and confirmation. The
184
+ `from`, `sender`, `swapperAddress`, and `feePayer` fields are public identity
185
+ checks, not signing authority. A pending RPC request's `.send()` performs the
186
+ network request and does not sign bytes.
187
+
188
+ | Concern | Owner |
189
+ | --- | --- |
190
+ | Key or hardware-wallet custody | Caller application or wallet provider |
191
+ | Transaction and allowance review | Caller application and user |
192
+ | Cryptographic signing | External wallet or signer |
193
+ | Signed-byte broadcast | Caller-selected ERPC RPC method |
194
+ | Confirmation and settlement interpretation | Caller application |
195
+
196
+ See the [shared wallet and signing model](https://github.com/elsoul/erpc-sdk/blob/main/README.md#wallets-and-signing)
197
+ and the [TypeScript signing and broadcast guide](https://github.com/elsoul/erpc-sdk/blob/main/packages/typescript/docs/signing-and-broadcast.md)
198
+ for initialized ethers 6 and `@solana/web3.js` 1.x examples. The guide keeps
199
+ the selected RPC URL identical for network checks and sends signed bytes only
200
+ through ERPC.
201
+
93
202
  ## Offline token catalog
94
203
 
95
204
  The token catalog is bundled with the package, so lookups do not need an
@@ -225,27 +334,22 @@ const simulation = await erpc.swap.simulateExactInputSwap(request)
225
334
  Preparation performs a fresh quote, validates the reviewed router and wrapped
226
335
  native deployment, and returns an immutable chain-bound unsigned transaction
227
336
  envelope. It does not create approval calldata, sign, send, or fill wallet
228
- fields. When a wallet API needs a raw transaction object, explicitly convert
229
- the envelope, for example:
230
-
231
- ```ts
232
- const { chainId: _chainId, kind: _kind, ...walletTransaction } =
233
- prepared.transaction
234
- await wallet.sendTransaction(walletTransaction)
235
- ```
337
+ fields. Review `prepared.transaction`, then pass the typed envelope to an
338
+ external signer and the ERPC-only broadcast helper in the
339
+ [TypeScript signing and broadcast guide](https://github.com/elsoul/erpc-sdk/blob/main/packages/typescript/docs/signing-and-broadcast.md).
236
340
 
237
341
  Use the `simulation` result to inspect the canonical allowance and router
238
342
  amounts before asking the caller's wallet to manage allowance, signing, or
239
343
  broadcasting. The simulation call itself is read-only and uses only the
240
344
  configured RPC transport.
241
345
 
242
- ## Optional Mayan Swift v2 bridge (introduced in 0.8.0)
346
+ ## Optional Mayan Swift v2 bridge
243
347
 
244
- The `0.8.0` API adds the Mayan Swift v2 client as an explicit standalone adapter
245
- for the reviewed
246
- issued EURC routes between Ethereum and Solana. It is not attached to the
247
- default `ErpcClient`; construct it separately when the external provider and
248
- its solver, relayer, and explorer dependencies are acceptable:
348
+ The published `0.8.1` API provides the Mayan Swift v2 client as an explicit
349
+ standalone adapter for the reviewed issued EURC routes between Ethereum and
350
+ Solana. It is not attached to the default `ErpcClient`; construct it separately
351
+ when the external provider and its solver, relayer, and explorer dependencies
352
+ are acceptable:
249
353
 
250
354
  ```ts
251
355
  import {
@@ -256,7 +360,6 @@ import {
256
360
  const mayan = createMayanSwiftV2BridgeClient({
257
361
  builderEndpoint: 'https://tx-builder.mayan.finance',
258
362
  explorerEndpoint: 'https://explorer-api.mayan.finance/v3',
259
- builderApiKey: 'provider-key',
260
363
  })
261
364
  const quotes = await mayan.quoteExactInput({
262
365
  sourceChainId: TOKEN_CHAIN_IDS.ethereumMainnet,
@@ -268,25 +371,19 @@ const quotes = await mayan.quoteExactInput({
268
371
  })
269
372
  ```
270
373
 
374
+ This keyless quote example reflects the provider's documented optional-key
375
+ policy. `buildUnsigned` has a separate SDK guard: supply a caller-managed
376
+ `builderApiKey` in a build client, or explicitly set
377
+ `allowUnauthenticatedBuild: true` to permit a keyless attempt. The opt-in does
378
+ not override provider authentication.
379
+
271
380
  The adapter posts the exact route request to Mayan's `/quote`, preserves the
272
381
  provider-signed quote text, and can build a structurally checked unsigned
273
382
  source transaction with `buildUnsigned`. It does not verify the provider
274
383
  signature locally or prove settlement, and it does not sign, approve, submit,
275
- refund, or broadcast transactions. For an EVM build, convert the returned
276
- chain-bound envelope before passing fields to a wallet API:
277
-
278
- ```ts
279
- const built = await mayan.buildUnsigned({
280
- quote: quotes[0],
281
- swapperAddress: '0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa',
282
- destinationAddress: '11111111111111111111111111111111',
283
- })
284
- if (built.transaction.kind === 'evm-unsigned-transaction') {
285
- const { chainId: _chainId, kind: _kind, ...walletTransaction } =
286
- built.transaction
287
- await wallet.sendTransaction(walletTransaction)
288
- }
289
- ```
384
+ refund, or broadcast transactions. Pass its typed unsigned envelope to an
385
+ external signer only after review; the signing and ERPC-only broadcast flow is
386
+ shown in the [TypeScript signing and broadcast guide](https://github.com/elsoul/erpc-sdk/blob/main/packages/typescript/docs/signing-and-broadcast.md).
290
387
 
291
388
  `builderEndpoint` and `explorerEndpoint` default to
292
389
  `https://tx-builder.mayan.finance` and `https://explorer-api.mayan.finance/v3`;
@@ -296,6 +393,67 @@ as unverified local settlement state. `builderApiKey` is a separate Mayan
296
393
  build-only key sent only to `/build`; quote and status calls do not receive it,
297
394
  and no eRPC credential is forwarded.
298
395
 
396
+ Mayan authentication has three separate layers:
397
+
398
+ | Layer | Behavior |
399
+ | --- | --- |
400
+ | Mayan documentation | The quote and transaction-builder documents describe the service key as optional. |
401
+ | SDK policy | `buildUnsigned` requires `builderApiKey` by default; `allowUnauthenticatedBuild: true` only permits the caller's keyless HTTP attempt. |
402
+ | Dated hosted observation | On 2026-09-17, four EURC/USDC quotes returned HTTP 200 without keys; default builds made no request, while explicit keyless `/build` attempts returned HTTP 401. This is bounded evidence, not a permanent provider requirement. |
403
+
404
+ The public `0.9.0` package supports the reviewed issued EURC directions and
405
+ native USDC direct routes. Native USDC uses Mayan's direct SWIFT route and does
406
+ not add Jupiter or another hosted source-swap dependency.
407
+
408
+ The `0.8.1` maintenance patch updated the Workers fetch invocation boundary;
409
+ it did not include the native USDC or local unsigned-builder paths that are
410
+ present in the public `0.9.0` package.
411
+
412
+ ### Local unsigned construction
413
+
414
+ The public `0.9.0` package exposes an explicit keyless construction path for
415
+ the reviewed EURC and native USDC directions. Pass a hosted normalized quote
416
+ and a fresh public 16-byte `orderNonce` to `prepareSourceSwap`, then pass its
417
+ plan to `buildLocalUnsigned`:
418
+
419
+ ```ts
420
+ const localClient = createMayanSwiftV2BridgeClient({
421
+ localBuild: {
422
+ sourceSwapEndpoint: 'https://price-api.mayan.finance/v3',
423
+ ethereumRpc: { httpUrl: 'https://your-ethereum-rpc.example' },
424
+ solanaRpc: { httpUrl: 'https://your-solana-rpc.example' },
425
+ },
426
+ })
427
+
428
+ const context = {
429
+ quote: quotes[0],
430
+ swapperAddress: '0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa',
431
+ destinationAddress: 'HQhyrHjgq5ftgsibxdUwLvDZ5HT4c9bNuBWJMmZvTd5b',
432
+ orderNonce: '0x00112233445566778899aabbccddeeff',
433
+ }
434
+ const sourceSwapPlan = await localClient.prepareSourceSwap(context)
435
+ const unsigned = await localClient.buildLocalUnsigned({
436
+ ...context,
437
+ sourceSwapPlan,
438
+ })
439
+ ```
440
+
441
+ `buildLocalUnsigned` requires the explicitly configured source RPC matching the
442
+ source chain. It performs bounded read-only identity and byte preflight, keeps
443
+ the original quote unchanged, and returns an unsigned EVM or Solana envelope.
444
+ Local source-swap requests are anonymous and use no Mayan builder key; direct
445
+ USDC uses `{ kind: 'none' }` and makes no source-swap request. There is no
446
+ fallback to hosted `/build`, and the local path never creates keys, approves,
447
+ signs, submits, broadcasts, or claims settlement. The caller owns wallet
448
+ custody and all signing and ERPC broadcast steps described in the
449
+ [TypeScript signing and broadcast guide](https://github.com/elsoul/erpc-sdk/blob/main/packages/typescript/docs/signing-and-broadcast.md).
450
+
451
+ These local methods and native USDC routes are included in the public `0.9.0`
452
+ baseline and the source/release cohort targets `0.9.1`. The bridge API remains
453
+ an explicit standalone EURC/native-USDC adapter with optional external provider
454
+ dependencies and configured source-RPC requirements, while normal swaps
455
+ continue to use configured RPC and local logic.
456
+
299
457
  ## Namespaces
300
458
 
301
459
  | Namespace | Purpose |
@@ -385,7 +543,7 @@ const monthlyUsage = await cloud.usage.getMonthlyApiKeyUsage()
385
543
 
386
544
  Catalog, credit, and resource results are projected onto documented public
387
545
  fields. Interactive login and operating-system keychain storage belong to
388
- `@elsoul/erpc-cli`.
546
+ the ERPC command-line client.
389
547
 
390
548
  ## Raw methods
391
549