@bounded-sh/server 0.0.41 → 0.0.44
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 +34 -4
- package/dist/auth/providers/evm-keypair-provider.d.ts +33 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +183 -12
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +184 -14
- package/dist/index.mjs.map +1 -1
- package/dist/wallet-client.d.ts +30 -6
- package/package.json +20 -15
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# @bounded-sh/server
|
|
2
2
|
|
|
3
|
-
Server SDK for
|
|
3
|
+
Server SDK for the Bounded API. It provides explicit, isolated Solana-keypair or EVM-private-key clients for backend applications; no signer is loaded from ambient process state.
|
|
4
4
|
|
|
5
5
|
## Installation
|
|
6
6
|
|
|
@@ -16,7 +16,7 @@ yarn add @bounded-sh/server
|
|
|
16
16
|
|
|
17
17
|
## Features
|
|
18
18
|
|
|
19
|
-
- Server-side authentication using Solana keypairs
|
|
19
|
+
- Server-side authentication using Solana keypairs or EVM private keys (SIWS/SIWE)
|
|
20
20
|
- In-memory session management (no cookies or local storage required)
|
|
21
21
|
- Support for all Tarobase data operations (get, getMany, set, query)
|
|
22
22
|
- Real-time subscriptions
|
|
@@ -86,6 +86,27 @@ const signature = await wallet.signMessage("Hello, world!");
|
|
|
86
86
|
// const signature = await wallet.signAndSubmitTransaction(transaction);
|
|
87
87
|
```
|
|
88
88
|
|
|
89
|
+
### EVM Keypair Client
|
|
90
|
+
|
|
91
|
+
EVM clients require a trusted RPC and deployed `BoundedRuntime` address. A write response can select only an explicitly configured chain/runtime pair, and the SDK verifies the returned `setDocuments` calldata against the requested app, paths, actions, and values before signing.
|
|
92
|
+
|
|
93
|
+
```typescript
|
|
94
|
+
import { init, createWalletClient } from '@bounded-sh/server';
|
|
95
|
+
|
|
96
|
+
await init({ appId: 'your-app-id', chain: 'base' });
|
|
97
|
+
|
|
98
|
+
const wallet = await createWalletClient({
|
|
99
|
+
evmPrivateKey: process.env.EVM_PRIVATE_KEY!,
|
|
100
|
+
chainId: 8453,
|
|
101
|
+
rpcUrl: process.env.BASE_RPC_URL!,
|
|
102
|
+
runtimeAddress: process.env.BOUNDED_RUNTIME_BASE!,
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
await wallet.set('todos/123', { text: 'Buy milk', completed: false });
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
For deliberate multi-chain use, provide `chains: { [chainId]: { rpcUrl, runtimeAddress } }`. There is no implicit RPC, runtime address, or chain switch.
|
|
109
|
+
|
|
89
110
|
### Subscriptions
|
|
90
111
|
|
|
91
112
|
```typescript
|
|
@@ -117,7 +138,16 @@ function getWebhookKeysUrl(): string | undefined;
|
|
|
117
138
|
### Authentication
|
|
118
139
|
|
|
119
140
|
```typescript
|
|
120
|
-
function createWalletClient(options:
|
|
141
|
+
function createWalletClient(options:
|
|
142
|
+
| { keypair: string }
|
|
143
|
+
| {
|
|
144
|
+
evmPrivateKey: string;
|
|
145
|
+
chainId: number;
|
|
146
|
+
rpcUrl?: string;
|
|
147
|
+
runtimeAddress?: string;
|
|
148
|
+
chains?: Record<string, { rpcUrl: string; runtimeAddress: string; name?: string }>;
|
|
149
|
+
}
|
|
150
|
+
): Promise<WalletClient>;
|
|
121
151
|
function getAuthProvider(): Promise<AuthProvider>; // always rejects; no process-global provider
|
|
122
152
|
function getIdToken(): Promise<string | null>; // always rejects; no process-global session
|
|
123
153
|
```
|
|
@@ -212,7 +242,7 @@ Please see the main repository for contribution guidelines.
|
|
|
212
242
|
|
|
213
243
|
This server-side SDK differs from the web SDK in several important ways:
|
|
214
244
|
|
|
215
|
-
1. **Authentication Method**: Uses Solana
|
|
245
|
+
1. **Authentication Method**: Uses explicit Solana or EVM keys instead of browser wallets
|
|
216
246
|
2. **Storage Strategy**: Uses in-memory storage instead of localStorage/sessionStorage
|
|
217
247
|
3. **Environment**: Optimized for Node.js/backend environments rather than browsers
|
|
218
248
|
4. **Session Management**: Does not rely on browser-specific APIs
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import type { AuthProvider, EVMTransaction, SolTransaction, TransactionResult, User, SetOptions } from '@bounded-sh/core';
|
|
2
|
+
import type { PublicKey, Transaction, VersionedTransaction } from '@solana/web3.js';
|
|
3
|
+
export interface EvmKeypairChainConfig {
|
|
4
|
+
chainId: number;
|
|
5
|
+
rpcUrl: string;
|
|
6
|
+
runtimeAddress: string;
|
|
7
|
+
name?: string;
|
|
8
|
+
}
|
|
9
|
+
export declare class EvmKeypairProvider implements AuthProvider {
|
|
10
|
+
readonly address: string;
|
|
11
|
+
readonly defaultChainId: number;
|
|
12
|
+
private readonly account;
|
|
13
|
+
private readonly chains;
|
|
14
|
+
constructor(privateKey: string, defaultChainId: number, chainConfigs: EvmKeypairChainConfig[]);
|
|
15
|
+
private user;
|
|
16
|
+
createBoundedSession(): Promise<{
|
|
17
|
+
address: string;
|
|
18
|
+
accessToken: string;
|
|
19
|
+
idToken: string;
|
|
20
|
+
refreshToken: string;
|
|
21
|
+
}>;
|
|
22
|
+
login(): Promise<User>;
|
|
23
|
+
restoreSession(): Promise<User>;
|
|
24
|
+
logout(): Promise<void>;
|
|
25
|
+
signMessage(message: string): Promise<string>;
|
|
26
|
+
signTransaction(_transaction: Transaction | VersionedTransaction): Promise<Transaction | VersionedTransaction>;
|
|
27
|
+
signAndSubmitTransaction(_transaction: Transaction | VersionedTransaction, _feePayer?: PublicKey): Promise<string>;
|
|
28
|
+
runTransaction(evm?: EVMTransaction, sol?: SolTransaction, options?: SetOptions): Promise<TransactionResult>;
|
|
29
|
+
getNativeMethods(): Promise<any>;
|
|
30
|
+
transactionPolicy(): {
|
|
31
|
+
runtimeAddresses: Record<string, string>;
|
|
32
|
+
};
|
|
33
|
+
}
|
package/dist/index.d.ts
CHANGED
|
@@ -8,5 +8,7 @@ export type { AuthProvider, ClientConfig, User, GetOptions, SearchOptions, SetOp
|
|
|
8
8
|
export { getIdToken } from './utils';
|
|
9
9
|
export { createWalletClient, WalletClient } from './wallet-client';
|
|
10
10
|
export type { CreateWalletClientOptions } from './wallet-client';
|
|
11
|
+
export { EvmKeypairProvider } from './auth/providers/evm-keypair-provider';
|
|
12
|
+
export type { EvmKeypairChainConfig } from './auth/providers/evm-keypair-provider';
|
|
11
13
|
export { verifyWebhook, clearWebhookKeyCache, clearWebhookReplayCache, WebhookVerificationError, DEFAULT_WEBHOOK_KEYS_URL, InMemoryReplayStore, } from './webhooks';
|
|
12
14
|
export type { WebhookPayload, WebhookPublicKey, WebhookOperation, VerifyWebhookOptions, WebhookHeaders, WebhookReplayStore, } from './webhooks';
|
package/dist/index.js
CHANGED
|
@@ -6,6 +6,8 @@ var bs58 = require('bs58');
|
|
|
6
6
|
var buffer = require('buffer');
|
|
7
7
|
var anchor = require('@coral-xyz/anchor');
|
|
8
8
|
var nacl = require('tweetnacl');
|
|
9
|
+
var viem = require('viem');
|
|
10
|
+
var accounts = require('viem/accounts');
|
|
9
11
|
|
|
10
12
|
function _interopNamespaceDefault(e) {
|
|
11
13
|
var n = Object.create(null);
|
|
@@ -677,6 +679,144 @@ class OffchainAuthProvider {
|
|
|
677
679
|
}
|
|
678
680
|
}
|
|
679
681
|
|
|
682
|
+
const NO_SOLANA = 'An EVM keypair client cannot sign Solana transactions.';
|
|
683
|
+
function normalizeChainConfig(input) {
|
|
684
|
+
var _a;
|
|
685
|
+
if (!Number.isSafeInteger(input.chainId) || input.chainId <= 0)
|
|
686
|
+
throw new Error('EVM chainId must be a positive safe integer');
|
|
687
|
+
let rpc;
|
|
688
|
+
try {
|
|
689
|
+
rpc = new URL(input.rpcUrl);
|
|
690
|
+
}
|
|
691
|
+
catch (_b) {
|
|
692
|
+
throw new Error(`EVM RPC URL is invalid for chain ${input.chainId}`);
|
|
693
|
+
}
|
|
694
|
+
if (rpc.protocol !== 'https:' && !(rpc.protocol === 'http:' && (rpc.hostname === 'localhost' || rpc.hostname === '127.0.0.1' || rpc.hostname === '[::1]'))) {
|
|
695
|
+
throw new Error(`EVM RPC URL must use HTTPS for chain ${input.chainId}`);
|
|
696
|
+
}
|
|
697
|
+
const runtimeAddress = core.normalizeEvmAddress(input.runtimeAddress);
|
|
698
|
+
if (!runtimeAddress)
|
|
699
|
+
throw new Error(`BoundedRuntime address is invalid for chain ${input.chainId}`);
|
|
700
|
+
return { chainId: input.chainId, rpcUrl: rpc.toString(), runtimeAddress, name: ((_a = input.name) === null || _a === void 0 ? void 0 : _a.trim()) || `EVM ${input.chainId}` };
|
|
701
|
+
}
|
|
702
|
+
function asViemChain(config) {
|
|
703
|
+
return viem.defineChain({
|
|
704
|
+
id: config.chainId,
|
|
705
|
+
name: config.name,
|
|
706
|
+
nativeCurrency: { name: 'Native token', symbol: 'NATIVE', decimals: 18 },
|
|
707
|
+
rpcUrls: { default: { http: [config.rpcUrl] } },
|
|
708
|
+
});
|
|
709
|
+
}
|
|
710
|
+
class EvmKeypairProvider {
|
|
711
|
+
constructor(privateKey, defaultChainId, chainConfigs) {
|
|
712
|
+
this.chains = new Map();
|
|
713
|
+
if (!/^0x[0-9a-fA-F]{64}$/.test(privateKey))
|
|
714
|
+
throw new Error('Invalid EVM private key: expected 0x followed by 64 hex characters.');
|
|
715
|
+
this.account = accounts.privateKeyToAccount(privateKey);
|
|
716
|
+
const address = core.normalizeEvmAddress(this.account.address);
|
|
717
|
+
if (!address)
|
|
718
|
+
throw new Error('Could not derive a valid EVM address from the private key');
|
|
719
|
+
this.address = address;
|
|
720
|
+
for (const raw of chainConfigs) {
|
|
721
|
+
const chain = normalizeChainConfig(raw);
|
|
722
|
+
if (this.chains.has(chain.chainId))
|
|
723
|
+
throw new Error(`Duplicate EVM chain configuration: ${chain.chainId}`);
|
|
724
|
+
this.chains.set(chain.chainId, chain);
|
|
725
|
+
}
|
|
726
|
+
if (!this.chains.has(defaultChainId))
|
|
727
|
+
throw new Error(`Default EVM chain ${defaultChainId} is not configured`);
|
|
728
|
+
this.defaultChainId = defaultChainId;
|
|
729
|
+
}
|
|
730
|
+
user() {
|
|
731
|
+
return { id: this.address, address: null, evmAddress: this.address, provider: this };
|
|
732
|
+
}
|
|
733
|
+
async createBoundedSession() {
|
|
734
|
+
var _a, _b, _c;
|
|
735
|
+
const nonce = await core.genAuthNonce();
|
|
736
|
+
const { appId } = await core.getConfig();
|
|
737
|
+
const message = core.genSiweMessage(this.address, nonce, appId, 'server', 'https://server/login', { chainId: this.defaultChainId });
|
|
738
|
+
const signature = await this.account.signMessage({ message });
|
|
739
|
+
const session = await core.createSessionWithSignature(this.address, message, signature, 'siwe');
|
|
740
|
+
return {
|
|
741
|
+
address: this.address,
|
|
742
|
+
accessToken: String((_a = session.accessToken) !== null && _a !== void 0 ? _a : ''),
|
|
743
|
+
idToken: String((_b = session.idToken) !== null && _b !== void 0 ? _b : ''),
|
|
744
|
+
refreshToken: String((_c = session.refreshToken) !== null && _c !== void 0 ? _c : ''),
|
|
745
|
+
};
|
|
746
|
+
}
|
|
747
|
+
async login() { return this.user(); }
|
|
748
|
+
async restoreSession() { return this.user(); }
|
|
749
|
+
async logout() { }
|
|
750
|
+
async signMessage(message) {
|
|
751
|
+
return this.account.signMessage({ message });
|
|
752
|
+
}
|
|
753
|
+
async signTransaction(_transaction) {
|
|
754
|
+
throw new Error(NO_SOLANA);
|
|
755
|
+
}
|
|
756
|
+
async signAndSubmitTransaction(_transaction, _feePayer) {
|
|
757
|
+
throw new Error(NO_SOLANA);
|
|
758
|
+
}
|
|
759
|
+
async runTransaction(evm, sol, options) {
|
|
760
|
+
var _a;
|
|
761
|
+
if (evm && sol)
|
|
762
|
+
throw new Error('A transaction cannot target EVM and Solana at the same time.');
|
|
763
|
+
if (!evm || !evm.chainId || !evm.to || !evm.data)
|
|
764
|
+
throw new Error('A complete EVM transaction is required');
|
|
765
|
+
if ((options === null || options === void 0 ? void 0 : options.shouldSubmitTx) === false)
|
|
766
|
+
throw new Error('EVM keypair writes submit atomically; shouldSubmitTx:false is unsupported.');
|
|
767
|
+
const config = this.chains.get(evm.chainId);
|
|
768
|
+
if (!config)
|
|
769
|
+
throw new Error(`EVM chain ${evm.chainId} is not configured for this wallet client`);
|
|
770
|
+
if (core.normalizeEvmAddress(evm.to) !== config.runtimeAddress)
|
|
771
|
+
throw new Error('EVM transaction target is not the configured BoundedRuntime');
|
|
772
|
+
if (evm.nonce !== undefined)
|
|
773
|
+
throw new Error('Server-supplied EVM nonces are not accepted');
|
|
774
|
+
try {
|
|
775
|
+
if (BigInt((_a = evm.value) !== null && _a !== void 0 ? _a : '0') !== BigInt(0))
|
|
776
|
+
throw new Error('BoundedRuntime.setDocuments cannot transfer native value');
|
|
777
|
+
}
|
|
778
|
+
catch (error) {
|
|
779
|
+
if (error instanceof Error && error.message.includes('cannot transfer'))
|
|
780
|
+
throw error;
|
|
781
|
+
throw new Error('Invalid EVM transaction value');
|
|
782
|
+
}
|
|
783
|
+
// The shared decoder accepts only canonical ordinary/attested document
|
|
784
|
+
// writes and rejects selector-prefix smuggling, aliases and trailing bytes.
|
|
785
|
+
core.assertCanonicalBoundedRuntimeWriteCalldata(evm.data);
|
|
786
|
+
// A server key can safely switch between explicitly configured chains: each
|
|
787
|
+
// tx selects its own immutable viem client/RPC/runtime tuple. No untrusted
|
|
788
|
+
// server response may introduce a new chain or RPC endpoint.
|
|
789
|
+
const chain = asViemChain(config);
|
|
790
|
+
const transport = viem.http(config.rpcUrl);
|
|
791
|
+
const wallet = viem.createWalletClient({ account: this.account, chain, transport });
|
|
792
|
+
const publicClient = viem.createPublicClient({ chain, transport });
|
|
793
|
+
const hash = await wallet.sendTransaction({
|
|
794
|
+
account: this.account,
|
|
795
|
+
chain,
|
|
796
|
+
to: config.runtimeAddress,
|
|
797
|
+
data: evm.data,
|
|
798
|
+
value: BigInt(0),
|
|
799
|
+
});
|
|
800
|
+
const receipt = await publicClient.waitForTransactionReceipt({ hash });
|
|
801
|
+
if (receipt.status !== 'success')
|
|
802
|
+
throw new Error(`EVM transaction ${hash} reverted on-chain`);
|
|
803
|
+
if (receipt.blockNumber > BigInt(Number.MAX_SAFE_INTEGER))
|
|
804
|
+
throw new Error('EVM receipt block number exceeds the SDK safe-integer range');
|
|
805
|
+
return {
|
|
806
|
+
transactionSignature: hash,
|
|
807
|
+
blockNumber: Number(receipt.blockNumber),
|
|
808
|
+
gasUsed: receipt.gasUsed.toString(),
|
|
809
|
+
data: receipt,
|
|
810
|
+
};
|
|
811
|
+
}
|
|
812
|
+
async getNativeMethods() { return this.account; }
|
|
813
|
+
transactionPolicy() {
|
|
814
|
+
return {
|
|
815
|
+
runtimeAddresses: Object.fromEntries([...this.chains].map(([id, config]) => [String(id), config.runtimeAddress])),
|
|
816
|
+
};
|
|
817
|
+
}
|
|
818
|
+
}
|
|
819
|
+
|
|
680
820
|
var __rest = (undefined && undefined.__rest) || function (s, e) {
|
|
681
821
|
var t = {};
|
|
682
822
|
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
|
|
@@ -728,10 +868,11 @@ function jwtExpiringSoon(token) {
|
|
|
728
868
|
/* WalletClient */
|
|
729
869
|
/* ------------------------------------------------------------------ */
|
|
730
870
|
class WalletClient {
|
|
731
|
-
constructor(provider, sessionManager, address) {
|
|
871
|
+
constructor(provider, sessionManager, address, evmTransactionPolicy) {
|
|
732
872
|
this.provider = provider;
|
|
733
873
|
this.sessionManager = sessionManager;
|
|
734
874
|
this.address = address;
|
|
875
|
+
this.evmTransactionPolicy = evmTransactionPolicy;
|
|
735
876
|
this.live = {
|
|
736
877
|
intent: (roomPath, intent, opts = {}) => core.live.intent(roomPath, intent, this.mergeLiveIntentOptions(opts)),
|
|
737
878
|
status: (roomPath, opts = {}) => core.live.status(roomPath, Object.assign(Object.assign({}, opts), { headers: this.sanitizeHeaders(opts.headers) })),
|
|
@@ -759,9 +900,7 @@ class WalletClient {
|
|
|
759
900
|
}
|
|
760
901
|
/* ---- Auth override helpers ---- */
|
|
761
902
|
buildOverrides() {
|
|
762
|
-
return {
|
|
763
|
-
authProvider: this.provider,
|
|
764
|
-
_getAuthHeaders: async () => {
|
|
903
|
+
return Object.assign({ authProvider: this.provider, _getAuthHeaders: async () => {
|
|
765
904
|
let s = await this.sessionManager.getSession();
|
|
766
905
|
// Keypair-backed session: if the cached token is expired/near-expiry,
|
|
767
906
|
// re-sign for a fresh one (we always hold the key). Keeps long-lived WS
|
|
@@ -772,12 +911,9 @@ class WalletClient {
|
|
|
772
911
|
s = await this.sessionManager.getSession();
|
|
773
912
|
}
|
|
774
913
|
return { Authorization: `Bearer ${s.idToken}` };
|
|
775
|
-
},
|
|
776
|
-
_clearAuth: async () => {
|
|
914
|
+
}, _clearAuth: async () => {
|
|
777
915
|
this.sessionManager.clearSession();
|
|
778
|
-
},
|
|
779
|
-
_walletAddress: this.address,
|
|
780
|
-
};
|
|
916
|
+
}, _walletAddress: this.address }, (this.evmTransactionPolicy ? { _evmTransactionPolicy: this.evmTransactionPolicy } : {}));
|
|
781
917
|
}
|
|
782
918
|
/** Strip Authorization from caller headers to prevent overriding wallet token */
|
|
783
919
|
sanitizeHeaders(headers) {
|
|
@@ -789,7 +925,7 @@ class WalletClient {
|
|
|
789
925
|
mergeSetOverrides(opts) {
|
|
790
926
|
var _a;
|
|
791
927
|
const ovr = this.buildOverrides();
|
|
792
|
-
return Object.assign(Object.assign({}, opts), { _overrides: Object.assign(Object.assign({}, opts === null || opts === void 0 ? void 0 : opts._overrides), { headers: this.sanitizeHeaders((_a = opts === null || opts === void 0 ? void 0 : opts._overrides) === null || _a === void 0 ? void 0 : _a.headers), authProvider: ovr.authProvider, _getAuthHeaders: ovr._getAuthHeaders, _clearAuth: ovr._clearAuth }) });
|
|
928
|
+
return Object.assign(Object.assign({}, opts), { _overrides: Object.assign(Object.assign({}, opts === null || opts === void 0 ? void 0 : opts._overrides), { headers: this.sanitizeHeaders((_a = opts === null || opts === void 0 ? void 0 : opts._overrides) === null || _a === void 0 ? void 0 : _a.headers), authProvider: ovr.authProvider, _getAuthHeaders: ovr._getAuthHeaders, _clearAuth: ovr._clearAuth, _evmTransactionPolicy: ovr._evmTransactionPolicy }) });
|
|
793
929
|
}
|
|
794
930
|
mergeReadOverrides(existing) {
|
|
795
931
|
const ovr = this.buildOverrides();
|
|
@@ -883,19 +1019,53 @@ class WalletClient {
|
|
|
883
1019
|
}
|
|
884
1020
|
}
|
|
885
1021
|
/**
|
|
886
|
-
* Create a self-contained wallet client bound to
|
|
1022
|
+
* Create a self-contained wallet client bound to one Solana or EVM keypair.
|
|
887
1023
|
* Each client has its own auth session — no global state is mutated.
|
|
888
1024
|
*
|
|
889
1025
|
* @example
|
|
890
1026
|
* ```ts
|
|
891
1027
|
* const vault = await createWalletClient({ keypair: process.env.VAULT_KEY });
|
|
892
1028
|
* await vault.set('markets/123', data);
|
|
1029
|
+
*
|
|
1030
|
+
* const evmVault = await createWalletClient({
|
|
1031
|
+
* evmPrivateKey: process.env.EVM_PRIVATE_KEY,
|
|
1032
|
+
* chainId: 8453,
|
|
1033
|
+
* rpcUrl: process.env.BASE_RPC_URL,
|
|
1034
|
+
* runtimeAddress: process.env.BOUNDED_RUNTIME,
|
|
1035
|
+
* });
|
|
893
1036
|
* ```
|
|
894
1037
|
*/
|
|
895
1038
|
async function createWalletClient(opts) {
|
|
896
1039
|
var _a;
|
|
897
|
-
const kp = parseKeypair(opts.keypair);
|
|
898
1040
|
const config = await core.getConfig();
|
|
1041
|
+
if ('evmPrivateKey' in opts && typeof opts.evmPrivateKey === 'string') {
|
|
1042
|
+
const chainConfigs = [];
|
|
1043
|
+
if (opts.chains) {
|
|
1044
|
+
for (const [rawId, chain] of Object.entries(opts.chains)) {
|
|
1045
|
+
const chainId = Number(rawId);
|
|
1046
|
+
if (!Number.isSafeInteger(chainId) || chainId <= 0)
|
|
1047
|
+
throw new Error(`Invalid EVM chain id in chains map: ${rawId}`);
|
|
1048
|
+
chainConfigs.push({ chainId, rpcUrl: chain.rpcUrl, runtimeAddress: chain.runtimeAddress, name: chain.name });
|
|
1049
|
+
}
|
|
1050
|
+
}
|
|
1051
|
+
if (opts.rpcUrl !== undefined || opts.runtimeAddress !== undefined) {
|
|
1052
|
+
if (!opts.rpcUrl || !opts.runtimeAddress)
|
|
1053
|
+
throw new Error('Single-chain EVM clients require both rpcUrl and runtimeAddress');
|
|
1054
|
+
if (chainConfigs.some((chain) => chain.chainId === opts.chainId))
|
|
1055
|
+
throw new Error(`EVM chain ${opts.chainId} is configured twice`);
|
|
1056
|
+
chainConfigs.push({ chainId: opts.chainId, rpcUrl: opts.rpcUrl, runtimeAddress: opts.runtimeAddress });
|
|
1057
|
+
}
|
|
1058
|
+
if (chainConfigs.length === 0)
|
|
1059
|
+
throw new Error('EVM wallet clients require an explicit RPC URL and BoundedRuntime address');
|
|
1060
|
+
const provider = new EvmKeypairProvider(opts.evmPrivateKey, opts.chainId, chainConfigs);
|
|
1061
|
+
const sessionManager = core.ServerSessionManager.forSessionFactory(() => provider.createBoundedSession());
|
|
1062
|
+
await sessionManager.getSession();
|
|
1063
|
+
return new WalletClient(provider, sessionManager, provider.address, provider.transactionPolicy());
|
|
1064
|
+
}
|
|
1065
|
+
if (!('keypair' in opts) || typeof opts.keypair !== 'string') {
|
|
1066
|
+
throw new Error('createWalletClient requires exactly one of keypair or evmPrivateKey');
|
|
1067
|
+
}
|
|
1068
|
+
const kp = parseKeypair(opts.keypair);
|
|
899
1069
|
let provider = new SolanaKeypairProvider((_a = config.rpcUrl) !== null && _a !== void 0 ? _a : null, kp);
|
|
900
1070
|
if (config.chain === 'offchain') {
|
|
901
1071
|
provider = new OffchainAuthProvider(provider);
|
|
@@ -1193,6 +1363,7 @@ Object.defineProperty(exports, "getWebhookKeysUrl", {
|
|
|
1193
1363
|
get: function () { return core.getWebhookKeysUrl; }
|
|
1194
1364
|
});
|
|
1195
1365
|
exports.DEFAULT_WEBHOOK_KEYS_URL = DEFAULT_WEBHOOK_KEYS_URL;
|
|
1366
|
+
exports.EvmKeypairProvider = EvmKeypairProvider;
|
|
1196
1367
|
exports.InMemoryReplayStore = InMemoryReplayStore;
|
|
1197
1368
|
exports.WalletClient = WalletClient;
|
|
1198
1369
|
exports.WebhookVerificationError = WebhookVerificationError;
|