@buildersgarden/siwa 0.0.14 → 0.0.16
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/bankr.d.ts +51 -0
- package/dist/signer/bankr.js +123 -0
- package/dist/signer/circle.d.ts +79 -0
- package/dist/signer/circle.js +120 -0
- package/dist/signer/index.d.ts +32 -0
- package/dist/signer/index.js +32 -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,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* bankr.ts
|
|
3
|
+
*
|
|
4
|
+
* Bankr wallet signer implementation.
|
|
5
|
+
*
|
|
6
|
+
* Uses the Bankr Agent API (https://api.bankr.bot) for signing operations.
|
|
7
|
+
* Wallet address is fetched via GET /agent/me, messages are signed via POST /agent/sign.
|
|
8
|
+
*/
|
|
9
|
+
import type { Signer } from "./types.js";
|
|
10
|
+
/**
|
|
11
|
+
* Configuration for the Bankr SIWA signer.
|
|
12
|
+
*/
|
|
13
|
+
export interface BankrSiwaSignerConfig {
|
|
14
|
+
/** Bankr API key (or BANKR_API_KEY env var) */
|
|
15
|
+
apiKey?: string;
|
|
16
|
+
/** Bankr API base URL (defaults to https://api.bankr.bot) */
|
|
17
|
+
baseUrl?: string;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Creates a SIWA Signer that wraps the Bankr Agent API.
|
|
21
|
+
*
|
|
22
|
+
* This signer implements the core Signer interface for SIWA message signing.
|
|
23
|
+
* It supports both standard message signing (EIP-191) and raw hex signing
|
|
24
|
+
* for ERC-8128 HTTP message signatures.
|
|
25
|
+
*
|
|
26
|
+
* The wallet address is fetched from the Bankr API on creation.
|
|
27
|
+
*
|
|
28
|
+
* @param config - Bankr API configuration
|
|
29
|
+
* @returns A Promise that resolves to a Signer compatible with SIWA's signSIWAMessage function
|
|
30
|
+
*
|
|
31
|
+
* @example
|
|
32
|
+
* ```typescript
|
|
33
|
+
* import { signSIWAMessage } from '@buildersgarden/siwa';
|
|
34
|
+
* import { createBankrSiwaSigner } from '@buildersgarden/siwa/signer';
|
|
35
|
+
*
|
|
36
|
+
* const signer = await createBankrSiwaSigner({
|
|
37
|
+
* apiKey: process.env.BANKR_API_KEY!,
|
|
38
|
+
* });
|
|
39
|
+
*
|
|
40
|
+
* const { message, signature, address } = await signSIWAMessage({
|
|
41
|
+
* domain: 'example.com',
|
|
42
|
+
* uri: 'https://example.com/login',
|
|
43
|
+
* agentId: 123,
|
|
44
|
+
* agentRegistry: 'eip155:84532:0x...',
|
|
45
|
+
* chainId: 84532,
|
|
46
|
+
* nonce: generateNonce(),
|
|
47
|
+
* issuedAt: new Date().toISOString(),
|
|
48
|
+
* }, signer);
|
|
49
|
+
* ```
|
|
50
|
+
*/
|
|
51
|
+
export declare function createBankrSiwaSigner(config?: BankrSiwaSignerConfig): Promise<Signer>;
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* bankr.ts
|
|
3
|
+
*
|
|
4
|
+
* Bankr wallet signer implementation.
|
|
5
|
+
*
|
|
6
|
+
* Uses the Bankr Agent API (https://api.bankr.bot) for signing operations.
|
|
7
|
+
* Wallet address is fetched via GET /agent/me, messages are signed via POST /agent/sign.
|
|
8
|
+
*/
|
|
9
|
+
function resolveConfig(config) {
|
|
10
|
+
const apiKey = config.apiKey ?? process.env.BANKR_API_KEY;
|
|
11
|
+
if (!apiKey) {
|
|
12
|
+
throw new Error("Bankr API key is required. Provide apiKey in config or set BANKR_API_KEY env var.");
|
|
13
|
+
}
|
|
14
|
+
return {
|
|
15
|
+
apiKey,
|
|
16
|
+
baseUrl: config.baseUrl ?? "https://api.bankr.bot",
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Fetches the EVM wallet address from the Bankr API.
|
|
21
|
+
*/
|
|
22
|
+
async function fetchWalletAddress(config) {
|
|
23
|
+
const response = await fetch(`${config.baseUrl}/agent/me`, {
|
|
24
|
+
headers: {
|
|
25
|
+
"X-API-Key": config.apiKey,
|
|
26
|
+
},
|
|
27
|
+
});
|
|
28
|
+
if (!response.ok) {
|
|
29
|
+
throw new Error(`Bankr API /agent/me failed: ${response.status} ${response.statusText}`);
|
|
30
|
+
}
|
|
31
|
+
const data = await response.json();
|
|
32
|
+
const evmWallet = data.wallets?.find((w) => w.chain === "evm");
|
|
33
|
+
if (!evmWallet?.address) {
|
|
34
|
+
throw new Error("No EVM wallet found in Bankr account");
|
|
35
|
+
}
|
|
36
|
+
return evmWallet.address;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Signs a message using the Bankr Agent API.
|
|
40
|
+
*/
|
|
41
|
+
async function bankrSign(config, signatureType, payload) {
|
|
42
|
+
const response = await fetch(`${config.baseUrl}/agent/sign`, {
|
|
43
|
+
method: "POST",
|
|
44
|
+
headers: {
|
|
45
|
+
"Content-Type": "application/json",
|
|
46
|
+
"X-API-Key": config.apiKey,
|
|
47
|
+
},
|
|
48
|
+
body: JSON.stringify({ signatureType, ...payload }),
|
|
49
|
+
});
|
|
50
|
+
if (!response.ok) {
|
|
51
|
+
throw new Error(`Bankr sign failed: ${response.status} ${response.statusText}`);
|
|
52
|
+
}
|
|
53
|
+
const result = await response.json();
|
|
54
|
+
if (!result.success || !result.signature) {
|
|
55
|
+
throw new Error(`Bankr sign failed: ${result.error ?? "no signature returned"}`);
|
|
56
|
+
}
|
|
57
|
+
return {
|
|
58
|
+
signature: result.signature,
|
|
59
|
+
signer: result.signer,
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Creates a SIWA Signer that wraps the Bankr Agent API.
|
|
64
|
+
*
|
|
65
|
+
* This signer implements the core Signer interface for SIWA message signing.
|
|
66
|
+
* It supports both standard message signing (EIP-191) and raw hex signing
|
|
67
|
+
* for ERC-8128 HTTP message signatures.
|
|
68
|
+
*
|
|
69
|
+
* The wallet address is fetched from the Bankr API on creation.
|
|
70
|
+
*
|
|
71
|
+
* @param config - Bankr API configuration
|
|
72
|
+
* @returns A Promise that resolves to a Signer compatible with SIWA's signSIWAMessage function
|
|
73
|
+
*
|
|
74
|
+
* @example
|
|
75
|
+
* ```typescript
|
|
76
|
+
* import { signSIWAMessage } from '@buildersgarden/siwa';
|
|
77
|
+
* import { createBankrSiwaSigner } from '@buildersgarden/siwa/signer';
|
|
78
|
+
*
|
|
79
|
+
* const signer = await createBankrSiwaSigner({
|
|
80
|
+
* apiKey: process.env.BANKR_API_KEY!,
|
|
81
|
+
* });
|
|
82
|
+
*
|
|
83
|
+
* const { message, signature, address } = await signSIWAMessage({
|
|
84
|
+
* domain: 'example.com',
|
|
85
|
+
* uri: 'https://example.com/login',
|
|
86
|
+
* agentId: 123,
|
|
87
|
+
* agentRegistry: 'eip155:84532:0x...',
|
|
88
|
+
* chainId: 84532,
|
|
89
|
+
* nonce: generateNonce(),
|
|
90
|
+
* issuedAt: new Date().toISOString(),
|
|
91
|
+
* }, signer);
|
|
92
|
+
* ```
|
|
93
|
+
*/
|
|
94
|
+
export async function createBankrSiwaSigner(config = {}) {
|
|
95
|
+
const resolved = resolveConfig(config);
|
|
96
|
+
const walletAddress = await fetchWalletAddress(resolved);
|
|
97
|
+
return {
|
|
98
|
+
/**
|
|
99
|
+
* Returns the wallet address.
|
|
100
|
+
*/
|
|
101
|
+
async getAddress() {
|
|
102
|
+
return walletAddress;
|
|
103
|
+
},
|
|
104
|
+
/**
|
|
105
|
+
* Signs a message using EIP-191 personal_sign.
|
|
106
|
+
* Used for standard SIWA message signing.
|
|
107
|
+
*/
|
|
108
|
+
async signMessage(message) {
|
|
109
|
+
const result = await bankrSign(resolved, "personal_sign", { message });
|
|
110
|
+
return result.signature;
|
|
111
|
+
},
|
|
112
|
+
/**
|
|
113
|
+
* Signs raw hex bytes.
|
|
114
|
+
* Used by ERC-8128 for HTTP message signatures.
|
|
115
|
+
*/
|
|
116
|
+
async signRawMessage(rawHex) {
|
|
117
|
+
const result = await bankrSign(resolved, "personal_sign", {
|
|
118
|
+
message: rawHex,
|
|
119
|
+
});
|
|
120
|
+
return result.signature;
|
|
121
|
+
},
|
|
122
|
+
};
|
|
123
|
+
}
|
|
@@ -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>;
|