accounts 0.6.0 → 0.6.2
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/CHANGELOG.md +15 -0
- package/dist/core/Adapter.d.ts +2 -2
- package/dist/core/Adapter.d.ts.map +1 -1
- package/dist/core/Client.d.ts +2 -2
- package/dist/core/Client.d.ts.map +1 -1
- package/dist/core/Client.js +13 -4
- package/dist/core/Client.js.map +1 -1
- package/dist/core/Provider.d.ts.map +1 -1
- package/dist/core/Provider.js +9 -2
- package/dist/core/Provider.js.map +1 -1
- package/dist/core/Schema.d.ts +22 -12
- package/dist/core/Schema.d.ts.map +1 -1
- package/dist/core/adapters/dialog.d.ts.map +1 -1
- package/dist/core/adapters/dialog.js +24 -4
- package/dist/core/adapters/dialog.js.map +1 -1
- package/dist/core/adapters/local.d.ts.map +1 -1
- package/dist/core/adapters/local.js +21 -3
- package/dist/core/adapters/local.js.map +1 -1
- package/dist/core/zod/rpc.d.ts +14 -9
- package/dist/core/zod/rpc.d.ts.map +1 -1
- package/dist/core/zod/rpc.js +8 -2
- package/dist/core/zod/rpc.js.map +1 -1
- package/dist/server/CliAuth.d.ts +11 -11
- package/dist/server/CliAuth.js +1 -1
- package/dist/server/CliAuth.js.map +1 -1
- package/dist/server/Handler.d.ts +4 -252
- package/dist/server/Handler.d.ts.map +1 -1
- package/dist/server/Handler.js +4 -573
- package/dist/server/Handler.js.map +1 -1
- package/dist/server/internal/handlers/codeAuth.d.ts +41 -0
- package/dist/server/internal/handlers/codeAuth.d.ts.map +1 -0
- package/dist/server/internal/handlers/codeAuth.js +104 -0
- package/dist/server/internal/handlers/codeAuth.js.map +1 -0
- package/dist/server/internal/handlers/feePayer.d.ts +73 -0
- package/dist/server/internal/handlers/feePayer.d.ts.map +1 -0
- package/dist/server/internal/handlers/feePayer.js +184 -0
- package/dist/server/internal/handlers/feePayer.js.map +1 -0
- package/dist/server/internal/handlers/relay.d.ts +148 -0
- package/dist/server/internal/handlers/relay.d.ts.map +1 -0
- package/dist/server/internal/handlers/relay.js +600 -0
- package/dist/server/internal/handlers/relay.js.map +1 -0
- package/dist/server/internal/handlers/utils.d.ts +12 -0
- package/dist/server/internal/handlers/utils.d.ts.map +1 -0
- package/dist/server/internal/handlers/utils.js +80 -0
- package/dist/server/internal/handlers/utils.js.map +1 -0
- package/dist/server/internal/handlers/webAuthn.d.ts +57 -0
- package/dist/server/internal/handlers/webAuthn.d.ts.map +1 -0
- package/dist/server/internal/handlers/webAuthn.js +143 -0
- package/dist/server/internal/handlers/webAuthn.js.map +1 -0
- package/package.json +2 -2
- package/src/core/Adapter.ts +2 -2
- package/src/core/Client.ts +13 -6
- package/src/core/Provider.connect.browser.test.ts +23 -2
- package/src/core/Provider.test.ts +292 -0
- package/src/core/Provider.ts +11 -3
- package/src/core/adapters/dialog.ts +21 -4
- package/src/core/adapters/local.ts +15 -3
- package/src/core/zod/rpc.ts +12 -2
- package/src/server/CliAuth.ts +1 -1
- package/src/server/Handler.test.ts +3 -418
- package/src/server/Handler.ts +5 -766
- package/src/server/internal/handlers/codeAuth.ts +148 -0
- package/src/server/internal/handlers/feePayer.test.ts +335 -0
- package/src/server/internal/handlers/feePayer.ts +271 -0
- package/src/server/internal/handlers/relay.test.ts +767 -0
- package/src/server/internal/handlers/relay.ts +817 -0
- package/src/server/internal/handlers/utils.ts +96 -0
- package/src/server/internal/handlers/webAuthn.test.ts +170 -0
- package/src/server/internal/handlers/webAuthn.ts +213 -0
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { Hex, RpcRequest, RpcResponse } from 'ox';
|
|
2
|
+
import { Transaction as core_Transaction } from 'ox/tempo';
|
|
3
|
+
import * as z from 'zod/mini';
|
|
4
|
+
export function resolveChainId(value) {
|
|
5
|
+
if (typeof value === 'number')
|
|
6
|
+
return value;
|
|
7
|
+
if (typeof value === 'bigint')
|
|
8
|
+
return Number(value);
|
|
9
|
+
if (typeof value === 'string' && Hex.validate(value))
|
|
10
|
+
return Hex.toNumber(value);
|
|
11
|
+
return undefined;
|
|
12
|
+
}
|
|
13
|
+
export function formatFillTransactionRequest(client, value) {
|
|
14
|
+
const format = client.chain?.formatters?.transactionRequest?.format;
|
|
15
|
+
if (!format)
|
|
16
|
+
return value;
|
|
17
|
+
return format({ ...value }, 'fillTransaction');
|
|
18
|
+
}
|
|
19
|
+
export function normalizeFillTransactionRequest(value) {
|
|
20
|
+
if (typeof value.to !== 'undefined' || typeof value.data !== 'undefined')
|
|
21
|
+
return value;
|
|
22
|
+
if (!Array.isArray(value.calls) || value.calls.length !== 1)
|
|
23
|
+
return value;
|
|
24
|
+
const [call] = value.calls;
|
|
25
|
+
const { calls: _, ...rest } = value;
|
|
26
|
+
return {
|
|
27
|
+
...rest,
|
|
28
|
+
...(typeof call?.data !== 'undefined' ? { data: call.data } : {}),
|
|
29
|
+
...(typeof call?.to !== 'undefined' ? { to: call.to } : {}),
|
|
30
|
+
...(typeof call?.value !== 'undefined' ? { value: normalizeFillValue(call.value) } : {}),
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
function normalizeFillValue(value) {
|
|
34
|
+
if (typeof value !== 'string' || !value.startsWith('0x'))
|
|
35
|
+
return value;
|
|
36
|
+
return BigInt(value === '0x' ? '0x0' : value);
|
|
37
|
+
}
|
|
38
|
+
export function normalizeTempoTransaction(value) {
|
|
39
|
+
if (!value)
|
|
40
|
+
throw new Error('Expected `tx` in eth_fillTransaction response.');
|
|
41
|
+
return core_Transaction.fromRpc({ type: '0x76', ...value });
|
|
42
|
+
}
|
|
43
|
+
export function rpcError(request, error) {
|
|
44
|
+
if (error instanceof RpcResponse.InvalidParamsError)
|
|
45
|
+
return Response.json(RpcResponse.from({ error }, { request }));
|
|
46
|
+
if (error instanceof RpcResponse.MethodNotSupportedError)
|
|
47
|
+
return Response.json(RpcResponse.from({ error }, { request }));
|
|
48
|
+
if (error.name === 'ZodError')
|
|
49
|
+
return Response.json(RpcResponse.from({
|
|
50
|
+
error: new RpcResponse.InvalidParamsError({
|
|
51
|
+
message: error.message,
|
|
52
|
+
}),
|
|
53
|
+
}, { request }));
|
|
54
|
+
const inner = resolveError(error);
|
|
55
|
+
const message = inner.message ?? error.message;
|
|
56
|
+
const code = inner.code ?? -32603;
|
|
57
|
+
const data = inner.data;
|
|
58
|
+
return Response.json(RpcResponse.from({
|
|
59
|
+
error: { code, message, ...(data ? { data } : {}) },
|
|
60
|
+
}, { request }));
|
|
61
|
+
}
|
|
62
|
+
export function rpcResult(request, result) {
|
|
63
|
+
return Response.json(RpcResponse.from({ result }, { request }));
|
|
64
|
+
}
|
|
65
|
+
export const parseParams = z.readonly(z.tuple([z.record(z.string(), z.unknown())]));
|
|
66
|
+
function resolveError(error) {
|
|
67
|
+
if (!error || typeof error !== 'object')
|
|
68
|
+
return {};
|
|
69
|
+
const e = error;
|
|
70
|
+
// Walk to the innermost cause with a numeric code (raw RPC error).
|
|
71
|
+
if (e.cause && typeof e.cause === 'object') {
|
|
72
|
+
const inner = resolveError(e.cause);
|
|
73
|
+
if (inner.message)
|
|
74
|
+
return inner;
|
|
75
|
+
}
|
|
76
|
+
if (typeof e.code === 'number' && typeof e.message === 'string')
|
|
77
|
+
return { message: e.message, code: e.code, data: e.data };
|
|
78
|
+
return {};
|
|
79
|
+
}
|
|
80
|
+
//# sourceMappingURL=utils.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utils.js","sourceRoot":"","sources":["../../../../src/server/internal/handlers/utils.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { type Handler, from } from '../../Handler.js';
|
|
2
|
+
import * as Kv from '../../Kv.js';
|
|
3
|
+
/**
|
|
4
|
+
* Instantiates a WebAuthn ceremony handler that manages registration and
|
|
5
|
+
* authentication flows server-side.
|
|
6
|
+
*
|
|
7
|
+
* Exposes 4 POST endpoints following the webauthx convention:
|
|
8
|
+
* - `POST /register/options` — generate credential creation options
|
|
9
|
+
* - `POST /register` — verify registration and store credential
|
|
10
|
+
* - `POST /login/options` — generate credential request options
|
|
11
|
+
* - `POST /login` — verify authentication
|
|
12
|
+
*
|
|
13
|
+
* @example
|
|
14
|
+
* ```ts
|
|
15
|
+
* import { Handler, Kv } from 'accounts/server'
|
|
16
|
+
*
|
|
17
|
+
* const handler = Handler.webAuthn({
|
|
18
|
+
* kv: Kv.memory(),
|
|
19
|
+
* origin: 'https://example.com',
|
|
20
|
+
* rpId: 'example.com',
|
|
21
|
+
* })
|
|
22
|
+
*
|
|
23
|
+
* export default handler
|
|
24
|
+
* ```
|
|
25
|
+
*
|
|
26
|
+
* @param options - Options.
|
|
27
|
+
* @returns Request handler.
|
|
28
|
+
*/
|
|
29
|
+
export declare function webAuthn(options: webAuthn.Options): Handler;
|
|
30
|
+
export declare namespace webAuthn {
|
|
31
|
+
type Options = from.Options & {
|
|
32
|
+
/** Maximum age of a challenge in seconds before it expires. @default 300 */
|
|
33
|
+
challengeTtl?: number | undefined;
|
|
34
|
+
/** Key-value store for challenges and credentials. */
|
|
35
|
+
kv: Kv.Kv;
|
|
36
|
+
/** Called after a successful registration. The returned response is merged onto the default JSON response. */
|
|
37
|
+
onRegister?: (parameters: {
|
|
38
|
+
credentialId: string;
|
|
39
|
+
publicKey: string;
|
|
40
|
+
request: Request;
|
|
41
|
+
}) => Response | Promise<Response> | void | Promise<void>;
|
|
42
|
+
/** Called after a successful authentication. The returned response is merged onto the default JSON response. */
|
|
43
|
+
onAuthenticate?: (parameters: {
|
|
44
|
+
credentialId: string;
|
|
45
|
+
publicKey: string;
|
|
46
|
+
userId?: string | undefined;
|
|
47
|
+
request: Request;
|
|
48
|
+
}) => Response | Promise<Response> | void | Promise<void>;
|
|
49
|
+
/** Expected origin(s) (e.g. `"https://example.com"` or `["https://a.com", "https://b.com"]`). */
|
|
50
|
+
origin: string | readonly string[];
|
|
51
|
+
/** Path prefix for the WebAuthn endpoints (e.g. `"/webauthn"`). @default "" */
|
|
52
|
+
path?: string | undefined;
|
|
53
|
+
/** Relying Party ID (e.g. `"example.com"`). */
|
|
54
|
+
rpId: string;
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
//# sourceMappingURL=webAuthn.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"webAuthn.d.ts","sourceRoot":"","sources":["../../../../src/server/internal/handlers/webAuthn.ts"],"names":[],"mappings":"AAQA,OAAO,EAAE,KAAK,OAAO,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAA;AACrD,OAAO,KAAK,EAAE,MAAM,aAAa,CAAA;AAEjC;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,wBAAgB,QAAQ,CAAC,OAAO,EAAE,QAAQ,CAAC,OAAO,GAAG,OAAO,CAqI3D;AAED,MAAM,CAAC,OAAO,WAAW,QAAQ,CAAC;IAChC,KAAK,OAAO,GAAG,IAAI,CAAC,OAAO,GAAG;QAC5B,4EAA4E;QAC5E,YAAY,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;QACjC,sDAAsD;QACtD,EAAE,EAAE,EAAE,CAAC,EAAE,CAAA;QACT,8GAA8G;QAC9G,UAAU,CAAC,EAAE,CAAC,UAAU,EAAE;YACxB,YAAY,EAAE,MAAM,CAAA;YACpB,SAAS,EAAE,MAAM,CAAA;YACjB,OAAO,EAAE,OAAO,CAAA;SACjB,KAAK,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC,GAAG,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;QACzD,gHAAgH;QAChH,cAAc,CAAC,EAAE,CAAC,UAAU,EAAE;YAC5B,YAAY,EAAE,MAAM,CAAA;YACpB,SAAS,EAAE,MAAM,CAAA;YACjB,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;YAC3B,OAAO,EAAE,OAAO,CAAA;SACjB,KAAK,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC,GAAG,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;QACzD,iGAAiG;QACjG,MAAM,EAAE,MAAM,GAAG,SAAS,MAAM,EAAE,CAAA;QAClC,+EAA+E;QAC/E,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;QACzB,+CAA+C;QAC/C,IAAI,EAAE,MAAM,CAAA;KACb,CAAA;CACF"}
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
import { Base64, Bytes, Hex } from 'ox';
|
|
2
|
+
import { Credential } from 'ox/webauthn';
|
|
3
|
+
import { Authentication, Registration, } from 'webauthx/server';
|
|
4
|
+
import { from } from '../../Handler.js';
|
|
5
|
+
import * as Kv from '../../Kv.js';
|
|
6
|
+
/**
|
|
7
|
+
* Instantiates a WebAuthn ceremony handler that manages registration and
|
|
8
|
+
* authentication flows server-side.
|
|
9
|
+
*
|
|
10
|
+
* Exposes 4 POST endpoints following the webauthx convention:
|
|
11
|
+
* - `POST /register/options` — generate credential creation options
|
|
12
|
+
* - `POST /register` — verify registration and store credential
|
|
13
|
+
* - `POST /login/options` — generate credential request options
|
|
14
|
+
* - `POST /login` — verify authentication
|
|
15
|
+
*
|
|
16
|
+
* @example
|
|
17
|
+
* ```ts
|
|
18
|
+
* import { Handler, Kv } from 'accounts/server'
|
|
19
|
+
*
|
|
20
|
+
* const handler = Handler.webAuthn({
|
|
21
|
+
* kv: Kv.memory(),
|
|
22
|
+
* origin: 'https://example.com',
|
|
23
|
+
* rpId: 'example.com',
|
|
24
|
+
* })
|
|
25
|
+
*
|
|
26
|
+
* export default handler
|
|
27
|
+
* ```
|
|
28
|
+
*
|
|
29
|
+
* @param options - Options.
|
|
30
|
+
* @returns Request handler.
|
|
31
|
+
*/
|
|
32
|
+
export function webAuthn(options) {
|
|
33
|
+
const { challengeTtl = 300, kv, onAuthenticate, onRegister, path = '', rpId, ...rest } = options;
|
|
34
|
+
const origin = options.origin;
|
|
35
|
+
const router = from(rest);
|
|
36
|
+
router.post(`${path}/register/options`, async (c) => {
|
|
37
|
+
try {
|
|
38
|
+
const body = await c.req.raw.json();
|
|
39
|
+
const { excludeCredentialIds, name, userId } = body;
|
|
40
|
+
const { challenge, options } = Registration.getOptions({
|
|
41
|
+
excludeCredentialIds,
|
|
42
|
+
name,
|
|
43
|
+
rp: { id: rpId, name: rpId },
|
|
44
|
+
...(userId ? { user: { id: new TextEncoder().encode(userId), name } } : undefined),
|
|
45
|
+
});
|
|
46
|
+
await kv.set(`challenge:${challenge}`, Date.now());
|
|
47
|
+
return Response.json({ options });
|
|
48
|
+
}
|
|
49
|
+
catch (error) {
|
|
50
|
+
return Response.json({ error: error.message }, { status: 400 });
|
|
51
|
+
}
|
|
52
|
+
});
|
|
53
|
+
router.post(`${path}/register`, async (c) => {
|
|
54
|
+
try {
|
|
55
|
+
const credential = (await c.req.raw.json());
|
|
56
|
+
const deserialized = Credential.deserialize(credential);
|
|
57
|
+
const clientData = JSON.parse(Bytes.toString(new Uint8Array(deserialized.clientDataJSON)));
|
|
58
|
+
const challenge = Hex.fromBytes(Base64.toBytes(clientData.challenge));
|
|
59
|
+
const stored = await kv.get(`challenge:${challenge}`);
|
|
60
|
+
if (!stored || Date.now() - stored > challengeTtl * 1_000)
|
|
61
|
+
throw new Error('Missing or expired challenge');
|
|
62
|
+
await kv.delete(`challenge:${challenge}`);
|
|
63
|
+
const result = Registration.verify(credential, {
|
|
64
|
+
challenge,
|
|
65
|
+
origin,
|
|
66
|
+
rpId,
|
|
67
|
+
});
|
|
68
|
+
const { publicKey } = result.credential;
|
|
69
|
+
const credentialId = credential.id;
|
|
70
|
+
await kv.set(`credential:${credentialId}`, { publicKey });
|
|
71
|
+
const json = { credentialId, publicKey };
|
|
72
|
+
const hook = await onRegister?.({ credentialId, publicKey, request: c.req.raw });
|
|
73
|
+
return mergeResponse(json, hook);
|
|
74
|
+
}
|
|
75
|
+
catch (error) {
|
|
76
|
+
return Response.json({ error: error.message }, { status: 400 });
|
|
77
|
+
}
|
|
78
|
+
});
|
|
79
|
+
router.post(`${path}/login/options`, async (c) => {
|
|
80
|
+
try {
|
|
81
|
+
const body = await c.req.raw.json();
|
|
82
|
+
const { allowCredentialIds, challenge: requestChallenge, credentialId, mediation, } = body;
|
|
83
|
+
const { challenge, options: authOptions } = Authentication.getOptions({
|
|
84
|
+
challenge: requestChallenge,
|
|
85
|
+
credentialId: allowCredentialIds ?? credentialId,
|
|
86
|
+
rpId,
|
|
87
|
+
});
|
|
88
|
+
const options = mediation ? { ...authOptions, mediation } : authOptions;
|
|
89
|
+
await kv.set(`challenge:${challenge}`, Date.now());
|
|
90
|
+
return Response.json({ options });
|
|
91
|
+
}
|
|
92
|
+
catch (error) {
|
|
93
|
+
return Response.json({ error: error.message }, { status: 400 });
|
|
94
|
+
}
|
|
95
|
+
});
|
|
96
|
+
router.post(`${path}/login`, async (c) => {
|
|
97
|
+
try {
|
|
98
|
+
const response = (await c.req.raw.json());
|
|
99
|
+
const clientData = JSON.parse(response.metadata.clientDataJSON);
|
|
100
|
+
const challenge = Hex.fromBytes(Base64.toBytes(clientData.challenge));
|
|
101
|
+
const stored = await kv.get(`challenge:${challenge}`);
|
|
102
|
+
if (!stored || Date.now() - stored > challengeTtl * 1_000)
|
|
103
|
+
throw new Error('Missing or expired challenge');
|
|
104
|
+
await kv.delete(`challenge:${challenge}`);
|
|
105
|
+
const credentialData = await kv.get(`credential:${response.id}`);
|
|
106
|
+
if (!credentialData)
|
|
107
|
+
throw new Error('Unknown credential');
|
|
108
|
+
const valid = Authentication.verify(response, {
|
|
109
|
+
challenge,
|
|
110
|
+
origin,
|
|
111
|
+
publicKey: credentialData.publicKey,
|
|
112
|
+
rpId,
|
|
113
|
+
});
|
|
114
|
+
if (!valid)
|
|
115
|
+
throw new Error('Authentication failed');
|
|
116
|
+
const rawResponse = response.raw?.response;
|
|
117
|
+
const userHandle = rawResponse?.userHandle;
|
|
118
|
+
const json = {
|
|
119
|
+
credentialId: response.id,
|
|
120
|
+
publicKey: credentialData.publicKey,
|
|
121
|
+
...(userHandle && userHandle.length > 0 ? { userId: userHandle } : undefined),
|
|
122
|
+
};
|
|
123
|
+
const hook = await onAuthenticate?.({ ...json, request: c.req.raw });
|
|
124
|
+
return mergeResponse(json, hook);
|
|
125
|
+
}
|
|
126
|
+
catch (error) {
|
|
127
|
+
return Response.json({ error: error.message }, { status: 400 });
|
|
128
|
+
}
|
|
129
|
+
});
|
|
130
|
+
return router;
|
|
131
|
+
}
|
|
132
|
+
async function mergeResponse(json, hook) {
|
|
133
|
+
if (!hook)
|
|
134
|
+
return Response.json(json);
|
|
135
|
+
const extra = (await hook.json().catch(() => ({})));
|
|
136
|
+
const headers = new Headers(hook.headers);
|
|
137
|
+
headers.set('content-type', 'application/json');
|
|
138
|
+
return new Response(JSON.stringify({ ...json, ...extra }), {
|
|
139
|
+
headers,
|
|
140
|
+
status: hook.status,
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
//# sourceMappingURL=webAuthn.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"webAuthn.js","sourceRoot":"","sources":["../../../../src/server/internal/handlers/webAuthn.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -2,13 +2,13 @@
|
|
|
2
2
|
"name": "accounts",
|
|
3
3
|
"description": "Tempo Accounts SDK",
|
|
4
4
|
"type": "module",
|
|
5
|
-
"version": "0.6.
|
|
5
|
+
"version": "0.6.2",
|
|
6
6
|
"dependencies": {
|
|
7
7
|
"hono": "^4.12.12",
|
|
8
8
|
"idb-keyval": "^6.2.2",
|
|
9
9
|
"mipd": "^0.0.7",
|
|
10
10
|
"mppx": "^0.5.10",
|
|
11
|
-
"ox": "~0.14.
|
|
11
|
+
"ox": "~0.14.15",
|
|
12
12
|
"webauthx": "~0.1.0",
|
|
13
13
|
"zod": "^4.3.6",
|
|
14
14
|
"zustand": "^5.0.11"
|
package/src/core/Adapter.ts
CHANGED
|
@@ -133,8 +133,8 @@ export declare namespace getClient {
|
|
|
133
133
|
type Options = {
|
|
134
134
|
/** Chain ID. Defaults to the active chain. */
|
|
135
135
|
chainId?: number | undefined
|
|
136
|
-
/** Fee payer service URL. */
|
|
137
|
-
feePayer?: string | undefined
|
|
136
|
+
/** Fee payer service URL, or `false` to opt out of fee payers for this transaction if set globally. */
|
|
137
|
+
feePayer?: string | false | undefined
|
|
138
138
|
}
|
|
139
139
|
}
|
|
140
140
|
|
package/src/core/Client.ts
CHANGED
|
@@ -20,12 +20,18 @@ export function fromChainId(
|
|
|
20
20
|
options: fromChainId.Options,
|
|
21
21
|
): Client<Transport, typeof tempo> {
|
|
22
22
|
const { chains, feePayer: feePayerOption, provider, store } = options
|
|
23
|
-
const feePayerUrl =
|
|
24
|
-
|
|
25
|
-
(typeof feePayerOption === '
|
|
26
|
-
|
|
23
|
+
const feePayerUrl = (() => {
|
|
24
|
+
if (feePayerOption === false) return undefined
|
|
25
|
+
if (typeof feePayerOption === 'string') return feePayerOption
|
|
26
|
+
return feePayerOption?.url
|
|
27
|
+
})()
|
|
28
|
+
const precedence = (() => {
|
|
29
|
+
if (typeof feePayerOption === 'object' && feePayerOption !== null)
|
|
30
|
+
return feePayerOption.precedence ?? 'fee-payer-first'
|
|
31
|
+
return 'fee-payer-first'
|
|
32
|
+
})()
|
|
27
33
|
const id = chainId ?? store.getState().chainId
|
|
28
|
-
const key = `${id}:${provider ? 'p' : ''}:${feePayerUrl ?? ''}:${precedence}`
|
|
34
|
+
const key = `${id}:${provider ? 'p' : ''}:${feePayerOption === false ? 'no-fp' : (feePayerUrl ?? '')}:${precedence}`
|
|
29
35
|
let client = clients.get(key)
|
|
30
36
|
if (!client) {
|
|
31
37
|
const chain = chains.find((c) => c.id === id) ?? chains[0]!
|
|
@@ -44,9 +50,10 @@ export declare namespace fromChainId {
|
|
|
44
50
|
type Options = {
|
|
45
51
|
/** Supported chains. */
|
|
46
52
|
chains: readonly [Chain, ...Chain[]]
|
|
47
|
-
/** Fee payer configuration. A URL string
|
|
53
|
+
/** Fee payer configuration. A URL string, config object, or `false` to opt out. */
|
|
48
54
|
feePayer?:
|
|
49
55
|
| string
|
|
56
|
+
| false
|
|
50
57
|
| {
|
|
51
58
|
/** Fee payer service URL. */
|
|
52
59
|
url: string
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { Hex } from 'ox'
|
|
1
|
+
import { Hex, WebCryptoP256 } from 'ox'
|
|
2
2
|
import { type Address, createClient, defineChain, parseUnits } from 'viem'
|
|
3
3
|
import { tempoLocalnet, tempoModerato } from 'viem/chains'
|
|
4
|
-
import { Actions, Addresses } from 'viem/tempo'
|
|
4
|
+
import { Account as TempoAccount, Actions, Addresses } from 'viem/tempo'
|
|
5
5
|
import { afterEach, beforeAll, describe, expect, test } from 'vp/test'
|
|
6
6
|
|
|
7
7
|
import { accounts, http } from '../../test/config.js'
|
|
@@ -311,6 +311,27 @@ describe('wallet_authorizeAccessKey', () => {
|
|
|
311
311
|
)
|
|
312
312
|
expect(result.keyAuthorization.address).toMatch(/^0x[0-9a-fA-F]{40}$/)
|
|
313
313
|
})
|
|
314
|
+
|
|
315
|
+
test('behavior: authorizes an external p256 access key via iframe confirm', async () => {
|
|
316
|
+
provider = getProvider()
|
|
317
|
+
await connectViaIframe(provider)
|
|
318
|
+
|
|
319
|
+
const keyPair = await WebCryptoP256.createKeyPair()
|
|
320
|
+
const accessKeyAccount = TempoAccount.fromWebCryptoP256(keyPair)
|
|
321
|
+
|
|
322
|
+
const result = await interact(
|
|
323
|
+
provider.request({
|
|
324
|
+
method: 'wallet_authorizeAccessKey',
|
|
325
|
+
params: [{ ...accessKeyAccount, expiry: Expiry.days(1) }],
|
|
326
|
+
}),
|
|
327
|
+
async (iframe) => {
|
|
328
|
+
await iframe.getByTestId('confirm').click()
|
|
329
|
+
},
|
|
330
|
+
)
|
|
331
|
+
|
|
332
|
+
expect(result.keyAuthorization.keyId).toBe(accessKeyAccount.address)
|
|
333
|
+
expect(result.keyAuthorization.keyType).toMatchInlineSnapshot(`"p256"`)
|
|
334
|
+
})
|
|
314
335
|
})
|
|
315
336
|
|
|
316
337
|
describe('wallet_revokeAccessKey', () => {
|