@elsoul/erpc-sdk 0.8.1 → 0.9.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 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,27 @@
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 is a `0.9.0` source candidate. The currently
11
+ published `0.8.1` npm package does not include it; use the reviewed `0.9.0`
12
+ candidate artifact or this source checkout until that version is published.
8
13
 
9
14
  ## Install
10
15
 
11
16
  ```bash
12
- npm install @elsoul/erpc-sdk
13
- # or: pnpm add @elsoul/erpc-sdk
17
+ # Once 0.9.0 is published:
18
+ npm install @elsoul/erpc-sdk@0.9.0
19
+ # or: pnpm add @elsoul/erpc-sdk@0.9.0
20
+ # Before publication, use the reviewed candidate tarball or this source checkout.
14
21
  ```
15
22
 
16
- The package has no runtime dependencies and includes ESM, CommonJS, and
17
- TypeScript declarations. Node.js 20 or later is supported.
23
+ The package includes its ESM, CommonJS, and TypeScript declarations. Node.js 20
24
+ or later is supported.
18
25
 
19
26
  ## Quick start
20
27
 
@@ -29,8 +36,9 @@ const erpc = createErpcClient({ apiKey })
29
36
  const slot = await erpc.solana.rpc.getSlot().send()
30
37
  const chainId = await erpc.ethereum.rpc.eth_chainId().send()
31
38
  const avalancheChainId = await erpc.avalanche.rpc.eth_chainId().send()
39
+ const baseChainId = await erpc.base.rpc.eth_chainId().send()
32
40
 
33
- console.log({ slot, chainId, avalancheChainId })
41
+ console.log({ slot, chainId, avalancheChainId, baseChainId })
34
42
  erpc.close()
35
43
  ```
36
44
 
@@ -62,6 +70,10 @@ const chainId = await erpc.ethereum.rpc.eth_chainId().send()
62
70
  The configured HTTP URL is treated as the final target. Redirect responses are
63
71
  returned as HTTP errors, and no redirected request is made.
64
72
 
73
+ For direct HTTP transports, the public `endpoint` property is diagnostic
74
+ metadata containing only the origin/root. The private request target still
75
+ preserves the configured path, query order, and percent encoding exactly.
76
+
65
77
  Direct HTTP requests use `credentials: 'omit'`, so ambient browser cookies and
66
78
  authentication are not sent implicitly. Add authentication explicitly through
67
79
  the endpoint's scoped headers when needed.
@@ -84,12 +96,108 @@ const erpc = createErpcClient({
84
96
  })
85
97
  ```
86
98
 
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
99
+ `solanaRpc`, `ethereumRpc`, `avalancheCRpc`, and `baseRpc` select direct Solana,
100
+ Ethereum, Avalanche C-Chain, and Base JSON-RPC transports. `baseRpc` accepts
101
+ only an HTTP URL and scoped HTTP headers because the Base facade has no
102
+ WebSocket or subscription surface. Without an API key, non-overridden chains
103
+ and ERPC REST, native, and index services fail locally. The
90
104
  `RpcEndpointConfig.headers` field applies to direct HTTP requests only; those
91
105
  headers are never sent on WSS connections.
92
106
 
107
+ ## Base read-only RPC (`0.9.0` candidate)
108
+
109
+ The `0.9.0` candidate API-key client uses `https://base.erpc.global/` at the
110
+ root JSON-RPC path.
111
+ The first check for a Base connection should be `eth_chainId()` and must return
112
+ `0x2105` (Base mainnet). The following uses the catalog's Base EURC record and
113
+ formats the raw response with integer arithmetic:
114
+
115
+ ```ts
116
+ import {
117
+ createErpcClient,
118
+ getTokenDeployment,
119
+ tokens,
120
+ } from '@elsoul/erpc-sdk'
121
+
122
+ const erpc = createErpcClient({ apiKey: process.env.ERPC_API_KEY! })
123
+ const wallet = '0x7A5837f5bB52C53e08fcFf214c2Cd11daa8EF9EE'
124
+ const eurc = getTokenDeployment(tokens.base.EURC)
125
+ if (eurc?.address === null || eurc === undefined) {
126
+ throw new Error('Base EURC is missing from the catalog')
127
+ }
128
+
129
+ const chainId = await erpc.base.rpc.eth_chainId().send()
130
+ if (chainId !== '0x2105') throw new Error(`Unexpected Base chain: ${chainId}`)
131
+
132
+ const nativeWei = BigInt(
133
+ await erpc.base.rpc.eth_getBalance(wallet, '0x3167564').send(),
134
+ )
135
+ const calldata = `0x70a08231${wallet.slice(2).padStart(64, '0')}`
136
+ const eurcAtomic = BigInt(
137
+ await erpc.base.rpc.eth_call(
138
+ { to: eurc.address, data: calldata },
139
+ '0x3167564',
140
+ ).send(),
141
+ )
142
+
143
+ const formatUnits = (value: bigint, decimals: number): string => {
144
+ const scale = 10n ** BigInt(decimals)
145
+ const whole = value / scale
146
+ const fraction = (value % scale).toString().padStart(decimals, '0').replace(/0+$/u, '')
147
+ return fraction.length === 0 ? whole.toString() : `${whole}.${fraction}`
148
+ }
149
+
150
+ const eurcDisplay = formatUnits(eurcAtomic, eurc.decimals)
151
+ // Pinned review read: eurcAtomic === 5_500_000n and eurcDisplay === '5.5'.
152
+ console.log({ chainId, nativeWei, eurcAtomic, eurcDecimals: eurc.decimals, eurcDisplay })
153
+ erpc.close()
154
+ ```
155
+
156
+ For a keyless caller-owned endpoint, use `baseRpc`. Its URL path and query are
157
+ sent exactly as configured, and its headers stay scoped to Base:
158
+
159
+ ```ts
160
+ const erpc = createErpcClient({
161
+ baseRpc: {
162
+ httpUrl: process.env.ERPC_BASE_RPC_URL!,
163
+ headers: { authorization: 'Bearer node-token' },
164
+ },
165
+ })
166
+
167
+ const chainId = await erpc.base.rpc.eth_chainId().send()
168
+ ```
169
+
170
+ The Base client exposes only `rpc`; the inner read-only facade has exactly
171
+ `endpoint`, `eth_chainId`, `eth_getBalance`, and `eth_call`. It does not provide
172
+ raw, batch, subscription, signing, or broadcast methods. `baseEndpoint` forwards
173
+ the main API key and global headers, so use it only for a caller-trusted,
174
+ eRPC-compatible host. `baseRpc` takes precedence over it and over global
175
+ headers; it sends only credentials explicitly scoped inside the direct override.
176
+
177
+ ## Wallets, signing, and broadcast
178
+
179
+ `ErpcClient` has no wallet, private-key, or signer configuration. Swap
180
+ preparation and Mayan `buildUnsigned` return unsigned transaction envelopes;
181
+ the caller owns account selection, allowance changes, nonce and fee policy,
182
+ transaction review, key custody, signing, broadcast, and confirmation. The
183
+ `from`, `sender`, `swapperAddress`, and `feePayer` fields are public identity
184
+ checks, not signing authority. A pending RPC request's `.send()` performs the
185
+ network request and does not sign bytes.
186
+
187
+ | Concern | Owner |
188
+ | --- | --- |
189
+ | Key or hardware-wallet custody | Caller application or wallet provider |
190
+ | Transaction and allowance review | Caller application and user |
191
+ | Cryptographic signing | External wallet or signer |
192
+ | Signed-byte broadcast | Caller-selected ERPC RPC method |
193
+ | Confirmation and settlement interpretation | Caller application |
194
+
195
+ See the [shared wallet and signing model](https://github.com/elsoul/erpc-sdk/blob/main/README.md#wallets-and-signing)
196
+ and the [TypeScript signing and broadcast guide](https://github.com/elsoul/erpc-sdk/blob/main/packages/typescript/docs/signing-and-broadcast.md)
197
+ for initialized ethers 6 and `@solana/web3.js` 1.x examples. The guide keeps
198
+ the selected RPC URL identical for network checks and sends signed bytes only
199
+ through ERPC.
200
+
93
201
  ## Offline token catalog
94
202
 
95
203
  The token catalog is bundled with the package, so lookups do not need an
@@ -225,27 +333,22 @@ const simulation = await erpc.swap.simulateExactInputSwap(request)
225
333
  Preparation performs a fresh quote, validates the reviewed router and wrapped
226
334
  native deployment, and returns an immutable chain-bound unsigned transaction
227
335
  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
- ```
336
+ fields. Review `prepared.transaction`, then pass the typed envelope to an
337
+ external signer and the ERPC-only broadcast helper in the
338
+ [TypeScript signing and broadcast guide](https://github.com/elsoul/erpc-sdk/blob/main/packages/typescript/docs/signing-and-broadcast.md).
236
339
 
237
340
  Use the `simulation` result to inspect the canonical allowance and router
238
341
  amounts before asking the caller's wallet to manage allowance, signing, or
239
342
  broadcasting. The simulation call itself is read-only and uses only the
240
343
  configured RPC transport.
241
344
 
242
- ## Optional Mayan Swift v2 bridge (introduced in 0.8.0)
345
+ ## Optional Mayan Swift v2 bridge
243
346
 
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:
347
+ The published `0.8.1` API provides the Mayan Swift v2 client as an explicit
348
+ standalone adapter for the reviewed issued EURC routes between Ethereum and
349
+ Solana. It is not attached to the default `ErpcClient`; construct it separately
350
+ when the external provider and its solver, relayer, and explorer dependencies
351
+ are acceptable:
249
352
 
250
353
  ```ts
251
354
  import {
@@ -256,7 +359,6 @@ import {
256
359
  const mayan = createMayanSwiftV2BridgeClient({
257
360
  builderEndpoint: 'https://tx-builder.mayan.finance',
258
361
  explorerEndpoint: 'https://explorer-api.mayan.finance/v3',
259
- builderApiKey: 'provider-key',
260
362
  })
261
363
  const quotes = await mayan.quoteExactInput({
262
364
  sourceChainId: TOKEN_CHAIN_IDS.ethereumMainnet,
@@ -268,25 +370,19 @@ const quotes = await mayan.quoteExactInput({
268
370
  })
269
371
  ```
270
372
 
373
+ This keyless quote example reflects the provider's documented optional-key
374
+ policy. `buildUnsigned` has a separate SDK guard: supply a caller-managed
375
+ `builderApiKey` in a build client, or explicitly set
376
+ `allowUnauthenticatedBuild: true` to permit a keyless attempt. The opt-in does
377
+ not override provider authentication.
378
+
271
379
  The adapter posts the exact route request to Mayan's `/quote`, preserves the
272
380
  provider-signed quote text, and can build a structurally checked unsigned
273
381
  source transaction with `buildUnsigned`. It does not verify the provider
274
382
  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
- ```
383
+ refund, or broadcast transactions. Pass its typed unsigned envelope to an
384
+ external signer only after review; the signing and ERPC-only broadcast flow is
385
+ shown in the [TypeScript signing and broadcast guide](https://github.com/elsoul/erpc-sdk/blob/main/packages/typescript/docs/signing-and-broadcast.md).
290
386
 
291
387
  `builderEndpoint` and `explorerEndpoint` default to
292
388
  `https://tx-builder.mayan.finance` and `https://explorer-api.mayan.finance/v3`;
@@ -296,6 +392,70 @@ as unverified local settlement state. `builderApiKey` is a separate Mayan
296
392
  build-only key sent only to `/build`; quote and status calls do not receive it,
297
393
  and no eRPC credential is forwarded.
298
394
 
395
+ Mayan authentication has three separate layers:
396
+
397
+ | Layer | Behavior |
398
+ | --- | --- |
399
+ | Mayan documentation | The quote and transaction-builder documents describe the service key as optional. |
400
+ | SDK policy | `buildUnsigned` requires `builderApiKey` by default; `allowUnauthenticatedBuild: true` only permits the caller's keyless HTTP attempt. |
401
+ | 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. |
402
+
403
+ The published `0.8.1` package supports the reviewed issued EURC directions.
404
+ Native USDC direct routes are a source-tree addition and remain unreleased;
405
+ they are not part of the published `0.8.1` package.
406
+
407
+ The source tree also contains an unreleased native USDC addition for the same
408
+ Ethereum/Solana directions. It uses Mayan's direct SWIFT route and does not add
409
+ Jupiter or another hosted source-swap dependency. The addition is not included
410
+ in the published `0.8.1` package; its package version and release publication
411
+ remain future work.
412
+
413
+ The `0.8.1` maintenance patch updates the Workers fetch invocation boundary;
414
+ it does not include the new native USDC or local unsigned-builder paths.
415
+
416
+ ### Local unsigned construction
417
+
418
+ The source tree also exposes an explicit keyless construction path for the
419
+ reviewed EURC and native USDC directions. Pass a hosted normalized quote and a
420
+ fresh public 16-byte `orderNonce` to `prepareSourceSwap`, then pass its plan to
421
+ `buildLocalUnsigned`:
422
+
423
+ ```ts
424
+ const localClient = createMayanSwiftV2BridgeClient({
425
+ localBuild: {
426
+ sourceSwapEndpoint: 'https://price-api.mayan.finance/v3',
427
+ ethereumRpc: { httpUrl: 'https://your-ethereum-rpc.example' },
428
+ solanaRpc: { httpUrl: 'https://your-solana-rpc.example' },
429
+ },
430
+ })
431
+
432
+ const context = {
433
+ quote: quotes[0],
434
+ swapperAddress: '0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa',
435
+ destinationAddress: 'HQhyrHjgq5ftgsibxdUwLvDZ5HT4c9bNuBWJMmZvTd5b',
436
+ orderNonce: '0x00112233445566778899aabbccddeeff',
437
+ }
438
+ const sourceSwapPlan = await localClient.prepareSourceSwap(context)
439
+ const unsigned = await localClient.buildLocalUnsigned({
440
+ ...context,
441
+ sourceSwapPlan,
442
+ })
443
+ ```
444
+
445
+ `buildLocalUnsigned` requires the explicitly configured source RPC matching the
446
+ source chain. It performs bounded read-only identity and byte preflight, keeps
447
+ the original quote unchanged, and returns an unsigned EVM or Solana envelope.
448
+ Local source-swap requests are anonymous and use no Mayan builder key; direct
449
+ USDC uses `{ kind: 'none' }` and makes no source-swap request. There is no
450
+ fallback to hosted `/build`, and the local path never creates keys, approves,
451
+ signs, submits, broadcasts, or claims settlement. The caller owns wallet
452
+ custody and all signing and ERPC broadcast steps described in the
453
+ [TypeScript signing and broadcast guide](https://github.com/elsoul/erpc-sdk/blob/main/packages/typescript/docs/signing-and-broadcast.md).
454
+
455
+ These local methods and native USDC routes are source-tree additions. They are
456
+ not part of the published TypeScript `0.8.1` package; the published bridge API
457
+ remains the hosted EURC adapter described above.
458
+
299
459
  ## Namespaces
300
460
 
301
461
  | Namespace | Purpose |