@buildersgarden/siwa 0.0.14 → 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 +1 -1
- package/dist/index.js +1 -1
- 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 +1 -1
- package/package.json +41 -8
- package/dist/signer.d.ts +0 -145
- package/dist/signer.js +0 -179
package/dist/erc8128.d.ts
CHANGED
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
*/
|
|
12
12
|
import type { Address, PublicClient } from 'viem';
|
|
13
13
|
import { type EthHttpSigner, type NonceStore } from '@slicekit/erc8128';
|
|
14
|
-
import type { Signer, SignerType } from './signer.js';
|
|
14
|
+
import type { Signer, SignerType } from './signer/index.js';
|
|
15
15
|
export interface VerifyOptions {
|
|
16
16
|
receiptSecret: string;
|
|
17
17
|
rpcUrl?: string;
|
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
package/dist/receipt.d.ts
CHANGED
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
* Format: base64url(json).base64url(hmac-sha256)
|
|
15
15
|
* Same token format as nonce tokens in siwa.ts.
|
|
16
16
|
*/
|
|
17
|
-
import type { SignerType } from './signer.js';
|
|
17
|
+
import type { SignerType } from './signer/index.js';
|
|
18
18
|
export interface ReceiptPayload {
|
|
19
19
|
address: string;
|
|
20
20
|
agentId: number;
|
package/dist/registry.d.ts
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
* npm install viem
|
|
9
9
|
*/
|
|
10
10
|
import { type PublicClient } from 'viem';
|
|
11
|
-
import type { TransactionSigner } from './signer.js';
|
|
11
|
+
import type { TransactionSigner } from './signer/index.js';
|
|
12
12
|
/** Service endpoint types defined in ERC-8004 */
|
|
13
13
|
export type ServiceType = 'web' | 'A2A' | 'MCP' | 'OASF' | 'ENS' | 'DID' | 'email';
|
|
14
14
|
/** Trust models defined in ERC-8004 */
|
|
@@ -15,8 +15,8 @@
|
|
|
15
15
|
* ```
|
|
16
16
|
*/
|
|
17
17
|
import type { RequestHandler } from 'express';
|
|
18
|
-
import { type SiwaAgent, type VerifyOptions } from '
|
|
19
|
-
import type { SignerType } from '
|
|
18
|
+
import { type SiwaAgent, type VerifyOptions } from '../erc8128.js';
|
|
19
|
+
import type { SignerType } from '../signer/index.js';
|
|
20
20
|
export type { SiwaAgent };
|
|
21
21
|
declare global {
|
|
22
22
|
namespace Express {
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
* ```
|
|
16
16
|
*/
|
|
17
17
|
import express from 'express';
|
|
18
|
-
import { verifyAuthenticatedRequest, expressToFetchRequest, resolveReceiptSecret, } from '
|
|
18
|
+
import { verifyAuthenticatedRequest, expressToFetchRequest, resolveReceiptSecret, } from '../erc8128.js';
|
|
19
19
|
// ---------------------------------------------------------------------------
|
|
20
20
|
// CORS middleware
|
|
21
21
|
// ---------------------------------------------------------------------------
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* fastify.ts
|
|
3
|
+
*
|
|
4
|
+
* Server-side wrappers for Fastify applications.
|
|
5
|
+
* Uses preHandler hooks for authentication.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* ```ts
|
|
9
|
+
* import Fastify from "fastify";
|
|
10
|
+
* import { siwaPlugin, siwaAuth } from "@buildersgarden/siwa/fastify";
|
|
11
|
+
*
|
|
12
|
+
* const fastify = Fastify();
|
|
13
|
+
* await fastify.register(siwaPlugin);
|
|
14
|
+
*
|
|
15
|
+
* fastify.post("/api/protected", { preHandler: siwaAuth() }, async (req) => {
|
|
16
|
+
* return { agent: req.agent };
|
|
17
|
+
* });
|
|
18
|
+
* ```
|
|
19
|
+
*/
|
|
20
|
+
import type { FastifyPluginAsync, preHandlerHookHandler } from 'fastify';
|
|
21
|
+
import { type SiwaAgent, type VerifyOptions } from '../erc8128.js';
|
|
22
|
+
import type { SignerType } from '../signer/index.js';
|
|
23
|
+
export type { SiwaAgent };
|
|
24
|
+
declare module 'fastify' {
|
|
25
|
+
interface FastifyRequest {
|
|
26
|
+
agent?: SiwaAgent;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
export interface SiwaAuthOptions {
|
|
30
|
+
/** HMAC secret for receipt verification. Defaults to RECEIPT_SECRET or SIWA_SECRET env. */
|
|
31
|
+
receiptSecret?: string;
|
|
32
|
+
/** RPC URL for optional onchain verification. */
|
|
33
|
+
rpcUrl?: string;
|
|
34
|
+
/** Enable onchain ownerOf check. */
|
|
35
|
+
verifyOnchain?: boolean;
|
|
36
|
+
/** Public client for ERC-1271 or onchain checks. */
|
|
37
|
+
publicClient?: VerifyOptions['publicClient'];
|
|
38
|
+
/** Allowed signer types. Omit to accept all. */
|
|
39
|
+
allowedSignerTypes?: SignerType[];
|
|
40
|
+
}
|
|
41
|
+
export interface SiwaPluginOptions {
|
|
42
|
+
/** CORS allowed origin(s). Defaults to true (reflect origin). */
|
|
43
|
+
origin?: boolean | string | string[];
|
|
44
|
+
/** Allowed headers including SIWA-specific ones. */
|
|
45
|
+
allowedHeaders?: string[];
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Fastify plugin that sets up CORS with SIWA-specific headers.
|
|
49
|
+
* Requires @fastify/cors to be installed.
|
|
50
|
+
*/
|
|
51
|
+
export declare const siwaPlugin: FastifyPluginAsync<SiwaPluginOptions>;
|
|
52
|
+
/**
|
|
53
|
+
* Fastify preHandler that verifies ERC-8128 HTTP Message Signatures + SIWA receipt.
|
|
54
|
+
*
|
|
55
|
+
* On success, sets `req.agent` with the verified agent identity.
|
|
56
|
+
* On failure, responds with 401.
|
|
57
|
+
*/
|
|
58
|
+
export declare function siwaAuth(options?: SiwaAuthOptions): preHandlerHookHandler;
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* fastify.ts
|
|
3
|
+
*
|
|
4
|
+
* Server-side wrappers for Fastify applications.
|
|
5
|
+
* Uses preHandler hooks for authentication.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* ```ts
|
|
9
|
+
* import Fastify from "fastify";
|
|
10
|
+
* import { siwaPlugin, siwaAuth } from "@buildersgarden/siwa/fastify";
|
|
11
|
+
*
|
|
12
|
+
* const fastify = Fastify();
|
|
13
|
+
* await fastify.register(siwaPlugin);
|
|
14
|
+
*
|
|
15
|
+
* fastify.post("/api/protected", { preHandler: siwaAuth() }, async (req) => {
|
|
16
|
+
* return { agent: req.agent };
|
|
17
|
+
* });
|
|
18
|
+
* ```
|
|
19
|
+
*/
|
|
20
|
+
import { verifyAuthenticatedRequest, resolveReceiptSecret, } from '../erc8128.js';
|
|
21
|
+
// ---------------------------------------------------------------------------
|
|
22
|
+
// CORS headers
|
|
23
|
+
// ---------------------------------------------------------------------------
|
|
24
|
+
const DEFAULT_SIWA_HEADERS = [
|
|
25
|
+
'Content-Type',
|
|
26
|
+
'X-SIWA-Receipt',
|
|
27
|
+
'Signature',
|
|
28
|
+
'Signature-Input',
|
|
29
|
+
'Content-Digest',
|
|
30
|
+
];
|
|
31
|
+
// ---------------------------------------------------------------------------
|
|
32
|
+
// Request conversion helper
|
|
33
|
+
// ---------------------------------------------------------------------------
|
|
34
|
+
/**
|
|
35
|
+
* Convert a Fastify request to a Fetch Request for verification.
|
|
36
|
+
*/
|
|
37
|
+
function toFetchRequest(req) {
|
|
38
|
+
const url = `${req.protocol}://${req.hostname}${req.url}`;
|
|
39
|
+
return new Request(url, {
|
|
40
|
+
method: req.method,
|
|
41
|
+
headers: req.headers,
|
|
42
|
+
body: req.method !== 'GET' && req.method !== 'HEAD'
|
|
43
|
+
? JSON.stringify(req.body)
|
|
44
|
+
: undefined,
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
// ---------------------------------------------------------------------------
|
|
48
|
+
// Fastify plugin
|
|
49
|
+
// ---------------------------------------------------------------------------
|
|
50
|
+
/**
|
|
51
|
+
* Fastify plugin that sets up CORS with SIWA-specific headers.
|
|
52
|
+
* Requires @fastify/cors to be installed.
|
|
53
|
+
*/
|
|
54
|
+
export const siwaPlugin = async (fastify, options) => {
|
|
55
|
+
// Try to register @fastify/cors if available
|
|
56
|
+
try {
|
|
57
|
+
const cors = await import('@fastify/cors');
|
|
58
|
+
await fastify.register(cors.default ?? cors, {
|
|
59
|
+
origin: options?.origin ?? true,
|
|
60
|
+
allowedHeaders: options?.allowedHeaders ?? DEFAULT_SIWA_HEADERS,
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
catch {
|
|
64
|
+
// @fastify/cors not installed, set headers manually
|
|
65
|
+
fastify.addHook('onSend', async (req, reply) => {
|
|
66
|
+
reply.header('Access-Control-Allow-Origin', '*');
|
|
67
|
+
reply.header('Access-Control-Allow-Methods', 'GET, POST, OPTIONS');
|
|
68
|
+
reply.header('Access-Control-Allow-Headers', (options?.allowedHeaders ?? DEFAULT_SIWA_HEADERS).join(', '));
|
|
69
|
+
});
|
|
70
|
+
// Handle OPTIONS preflight
|
|
71
|
+
fastify.options('*', async (req, reply) => {
|
|
72
|
+
reply.status(204).send();
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
};
|
|
76
|
+
// ---------------------------------------------------------------------------
|
|
77
|
+
// Auth preHandler
|
|
78
|
+
// ---------------------------------------------------------------------------
|
|
79
|
+
/**
|
|
80
|
+
* Fastify preHandler that verifies ERC-8128 HTTP Message Signatures + SIWA receipt.
|
|
81
|
+
*
|
|
82
|
+
* On success, sets `req.agent` with the verified agent identity.
|
|
83
|
+
* On failure, responds with 401.
|
|
84
|
+
*/
|
|
85
|
+
export function siwaAuth(options) {
|
|
86
|
+
return async (req, reply) => {
|
|
87
|
+
const hasSignature = req.headers['signature'] && req.headers['x-siwa-receipt'];
|
|
88
|
+
if (!hasSignature) {
|
|
89
|
+
return reply.status(401).send({
|
|
90
|
+
error: 'Unauthorized — provide ERC-8128 Signature + X-SIWA-Receipt headers',
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
try {
|
|
94
|
+
const secret = resolveReceiptSecret(options?.receiptSecret);
|
|
95
|
+
const result = await verifyAuthenticatedRequest(toFetchRequest(req), {
|
|
96
|
+
receiptSecret: secret,
|
|
97
|
+
rpcUrl: options?.rpcUrl,
|
|
98
|
+
verifyOnchain: options?.verifyOnchain,
|
|
99
|
+
publicClient: options?.publicClient,
|
|
100
|
+
allowedSignerTypes: options?.allowedSignerTypes,
|
|
101
|
+
});
|
|
102
|
+
if (!result.valid) {
|
|
103
|
+
return reply.status(401).send({ error: result.error });
|
|
104
|
+
}
|
|
105
|
+
req.agent = result.agent;
|
|
106
|
+
}
|
|
107
|
+
catch (err) {
|
|
108
|
+
return reply.status(401).send({ error: `ERC-8128 auth failed: ${err.message}` });
|
|
109
|
+
}
|
|
110
|
+
};
|
|
111
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* hono.ts
|
|
3
|
+
*
|
|
4
|
+
* Server-side wrappers for Hono applications.
|
|
5
|
+
* Uses web standard Request/Response APIs.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* ```ts
|
|
9
|
+
* import { Hono } from "hono";
|
|
10
|
+
* import { siwaMiddleware, siwaCors } from "@buildersgarden/siwa/hono";
|
|
11
|
+
*
|
|
12
|
+
* const app = new Hono();
|
|
13
|
+
* app.use("*", siwaCors());
|
|
14
|
+
* app.post("/api/protected", siwaMiddleware(), (c) => {
|
|
15
|
+
* return c.json({ agent: c.get("agent") });
|
|
16
|
+
* });
|
|
17
|
+
* ```
|
|
18
|
+
*/
|
|
19
|
+
import type { MiddlewareHandler } from 'hono';
|
|
20
|
+
import { type SiwaAgent, type VerifyOptions } from '../erc8128.js';
|
|
21
|
+
import type { SignerType } from '../signer/index.js';
|
|
22
|
+
export type { SiwaAgent };
|
|
23
|
+
export interface SiwaMiddlewareOptions {
|
|
24
|
+
/** HMAC secret for receipt verification. Defaults to RECEIPT_SECRET or SIWA_SECRET env. */
|
|
25
|
+
receiptSecret?: string;
|
|
26
|
+
/** RPC URL for optional onchain verification. */
|
|
27
|
+
rpcUrl?: string;
|
|
28
|
+
/** Enable onchain ownerOf check. */
|
|
29
|
+
verifyOnchain?: boolean;
|
|
30
|
+
/** Public client for ERC-1271 or onchain checks. */
|
|
31
|
+
publicClient?: VerifyOptions['publicClient'];
|
|
32
|
+
/** Allowed signer types. Omit to accept all. */
|
|
33
|
+
allowedSignerTypes?: SignerType[];
|
|
34
|
+
}
|
|
35
|
+
export interface SiwaCorsOptions {
|
|
36
|
+
/** Allowed origin(s). Defaults to "*". */
|
|
37
|
+
origin?: string;
|
|
38
|
+
/** Allowed HTTP methods. */
|
|
39
|
+
methods?: string[];
|
|
40
|
+
/** Allowed headers. */
|
|
41
|
+
headers?: string[];
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* CORS middleware pre-configured with SIWA-specific headers.
|
|
45
|
+
* Handles OPTIONS preflight automatically.
|
|
46
|
+
*/
|
|
47
|
+
export declare function siwaCors(options?: SiwaCorsOptions): MiddlewareHandler;
|
|
48
|
+
/**
|
|
49
|
+
* Hono middleware that verifies ERC-8128 HTTP Message Signatures + SIWA receipt.
|
|
50
|
+
*
|
|
51
|
+
* On success, sets `c.set("agent", agent)` with the verified agent identity.
|
|
52
|
+
* On failure, responds with 401.
|
|
53
|
+
*/
|
|
54
|
+
export declare function siwaMiddleware(options?: SiwaMiddlewareOptions): MiddlewareHandler;
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* hono.ts
|
|
3
|
+
*
|
|
4
|
+
* Server-side wrappers for Hono applications.
|
|
5
|
+
* Uses web standard Request/Response APIs.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* ```ts
|
|
9
|
+
* import { Hono } from "hono";
|
|
10
|
+
* import { siwaMiddleware, siwaCors } from "@buildersgarden/siwa/hono";
|
|
11
|
+
*
|
|
12
|
+
* const app = new Hono();
|
|
13
|
+
* app.use("*", siwaCors());
|
|
14
|
+
* app.post("/api/protected", siwaMiddleware(), (c) => {
|
|
15
|
+
* return c.json({ agent: c.get("agent") });
|
|
16
|
+
* });
|
|
17
|
+
* ```
|
|
18
|
+
*/
|
|
19
|
+
import { verifyAuthenticatedRequest, resolveReceiptSecret, } from '../erc8128.js';
|
|
20
|
+
// ---------------------------------------------------------------------------
|
|
21
|
+
// CORS middleware
|
|
22
|
+
// ---------------------------------------------------------------------------
|
|
23
|
+
const DEFAULT_SIWA_HEADERS = [
|
|
24
|
+
'Content-Type',
|
|
25
|
+
'X-SIWA-Receipt',
|
|
26
|
+
'Signature',
|
|
27
|
+
'Signature-Input',
|
|
28
|
+
'Content-Digest',
|
|
29
|
+
];
|
|
30
|
+
/**
|
|
31
|
+
* CORS middleware pre-configured with SIWA-specific headers.
|
|
32
|
+
* Handles OPTIONS preflight automatically.
|
|
33
|
+
*/
|
|
34
|
+
export function siwaCors(options) {
|
|
35
|
+
const origin = options?.origin ?? '*';
|
|
36
|
+
const methods = options?.methods ?? ['GET', 'POST', 'OPTIONS'];
|
|
37
|
+
const headers = options?.headers ?? DEFAULT_SIWA_HEADERS;
|
|
38
|
+
return async (c, next) => {
|
|
39
|
+
c.header('Access-Control-Allow-Origin', origin);
|
|
40
|
+
c.header('Access-Control-Allow-Methods', methods.join(', '));
|
|
41
|
+
c.header('Access-Control-Allow-Headers', headers.join(', '));
|
|
42
|
+
if (c.req.method === 'OPTIONS') {
|
|
43
|
+
return c.body(null, 204);
|
|
44
|
+
}
|
|
45
|
+
await next();
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
// ---------------------------------------------------------------------------
|
|
49
|
+
// Auth middleware
|
|
50
|
+
// ---------------------------------------------------------------------------
|
|
51
|
+
/**
|
|
52
|
+
* Hono middleware that verifies ERC-8128 HTTP Message Signatures + SIWA receipt.
|
|
53
|
+
*
|
|
54
|
+
* On success, sets `c.set("agent", agent)` with the verified agent identity.
|
|
55
|
+
* On failure, responds with 401.
|
|
56
|
+
*/
|
|
57
|
+
export function siwaMiddleware(options) {
|
|
58
|
+
return async (c, next) => {
|
|
59
|
+
const hasSignature = c.req.header('signature') && c.req.header('x-siwa-receipt');
|
|
60
|
+
if (!hasSignature) {
|
|
61
|
+
return c.json({ error: 'Unauthorized — provide ERC-8128 Signature + X-SIWA-Receipt headers' }, 401);
|
|
62
|
+
}
|
|
63
|
+
try {
|
|
64
|
+
const secret = resolveReceiptSecret(options?.receiptSecret);
|
|
65
|
+
const result = await verifyAuthenticatedRequest(c.req.raw, {
|
|
66
|
+
receiptSecret: secret,
|
|
67
|
+
rpcUrl: options?.rpcUrl,
|
|
68
|
+
verifyOnchain: options?.verifyOnchain,
|
|
69
|
+
publicClient: options?.publicClient,
|
|
70
|
+
allowedSignerTypes: options?.allowedSignerTypes,
|
|
71
|
+
});
|
|
72
|
+
if (!result.valid) {
|
|
73
|
+
return c.json({ error: result.error }, 401);
|
|
74
|
+
}
|
|
75
|
+
c.set('agent', result.agent);
|
|
76
|
+
await next();
|
|
77
|
+
}
|
|
78
|
+
catch (err) {
|
|
79
|
+
return c.json({ error: `ERC-8128 auth failed: ${err.message}` }, 401);
|
|
80
|
+
}
|
|
81
|
+
};
|
|
82
|
+
}
|
|
@@ -16,8 +16,8 @@
|
|
|
16
16
|
* export { siwaOptions as OPTIONS };
|
|
17
17
|
* ```
|
|
18
18
|
*/
|
|
19
|
-
import { type SiwaAgent } from '
|
|
20
|
-
import type { SignerType } from '
|
|
19
|
+
import { type SiwaAgent } from '../erc8128.js';
|
|
20
|
+
import type { SignerType } from '../signer/index.js';
|
|
21
21
|
export type { SiwaAgent };
|
|
22
22
|
export interface WithSiwaOptions {
|
|
23
23
|
/** HMAC secret for receipt verification. Defaults to RECEIPT_SECRET or SIWA_SECRET env. */
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
* export { siwaOptions as OPTIONS };
|
|
17
17
|
* ```
|
|
18
18
|
*/
|
|
19
|
-
import { verifyAuthenticatedRequest, nextjsToFetchRequest, resolveReceiptSecret, } from '
|
|
19
|
+
import { verifyAuthenticatedRequest, nextjsToFetchRequest, resolveReceiptSecret, } from '../erc8128.js';
|
|
20
20
|
// ---------------------------------------------------------------------------
|
|
21
21
|
// CORS helpers
|
|
22
22
|
// ---------------------------------------------------------------------------
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* circle.ts
|
|
3
|
+
*
|
|
4
|
+
* Circle developer-controlled wallet signer implementation.
|
|
5
|
+
*/
|
|
6
|
+
import type { CircleDeveloperControlledWalletsClient } from "@circle-fin/developer-controlled-wallets";
|
|
7
|
+
import type { Address } from "viem";
|
|
8
|
+
import type { Signer } from "./types.js";
|
|
9
|
+
/**
|
|
10
|
+
* Configuration for the Circle SIWA signer.
|
|
11
|
+
*/
|
|
12
|
+
export interface CircleSiwaSignerConfig {
|
|
13
|
+
/** Circle API key */
|
|
14
|
+
apiKey: string;
|
|
15
|
+
/** Circle entity secret */
|
|
16
|
+
entitySecret: string;
|
|
17
|
+
/** Circle wallet ID */
|
|
18
|
+
walletId: string;
|
|
19
|
+
/** Wallet address (optional - will be fetched from Circle if not provided) */
|
|
20
|
+
walletAddress?: Address;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Configuration using an existing Circle client.
|
|
24
|
+
*/
|
|
25
|
+
export interface CircleSiwaSignerClientConfig {
|
|
26
|
+
/** Existing Circle client instance */
|
|
27
|
+
client: CircleDeveloperControlledWalletsClient;
|
|
28
|
+
/** Circle wallet ID */
|
|
29
|
+
walletId: string;
|
|
30
|
+
/** Wallet address (optional - will be fetched from Circle if not provided) */
|
|
31
|
+
walletAddress?: Address;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Creates a SIWA Signer that wraps Circle's developer-controlled wallet SDK.
|
|
35
|
+
*
|
|
36
|
+
* This signer implements the core Signer interface for SIWA message signing.
|
|
37
|
+
* It supports both standard message signing (EIP-191) and raw hex signing
|
|
38
|
+
* for ERC-8128 HTTP message signatures.
|
|
39
|
+
*
|
|
40
|
+
* The wallet address can be provided explicitly or fetched automatically
|
|
41
|
+
* from Circle using the wallet ID.
|
|
42
|
+
*
|
|
43
|
+
* @param config - Circle wallet configuration
|
|
44
|
+
* @returns A Promise that resolves to a Signer compatible with SIWA's signSIWAMessage function
|
|
45
|
+
*
|
|
46
|
+
* @example
|
|
47
|
+
* ```typescript
|
|
48
|
+
* import { signSIWAMessage, generateNonce } from '@buildersgarden/siwa/siwa';
|
|
49
|
+
* import { createCircleSiwaSigner } from '@buildersgarden/siwa/signer';
|
|
50
|
+
*
|
|
51
|
+
* // Address is fetched automatically from Circle
|
|
52
|
+
* const signer = await createCircleSiwaSigner({
|
|
53
|
+
* apiKey: process.env.CIRCLE_API_KEY!,
|
|
54
|
+
* entitySecret: process.env.CIRCLE_ENTITY_SECRET!,
|
|
55
|
+
* walletId: 'your-wallet-id',
|
|
56
|
+
* });
|
|
57
|
+
*
|
|
58
|
+
* const { message, signature, address } = await signSIWAMessage({
|
|
59
|
+
* domain: 'example.com',
|
|
60
|
+
* uri: 'https://example.com/login',
|
|
61
|
+
* agentId: 123,
|
|
62
|
+
* agentRegistry: 'eip155:84532:0x...',
|
|
63
|
+
* chainId: 84532,
|
|
64
|
+
* nonce: generateNonce(),
|
|
65
|
+
* issuedAt: new Date().toISOString(),
|
|
66
|
+
* }, signer);
|
|
67
|
+
* ```
|
|
68
|
+
*/
|
|
69
|
+
export declare function createCircleSiwaSigner(config: CircleSiwaSignerConfig): Promise<Signer>;
|
|
70
|
+
/**
|
|
71
|
+
* Creates a SIWA Signer from an existing Circle client instance.
|
|
72
|
+
*
|
|
73
|
+
* Use this when you already have a Circle client initialized and want
|
|
74
|
+
* to reuse it for SIWA signing.
|
|
75
|
+
*
|
|
76
|
+
* @param config - Configuration with existing Circle client
|
|
77
|
+
* @returns A Promise that resolves to a Signer compatible with SIWA's signSIWAMessage function
|
|
78
|
+
*/
|
|
79
|
+
export declare function createCircleSiwaSignerFromClient(config: CircleSiwaSignerClientConfig): Promise<Signer>;
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* circle.ts
|
|
3
|
+
*
|
|
4
|
+
* Circle developer-controlled wallet signer implementation.
|
|
5
|
+
*/
|
|
6
|
+
import { initiateDeveloperControlledWalletsClient } from "@circle-fin/developer-controlled-wallets";
|
|
7
|
+
/**
|
|
8
|
+
* Fetches wallet address from Circle API using the wallet ID.
|
|
9
|
+
*/
|
|
10
|
+
async function fetchWalletAddress(client, walletId) {
|
|
11
|
+
const response = await client.getWallet({ id: walletId });
|
|
12
|
+
const address = response.data?.wallet?.address;
|
|
13
|
+
if (!address) {
|
|
14
|
+
throw new Error(`Failed to fetch wallet address for wallet ID: ${walletId}`);
|
|
15
|
+
}
|
|
16
|
+
return address;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Creates a SIWA Signer that wraps Circle's developer-controlled wallet SDK.
|
|
20
|
+
*
|
|
21
|
+
* This signer implements the core Signer interface for SIWA message signing.
|
|
22
|
+
* It supports both standard message signing (EIP-191) and raw hex signing
|
|
23
|
+
* for ERC-8128 HTTP message signatures.
|
|
24
|
+
*
|
|
25
|
+
* The wallet address can be provided explicitly or fetched automatically
|
|
26
|
+
* from Circle using the wallet ID.
|
|
27
|
+
*
|
|
28
|
+
* @param config - Circle wallet configuration
|
|
29
|
+
* @returns A Promise that resolves to a Signer compatible with SIWA's signSIWAMessage function
|
|
30
|
+
*
|
|
31
|
+
* @example
|
|
32
|
+
* ```typescript
|
|
33
|
+
* import { signSIWAMessage, generateNonce } from '@buildersgarden/siwa/siwa';
|
|
34
|
+
* import { createCircleSiwaSigner } from '@buildersgarden/siwa/signer';
|
|
35
|
+
*
|
|
36
|
+
* // Address is fetched automatically from Circle
|
|
37
|
+
* const signer = await createCircleSiwaSigner({
|
|
38
|
+
* apiKey: process.env.CIRCLE_API_KEY!,
|
|
39
|
+
* entitySecret: process.env.CIRCLE_ENTITY_SECRET!,
|
|
40
|
+
* walletId: 'your-wallet-id',
|
|
41
|
+
* });
|
|
42
|
+
*
|
|
43
|
+
* const { message, signature, address } = await signSIWAMessage({
|
|
44
|
+
* domain: 'example.com',
|
|
45
|
+
* uri: 'https://example.com/login',
|
|
46
|
+
* agentId: 123,
|
|
47
|
+
* agentRegistry: 'eip155:84532:0x...',
|
|
48
|
+
* chainId: 84532,
|
|
49
|
+
* nonce: generateNonce(),
|
|
50
|
+
* issuedAt: new Date().toISOString(),
|
|
51
|
+
* }, signer);
|
|
52
|
+
* ```
|
|
53
|
+
*/
|
|
54
|
+
export async function createCircleSiwaSigner(config) {
|
|
55
|
+
const client = initiateDeveloperControlledWalletsClient({
|
|
56
|
+
apiKey: config.apiKey,
|
|
57
|
+
entitySecret: config.entitySecret,
|
|
58
|
+
});
|
|
59
|
+
return createCircleSiwaSignerFromClient({
|
|
60
|
+
client,
|
|
61
|
+
walletId: config.walletId,
|
|
62
|
+
...(config.walletAddress && { walletAddress: config.walletAddress }),
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Creates a SIWA Signer from an existing Circle client instance.
|
|
67
|
+
*
|
|
68
|
+
* Use this when you already have a Circle client initialized and want
|
|
69
|
+
* to reuse it for SIWA signing.
|
|
70
|
+
*
|
|
71
|
+
* @param config - Configuration with existing Circle client
|
|
72
|
+
* @returns A Promise that resolves to a Signer compatible with SIWA's signSIWAMessage function
|
|
73
|
+
*/
|
|
74
|
+
export async function createCircleSiwaSignerFromClient(config) {
|
|
75
|
+
const { client, walletId } = config;
|
|
76
|
+
// Fetch wallet address from Circle if not provided
|
|
77
|
+
const walletAddress = config.walletAddress ?? (await fetchWalletAddress(client, walletId));
|
|
78
|
+
return {
|
|
79
|
+
/**
|
|
80
|
+
* Returns the wallet address.
|
|
81
|
+
*/
|
|
82
|
+
async getAddress() {
|
|
83
|
+
return walletAddress;
|
|
84
|
+
},
|
|
85
|
+
/**
|
|
86
|
+
* Signs a message using EIP-191 personal_sign.
|
|
87
|
+
* Used for standard SIWA message signing.
|
|
88
|
+
*/
|
|
89
|
+
async signMessage(message) {
|
|
90
|
+
const response = await client.signMessage({
|
|
91
|
+
walletId,
|
|
92
|
+
message,
|
|
93
|
+
encodedByHex: false,
|
|
94
|
+
});
|
|
95
|
+
const signature = response.data?.signature;
|
|
96
|
+
if (!signature) {
|
|
97
|
+
throw new Error("Circle signMessage failed: no signature returned");
|
|
98
|
+
}
|
|
99
|
+
return signature;
|
|
100
|
+
},
|
|
101
|
+
/**
|
|
102
|
+
* Signs raw hex bytes.
|
|
103
|
+
* Used by ERC-8128 for HTTP message signatures.
|
|
104
|
+
*/
|
|
105
|
+
async signRawMessage(rawHex) {
|
|
106
|
+
// Strip 0x prefix if present for Circle API
|
|
107
|
+
const hexMessage = rawHex.startsWith("0x") ? rawHex.slice(2) : rawHex;
|
|
108
|
+
const response = await client.signMessage({
|
|
109
|
+
walletId,
|
|
110
|
+
message: hexMessage,
|
|
111
|
+
encodedByHex: true,
|
|
112
|
+
});
|
|
113
|
+
const signature = response.data?.signature;
|
|
114
|
+
if (!signature) {
|
|
115
|
+
throw new Error("Circle signRawMessage failed: no signature returned");
|
|
116
|
+
}
|
|
117
|
+
return signature;
|
|
118
|
+
},
|
|
119
|
+
};
|
|
120
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* signer/index.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
|
+
* - createCircleSiwaSigner(config) — Circle developer-controlled wallet
|
|
14
|
+
* - createCircleSiwaSignerFromClient(config) — Circle with existing client
|
|
15
|
+
* - createPrivySiwaSigner(config) — Privy server wallet
|
|
16
|
+
*
|
|
17
|
+
* Usage:
|
|
18
|
+
* import { signSIWAMessage, createLocalAccountSigner } from '@buildersgarden/siwa';
|
|
19
|
+
* import { privateKeyToAccount } from 'viem/accounts';
|
|
20
|
+
*
|
|
21
|
+
* const account = privateKeyToAccount('0x...');
|
|
22
|
+
* const signer = createLocalAccountSigner(account);
|
|
23
|
+
* const { message, signature } = await signSIWAMessage(fields, signer);
|
|
24
|
+
*/
|
|
25
|
+
export type { Signer, SignerType, TransactionSigner, TransactionRequest, KeyringProxyConfig, } from './types.js';
|
|
26
|
+
export { createKeyringProxySigner } from './keyring-proxy.js';
|
|
27
|
+
export { createLocalAccountSigner } from './local-account.js';
|
|
28
|
+
export { createWalletClientSigner } from './wallet-client.js';
|
|
29
|
+
export { createCircleSiwaSigner, createCircleSiwaSignerFromClient, type CircleSiwaSignerConfig, type CircleSiwaSignerClientConfig, } from './circle.js';
|
|
30
|
+
export { createPrivySiwaSigner, type PrivySiwaSignerConfig, } from './privy.js';
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* signer/index.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
|
+
* - createCircleSiwaSigner(config) — Circle developer-controlled wallet
|
|
14
|
+
* - createCircleSiwaSignerFromClient(config) — Circle with existing client
|
|
15
|
+
* - createPrivySiwaSigner(config) — Privy server wallet
|
|
16
|
+
*
|
|
17
|
+
* Usage:
|
|
18
|
+
* import { signSIWAMessage, createLocalAccountSigner } from '@buildersgarden/siwa';
|
|
19
|
+
* import { privateKeyToAccount } from 'viem/accounts';
|
|
20
|
+
*
|
|
21
|
+
* const account = privateKeyToAccount('0x...');
|
|
22
|
+
* const signer = createLocalAccountSigner(account);
|
|
23
|
+
* const { message, signature } = await signSIWAMessage(fields, signer);
|
|
24
|
+
*/
|
|
25
|
+
// Signer implementations
|
|
26
|
+
export { createKeyringProxySigner } from './keyring-proxy.js';
|
|
27
|
+
export { createLocalAccountSigner } from './local-account.js';
|
|
28
|
+
export { createWalletClientSigner } from './wallet-client.js';
|
|
29
|
+
export { createCircleSiwaSigner, createCircleSiwaSignerFromClient, } from './circle.js';
|
|
30
|
+
export { createPrivySiwaSigner, } from './privy.js';
|