@daski/pay 0.3.0 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +18 -11
- package/dist/bin/daski.js +26 -11
- package/dist/bin/daski.js.map +1 -1
- package/dist/chain/reader.d.ts +92 -0
- package/dist/chain/reader.d.ts.map +1 -0
- package/dist/chain/reader.js +130 -0
- package/dist/chain/reader.js.map +1 -0
- package/dist/commands/approval.js +2 -2
- package/dist/commands/approval.js.map +1 -1
- package/dist/commands/buy.d.ts +0 -1
- package/dist/commands/buy.d.ts.map +1 -1
- package/dist/commands/buy.js +15 -22
- package/dist/commands/buy.js.map +1 -1
- package/dist/commands/confirmation.d.ts +322 -4
- package/dist/commands/confirmation.d.ts.map +1 -1
- package/dist/commands/confirmation.js +771 -60
- package/dist/commands/confirmation.js.map +1 -1
- package/dist/commands/doctor.d.ts +20 -0
- package/dist/commands/doctor.d.ts.map +1 -1
- package/dist/commands/doctor.js +204 -59
- package/dist/commands/doctor.js.map +1 -1
- package/dist/commands/order.d.ts +37 -6
- package/dist/commands/order.d.ts.map +1 -1
- package/dist/commands/order.js +181 -103
- package/dist/commands/order.js.map +1 -1
- package/dist/commands/signPayment.d.ts +2 -2
- package/dist/commands/signPayment.d.ts.map +1 -1
- package/dist/commands/signPayment.js +10 -5
- package/dist/commands/signPayment.js.map +1 -1
- package/dist/commands/wallet.d.ts +3 -0
- package/dist/commands/wallet.d.ts.map +1 -1
- package/dist/commands/wallet.js +72 -16
- package/dist/commands/wallet.js.map +1 -1
- package/dist/config.d.ts +10 -2
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +41 -1
- package/dist/config.js.map +1 -1
- package/dist/context.d.ts +28 -3
- package/dist/context.d.ts.map +1 -1
- package/dist/context.js +72 -3
- package/dist/context.js.map +1 -1
- package/dist/gateway/client.d.ts +20 -17
- package/dist/gateway/client.d.ts.map +1 -1
- package/dist/gateway/client.js +62 -43
- package/dist/gateway/client.js.map +1 -1
- package/dist/gateway/lifecycle.d.ts +4 -1
- package/dist/gateway/lifecycle.d.ts.map +1 -1
- package/dist/gateway/lifecycle.js +10 -5
- package/dist/gateway/lifecycle.js.map +1 -1
- package/dist/gateway/metadata.d.ts +66 -0
- package/dist/gateway/metadata.d.ts.map +1 -0
- package/dist/gateway/metadata.js +152 -0
- package/dist/gateway/metadata.js.map +1 -0
- package/dist/gateway/purchase.d.ts +51 -67
- package/dist/gateway/purchase.d.ts.map +1 -1
- package/dist/gateway/purchase.js +153 -125
- package/dist/gateway/purchase.js.map +1 -1
- package/dist/host.d.ts +41 -0
- package/dist/host.d.ts.map +1 -0
- package/dist/host.js +112 -0
- package/dist/host.js.map +1 -0
- package/dist/index.d.ts +12 -6
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +10 -4
- package/dist/index.js.map +1 -1
- package/dist/signers/circleAgent.d.ts +37 -0
- package/dist/signers/circleAgent.d.ts.map +1 -0
- package/dist/signers/circleAgent.js +244 -0
- package/dist/signers/circleAgent.js.map +1 -0
- package/dist/signers/contract.d.ts +34 -0
- package/dist/signers/contract.d.ts.map +1 -0
- package/dist/signers/contract.js +47 -0
- package/dist/signers/contract.js.map +1 -0
- package/dist/signers/index.d.ts +16 -7
- package/dist/signers/index.d.ts.map +1 -1
- package/dist/signers/index.js +7 -3
- package/dist/signers/index.js.map +1 -1
- package/dist/signers/local.d.ts +5 -1
- package/dist/signers/local.d.ts.map +1 -1
- package/dist/signers/local.js +16 -3
- package/dist/signers/local.js.map +1 -1
- package/dist/signers/selfTest.d.ts +32 -12
- package/dist/signers/selfTest.d.ts.map +1 -1
- package/dist/signers/selfTest.js +85 -12
- package/dist/signers/selfTest.js.map +1 -1
- package/dist/signers/signature.d.ts +10 -0
- package/dist/signers/signature.d.ts.map +1 -0
- package/dist/signers/signature.js +11 -0
- package/dist/signers/signature.js.map +1 -0
- package/dist/store/keystore.d.ts +48 -6
- package/dist/store/keystore.d.ts.map +1 -1
- package/dist/store/keystore.js +414 -110
- package/dist/store/keystore.js.map +1 -1
- package/dist/store/lock.d.ts +59 -0
- package/dist/store/lock.d.ts.map +1 -0
- package/dist/store/lock.js +269 -0
- package/dist/store/lock.js.map +1 -0
- package/dist/store/orders.d.ts +49 -9
- package/dist/store/orders.d.ts.map +1 -1
- package/dist/store/orders.js +173 -37
- package/dist/store/orders.js.map +1 -1
- package/package.json +2 -2
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What a contract-account signer must satisfy before it may buy.
|
|
3
|
+
*
|
|
4
|
+
* Two facts, both read rather than trusted: the gateway must verify contract
|
|
5
|
+
* accounts at all (`payerAccounts.types` in its well-known document), and the
|
|
6
|
+
* wallet must be deployed (`getCode` non-empty), because a counterfactual
|
|
7
|
+
* signature is refused at the gateway and the facilitator alike and a refusal
|
|
8
|
+
* there must never be the first signal. An EOA signer passes through here
|
|
9
|
+
* without a single RPC call (T7).
|
|
10
|
+
*/
|
|
11
|
+
import type { Address } from "viem";
|
|
12
|
+
import type { SignerAdapter } from "@daski/x402-scheme";
|
|
13
|
+
import { type ChainReader } from "../chain/reader.js";
|
|
14
|
+
import { CliError } from "../cli/errors.js";
|
|
15
|
+
import type { GatewayMetadata } from "../gateway/metadata.js";
|
|
16
|
+
export type Deployment = "deployed" | "not-deployed" | "not-applicable";
|
|
17
|
+
export declare const NOT_DEPLOYED_REMEDIATION = "Send a zero-value transfer from the wallet to itself with the circle CLI, then run doctor again.";
|
|
18
|
+
export declare function isContractSigner(signer: SignerAdapter): boolean;
|
|
19
|
+
export declare function signerNotDeployed(address: Address): CliError;
|
|
20
|
+
export declare function gatewayEoaOnly(gatewayUrl: string): CliError;
|
|
21
|
+
/** Whether a signer's wallet is deployed. EOA signers are not applicable and cost no RPC. */
|
|
22
|
+
export declare function checkDeployment(signer: SignerAdapter, chain: ChainReader): Promise<Deployment>;
|
|
23
|
+
/**
|
|
24
|
+
* Refuses a contract signer the gateway cannot verify or the chain has not
|
|
25
|
+
* seen deployed. Called before a purchase asks for a challenge, so nothing is
|
|
26
|
+
* signed for a wallet that cannot pay.
|
|
27
|
+
*/
|
|
28
|
+
export declare function assertContractSignerUsable(args: {
|
|
29
|
+
signer: SignerAdapter;
|
|
30
|
+
chain: ChainReader;
|
|
31
|
+
metadata: () => Promise<GatewayMetadata>;
|
|
32
|
+
gatewayUrl: string;
|
|
33
|
+
}): Promise<void>;
|
|
34
|
+
//# sourceMappingURL=contract.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"contract.d.ts","sourceRoot":"","sources":["../../src/signers/contract.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,MAAM,CAAC;AACpC,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACxD,OAAO,EAAkB,KAAK,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACtE,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAE9D,MAAM,MAAM,UAAU,GAAG,UAAU,GAAG,cAAc,GAAG,gBAAgB,CAAC;AAExE,eAAO,MAAM,wBAAwB,qGAC+D,CAAC;AAErG,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,aAAa,GAAG,OAAO,CAE/D;AAED,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,OAAO,GAAG,QAAQ,CAQ5D;AAED,wBAAgB,cAAc,CAAC,UAAU,EAAE,MAAM,GAAG,QAAQ,CAW3D;AAED,6FAA6F;AAC7F,wBAAsB,eAAe,CAAC,MAAM,EAAE,aAAa,EAAE,KAAK,EAAE,WAAW,GAAG,OAAO,CAAC,UAAU,CAAC,CAIpG;AAED;;;;GAIG;AACH,wBAAsB,0BAA0B,CAAC,IAAI,EAAE;IACrD,MAAM,EAAE,aAAa,CAAC;IACtB,KAAK,EAAE,WAAW,CAAC;IACnB,QAAQ,EAAE,MAAM,OAAO,CAAC,eAAe,CAAC,CAAC;IACzC,UAAU,EAAE,MAAM,CAAC;CACpB,GAAG,OAAO,CAAC,IAAI,CAAC,CAMhB"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { isDeployedCode } from "../chain/reader.js";
|
|
2
|
+
import { CliError } from "../cli/errors.js";
|
|
3
|
+
export const NOT_DEPLOYED_REMEDIATION = "Send a zero-value transfer from the wallet to itself with the circle CLI, then run doctor again.";
|
|
4
|
+
export function isContractSigner(signer) {
|
|
5
|
+
return signer.describe().accountType === "contract";
|
|
6
|
+
}
|
|
7
|
+
export function signerNotDeployed(address) {
|
|
8
|
+
return new CliError({
|
|
9
|
+
code: "DASKI_SIGNER_NOT_DEPLOYED",
|
|
10
|
+
message: `The contract wallet ${address} has no code on this chain, so its signatures cannot be ` +
|
|
11
|
+
"verified and its purchases would be refused as counterfactual.",
|
|
12
|
+
remediation: NOT_DEPLOYED_REMEDIATION,
|
|
13
|
+
});
|
|
14
|
+
}
|
|
15
|
+
export function gatewayEoaOnly(gatewayUrl) {
|
|
16
|
+
return new CliError({
|
|
17
|
+
code: "DASKI_GATEWAY_EOA_ONLY",
|
|
18
|
+
message: `The gateway at ${gatewayUrl} verifies plain wallets (EOA) only; it does not list ` +
|
|
19
|
+
"contract accounts under payerAccounts.types, so a contract wallet cannot buy there yet.",
|
|
20
|
+
remediation: "On a durable machine use a local key (daski wallet create). On an ephemeral host, stop " +
|
|
21
|
+
"and tell the user that purchasing from this host is not available until the gateway " +
|
|
22
|
+
"enables contract wallets.",
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
/** Whether a signer's wallet is deployed. EOA signers are not applicable and cost no RPC. */
|
|
26
|
+
export async function checkDeployment(signer, chain) {
|
|
27
|
+
if (!isContractSigner(signer))
|
|
28
|
+
return "not-applicable";
|
|
29
|
+
const code = await chain.getCode(await signer.getAddress());
|
|
30
|
+
return isDeployedCode(code) ? "deployed" : "not-deployed";
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Refuses a contract signer the gateway cannot verify or the chain has not
|
|
34
|
+
* seen deployed. Called before a purchase asks for a challenge, so nothing is
|
|
35
|
+
* signed for a wallet that cannot pay.
|
|
36
|
+
*/
|
|
37
|
+
export async function assertContractSignerUsable(args) {
|
|
38
|
+
if (!isContractSigner(args.signer))
|
|
39
|
+
return;
|
|
40
|
+
const metadata = await args.metadata();
|
|
41
|
+
if (!metadata.payerAccounts?.types.includes("contract"))
|
|
42
|
+
throw gatewayEoaOnly(args.gatewayUrl);
|
|
43
|
+
const address = await args.signer.getAddress();
|
|
44
|
+
if (!isDeployedCode(await args.chain.getCode(address)))
|
|
45
|
+
throw signerNotDeployed(address);
|
|
46
|
+
}
|
|
47
|
+
//# sourceMappingURL=contract.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"contract.js","sourceRoot":"","sources":["../../src/signers/contract.ts"],"names":[],"mappings":"AAYA,OAAO,EAAE,cAAc,EAAoB,MAAM,oBAAoB,CAAC;AACtE,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAK5C,MAAM,CAAC,MAAM,wBAAwB,GACnC,kGAAkG,CAAC;AAErG,MAAM,UAAU,gBAAgB,CAAC,MAAqB;IACpD,OAAO,MAAM,CAAC,QAAQ,EAAE,CAAC,WAAW,KAAK,UAAU,CAAC;AACtD,CAAC;AAED,MAAM,UAAU,iBAAiB,CAAC,OAAgB;IAChD,OAAO,IAAI,QAAQ,CAAC;QAClB,IAAI,EAAE,2BAA2B;QACjC,OAAO,EACL,uBAAuB,OAAO,0DAA0D;YACxF,gEAAgE;QAClE,WAAW,EAAE,wBAAwB;KACtC,CAAC,CAAC;AACL,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,UAAkB;IAC/C,OAAO,IAAI,QAAQ,CAAC;QAClB,IAAI,EAAE,wBAAwB;QAC9B,OAAO,EACL,kBAAkB,UAAU,uDAAuD;YACnF,yFAAyF;QAC3F,WAAW,EACT,yFAAyF;YACzF,sFAAsF;YACtF,2BAA2B;KAC9B,CAAC,CAAC;AACL,CAAC;AAED,6FAA6F;AAC7F,MAAM,CAAC,KAAK,UAAU,eAAe,CAAC,MAAqB,EAAE,KAAkB;IAC7E,IAAI,CAAC,gBAAgB,CAAC,MAAM,CAAC;QAAE,OAAO,gBAAgB,CAAC;IACvD,MAAM,IAAI,GAAG,MAAM,KAAK,CAAC,OAAO,CAAC,MAAM,MAAM,CAAC,UAAU,EAAE,CAAC,CAAC;IAC5D,OAAO,cAAc,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,cAAc,CAAC;AAC5D,CAAC;AAED;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,0BAA0B,CAAC,IAKhD;IACC,IAAI,CAAC,gBAAgB,CAAC,IAAI,CAAC,MAAM,CAAC;QAAE,OAAO;IAC3C,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,QAAQ,EAAE,CAAC;IACvC,IAAI,CAAC,QAAQ,CAAC,aAAa,EAAE,KAAK,CAAC,QAAQ,CAAC,UAAU,CAAC;QAAE,MAAM,cAAc,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;IAC/F,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,UAAU,EAAE,CAAC;IAC/C,IAAI,CAAC,cAAc,CAAC,MAAM,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;QAAE,MAAM,iBAAiB,CAAC,OAAO,CAAC,CAAC;AAC3F,CAAC"}
|
package/dist/signers/index.d.ts
CHANGED
|
@@ -1,23 +1,32 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Signer selection.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
* store, verified by the conformance suite),
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
4
|
+
* Four adapters behind one interface: `local` (a viem account from the key
|
|
5
|
+
* store, verified by the conformance suite), `circle-agent` (a deployed
|
|
6
|
+
* contract account operated through the pinned Circle CLI, the default for
|
|
7
|
+
* agent-hosted runtimes), and `cdp` and `circle` (developer-controlled
|
|
8
|
+
* candidates). Whatever the backend, the request it signs has already been
|
|
9
|
+
* through the §4 validator, and `daski doctor` puts every adapter through the
|
|
10
|
+
* self-test for its account type before calling it usable.
|
|
9
11
|
*/
|
|
10
12
|
import type { SignerAdapter } from "@daski/x402-scheme";
|
|
11
|
-
import type
|
|
13
|
+
import { type SignerKind } from "../config.js";
|
|
14
|
+
import type { HostEnvironment } from "../host.js";
|
|
12
15
|
import { createCdpSigner } from "./cdp.js";
|
|
13
16
|
import { createCircleSigner } from "./circle.js";
|
|
17
|
+
import { createCircleAgentSigner } from "./circleAgent.js";
|
|
14
18
|
import { createLocalSigner } from "./local.js";
|
|
15
19
|
export interface SignerSelection {
|
|
16
20
|
kind: SignerKind;
|
|
17
21
|
profile: string;
|
|
22
|
+
/** Where a local key may live on this host. */
|
|
23
|
+
host: HostEnvironment;
|
|
24
|
+
/** The profile's chain, which the Circle agent wallet maps to a chain name. */
|
|
25
|
+
chainId: number;
|
|
18
26
|
cdpAccount?: string | undefined;
|
|
27
|
+
/** A Circle developer-controlled wallet id, or the agent wallet address to select. */
|
|
19
28
|
circleWallet?: string | undefined;
|
|
20
29
|
}
|
|
21
30
|
export declare function createSigner(selection: SignerSelection): Promise<SignerAdapter>;
|
|
22
|
-
export { createCdpSigner, createCircleSigner, createLocalSigner };
|
|
31
|
+
export { createCdpSigner, createCircleAgentSigner, createCircleSigner, createLocalSigner };
|
|
23
32
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/signers/index.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/signers/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAExD,OAAO,EAAgB,KAAK,UAAU,EAAE,MAAM,cAAc,CAAC;AAC7D,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAClD,OAAO,EAAE,eAAe,EAAE,MAAM,UAAU,CAAC;AAC3C,OAAO,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AACjD,OAAO,EAAE,uBAAuB,EAAE,MAAM,kBAAkB,CAAC;AAC3D,OAAO,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAE/C,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,UAAU,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,+CAA+C;IAC/C,IAAI,EAAE,eAAe,CAAC;IACtB,+EAA+E;IAC/E,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAChC,sFAAsF;IACtF,YAAY,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CACnC;AAED,wBAAsB,YAAY,CAAC,SAAS,EAAE,eAAe,GAAG,OAAO,CAAC,aAAa,CAAC,CAiBrF;AAED,OAAO,EAAE,eAAe,EAAE,uBAAuB,EAAE,kBAAkB,EAAE,iBAAiB,EAAE,CAAC"}
|
package/dist/signers/index.js
CHANGED
|
@@ -1,11 +1,15 @@
|
|
|
1
1
|
import { CliError } from "../cli/errors.js";
|
|
2
|
+
import { SIGNER_KINDS } from "../config.js";
|
|
2
3
|
import { createCdpSigner } from "./cdp.js";
|
|
3
4
|
import { createCircleSigner } from "./circle.js";
|
|
5
|
+
import { createCircleAgentSigner } from "./circleAgent.js";
|
|
4
6
|
import { createLocalSigner } from "./local.js";
|
|
5
7
|
export async function createSigner(selection) {
|
|
6
8
|
switch (selection.kind) {
|
|
7
9
|
case "local":
|
|
8
|
-
return createLocalSigner(selection.profile);
|
|
10
|
+
return createLocalSigner(selection.profile, selection.host);
|
|
11
|
+
case "circle-agent":
|
|
12
|
+
return createCircleAgentSigner({ chainId: selection.chainId, address: selection.circleWallet });
|
|
9
13
|
case "cdp":
|
|
10
14
|
return createCdpSigner({ account: selection.cdpAccount });
|
|
11
15
|
case "circle":
|
|
@@ -14,9 +18,9 @@ export async function createSigner(selection) {
|
|
|
14
18
|
throw new CliError({
|
|
15
19
|
code: "DASKI_SIGNER_UNKNOWN",
|
|
16
20
|
message: `Unknown signer "${String(selection.kind)}".`,
|
|
17
|
-
remediation:
|
|
21
|
+
remediation: `Set profiles.<name>.signer to one of: ${SIGNER_KINDS.join(", ")}.`,
|
|
18
22
|
});
|
|
19
23
|
}
|
|
20
24
|
}
|
|
21
|
-
export { createCdpSigner, createCircleSigner, createLocalSigner };
|
|
25
|
+
export { createCdpSigner, createCircleAgentSigner, createCircleSigner, createLocalSigner };
|
|
22
26
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/signers/index.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/signers/index.ts"],"names":[],"mappings":"AAYA,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,EAAE,YAAY,EAAmB,MAAM,cAAc,CAAC;AAE7D,OAAO,EAAE,eAAe,EAAE,MAAM,UAAU,CAAC;AAC3C,OAAO,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AACjD,OAAO,EAAE,uBAAuB,EAAE,MAAM,kBAAkB,CAAC;AAC3D,OAAO,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAc/C,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,SAA0B;IAC3D,QAAQ,SAAS,CAAC,IAAI,EAAE,CAAC;QACvB,KAAK,OAAO;YACV,OAAO,iBAAiB,CAAC,SAAS,CAAC,OAAO,EAAE,SAAS,CAAC,IAAI,CAAC,CAAC;QAC9D,KAAK,cAAc;YACjB,OAAO,uBAAuB,CAAC,EAAE,OAAO,EAAE,SAAS,CAAC,OAAO,EAAE,OAAO,EAAE,SAAS,CAAC,YAAY,EAAE,CAAC,CAAC;QAClG,KAAK,KAAK;YACR,OAAO,eAAe,CAAC,EAAE,OAAO,EAAE,SAAS,CAAC,UAAU,EAAE,CAAC,CAAC;QAC5D,KAAK,QAAQ;YACX,OAAO,kBAAkB,CAAC,EAAE,MAAM,EAAE,SAAS,CAAC,YAAY,EAAE,CAAC,CAAC;QAChE;YACE,MAAM,IAAI,QAAQ,CAAC;gBACjB,IAAI,EAAE,sBAAsB;gBAC5B,OAAO,EAAE,mBAAmB,MAAM,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI;gBACtD,WAAW,EAAE,yCAAyC,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG;aACjF,CAAC,CAAC;IACP,CAAC;AACH,CAAC;AAED,OAAO,EAAE,eAAe,EAAE,uBAAuB,EAAE,kBAAkB,EAAE,iBAAiB,EAAE,CAAC"}
|
package/dist/signers/local.d.ts
CHANGED
|
@@ -1,3 +1,7 @@
|
|
|
1
1
|
import type { SignerAdapter } from "@daski/x402-scheme";
|
|
2
|
-
|
|
2
|
+
import { type HostEnvironment } from "../host.js";
|
|
3
|
+
import { type KeyStoreSelection } from "../store/keystore.js";
|
|
4
|
+
/** The store a profile's local key uses on this host. */
|
|
5
|
+
export declare function localKeyStore(host: HostEnvironment): KeyStoreSelection;
|
|
6
|
+
export declare function createLocalSigner(profile: string, host: HostEnvironment): Promise<SignerAdapter>;
|
|
3
7
|
//# sourceMappingURL=local.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"local.d.ts","sourceRoot":"","sources":["../../src/signers/local.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"local.d.ts","sourceRoot":"","sources":["../../src/signers/local.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAE,aAAa,EAAuC,MAAM,oBAAoB,CAAC;AAC7F,OAAO,EACmD,KAAK,eAAe,EAC7E,MAAM,YAAY,CAAC;AACpB,OAAO,EAAsB,KAAK,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AAElF,yDAAyD;AACzD,wBAAgB,aAAa,CAAC,IAAI,EAAE,eAAe,GAAG,iBAAiB,CAEtE;AAED,wBAAsB,iBAAiB,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,eAAe,GAAG,OAAO,CAAC,aAAa,CAAC,CAgBtG"}
|
package/dist/signers/local.js
CHANGED
|
@@ -3,13 +3,26 @@
|
|
|
3
3
|
*
|
|
4
4
|
* The key is held in this closure and never leaves it. `describe()` reports
|
|
5
5
|
* where it came from so `doctor` can flag the developer environment variable.
|
|
6
|
+
*
|
|
7
|
+
* Before the key is loaded, the paid-use gate runs: a Linux host whose
|
|
8
|
+
* profile key was left in the kernel session keyring by an earlier release
|
|
9
|
+
* has no durable key, and that key is never used (`DASKI_KEY_NOT_DURABLE`).
|
|
10
|
+
* Hosted signers hold no local key and are not subject to this gate.
|
|
6
11
|
*/
|
|
7
12
|
import { privateKeyToAccount } from "viem/accounts";
|
|
8
13
|
import {} from "viem";
|
|
14
|
+
import { detectLegacyKeyringEntry, keyBackendFor, keyNotDurable, } from "../host.js";
|
|
9
15
|
import { loadKey, locateKey } from "../store/keystore.js";
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
16
|
+
/** The store a profile's local key uses on this host. */
|
|
17
|
+
export function localKeyStore(host) {
|
|
18
|
+
return { host, backend: keyBackendFor(host, "local") };
|
|
19
|
+
}
|
|
20
|
+
export async function createLocalSigner(profile, host) {
|
|
21
|
+
const store = localKeyStore(host);
|
|
22
|
+
const location = await locateKey(profile, store);
|
|
23
|
+
if (!location && detectLegacyKeyringEntry(host, profile))
|
|
24
|
+
throw keyNotDurable(profile);
|
|
25
|
+
const account = privateKeyToAccount(await loadKey(profile, store));
|
|
13
26
|
const description = {
|
|
14
27
|
provider: location?.source === "environment" ? "local (env)" : "local",
|
|
15
28
|
accountType: "eoa",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"local.js","sourceRoot":"","sources":["../../src/signers/local.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"local.js","sourceRoot":"","sources":["../../src/signers/local.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,OAAO,EAAE,mBAAmB,EAAE,MAAM,eAAe,CAAC;AACpD,OAAO,EAA0B,MAAM,MAAM,CAAC;AAE9C,OAAO,EACL,wBAAwB,EAAE,aAAa,EAAE,aAAa,GACvD,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,OAAO,EAAE,SAAS,EAA0B,MAAM,sBAAsB,CAAC;AAElF,yDAAyD;AACzD,MAAM,UAAU,aAAa,CAAC,IAAqB;IACjD,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,aAAa,CAAC,IAAI,EAAE,OAAO,CAAC,EAAE,CAAC;AACzD,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,iBAAiB,CAAC,OAAe,EAAE,IAAqB;IAC5E,MAAM,KAAK,GAAG,aAAa,CAAC,IAAI,CAAC,CAAC;IAClC,MAAM,QAAQ,GAAG,MAAM,SAAS,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;IACjD,IAAI,CAAC,QAAQ,IAAI,wBAAwB,CAAC,IAAI,EAAE,OAAO,CAAC;QAAE,MAAM,aAAa,CAAC,OAAO,CAAC,CAAC;IACvF,MAAM,OAAO,GAAG,mBAAmB,CAAC,MAAM,OAAO,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC,CAAC;IACnE,MAAM,WAAW,GAAsB;QACrC,QAAQ,EAAE,QAAQ,EAAE,MAAM,KAAK,aAAa,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,OAAO;QACtE,WAAW,EAAE,KAAK;QAClB,WAAW,EAAE,UAAU;KACxB,CAAC;IACF,OAAO;QACL,UAAU,EAAE,KAAK,IAAsB,EAAE,CAAC,OAAO,CAAC,OAAO;QACzD,aAAa,EAAE,CAAC,OAAyB,EAAgB,EAAE,CACzD,OAAO,CAAC,aAAa,CAAC,OAAgB,CAAC;QACzC,QAAQ,EAAE,GAAG,EAAE,CAAC,WAAW;KAC5B,CAAC;AACJ,CAAC"}
|
|
@@ -3,11 +3,15 @@
|
|
|
3
3
|
*
|
|
4
4
|
* `daski doctor` does not take a signer's word for it. Before reporting one as
|
|
5
5
|
* usable it has the signer sign one fixed vector and checks the result the way
|
|
6
|
-
* the gateway will: the address recovered from the
|
|
7
|
-
* address the adapter claims, `s` must be in the low
|
|
8
|
-
* and the whole thing must be 65 bytes.
|
|
9
|
-
*
|
|
10
|
-
*
|
|
6
|
+
* the gateway will. For a plain wallet (EOA): the address recovered from the
|
|
7
|
+
* typed data must be the address the adapter claims, `s` must be in the low
|
|
8
|
+
* half of the curve order, and the whole thing must be 65 bytes. For a
|
|
9
|
+
* deployed contract account: the bytes are opaque beyond their size, and the
|
|
10
|
+
* contract itself must answer `isValidSignature` with the ERC-1271 magic value
|
|
11
|
+
* for the hash this CLI computed, through one bounded read-only call against
|
|
12
|
+
* the profile RPC. A signer that rewrites a field, wraps an ERC-6492 blob,
|
|
13
|
+
* emits a malleable twin, or simply throws fails here, on a machine with
|
|
14
|
+
* nothing at stake, instead of at settlement.
|
|
11
15
|
*
|
|
12
16
|
* The vector has the *shape* of a purchase — the closed 6-field
|
|
13
17
|
* `TransferWithAuthorization` type set, so an adapter that mishandles that
|
|
@@ -18,6 +22,7 @@
|
|
|
18
22
|
*/
|
|
19
23
|
import { type Address, type Hex } from "viem";
|
|
20
24
|
import { type SignerAdapter, type TypedDataRequest } from "@daski/x402-scheme";
|
|
25
|
+
import { type ChainReader } from "../chain/reader.js";
|
|
21
26
|
/** The vector's nonce: a commitment to nothing but its own name. */
|
|
22
27
|
export declare const SELF_TEST_NONCE: Hex;
|
|
23
28
|
export declare const LOW_S_MAX: bigint;
|
|
@@ -30,17 +35,32 @@ export declare const LOW_S_MAX: bigint;
|
|
|
30
35
|
export declare function selfTestVector(signerAddress: Address, chainId: number): TypedDataRequest;
|
|
31
36
|
export interface SignerSelfTestResult {
|
|
32
37
|
passed: boolean;
|
|
33
|
-
/**
|
|
38
|
+
/** How the signature verified: `recovery` for a plain wallet, `erc1271` for a contract account. */
|
|
39
|
+
verifiedVia: "recovery" | "erc1271" | null;
|
|
40
|
+
/** The address the signature recovers to on the EOA path, or null when nothing recovers. */
|
|
34
41
|
recovered: Address | null;
|
|
35
|
-
/** True when `s` is at most secp256k1n/2. */
|
|
36
|
-
lowS: boolean;
|
|
42
|
+
/** True when `s` is at most secp256k1n/2 on the EOA path; null on the contract path. */
|
|
43
|
+
lowS: boolean | null;
|
|
37
44
|
/** Why the test failed. Absent on a pass. */
|
|
38
45
|
reason?: string;
|
|
39
46
|
}
|
|
40
47
|
/**
|
|
41
|
-
*
|
|
42
|
-
*
|
|
43
|
-
* says so.
|
|
48
|
+
* Runs the self-test that matches the signer's account type. Never throws: a
|
|
49
|
+
* signer that throws has failed the test, and the reason says so.
|
|
44
50
|
*/
|
|
45
|
-
export declare function runSignerSelfTest(signer: SignerAdapter, chainId: number): Promise<SignerSelfTestResult>;
|
|
51
|
+
export declare function runSignerSelfTest(signer: SignerAdapter, chainId: number, chain?: ChainReader): Promise<SignerSelfTestResult>;
|
|
52
|
+
/**
|
|
53
|
+
* Signs the vector with `signer` and checks the signature the way the
|
|
54
|
+
* gateway's EOA path will: exactly 65 bytes, low-s, recovering to the claimed
|
|
55
|
+
* address. No RPC is involved.
|
|
56
|
+
*/
|
|
57
|
+
export declare function runEoaSignerSelfTest(signer: SignerAdapter, chainId: number): Promise<SignerSelfTestResult>;
|
|
58
|
+
/**
|
|
59
|
+
* Signs the vector and asks the deployed wallet itself whether the signature
|
|
60
|
+
* is valid for the EIP-712 hash this CLI computed: one `isValidSignature`
|
|
61
|
+
* `eth_call` with a gas bound and a deadline, accepting only the ERC-1271
|
|
62
|
+
* magic value. A revert, another value, or a malformed return fails; an RPC
|
|
63
|
+
* that cannot be reached fails with a reason that says so, never as invalid.
|
|
64
|
+
*/
|
|
65
|
+
export declare function runContractSignerSelfTest(signer: SignerAdapter, chainId: number, chain: ChainReader | undefined): Promise<SignerSelfTestResult>;
|
|
46
66
|
//# sourceMappingURL=selfTest.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"selfTest.d.ts","sourceRoot":"","sources":["../../src/signers/selfTest.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"selfTest.d.ts","sourceRoot":"","sources":["../../src/signers/selfTest.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,OAAO,EASL,KAAK,OAAO,EACZ,KAAK,GAAG,EACT,MAAM,MAAM,CAAC;AACd,OAAO,EAGL,KAAK,aAAa,EAClB,KAAK,gBAAgB,EACtB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAC0C,KAAK,WAAW,EAChE,MAAM,oBAAoB,CAAC;AAK5B,oEAAoE;AACpE,eAAO,MAAM,eAAe,EAAE,GAAsD,CAAC;AAIrF,eAAO,MAAM,SAAS,QAAmB,CAAC;AAE1C;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,aAAa,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,GAAG,gBAAgB,CAmBxF;AAED,MAAM,WAAW,oBAAoB;IACnC,MAAM,EAAE,OAAO,CAAC;IAChB,mGAAmG;IACnG,WAAW,EAAE,UAAU,GAAG,SAAS,GAAG,IAAI,CAAC;IAC3C,4FAA4F;IAC5F,SAAS,EAAE,OAAO,GAAG,IAAI,CAAC;IAC1B,wFAAwF;IACxF,IAAI,EAAE,OAAO,GAAG,IAAI,CAAC;IACrB,6CAA6C;IAC7C,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED;;;GAGG;AACH,wBAAsB,iBAAiB,CACrC,MAAM,EAAE,aAAa,EACrB,OAAO,EAAE,MAAM,EACf,KAAK,CAAC,EAAE,WAAW,GAClB,OAAO,CAAC,oBAAoB,CAAC,CAK/B;AAED;;;;GAIG;AACH,wBAAsB,oBAAoB,CACxC,MAAM,EAAE,aAAa,EACrB,OAAO,EAAE,MAAM,GACd,OAAO,CAAC,oBAAoB,CAAC,CAiD/B;AAED;;;;;;GAMG;AACH,wBAAsB,yBAAyB,CAC7C,MAAM,EAAE,aAAa,EACrB,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,WAAW,GAAG,SAAS,GAC7B,OAAO,CAAC,oBAAoB,CAAC,CAyC/B"}
|
package/dist/signers/selfTest.js
CHANGED
|
@@ -3,11 +3,15 @@
|
|
|
3
3
|
*
|
|
4
4
|
* `daski doctor` does not take a signer's word for it. Before reporting one as
|
|
5
5
|
* usable it has the signer sign one fixed vector and checks the result the way
|
|
6
|
-
* the gateway will: the address recovered from the
|
|
7
|
-
* address the adapter claims, `s` must be in the low
|
|
8
|
-
* and the whole thing must be 65 bytes.
|
|
9
|
-
*
|
|
10
|
-
*
|
|
6
|
+
* the gateway will. For a plain wallet (EOA): the address recovered from the
|
|
7
|
+
* typed data must be the address the adapter claims, `s` must be in the low
|
|
8
|
+
* half of the curve order, and the whole thing must be 65 bytes. For a
|
|
9
|
+
* deployed contract account: the bytes are opaque beyond their size, and the
|
|
10
|
+
* contract itself must answer `isValidSignature` with the ERC-1271 magic value
|
|
11
|
+
* for the hash this CLI computed, through one bounded read-only call against
|
|
12
|
+
* the profile RPC. A signer that rewrites a field, wraps an ERC-6492 blob,
|
|
13
|
+
* emits a malleable twin, or simply throws fails here, on a machine with
|
|
14
|
+
* nothing at stake, instead of at settlement.
|
|
11
15
|
*
|
|
12
16
|
* The vector has the *shape* of a purchase — the closed 6-field
|
|
13
17
|
* `TransferWithAuthorization` type set, so an adapter that mishandles that
|
|
@@ -16,8 +20,10 @@
|
|
|
16
20
|
* and recipient are zero; the validity window is closed. No contract will
|
|
17
21
|
* ever accept it.
|
|
18
22
|
*/
|
|
19
|
-
import { getAddress, hexToBigInt, keccak256, parseSignature, recoverTypedDataAddress, stringToHex, } from "viem";
|
|
23
|
+
import { encodeFunctionData, getAddress, hashTypedData, hexToBigInt, keccak256, parseSignature, recoverTypedDataAddress, stringToHex, } from "viem";
|
|
20
24
|
import { TRANSFER_WITH_AUTHORIZATION_PRIMARY_TYPE, TRANSFER_WITH_AUTHORIZATION_TYPES, } from "@daski/x402-scheme";
|
|
25
|
+
import { ERC1271_ABI, ERC1271_CALL_GAS, isErc1271Magic, } from "../chain/reader.js";
|
|
26
|
+
import { hasErc6492Suffix, isBoundedSignature, MAX_SIGNATURE_BYTES } from "./signature.js";
|
|
21
27
|
const ZERO_ADDRESS = "0x0000000000000000000000000000000000000000";
|
|
22
28
|
/** The vector's nonce: a commitment to nothing but its own name. */
|
|
23
29
|
export const SELF_TEST_NONCE = keccak256(stringToHex("daski-doctor-self-test"));
|
|
@@ -51,11 +57,21 @@ export function selfTestVector(signerAddress, chainId) {
|
|
|
51
57
|
};
|
|
52
58
|
}
|
|
53
59
|
/**
|
|
54
|
-
*
|
|
55
|
-
*
|
|
56
|
-
* says so.
|
|
60
|
+
* Runs the self-test that matches the signer's account type. Never throws: a
|
|
61
|
+
* signer that throws has failed the test, and the reason says so.
|
|
57
62
|
*/
|
|
58
|
-
export async function runSignerSelfTest(signer, chainId) {
|
|
63
|
+
export async function runSignerSelfTest(signer, chainId, chain) {
|
|
64
|
+
if (signer.describe().accountType === "contract") {
|
|
65
|
+
return runContractSignerSelfTest(signer, chainId, chain);
|
|
66
|
+
}
|
|
67
|
+
return runEoaSignerSelfTest(signer, chainId);
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Signs the vector with `signer` and checks the signature the way the
|
|
71
|
+
* gateway's EOA path will: exactly 65 bytes, low-s, recovering to the claimed
|
|
72
|
+
* address. No RPC is involved.
|
|
73
|
+
*/
|
|
74
|
+
export async function runEoaSignerSelfTest(signer, chainId) {
|
|
59
75
|
let claimed;
|
|
60
76
|
let vector;
|
|
61
77
|
let signature;
|
|
@@ -83,6 +99,7 @@ export async function runSignerSelfTest(signer, chainId) {
|
|
|
83
99
|
if (recovered !== claimed) {
|
|
84
100
|
return {
|
|
85
101
|
passed: false,
|
|
102
|
+
verifiedVia: null,
|
|
86
103
|
recovered,
|
|
87
104
|
lowS,
|
|
88
105
|
reason: `recovered-address mismatch: the signature recovers to ${recovered} but the ` +
|
|
@@ -93,16 +110,67 @@ export async function runSignerSelfTest(signer, chainId) {
|
|
|
93
110
|
if (!lowS) {
|
|
94
111
|
return {
|
|
95
112
|
passed: false,
|
|
113
|
+
verifiedVia: null,
|
|
96
114
|
recovered,
|
|
97
115
|
lowS,
|
|
98
116
|
reason: "high-s signature: s is above secp256k1n/2, which the gateway's low-s ECDSA " +
|
|
99
117
|
"recovery rejects",
|
|
100
118
|
};
|
|
101
119
|
}
|
|
102
|
-
return { passed: true, recovered, lowS };
|
|
120
|
+
return { passed: true, verifiedVia: "recovery", recovered, lowS };
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* Signs the vector and asks the deployed wallet itself whether the signature
|
|
124
|
+
* is valid for the EIP-712 hash this CLI computed: one `isValidSignature`
|
|
125
|
+
* `eth_call` with a gas bound and a deadline, accepting only the ERC-1271
|
|
126
|
+
* magic value. A revert, another value, or a malformed return fails; an RPC
|
|
127
|
+
* that cannot be reached fails with a reason that says so, never as invalid.
|
|
128
|
+
*/
|
|
129
|
+
export async function runContractSignerSelfTest(signer, chainId, chain) {
|
|
130
|
+
let claimed;
|
|
131
|
+
let vector;
|
|
132
|
+
let signature;
|
|
133
|
+
try {
|
|
134
|
+
claimed = getAddress(await signer.getAddress());
|
|
135
|
+
vector = selfTestVector(claimed, chainId);
|
|
136
|
+
signature = await signer.signTypedData(vector);
|
|
137
|
+
}
|
|
138
|
+
catch (error) {
|
|
139
|
+
return failedContract(`the signer threw: ${errorMessage(error)}`);
|
|
140
|
+
}
|
|
141
|
+
if (!isBoundedSignature(signature)) {
|
|
142
|
+
return failedContract(`malformed signature: expected 0x-prefixed hex of at most ${MAX_SIGNATURE_BYTES} bytes, ` +
|
|
143
|
+
`got ${describeShape(signature)}`);
|
|
144
|
+
}
|
|
145
|
+
if (hasErc6492Suffix(signature)) {
|
|
146
|
+
return failedContract("counterfactual (ERC-6492) signature: the wallet is not deployed, and Daski refuses " +
|
|
147
|
+
"ERC-6492 wrappers");
|
|
148
|
+
}
|
|
149
|
+
if (!chain)
|
|
150
|
+
return failedContract("no RPC reader was available to call isValidSignature");
|
|
151
|
+
const hash = hashTypedData(vector);
|
|
152
|
+
const data = encodeFunctionData({
|
|
153
|
+
abi: ERC1271_ABI, functionName: "isValidSignature", args: [hash, signature],
|
|
154
|
+
});
|
|
155
|
+
let result;
|
|
156
|
+
try {
|
|
157
|
+
result = await chain.call({ to: claimed, data, gas: ERC1271_CALL_GAS });
|
|
158
|
+
}
|
|
159
|
+
catch (error) {
|
|
160
|
+
return failedContract(`isValidSignature could not be called: ${errorMessage(error)}`);
|
|
161
|
+
}
|
|
162
|
+
if (result.reverted)
|
|
163
|
+
return failedContract("isValidSignature reverted for the vector");
|
|
164
|
+
if (!isErc1271Magic(result.data)) {
|
|
165
|
+
return failedContract(`isValidSignature returned ${describeReturn(result.data)}, not the ERC-1271 magic value`);
|
|
166
|
+
}
|
|
167
|
+
return { passed: true, verifiedVia: "erc1271", recovered: null, lowS: null };
|
|
103
168
|
}
|
|
104
169
|
function failed(reason) {
|
|
105
|
-
return { passed: false, recovered: null, lowS: false, reason };
|
|
170
|
+
return { passed: false, verifiedVia: null, recovered: null, lowS: false, reason };
|
|
171
|
+
}
|
|
172
|
+
function failedContract(reason) {
|
|
173
|
+
return { passed: false, verifiedVia: null, recovered: null, lowS: null, reason };
|
|
106
174
|
}
|
|
107
175
|
function errorMessage(error) {
|
|
108
176
|
return error instanceof Error ? error.message : String(error);
|
|
@@ -110,4 +178,9 @@ function errorMessage(error) {
|
|
|
110
178
|
function describeShape(value) {
|
|
111
179
|
return typeof value === "string" ? `a ${value.length}-character string` : typeof value;
|
|
112
180
|
}
|
|
181
|
+
function describeReturn(data) {
|
|
182
|
+
if (data === undefined || data === "0x")
|
|
183
|
+
return "no data";
|
|
184
|
+
return `${(data.length - 2) / 2} bytes starting ${data.slice(0, 10)}`;
|
|
185
|
+
}
|
|
113
186
|
//# sourceMappingURL=selfTest.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"selfTest.js","sourceRoot":"","sources":["../../src/signers/selfTest.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"selfTest.js","sourceRoot":"","sources":["../../src/signers/selfTest.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The shape rule for any signature this CLI validates: `0x` plus an even
|
|
3
|
+
* number of hex characters, at most 4,096 bytes. The 65-byte low-s rule is
|
|
4
|
+
* the EOA path's alone; a contract account's bytes are opaque beyond size.
|
|
5
|
+
*/
|
|
6
|
+
import type { Hex } from "viem";
|
|
7
|
+
export declare const MAX_SIGNATURE_BYTES = 4096;
|
|
8
|
+
export declare function isBoundedSignature(value: unknown): value is Hex;
|
|
9
|
+
export declare function hasErc6492Suffix(signature: Hex): boolean;
|
|
10
|
+
//# sourceMappingURL=signature.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"signature.d.ts","sourceRoot":"","sources":["../../src/signers/signature.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,MAAM,CAAC;AAEhC,eAAO,MAAM,mBAAmB,OAAQ,CAAC;AAKzC,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,GAAG,CAG/D;AAED,wBAAgB,gBAAgB,CAAC,SAAS,EAAE,GAAG,GAAG,OAAO,CAExD"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export const MAX_SIGNATURE_BYTES = 4_096;
|
|
2
|
+
/** The 32-byte suffix an ERC-6492 wrapper ends with. Daski never accepts one. */
|
|
3
|
+
const ERC6492_SUFFIX = "6492".repeat(16);
|
|
4
|
+
export function isBoundedSignature(value) {
|
|
5
|
+
return typeof value === "string" && /^0x(?:[0-9a-fA-F]{2})+$/.test(value) &&
|
|
6
|
+
(value.length - 2) / 2 <= MAX_SIGNATURE_BYTES;
|
|
7
|
+
}
|
|
8
|
+
export function hasErc6492Suffix(signature) {
|
|
9
|
+
return signature.length > 66 && signature.toLowerCase().endsWith(ERC6492_SUFFIX);
|
|
10
|
+
}
|
|
11
|
+
//# sourceMappingURL=signature.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"signature.js","sourceRoot":"","sources":["../../src/signers/signature.ts"],"names":[],"mappings":"AAOA,MAAM,CAAC,MAAM,mBAAmB,GAAG,KAAK,CAAC;AAEzC,iFAAiF;AACjF,MAAM,cAAc,GAAG,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;AAEzC,MAAM,UAAU,kBAAkB,CAAC,KAAc;IAC/C,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,yBAAyB,CAAC,IAAI,CAAC,KAAK,CAAC;QACvE,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,GAAG,CAAC,IAAI,mBAAmB,CAAC;AAClD,CAAC;AAED,MAAM,UAAU,gBAAgB,CAAC,SAAc;IAC7C,OAAO,SAAS,CAAC,MAAM,GAAG,EAAE,IAAI,SAAS,CAAC,WAAW,EAAE,CAAC,QAAQ,CAAC,cAAc,CAAC,CAAC;AACnF,CAAC"}
|
package/dist/store/keystore.d.ts
CHANGED
|
@@ -1,19 +1,61 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { type Hex } from "viem";
|
|
2
|
+
import { CliError } from "../cli/errors.js";
|
|
3
|
+
import { type HostEnvironment, type KeyBackend, type KeyDurability } from "../host.js";
|
|
2
4
|
export type KeySource = "keychain" | "encrypted-file" | "environment";
|
|
3
5
|
export interface KeyLocation {
|
|
4
6
|
source: KeySource;
|
|
5
7
|
/** Human-readable, never the key. */
|
|
6
8
|
description: string;
|
|
9
|
+
/** What the store guarantees by construction. */
|
|
10
|
+
durability: KeyDurability;
|
|
7
11
|
}
|
|
12
|
+
/** Which store a profile's local key lives in on this host. */
|
|
13
|
+
export interface KeyStoreSelection {
|
|
14
|
+
host: HostEnvironment;
|
|
15
|
+
backend: KeyBackend;
|
|
16
|
+
}
|
|
17
|
+
interface KeyringEntry {
|
|
18
|
+
getPassword(): string | null;
|
|
19
|
+
setPassword(password: string): void;
|
|
20
|
+
deletePassword(): boolean;
|
|
21
|
+
}
|
|
22
|
+
export declare function keychainUnsupportedOnLinux(profile: string): CliError;
|
|
23
|
+
/**
|
|
24
|
+
* Reads the passphrase from the file `DASKI_KEYSTORE_PASSPHRASE_FILE` names.
|
|
25
|
+
* The file must be a regular file with owner-only permissions; a passphrase
|
|
26
|
+
* never travels on a command line.
|
|
27
|
+
*/
|
|
28
|
+
export declare function readPassphraseFile(path: string, platform: NodeJS.Platform): string;
|
|
29
|
+
/**
|
|
30
|
+
* The passphrase for the file store: from `DASKI_KEYSTORE_PASSPHRASE_FILE`
|
|
31
|
+
* when set, otherwise from the terminal. With neither, the command refuses.
|
|
32
|
+
*/
|
|
33
|
+
export declare function keystorePassphrase(host: HostEnvironment, purpose: "create" | "unlock", profile: string): Promise<string>;
|
|
34
|
+
/** The refusal for a host whose backend holds no local key. */
|
|
35
|
+
export declare function localKeyRefusedOnHost(profile: string, backend: KeyBackend): CliError;
|
|
8
36
|
/** Where a key for this profile lives, without loading it. */
|
|
9
|
-
export declare function locateKey(profile: string): Promise<KeyLocation | undefined>;
|
|
37
|
+
export declare function locateKey(profile: string, store: KeyStoreSelection): Promise<KeyLocation | undefined>;
|
|
10
38
|
/** Loads the private key for a profile, prompting for a passphrase if needed. */
|
|
11
|
-
export declare function loadKey(profile: string): Promise<Hex>;
|
|
39
|
+
export declare function loadKey(profile: string, store: KeyStoreSelection): Promise<Hex>;
|
|
40
|
+
/** Hooks a test uses to interrupt an update between its steps. Production passes none. */
|
|
41
|
+
export interface StoreKeyHooks {
|
|
42
|
+
/** Runs after the file has been replaced and before it is read back. */
|
|
43
|
+
afterWrite?: (() => void) | undefined;
|
|
44
|
+
/** Substitutes the native keychain entry, so the keychain path runs against a double. */
|
|
45
|
+
keyring?: ((profile: string) => KeyringEntry) | undefined;
|
|
46
|
+
/** Runs after the keychain existence check and before the write. */
|
|
47
|
+
beforeKeychainWrite?: (() => Promise<void> | void) | undefined;
|
|
48
|
+
/** Where the keychain lock lives; defaults to a per-user temporary directory. */
|
|
49
|
+
lockDirectory?: string | undefined;
|
|
50
|
+
}
|
|
12
51
|
/**
|
|
13
52
|
* Stores a key for a profile. Returns where it landed so the caller can tell
|
|
14
|
-
* the operator — the caller prints the location, never the key.
|
|
53
|
+
* the operator — the caller prints the location, never the key. The store is
|
|
54
|
+
* re-read under the lock, so two creations for the same profile serialize to
|
|
55
|
+
* one key: the second finds the first and refuses.
|
|
15
56
|
*/
|
|
16
|
-
export declare function storeKey(profile: string, privateKey: Hex): Promise<KeyLocation>;
|
|
57
|
+
export declare function storeKey(profile: string, privateKey: Hex, store: KeyStoreSelection, hooks?: StoreKeyHooks): Promise<KeyLocation>;
|
|
17
58
|
/** True when a key already exists for this profile. */
|
|
18
|
-
export declare function hasKey(profile: string): Promise<boolean>;
|
|
59
|
+
export declare function hasKey(profile: string, store: KeyStoreSelection): Promise<boolean>;
|
|
60
|
+
export {};
|
|
19
61
|
//# sourceMappingURL=keystore.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"keystore.d.ts","sourceRoot":"","sources":["../../src/store/keystore.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"keystore.d.ts","sourceRoot":"","sources":["../../src/store/keystore.ts"],"names":[],"mappings":"AAoCA,OAAO,EAA4B,KAAK,GAAG,EAAE,MAAM,MAAM,CAAC;AAC1D,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAE5C,OAAO,EACY,KAAK,eAAe,EAAE,KAAK,UAAU,EAAE,KAAK,aAAa,EAC3E,MAAM,YAAY,CAAC;AA2BpB,MAAM,MAAM,SAAS,GAAG,UAAU,GAAG,gBAAgB,GAAG,aAAa,CAAC;AAEtE,MAAM,WAAW,WAAW;IAC1B,MAAM,EAAE,SAAS,CAAC;IAClB,qCAAqC;IACrC,WAAW,EAAE,MAAM,CAAC;IACpB,iDAAiD;IACjD,UAAU,EAAE,aAAa,CAAC;CAC3B;AAED,+DAA+D;AAC/D,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,eAAe,CAAC;IACtB,OAAO,EAAE,UAAU,CAAC;CACrB;AAwED,UAAU,YAAY;IACpB,WAAW,IAAI,MAAM,GAAG,IAAI,CAAC;IAC7B,WAAW,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACpC,cAAc,IAAI,OAAO,CAAC;CAC3B;AAED,wBAAgB,0BAA0B,CAAC,OAAO,EAAE,MAAM,GAAG,QAAQ,CAUpE;AA2LD;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,CAAC,QAAQ,GAAG,MAAM,CA4BlF;AAUD;;;GAGG;AACH,wBAAsB,kBAAkB,CACtC,IAAI,EAAE,eAAe,EACrB,OAAO,EAAE,QAAQ,GAAG,QAAQ,EAC5B,OAAO,EAAE,MAAM,GACd,OAAO,CAAC,MAAM,CAAC,CA4BjB;AAID,+DAA+D;AAC/D,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,UAAU,GAAG,QAAQ,CAYpF;AAED,8DAA8D;AAC9D,wBAAsB,SAAS,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,iBAAiB,GAAG,OAAO,CAAC,WAAW,GAAG,SAAS,CAAC,CAY3G;AAED,iFAAiF;AACjF,wBAAsB,OAAO,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,iBAAiB,GAAG,OAAO,CAAC,GAAG,CAAC,CAwBrF;AAUD,0FAA0F;AAC1F,MAAM,WAAW,aAAa;IAC5B,wEAAwE;IACxE,UAAU,CAAC,EAAE,CAAC,MAAM,IAAI,CAAC,GAAG,SAAS,CAAC;IACtC,yFAAyF;IACzF,OAAO,CAAC,EAAE,CAAC,CAAC,OAAO,EAAE,MAAM,KAAK,YAAY,CAAC,GAAG,SAAS,CAAC;IAC1D,oEAAoE;IACpE,mBAAmB,CAAC,EAAE,CAAC,MAAM,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,SAAS,CAAC;IAC/D,iFAAiF;IACjF,aAAa,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CACpC;AA2BD;;;;;GAKG;AACH,wBAAsB,QAAQ,CAC5B,OAAO,EAAE,MAAM,EACf,UAAU,EAAE,GAAG,EACf,KAAK,EAAE,iBAAiB,EACxB,KAAK,GAAE,aAAkB,GACxB,OAAO,CAAC,WAAW,CAAC,CA0CtB;AAsBD,uDAAuD;AACvD,wBAAsB,MAAM,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,iBAAiB,GAAG,OAAO,CAAC,OAAO,CAAC,CAExF"}
|