@buildersgarden/siwa 0.0.13 → 0.0.15
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/dist/erc8128.d.ts +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.js +2 -1
- package/dist/nonce-store.d.ts +101 -0
- package/dist/nonce-store.js +135 -0
- package/dist/receipt.d.ts +1 -1
- package/dist/registry.d.ts +1 -1
- package/dist/{express.d.ts → server-side-wrappers/express.d.ts} +2 -2
- package/dist/{express.js → server-side-wrappers/express.js} +1 -1
- package/dist/server-side-wrappers/fastify.d.ts +58 -0
- package/dist/server-side-wrappers/fastify.js +111 -0
- package/dist/server-side-wrappers/hono.d.ts +54 -0
- package/dist/server-side-wrappers/hono.js +82 -0
- package/dist/{next.d.ts → server-side-wrappers/next.d.ts} +2 -2
- package/dist/{next.js → server-side-wrappers/next.js} +1 -1
- package/dist/signer/circle.d.ts +79 -0
- package/dist/signer/circle.js +120 -0
- package/dist/signer/index.d.ts +30 -0
- package/dist/signer/index.js +30 -0
- package/dist/signer/keyring-proxy.d.ts +27 -0
- package/dist/signer/keyring-proxy.js +77 -0
- package/dist/signer/local-account.d.ts +26 -0
- package/dist/signer/local-account.js +39 -0
- package/dist/signer/privy.d.ts +58 -0
- package/dist/signer/privy.js +74 -0
- package/dist/signer/types.d.ts +60 -0
- package/dist/signer/types.js +6 -0
- package/dist/signer/wallet-client.d.ts +36 -0
- package/dist/signer/wallet-client.js +57 -0
- package/dist/siwa.d.ts +5 -1
- package/dist/siwa.js +8 -0
- package/package.json +45 -8
- package/dist/signer.d.ts +0 -145
- package/dist/signer.js +0 -179
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* wallet-client.ts
|
|
3
|
+
*
|
|
4
|
+
* WalletClient signer implementation for browser wallets and embedded wallets.
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* Create a signer from a viem WalletClient.
|
|
8
|
+
*
|
|
9
|
+
* Use this for browser wallets (MetaMask, etc.), embedded wallets (Privy),
|
|
10
|
+
* WalletConnect, or any wallet that provides an EIP-1193 provider.
|
|
11
|
+
*
|
|
12
|
+
* @param client - A viem WalletClient
|
|
13
|
+
* @param account - Optional specific account address to use
|
|
14
|
+
* @returns A Signer that delegates to the WalletClient
|
|
15
|
+
*
|
|
16
|
+
* @example
|
|
17
|
+
* ```typescript
|
|
18
|
+
* // With Privy embedded wallet
|
|
19
|
+
* const provider = await privyWallet.getEthereumProvider();
|
|
20
|
+
* const walletClient = createWalletClient({
|
|
21
|
+
* chain: baseSepolia,
|
|
22
|
+
* transport: custom(provider),
|
|
23
|
+
* });
|
|
24
|
+
* const signer = createWalletClientSigner(walletClient);
|
|
25
|
+
*
|
|
26
|
+
* // With browser wallet (MetaMask)
|
|
27
|
+
* const walletClient = createWalletClient({
|
|
28
|
+
* chain: mainnet,
|
|
29
|
+
* transport: custom(window.ethereum),
|
|
30
|
+
* });
|
|
31
|
+
* const signer = createWalletClientSigner(walletClient);
|
|
32
|
+
* ```
|
|
33
|
+
*/
|
|
34
|
+
export function createWalletClientSigner(client, account) {
|
|
35
|
+
const resolveAccount = async () => {
|
|
36
|
+
if (account)
|
|
37
|
+
return account;
|
|
38
|
+
const addresses = await client.getAddresses();
|
|
39
|
+
if (!addresses || addresses.length === 0) {
|
|
40
|
+
throw new Error('No address found in wallet');
|
|
41
|
+
}
|
|
42
|
+
return addresses[0];
|
|
43
|
+
};
|
|
44
|
+
return {
|
|
45
|
+
async getAddress() {
|
|
46
|
+
return resolveAccount();
|
|
47
|
+
},
|
|
48
|
+
async signMessage(message) {
|
|
49
|
+
const addr = await resolveAccount();
|
|
50
|
+
return client.signMessage({ account: addr, message });
|
|
51
|
+
},
|
|
52
|
+
async signRawMessage(rawHex) {
|
|
53
|
+
const addr = await resolveAccount();
|
|
54
|
+
return client.signMessage({ account: addr, message: { raw: rawHex } });
|
|
55
|
+
},
|
|
56
|
+
};
|
|
57
|
+
}
|
package/dist/siwa.d.ts
CHANGED
|
@@ -9,7 +9,8 @@
|
|
|
9
9
|
*/
|
|
10
10
|
import { type PublicClient } from 'viem';
|
|
11
11
|
import { AgentProfile, ServiceType, TrustModel } from './registry.js';
|
|
12
|
-
import type { Signer, SignerType } from './signer.js';
|
|
12
|
+
import type { Signer, SignerType } from './signer/index.js';
|
|
13
|
+
import type { SIWANonceStore } from './nonce-store.js';
|
|
13
14
|
export declare enum SIWAErrorCode {
|
|
14
15
|
INVALID_SIGNATURE = "INVALID_SIGNATURE",
|
|
15
16
|
DOMAIN_MISMATCH = "DOMAIN_MISMATCH",
|
|
@@ -117,6 +118,7 @@ export interface SIWANonceParams {
|
|
|
117
118
|
export interface SIWANonceOptions {
|
|
118
119
|
expirationTTL?: number;
|
|
119
120
|
secret?: string;
|
|
121
|
+
nonceStore?: SIWANonceStore;
|
|
120
122
|
}
|
|
121
123
|
export type SIWANonceResult = {
|
|
122
124
|
status: 'nonce_issued';
|
|
@@ -203,6 +205,8 @@ export declare function signSIWAMessage(fields: SIWASignFields, signer: Signer):
|
|
|
203
205
|
export type NonceValidator = ((nonce: string) => boolean | Promise<boolean>) | {
|
|
204
206
|
nonceToken: string;
|
|
205
207
|
secret: string;
|
|
208
|
+
} | {
|
|
209
|
+
nonceStore: SIWANonceStore;
|
|
206
210
|
};
|
|
207
211
|
/**
|
|
208
212
|
* Verify a SIWA message + signature.
|
package/dist/siwa.js
CHANGED
|
@@ -272,6 +272,10 @@ export async function createSIWANonce(params, client, options) {
|
|
|
272
272
|
const now = new Date();
|
|
273
273
|
const expiresAt = new Date(now.getTime() + ttl);
|
|
274
274
|
const nonce = generateNonce();
|
|
275
|
+
// Track nonce in the store (for replay protection)
|
|
276
|
+
if (options?.nonceStore) {
|
|
277
|
+
await options.nonceStore.issue(nonce, ttl);
|
|
278
|
+
}
|
|
275
279
|
const result = {
|
|
276
280
|
status: 'nonce_issued',
|
|
277
281
|
nonce,
|
|
@@ -385,6 +389,10 @@ export async function verifySIWA(message, signature, expectedDomain, nonceValid,
|
|
|
385
389
|
if (typeof nonceValid === 'function') {
|
|
386
390
|
nonceOk = await nonceValid(fields.nonce);
|
|
387
391
|
}
|
|
392
|
+
else if ('nonceStore' in nonceValid) {
|
|
393
|
+
// Store-based validation: atomic consume (check + delete)
|
|
394
|
+
nonceOk = await nonceValid.nonceStore.consume(fields.nonce);
|
|
395
|
+
}
|
|
388
396
|
else {
|
|
389
397
|
// Stateless validation via HMAC token
|
|
390
398
|
const payload = verifyNonceToken(nonceValid.nonceToken, nonceValid.secret);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@buildersgarden/siwa",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.15",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"exports": {
|
|
6
6
|
".": {
|
|
@@ -8,8 +8,8 @@
|
|
|
8
8
|
"default": "./dist/index.js"
|
|
9
9
|
},
|
|
10
10
|
"./signer": {
|
|
11
|
-
"types": "./dist/signer.d.ts",
|
|
12
|
-
"default": "./dist/signer.js"
|
|
11
|
+
"types": "./dist/signer/index.d.ts",
|
|
12
|
+
"default": "./dist/signer/index.js"
|
|
13
13
|
},
|
|
14
14
|
"./keystore": {
|
|
15
15
|
"types": "./dist/keystore.d.ts",
|
|
@@ -43,13 +43,25 @@
|
|
|
43
43
|
"types": "./dist/erc8128.d.ts",
|
|
44
44
|
"default": "./dist/erc8128.js"
|
|
45
45
|
},
|
|
46
|
+
"./nonce-store": {
|
|
47
|
+
"types": "./dist/nonce-store.d.ts",
|
|
48
|
+
"default": "./dist/nonce-store.js"
|
|
49
|
+
},
|
|
46
50
|
"./next": {
|
|
47
|
-
"types": "./dist/next.d.ts",
|
|
48
|
-
"default": "./dist/next.js"
|
|
51
|
+
"types": "./dist/server-side-wrappers/next.d.ts",
|
|
52
|
+
"default": "./dist/server-side-wrappers/next.js"
|
|
49
53
|
},
|
|
50
54
|
"./express": {
|
|
51
|
-
"types": "./dist/express.d.ts",
|
|
52
|
-
"default": "./dist/express.js"
|
|
55
|
+
"types": "./dist/server-side-wrappers/express.d.ts",
|
|
56
|
+
"default": "./dist/server-side-wrappers/express.js"
|
|
57
|
+
},
|
|
58
|
+
"./hono": {
|
|
59
|
+
"types": "./dist/server-side-wrappers/hono.d.ts",
|
|
60
|
+
"default": "./dist/server-side-wrappers/hono.js"
|
|
61
|
+
},
|
|
62
|
+
"./fastify": {
|
|
63
|
+
"types": "./dist/server-side-wrappers/fastify.d.ts",
|
|
64
|
+
"default": "./dist/server-side-wrappers/fastify.js"
|
|
53
65
|
},
|
|
54
66
|
"./tba": {
|
|
55
67
|
"types": "./dist/tba.d.ts",
|
|
@@ -78,16 +90,41 @@
|
|
|
78
90
|
"viem": "^2.21.0"
|
|
79
91
|
},
|
|
80
92
|
"peerDependencies": {
|
|
81
|
-
"
|
|
93
|
+
"@circle-fin/developer-controlled-wallets": ">=6.0.0",
|
|
94
|
+
"@fastify/cors": ">=9.0.0",
|
|
95
|
+
"@privy-io/node": ">=1.0.0",
|
|
96
|
+
"express": "^4.0.0 || ^5.0.0",
|
|
97
|
+
"fastify": ">=4.0.0",
|
|
98
|
+
"hono": ">=4.0.0"
|
|
82
99
|
},
|
|
83
100
|
"peerDependenciesMeta": {
|
|
84
101
|
"express": {
|
|
85
102
|
"optional": true
|
|
103
|
+
},
|
|
104
|
+
"@circle-fin/developer-controlled-wallets": {
|
|
105
|
+
"optional": true
|
|
106
|
+
},
|
|
107
|
+
"@privy-io/node": {
|
|
108
|
+
"optional": true
|
|
109
|
+
},
|
|
110
|
+
"hono": {
|
|
111
|
+
"optional": true
|
|
112
|
+
},
|
|
113
|
+
"fastify": {
|
|
114
|
+
"optional": true
|
|
115
|
+
},
|
|
116
|
+
"@fastify/cors": {
|
|
117
|
+
"optional": true
|
|
86
118
|
}
|
|
87
119
|
},
|
|
88
120
|
"devDependencies": {
|
|
121
|
+
"@circle-fin/developer-controlled-wallets": "^10.1.0",
|
|
122
|
+
"@fastify/cors": "^10.1.0",
|
|
123
|
+
"@privy-io/node": "^0.8.0",
|
|
89
124
|
"@types/express": "^4.17.0",
|
|
90
125
|
"@types/node": "^25.2.1",
|
|
126
|
+
"fastify": "^5.7.4",
|
|
127
|
+
"hono": "^4.0.0",
|
|
91
128
|
"typescript": "^5.5.0"
|
|
92
129
|
}
|
|
93
130
|
}
|
package/dist/signer.d.ts
DELETED
|
@@ -1,145 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* signer.ts
|
|
3
|
-
*
|
|
4
|
-
* Wallet-agnostic signing abstraction for SIWA.
|
|
5
|
-
*
|
|
6
|
-
* This module provides a `Signer` interface that abstracts signing operations,
|
|
7
|
-
* allowing developers to use any wallet provider without changing the SDK.
|
|
8
|
-
*
|
|
9
|
-
* Available signer implementations:
|
|
10
|
-
* - createKeyringProxySigner(config) — Keyring proxy server (HMAC-authenticated)
|
|
11
|
-
* - createLocalAccountSigner(account) — viem LocalAccount (privateKeyToAccount)
|
|
12
|
-
* - createWalletClientSigner(client) — viem WalletClient (Privy, MetaMask, etc.)
|
|
13
|
-
*
|
|
14
|
-
* Usage:
|
|
15
|
-
* import { signSIWAMessage, createLocalAccountSigner } from '@buildersgarden/siwa';
|
|
16
|
-
* import { privateKeyToAccount } from 'viem/accounts';
|
|
17
|
-
*
|
|
18
|
-
* const account = privateKeyToAccount('0x...');
|
|
19
|
-
* const signer = createLocalAccountSigner(account);
|
|
20
|
-
* const { message, signature } = await signSIWAMessage(fields, signer);
|
|
21
|
-
*/
|
|
22
|
-
import type { Address, Hex, WalletClient } from 'viem';
|
|
23
|
-
import type { LocalAccount } from 'viem/accounts';
|
|
24
|
-
/**
|
|
25
|
-
* Signer type detected during SIWA sign-in.
|
|
26
|
-
*
|
|
27
|
-
* - `'eoa'` — Externally Owned Account (ECDSA key pair)
|
|
28
|
-
* - `'sca'` — Smart Contract Account (ERC-1271, e.g. Safe, TBA, Kernel)
|
|
29
|
-
*/
|
|
30
|
-
export type SignerType = 'eoa' | 'sca';
|
|
31
|
-
/**
|
|
32
|
-
* Core signer interface for message signing.
|
|
33
|
-
*
|
|
34
|
-
* Implement this interface to add support for new wallet providers.
|
|
35
|
-
*/
|
|
36
|
-
export interface Signer {
|
|
37
|
-
/** Get the signer's address */
|
|
38
|
-
getAddress(): Promise<Address>;
|
|
39
|
-
/** Sign a message (EIP-191 personal_sign) */
|
|
40
|
-
signMessage(message: string): Promise<Hex>;
|
|
41
|
-
/**
|
|
42
|
-
* Sign raw bytes (optional).
|
|
43
|
-
* Used by ERC-8128 for HTTP message signatures.
|
|
44
|
-
* If not implemented, signMessage will be used as fallback.
|
|
45
|
-
*/
|
|
46
|
-
signRawMessage?(rawHex: Hex): Promise<Hex>;
|
|
47
|
-
}
|
|
48
|
-
/**
|
|
49
|
-
* Extended signer with transaction signing capabilities.
|
|
50
|
-
*
|
|
51
|
-
* Required for onchain operations like agent registration.
|
|
52
|
-
*/
|
|
53
|
-
export interface TransactionSigner extends Signer {
|
|
54
|
-
/** Sign a transaction and return the serialized signed transaction */
|
|
55
|
-
signTransaction(tx: TransactionRequest): Promise<Hex>;
|
|
56
|
-
}
|
|
57
|
-
/** Transaction request compatible with viem */
|
|
58
|
-
export interface TransactionRequest {
|
|
59
|
-
to?: Address;
|
|
60
|
-
data?: Hex;
|
|
61
|
-
value?: bigint;
|
|
62
|
-
nonce?: number;
|
|
63
|
-
chainId?: number;
|
|
64
|
-
gas?: bigint;
|
|
65
|
-
maxFeePerGas?: bigint;
|
|
66
|
-
maxPriorityFeePerGas?: bigint;
|
|
67
|
-
gasPrice?: bigint;
|
|
68
|
-
type?: number | string;
|
|
69
|
-
accessList?: any[];
|
|
70
|
-
}
|
|
71
|
-
/** Configuration for the keyring proxy signer */
|
|
72
|
-
export interface KeyringProxyConfig {
|
|
73
|
-
/** URL of the keyring proxy server (or KEYRING_PROXY_URL env var) */
|
|
74
|
-
proxyUrl?: string;
|
|
75
|
-
/** HMAC shared secret (or KEYRING_PROXY_SECRET env var) */
|
|
76
|
-
proxySecret?: string;
|
|
77
|
-
}
|
|
78
|
-
/**
|
|
79
|
-
* Create a signer backed by the keyring proxy server.
|
|
80
|
-
*
|
|
81
|
-
* The private key is stored securely in the proxy server and never
|
|
82
|
-
* enters the calling process. All signing operations are performed
|
|
83
|
-
* via HMAC-authenticated HTTP requests.
|
|
84
|
-
*
|
|
85
|
-
* @param config - Proxy URL and secret (or use env vars)
|
|
86
|
-
* @returns A TransactionSigner that delegates to the keyring proxy
|
|
87
|
-
*
|
|
88
|
-
* @example
|
|
89
|
-
* ```typescript
|
|
90
|
-
* const signer = createKeyringProxySigner({
|
|
91
|
-
* proxyUrl: 'http://localhost:3100',
|
|
92
|
-
* proxySecret: 'my-secret',
|
|
93
|
-
* });
|
|
94
|
-
* const { message, signature } = await signSIWAMessage(fields, signer);
|
|
95
|
-
* ```
|
|
96
|
-
*/
|
|
97
|
-
export declare function createKeyringProxySigner(config?: KeyringProxyConfig): TransactionSigner;
|
|
98
|
-
/**
|
|
99
|
-
* Create a signer from a viem LocalAccount.
|
|
100
|
-
*
|
|
101
|
-
* Use this when you have direct access to a private key via
|
|
102
|
-
* viem's `privateKeyToAccount()` or similar.
|
|
103
|
-
*
|
|
104
|
-
* @param account - A viem LocalAccount (from privateKeyToAccount, mnemonicToAccount, etc.)
|
|
105
|
-
* @returns A TransactionSigner that signs using the local account
|
|
106
|
-
*
|
|
107
|
-
* @example
|
|
108
|
-
* ```typescript
|
|
109
|
-
* import { privateKeyToAccount } from 'viem/accounts';
|
|
110
|
-
*
|
|
111
|
-
* const account = privateKeyToAccount('0x...');
|
|
112
|
-
* const signer = createLocalAccountSigner(account);
|
|
113
|
-
* const { message, signature } = await signSIWAMessage(fields, signer);
|
|
114
|
-
* ```
|
|
115
|
-
*/
|
|
116
|
-
export declare function createLocalAccountSigner(account: LocalAccount): TransactionSigner;
|
|
117
|
-
/**
|
|
118
|
-
* Create a signer from a viem WalletClient.
|
|
119
|
-
*
|
|
120
|
-
* Use this for browser wallets (MetaMask, etc.), embedded wallets (Privy),
|
|
121
|
-
* WalletConnect, or any wallet that provides an EIP-1193 provider.
|
|
122
|
-
*
|
|
123
|
-
* @param client - A viem WalletClient
|
|
124
|
-
* @param account - Optional specific account address to use
|
|
125
|
-
* @returns A Signer that delegates to the WalletClient
|
|
126
|
-
*
|
|
127
|
-
* @example
|
|
128
|
-
* ```typescript
|
|
129
|
-
* // With Privy embedded wallet
|
|
130
|
-
* const provider = await privyWallet.getEthereumProvider();
|
|
131
|
-
* const walletClient = createWalletClient({
|
|
132
|
-
* chain: baseSepolia,
|
|
133
|
-
* transport: custom(provider),
|
|
134
|
-
* });
|
|
135
|
-
* const signer = createWalletClientSigner(walletClient);
|
|
136
|
-
*
|
|
137
|
-
* // With browser wallet (MetaMask)
|
|
138
|
-
* const walletClient = createWalletClient({
|
|
139
|
-
* chain: mainnet,
|
|
140
|
-
* transport: custom(window.ethereum),
|
|
141
|
-
* });
|
|
142
|
-
* const signer = createWalletClientSigner(walletClient);
|
|
143
|
-
* ```
|
|
144
|
-
*/
|
|
145
|
-
export declare function createWalletClientSigner(client: WalletClient, account?: Address): Signer;
|
package/dist/signer.js
DELETED
|
@@ -1,179 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* signer.ts
|
|
3
|
-
*
|
|
4
|
-
* Wallet-agnostic signing abstraction for SIWA.
|
|
5
|
-
*
|
|
6
|
-
* This module provides a `Signer` interface that abstracts signing operations,
|
|
7
|
-
* allowing developers to use any wallet provider without changing the SDK.
|
|
8
|
-
*
|
|
9
|
-
* Available signer implementations:
|
|
10
|
-
* - createKeyringProxySigner(config) — Keyring proxy server (HMAC-authenticated)
|
|
11
|
-
* - createLocalAccountSigner(account) — viem LocalAccount (privateKeyToAccount)
|
|
12
|
-
* - createWalletClientSigner(client) — viem WalletClient (Privy, MetaMask, etc.)
|
|
13
|
-
*
|
|
14
|
-
* Usage:
|
|
15
|
-
* import { signSIWAMessage, createLocalAccountSigner } from '@buildersgarden/siwa';
|
|
16
|
-
* import { privateKeyToAccount } from 'viem/accounts';
|
|
17
|
-
*
|
|
18
|
-
* const account = privateKeyToAccount('0x...');
|
|
19
|
-
* const signer = createLocalAccountSigner(account);
|
|
20
|
-
* const { message, signature } = await signSIWAMessage(fields, signer);
|
|
21
|
-
*/
|
|
22
|
-
import { computeHmac } from './proxy-auth.js';
|
|
23
|
-
// ─── Internal: Keyring Proxy Request ─────────────────────────────────
|
|
24
|
-
async function proxyRequest(config, endpoint, body = {}) {
|
|
25
|
-
const url = config.proxyUrl || process.env.KEYRING_PROXY_URL;
|
|
26
|
-
const secret = config.proxySecret || process.env.KEYRING_PROXY_SECRET;
|
|
27
|
-
if (!url) {
|
|
28
|
-
throw new Error('Keyring proxy requires KEYRING_PROXY_URL or config.proxyUrl');
|
|
29
|
-
}
|
|
30
|
-
if (!secret) {
|
|
31
|
-
throw new Error('Keyring proxy requires KEYRING_PROXY_SECRET or config.proxySecret');
|
|
32
|
-
}
|
|
33
|
-
const bodyStr = JSON.stringify(body, (_key, value) => typeof value === 'bigint' ? '0x' + value.toString(16) : value);
|
|
34
|
-
const hmacHeaders = computeHmac(secret, 'POST', endpoint, bodyStr);
|
|
35
|
-
const res = await fetch(`${url}${endpoint}`, {
|
|
36
|
-
method: 'POST',
|
|
37
|
-
headers: {
|
|
38
|
-
'Content-Type': 'application/json',
|
|
39
|
-
...hmacHeaders,
|
|
40
|
-
},
|
|
41
|
-
body: bodyStr,
|
|
42
|
-
});
|
|
43
|
-
if (!res.ok) {
|
|
44
|
-
const text = await res.text();
|
|
45
|
-
throw new Error(`Proxy ${endpoint} failed (${res.status}): ${text}`);
|
|
46
|
-
}
|
|
47
|
-
return res.json();
|
|
48
|
-
}
|
|
49
|
-
// ─── Keyring Proxy Signer ────────────────────────────────────────────
|
|
50
|
-
/**
|
|
51
|
-
* Create a signer backed by the keyring proxy server.
|
|
52
|
-
*
|
|
53
|
-
* The private key is stored securely in the proxy server and never
|
|
54
|
-
* enters the calling process. All signing operations are performed
|
|
55
|
-
* via HMAC-authenticated HTTP requests.
|
|
56
|
-
*
|
|
57
|
-
* @param config - Proxy URL and secret (or use env vars)
|
|
58
|
-
* @returns A TransactionSigner that delegates to the keyring proxy
|
|
59
|
-
*
|
|
60
|
-
* @example
|
|
61
|
-
* ```typescript
|
|
62
|
-
* const signer = createKeyringProxySigner({
|
|
63
|
-
* proxyUrl: 'http://localhost:3100',
|
|
64
|
-
* proxySecret: 'my-secret',
|
|
65
|
-
* });
|
|
66
|
-
* const { message, signature } = await signSIWAMessage(fields, signer);
|
|
67
|
-
* ```
|
|
68
|
-
*/
|
|
69
|
-
export function createKeyringProxySigner(config = {}) {
|
|
70
|
-
return {
|
|
71
|
-
async getAddress() {
|
|
72
|
-
const data = await proxyRequest(config, '/get-address');
|
|
73
|
-
return data.address;
|
|
74
|
-
},
|
|
75
|
-
async signMessage(message) {
|
|
76
|
-
const data = await proxyRequest(config, '/sign-message', { message });
|
|
77
|
-
return data.signature;
|
|
78
|
-
},
|
|
79
|
-
async signRawMessage(rawHex) {
|
|
80
|
-
const data = await proxyRequest(config, '/sign-message', {
|
|
81
|
-
message: rawHex,
|
|
82
|
-
raw: true,
|
|
83
|
-
});
|
|
84
|
-
return data.signature;
|
|
85
|
-
},
|
|
86
|
-
async signTransaction(tx) {
|
|
87
|
-
const data = await proxyRequest(config, '/sign-transaction', { tx });
|
|
88
|
-
return data.signedTx;
|
|
89
|
-
},
|
|
90
|
-
};
|
|
91
|
-
}
|
|
92
|
-
// ─── Local Account Signer ────────────────────────────────────────────
|
|
93
|
-
/**
|
|
94
|
-
* Create a signer from a viem LocalAccount.
|
|
95
|
-
*
|
|
96
|
-
* Use this when you have direct access to a private key via
|
|
97
|
-
* viem's `privateKeyToAccount()` or similar.
|
|
98
|
-
*
|
|
99
|
-
* @param account - A viem LocalAccount (from privateKeyToAccount, mnemonicToAccount, etc.)
|
|
100
|
-
* @returns A TransactionSigner that signs using the local account
|
|
101
|
-
*
|
|
102
|
-
* @example
|
|
103
|
-
* ```typescript
|
|
104
|
-
* import { privateKeyToAccount } from 'viem/accounts';
|
|
105
|
-
*
|
|
106
|
-
* const account = privateKeyToAccount('0x...');
|
|
107
|
-
* const signer = createLocalAccountSigner(account);
|
|
108
|
-
* const { message, signature } = await signSIWAMessage(fields, signer);
|
|
109
|
-
* ```
|
|
110
|
-
*/
|
|
111
|
-
export function createLocalAccountSigner(account) {
|
|
112
|
-
return {
|
|
113
|
-
async getAddress() {
|
|
114
|
-
return account.address;
|
|
115
|
-
},
|
|
116
|
-
async signMessage(message) {
|
|
117
|
-
return account.signMessage({ message });
|
|
118
|
-
},
|
|
119
|
-
async signRawMessage(rawHex) {
|
|
120
|
-
return account.signMessage({ message: { raw: rawHex } });
|
|
121
|
-
},
|
|
122
|
-
async signTransaction(tx) {
|
|
123
|
-
return account.signTransaction(tx);
|
|
124
|
-
},
|
|
125
|
-
};
|
|
126
|
-
}
|
|
127
|
-
// ─── WalletClient Signer ─────────────────────────────────────────────
|
|
128
|
-
/**
|
|
129
|
-
* Create a signer from a viem WalletClient.
|
|
130
|
-
*
|
|
131
|
-
* Use this for browser wallets (MetaMask, etc.), embedded wallets (Privy),
|
|
132
|
-
* WalletConnect, or any wallet that provides an EIP-1193 provider.
|
|
133
|
-
*
|
|
134
|
-
* @param client - A viem WalletClient
|
|
135
|
-
* @param account - Optional specific account address to use
|
|
136
|
-
* @returns A Signer that delegates to the WalletClient
|
|
137
|
-
*
|
|
138
|
-
* @example
|
|
139
|
-
* ```typescript
|
|
140
|
-
* // With Privy embedded wallet
|
|
141
|
-
* const provider = await privyWallet.getEthereumProvider();
|
|
142
|
-
* const walletClient = createWalletClient({
|
|
143
|
-
* chain: baseSepolia,
|
|
144
|
-
* transport: custom(provider),
|
|
145
|
-
* });
|
|
146
|
-
* const signer = createWalletClientSigner(walletClient);
|
|
147
|
-
*
|
|
148
|
-
* // With browser wallet (MetaMask)
|
|
149
|
-
* const walletClient = createWalletClient({
|
|
150
|
-
* chain: mainnet,
|
|
151
|
-
* transport: custom(window.ethereum),
|
|
152
|
-
* });
|
|
153
|
-
* const signer = createWalletClientSigner(walletClient);
|
|
154
|
-
* ```
|
|
155
|
-
*/
|
|
156
|
-
export function createWalletClientSigner(client, account) {
|
|
157
|
-
const resolveAccount = async () => {
|
|
158
|
-
if (account)
|
|
159
|
-
return account;
|
|
160
|
-
const addresses = await client.getAddresses();
|
|
161
|
-
if (!addresses || addresses.length === 0) {
|
|
162
|
-
throw new Error('No address found in wallet');
|
|
163
|
-
}
|
|
164
|
-
return addresses[0];
|
|
165
|
-
};
|
|
166
|
-
return {
|
|
167
|
-
async getAddress() {
|
|
168
|
-
return resolveAccount();
|
|
169
|
-
},
|
|
170
|
-
async signMessage(message) {
|
|
171
|
-
const addr = await resolveAccount();
|
|
172
|
-
return client.signMessage({ account: addr, message });
|
|
173
|
-
},
|
|
174
|
-
async signRawMessage(rawHex) {
|
|
175
|
-
const addr = await resolveAccount();
|
|
176
|
-
return client.signMessage({ account: addr, message: { raw: rawHex } });
|
|
177
|
-
},
|
|
178
|
-
};
|
|
179
|
-
}
|