@agenticprimitives/key-custody 0.1.0-alpha.2 → 1.0.0-alpha.10
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 +22 -5
- package/bin/ap-provision-gcp.mjs +91 -0
- package/dist/account.js +1 -1
- package/dist/account.js.map +1 -1
- package/dist/derive-subject.js +4 -4
- package/dist/derive-subject.js.map +1 -1
- package/dist/factories.d.ts.map +1 -1
- package/dist/factories.js +3 -2
- package/dist/factories.js.map +1 -1
- package/dist/index.d.ts +4 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +24 -2
- package/dist/index.js.map +1 -1
- package/dist/kms/gcp-transport.d.ts +36 -0
- package/dist/kms/gcp-transport.d.ts.map +1 -0
- package/dist/kms/gcp-transport.js +114 -0
- package/dist/kms/gcp-transport.js.map +1 -0
- package/dist/kms/key-map.d.ts +13 -0
- package/dist/kms/key-map.d.ts.map +1 -0
- package/dist/kms/key-map.js +65 -0
- package/dist/kms/key-map.js.map +1 -0
- package/dist/kms/kms-core.d.ts +4 -0
- package/dist/kms/kms-core.d.ts.map +1 -0
- package/dist/kms/kms-core.js +14 -0
- package/dist/kms/kms-core.js.map +1 -0
- package/dist/kms/provision-gcp.d.ts +56 -0
- package/dist/kms/provision-gcp.d.ts.map +1 -0
- package/dist/kms/provision-gcp.js +107 -0
- package/dist/kms/provision-gcp.js.map +1 -0
- package/dist/kms/secp256k1-core.d.ts +46 -0
- package/dist/kms/secp256k1-core.d.ts.map +1 -0
- package/dist/kms/secp256k1-core.js +209 -0
- package/dist/kms/secp256k1-core.js.map +1 -0
- package/dist/providers/aws.d.ts +3 -0
- package/dist/providers/aws.d.ts.map +1 -1
- package/dist/providers/aws.js +17 -7
- package/dist/providers/aws.js.map +1 -1
- package/dist/providers/gcp.d.ts +5 -34
- package/dist/providers/gcp.d.ts.map +1 -1
- package/dist/providers/gcp.js +36 -329
- package/dist/providers/gcp.js.map +1 -1
- package/dist/providers/local.d.ts +3 -3
- package/dist/providers/local.d.ts.map +1 -1
- package/dist/providers/local.js +16 -6
- package/dist/providers/local.js.map +1 -1
- package/dist/relayer-account.d.ts +44 -0
- package/dist/relayer-account.d.ts.map +1 -0
- package/dist/relayer-account.js +146 -0
- package/dist/relayer-account.js.map +1 -0
- package/dist/spend-capped-account.d.ts +71 -0
- package/dist/spend-capped-account.d.ts.map +1 -0
- package/dist/spend-capped-account.js +181 -0
- package/dist/spend-capped-account.js.map +1 -0
- package/package.json +50 -19
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"relayer-account.d.ts","sourceRoot":"","sources":["../src/relayer-account.ts"],"names":[],"mappings":"AA2CA,OAAO,EAML,KAAK,YAAY,EAElB,MAAM,MAAM,CAAC;AACd,OAAO,EAAc,KAAK,SAAS,EAAE,MAAM,0BAA0B,CAAC;AAEtE,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,SAAS,CAAC;AAEjD;;;;;;;;;;;GAWG;AACH,MAAM,WAAW,wBAAwB;IACvC,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,CAAC,EAAE,SAAS,CAAC;CACvB;AA6CD;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAsB,oBAAoB,CACxC,OAAO,EAAE,iBAAiB,EAC1B,IAAI,EAAE,wBAAwB,GAC7B,OAAO,CAAC,YAAY,CAAC,CAgDvB"}
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
// createRelayerAccount — KMS-backed viem LocalAccount with built-in audit
|
|
2
|
+
// emission for funded relayer/operator chain calls.
|
|
3
|
+
//
|
|
4
|
+
// R5.12a / PKG-KEY-CUSTODY-005 (relayer-pattern package gap).
|
|
5
|
+
//
|
|
6
|
+
// Why a separate factory from `createKmsViemAccount`:
|
|
7
|
+
//
|
|
8
|
+
// `createKmsViemAccount(backend)` returns a general-purpose viem
|
|
9
|
+
// LocalAccount. App-level relayers that pay gas for sponsored deploys,
|
|
10
|
+
// name registrations, custody-policy applies, paymaster top-ups, etc.
|
|
11
|
+
// need ONE more thing: a forensic trail. Every relayed sign op must
|
|
12
|
+
// emit an audit row tagged with the operator ROLE so the on-chain
|
|
13
|
+
// action stitches back to the off-chain `(role, target, value)` tuple
|
|
14
|
+
// in audit logs.
|
|
15
|
+
//
|
|
16
|
+
// The `createRelayerAccount(backend, { role, auditSink })` factory
|
|
17
|
+
// composes the existing `createKmsViemAccount` + audit emission so
|
|
18
|
+
// app code reaches for THIS when migrating off raw private keys.
|
|
19
|
+
//
|
|
20
|
+
// Why this matters: pre-R5.12a, app authors reached for
|
|
21
|
+
// `privateKeyToAccount(DEPLOYER_PRIVATE_KEY)` because there was no
|
|
22
|
+
// obvious "use me for funded relayer ops" entry point. The packages
|
|
23
|
+
// had all the primitives (`buildSignerBackend` + `createKmsViemAccount`),
|
|
24
|
+
// but no convention. This factory IS the convention.
|
|
25
|
+
//
|
|
26
|
+
// Audit event emitted on every sign op:
|
|
27
|
+
// action: `key-custody.relay.sign`
|
|
28
|
+
// actor: { type: 'system', id: <role> }
|
|
29
|
+
// subject: { type: <opType>, id: <digestFingerprint> }
|
|
30
|
+
// context:
|
|
31
|
+
// role: caller-supplied role tag
|
|
32
|
+
// signerAddress: the relayer EOA
|
|
33
|
+
// opType: 'message' | 'transaction' | 'typed-data'
|
|
34
|
+
// to: tx target address (transaction only)
|
|
35
|
+
// value: tx value in wei (transaction only)
|
|
36
|
+
// digestFingerprint: keccak256(digest).slice(0, 18) — 9 bytes of
|
|
37
|
+
// the digest, never the digest itself
|
|
38
|
+
//
|
|
39
|
+
// Fail-soft: audit emission errors are caught and silently dropped so
|
|
40
|
+
// a logging outage cannot break the relay flow. Consumers who need
|
|
41
|
+
// fail-hard semantics should wrap the supplied sink with
|
|
42
|
+
// `composeFailHardSinks` from @agenticprimitives/audit.
|
|
43
|
+
import { hashMessage, hashTypedData, keccak256, serializeTransaction, } from 'viem';
|
|
44
|
+
import { buildEvent } from '@agenticprimitives/audit';
|
|
45
|
+
import { createKmsViemAccount } from './kms-viem-account';
|
|
46
|
+
function digestFingerprint(digest) {
|
|
47
|
+
// 18 chars = 9 bytes of the keccak hash. Enough to disambiguate in
|
|
48
|
+
// logs; far too short to be a preimage. Same redaction shape used by
|
|
49
|
+
// LocalSecp256k1Signer / GcpKmsSigner for digests in audit rows.
|
|
50
|
+
return keccak256(digest).slice(0, 18);
|
|
51
|
+
}
|
|
52
|
+
async function emitRelaySign(auditSink, role, signerAddress, opType, digest, txContext) {
|
|
53
|
+
if (!auditSink)
|
|
54
|
+
return;
|
|
55
|
+
try {
|
|
56
|
+
await auditSink.write(buildEvent({
|
|
57
|
+
action: 'key-custody.relay.sign',
|
|
58
|
+
outcome: 'success',
|
|
59
|
+
actor: { type: 'system', id: role },
|
|
60
|
+
subject: { type: opType, id: digestFingerprint(digest) },
|
|
61
|
+
context: {
|
|
62
|
+
role,
|
|
63
|
+
signerAddress,
|
|
64
|
+
opType,
|
|
65
|
+
to: txContext?.to ?? null,
|
|
66
|
+
// Audit context values must be JSON-serialisable; emit value as
|
|
67
|
+
// a decimal string (bigint loses precision on JSON.stringify).
|
|
68
|
+
value: txContext?.value !== undefined ? txContext.value.toString() : null,
|
|
69
|
+
digestFingerprint: digestFingerprint(digest),
|
|
70
|
+
},
|
|
71
|
+
}));
|
|
72
|
+
}
|
|
73
|
+
catch {
|
|
74
|
+
// Fail-soft: an audit sink outage cannot break the relay flow.
|
|
75
|
+
// Consumers who want fail-hard semantics wrap with
|
|
76
|
+
// composeFailHardSinks from @agenticprimitives/audit.
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Wrap a {@link KmsAccountBackend} as a viem {@link LocalAccount} suitable
|
|
81
|
+
* for funded relayer / operator chain calls.
|
|
82
|
+
*
|
|
83
|
+
* The returned account delegates signing to `createKmsViemAccount(backend)`
|
|
84
|
+
* (same HSM-backed digest signing, no key material leaves KMS) and
|
|
85
|
+
* additionally emits a `key-custody.relay.sign` audit row on every
|
|
86
|
+
* sign op tagged with the supplied `role`.
|
|
87
|
+
*
|
|
88
|
+
* Migration target for app code that previously used
|
|
89
|
+
* `privateKeyToAccount(env.X_PRIVATE_KEY)` for funded ops.
|
|
90
|
+
*
|
|
91
|
+
* @example
|
|
92
|
+
* ```ts
|
|
93
|
+
* const backend = buildSignerBackend({ backend: 'gcp-kms' });
|
|
94
|
+
* const relayer = await createRelayerAccount(backend, {
|
|
95
|
+
* role: 'direct-deploy',
|
|
96
|
+
* auditSink,
|
|
97
|
+
* });
|
|
98
|
+
* await walletClient.writeContract({ account: relayer, ... });
|
|
99
|
+
* // emits: key-custody.relay.sign { role: 'direct-deploy', opType: 'transaction', to, value, ... }
|
|
100
|
+
* ```
|
|
101
|
+
*/
|
|
102
|
+
export async function createRelayerAccount(backend, opts) {
|
|
103
|
+
const inner = await createKmsViemAccount(backend);
|
|
104
|
+
const { role, auditSink } = opts;
|
|
105
|
+
return {
|
|
106
|
+
address: inner.address,
|
|
107
|
+
type: 'local',
|
|
108
|
+
source: 'kms-relayer',
|
|
109
|
+
publicKey: inner.publicKey,
|
|
110
|
+
async signMessage({ message }) {
|
|
111
|
+
const digest = hashMessage(message);
|
|
112
|
+
const signed = await inner.signMessage({ message });
|
|
113
|
+
await emitRelaySign(auditSink, role, inner.address, 'message', digest);
|
|
114
|
+
return signed;
|
|
115
|
+
},
|
|
116
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
117
|
+
async signTransaction(transaction, options) {
|
|
118
|
+
// Compute the digest for audit emission BEFORE handing off to
|
|
119
|
+
// the inner account (which recomputes it internally; viem doesn't
|
|
120
|
+
// expose the precomputed digest from privateKeyToAccount-style
|
|
121
|
+
// accounts, so we re-do it here for the audit subject).
|
|
122
|
+
const serializer = options?.serializer ?? serializeTransaction;
|
|
123
|
+
const unsigned = serializer(transaction);
|
|
124
|
+
const digest = keccak256(unsigned);
|
|
125
|
+
const signed = await inner.signTransaction(transaction, options);
|
|
126
|
+
await emitRelaySign(auditSink, role, inner.address, 'transaction', digest, {
|
|
127
|
+
to: transaction.to ?? null,
|
|
128
|
+
// viem transactions use bigint for value; default to 0n when omitted.
|
|
129
|
+
value: typeof transaction.value === 'bigint'
|
|
130
|
+
? transaction.value
|
|
131
|
+
: transaction.value !== undefined
|
|
132
|
+
? BigInt(transaction.value)
|
|
133
|
+
: 0n,
|
|
134
|
+
});
|
|
135
|
+
return signed;
|
|
136
|
+
},
|
|
137
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
138
|
+
async signTypedData(args) {
|
|
139
|
+
const digest = hashTypedData(args);
|
|
140
|
+
const signed = await inner.signTypedData(args);
|
|
141
|
+
await emitRelaySign(auditSink, role, inner.address, 'typed-data', digest);
|
|
142
|
+
return signed;
|
|
143
|
+
},
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
//# sourceMappingURL=relayer-account.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"relayer-account.js","sourceRoot":"","sources":["../src/relayer-account.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { type Hex, type LocalAccount } from 'viem';
|
|
2
|
+
import { type AuditSink } from '@agenticprimitives/audit';
|
|
3
|
+
export interface CreateSpendCappedAccountOpts {
|
|
4
|
+
/**
|
|
5
|
+
* Maximum ETH value (in wei) this account is allowed to send PER
|
|
6
|
+
* TRANSACTION. A `signTransaction` request with `value > capWei`
|
|
7
|
+
* is rejected with {@link SpendCapExceededError} before any signing
|
|
8
|
+
* round-trip.
|
|
9
|
+
*
|
|
10
|
+
* `0n` is permitted and meaningful — it blocks ALL value-transferring
|
|
11
|
+
* txs while still allowing contract writes that don't send ETH.
|
|
12
|
+
* Useful for a signer that can call `register(...)` but cannot
|
|
13
|
+
* `transfer(...)` natively.
|
|
14
|
+
*/
|
|
15
|
+
capWei: bigint;
|
|
16
|
+
/**
|
|
17
|
+
* Where to write `key-custody.relay.spend-cap.reject` events. Omit
|
|
18
|
+
* only for tests; production deploys SHOULD wire a durable sink so
|
|
19
|
+
* cap rejections leave a forensic trail (operators will want to
|
|
20
|
+
* detect the request pattern that triggered the reject).
|
|
21
|
+
*/
|
|
22
|
+
auditSink?: AuditSink;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Thrown by a spend-capped account's `signTransaction` when the
|
|
26
|
+
* requested `value` exceeds the configured `capWei`. The HSM is
|
|
27
|
+
* never asked to sign — this is a pre-signing fail-closed gate.
|
|
28
|
+
*/
|
|
29
|
+
export declare class SpendCapExceededError extends Error {
|
|
30
|
+
readonly capWei: bigint;
|
|
31
|
+
readonly requestedValue: bigint;
|
|
32
|
+
readonly to: Hex | null;
|
|
33
|
+
readonly signerAddress: Hex;
|
|
34
|
+
constructor(opts: {
|
|
35
|
+
capWei: bigint;
|
|
36
|
+
requestedValue: bigint;
|
|
37
|
+
to: Hex | null;
|
|
38
|
+
signerAddress: Hex;
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Wrap any viem {@link LocalAccount} with a per-transaction ETH-value
|
|
43
|
+
* cap. The cap is enforced BEFORE signing: a `signTransaction` call
|
|
44
|
+
* with `value > capWei` throws {@link SpendCapExceededError} and the
|
|
45
|
+
* HSM / KMS never sees the digest.
|
|
46
|
+
*
|
|
47
|
+
* `signMessage` and `signTypedData` are forwarded verbatim — they
|
|
48
|
+
* don't carry an on-chain ETH value, so the cap doesn't apply.
|
|
49
|
+
*
|
|
50
|
+
* Composes with `createRelayerAccount`: wrap the relayer with the
|
|
51
|
+
* cap to get role-tagged audit emission AND a per-tx spend limit.
|
|
52
|
+
*
|
|
53
|
+
* Synchronous factory — the wrapper holds no async state. The inner
|
|
54
|
+
* account must already be resolved (it carries the address).
|
|
55
|
+
*
|
|
56
|
+
* @example
|
|
57
|
+
* ```ts
|
|
58
|
+
* const inner = await createRelayerAccount(backend, {
|
|
59
|
+
* role: 'paymaster-topup',
|
|
60
|
+
* auditSink,
|
|
61
|
+
* });
|
|
62
|
+
* const capped = createSpendCappedAccount(inner, {
|
|
63
|
+
* capWei: 10n ** 17n, // 0.1 ETH
|
|
64
|
+
* auditSink,
|
|
65
|
+
* });
|
|
66
|
+
* await walletClient.sendTransaction({ account: capped, to, value: 5n * 10n ** 16n }); // 0.05 ETH — OK
|
|
67
|
+
* await walletClient.sendTransaction({ account: capped, to, value: 10n ** 18n }); // throws SpendCapExceededError
|
|
68
|
+
* ```
|
|
69
|
+
*/
|
|
70
|
+
export declare function createSpendCappedAccount(inner: LocalAccount, opts: CreateSpendCappedAccountOpts): LocalAccount;
|
|
71
|
+
//# sourceMappingURL=spend-capped-account.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"spend-capped-account.d.ts","sourceRoot":"","sources":["../src/spend-capped-account.ts"],"names":[],"mappings":"AAkDA,OAAO,EACL,KAAK,GAAG,EACR,KAAK,YAAY,EAElB,MAAM,MAAM,CAAC;AACd,OAAO,EAAc,KAAK,SAAS,EAAE,MAAM,0BAA0B,CAAC;AAEtE,MAAM,WAAW,4BAA4B;IAC3C;;;;;;;;;;OAUG;IACH,MAAM,EAAE,MAAM,CAAC;IACf;;;;;OAKG;IACH,SAAS,CAAC,EAAE,SAAS,CAAC;CACvB;AAED;;;;GAIG;AACH,qBAAa,qBAAsB,SAAQ,KAAK;IAC9C,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;IAChC,QAAQ,CAAC,EAAE,EAAE,GAAG,GAAG,IAAI,CAAC;IACxB,QAAQ,CAAC,aAAa,EAAE,GAAG,CAAC;gBAEhB,IAAI,EAAE;QAChB,MAAM,EAAE,MAAM,CAAC;QACf,cAAc,EAAE,MAAM,CAAC;QACvB,EAAE,EAAE,GAAG,GAAG,IAAI,CAAC;QACf,aAAa,EAAE,GAAG,CAAC;KACpB;CAYF;AA+CD;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,wBAAgB,wBAAwB,CACtC,KAAK,EAAE,YAAY,EACnB,IAAI,EAAE,4BAA4B,GACjC,YAAY,CAgDd"}
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
// createSpendCappedAccount — wrap any viem LocalAccount with a per-tx
|
|
2
|
+
// ETH-value cap that fails CLOSED before any signing round-trip.
|
|
3
|
+
//
|
|
4
|
+
// R5.12b / PKG-KEY-CUSTODY-010 (relayer-pattern gap, follow-on to R5.12a).
|
|
5
|
+
//
|
|
6
|
+
// Use case:
|
|
7
|
+
// You're running a funded operator key — say the paymaster top-up key
|
|
8
|
+
// — that legitimately needs to send ETH on chain. The key is meant
|
|
9
|
+
// to send AT MOST `capWei` per transaction. A compromised app
|
|
10
|
+
// process holding this account should not be able to drain funds in
|
|
11
|
+
// one shot.
|
|
12
|
+
//
|
|
13
|
+
// Pre-R5.12b, the only way to enforce this was operationally:
|
|
14
|
+
// monitor the on-chain balance, hope the operator catches a drain
|
|
15
|
+
// in time, rotate keys after the fact. The cap was unenforceable
|
|
16
|
+
// at signing time.
|
|
17
|
+
//
|
|
18
|
+
// Post-R5.12b, `createSpendCappedAccount(inner, { capWei })`
|
|
19
|
+
// wraps any viem LocalAccount and inspects `transaction.value` in
|
|
20
|
+
// `signTransaction`. If `value > capWei`, throws a
|
|
21
|
+
// `SpendCapExceededError` BEFORE the KMS round-trip — the HSM
|
|
22
|
+
// never even sees the digest.
|
|
23
|
+
//
|
|
24
|
+
// What it does NOT do:
|
|
25
|
+
// - Track cumulative spend across calls (the cap is per-tx, not a
|
|
26
|
+
// rolling budget). A cumulative tracker is operational state
|
|
27
|
+
// (sticky across processes / restarts), which belongs at the
|
|
28
|
+
// app or substrate layer, not in a stateless signer wrapper.
|
|
29
|
+
// - Inspect calldata (no introspection of internal ETH transfers
|
|
30
|
+
// a contract call might perform). The cap is on the value the
|
|
31
|
+
// account itself sends; downstream contract behavior is the
|
|
32
|
+
// contract's contract.
|
|
33
|
+
//
|
|
34
|
+
// Composition:
|
|
35
|
+
// Designed to compose with `createRelayerAccount` (R5.12a):
|
|
36
|
+
//
|
|
37
|
+
// const inner = await createRelayerAccount(backend, {
|
|
38
|
+
// role: 'paymaster-topup',
|
|
39
|
+
// auditSink,
|
|
40
|
+
// });
|
|
41
|
+
// const capped = createSpendCappedAccount(inner, {
|
|
42
|
+
// capWei: 10n ** 17n, // 0.1 ETH per tx
|
|
43
|
+
// auditSink,
|
|
44
|
+
// });
|
|
45
|
+
//
|
|
46
|
+
// When a tx is rejected, the cap wrapper emits its own
|
|
47
|
+
// `key-custody.relay.spend-cap.reject` event so the relayer's
|
|
48
|
+
// `key-custody.relay.sign.success` and the cap's reject are both
|
|
49
|
+
// in the audit trail with matching `signerAddress`.
|
|
50
|
+
import { buildEvent } from '@agenticprimitives/audit';
|
|
51
|
+
/**
|
|
52
|
+
* Thrown by a spend-capped account's `signTransaction` when the
|
|
53
|
+
* requested `value` exceeds the configured `capWei`. The HSM is
|
|
54
|
+
* never asked to sign — this is a pre-signing fail-closed gate.
|
|
55
|
+
*/
|
|
56
|
+
export class SpendCapExceededError extends Error {
|
|
57
|
+
capWei;
|
|
58
|
+
requestedValue;
|
|
59
|
+
to;
|
|
60
|
+
signerAddress;
|
|
61
|
+
constructor(opts) {
|
|
62
|
+
super(`[key-custody] spend cap exceeded: requested ${opts.requestedValue.toString()} wei to ${opts.to ?? '<no target>'}, cap is ${opts.capWei.toString()} wei (signer ${opts.signerAddress})`);
|
|
63
|
+
this.name = 'SpendCapExceededError';
|
|
64
|
+
this.capWei = opts.capWei;
|
|
65
|
+
this.requestedValue = opts.requestedValue;
|
|
66
|
+
this.to = opts.to;
|
|
67
|
+
this.signerAddress = opts.signerAddress;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
function readTxValue(tx) {
|
|
71
|
+
// viem accepts bigint (canonical), number, string. Normalise to bigint;
|
|
72
|
+
// undefined / null → 0n.
|
|
73
|
+
const v = tx.value;
|
|
74
|
+
if (v === undefined || v === null)
|
|
75
|
+
return 0n;
|
|
76
|
+
if (typeof v === 'bigint')
|
|
77
|
+
return v;
|
|
78
|
+
if (typeof v === 'number')
|
|
79
|
+
return BigInt(v);
|
|
80
|
+
if (typeof v === 'string')
|
|
81
|
+
return BigInt(v);
|
|
82
|
+
// Defensive: any other shape is treated as "we don't know, fail closed
|
|
83
|
+
// by reporting as MAX_UINT256". A signer that can't reason about value
|
|
84
|
+
// shouldn't be allowed to send arbitrary amounts.
|
|
85
|
+
return (1n << 256n) - 1n;
|
|
86
|
+
}
|
|
87
|
+
async function emitCapReject(auditSink, opts) {
|
|
88
|
+
if (!auditSink)
|
|
89
|
+
return;
|
|
90
|
+
try {
|
|
91
|
+
await auditSink.write(buildEvent({
|
|
92
|
+
action: 'key-custody.relay.spend-cap.reject',
|
|
93
|
+
outcome: 'denied',
|
|
94
|
+
actor: { type: 'system', id: opts.signerAddress },
|
|
95
|
+
subject: { type: 'transaction', id: opts.to ?? '<no-target>' },
|
|
96
|
+
context: {
|
|
97
|
+
signerAddress: opts.signerAddress,
|
|
98
|
+
to: opts.to,
|
|
99
|
+
capWei: opts.capWei.toString(),
|
|
100
|
+
requestedValue: opts.requestedValue.toString(),
|
|
101
|
+
},
|
|
102
|
+
}));
|
|
103
|
+
}
|
|
104
|
+
catch {
|
|
105
|
+
// Fail-soft: a sink outage does not affect the rejection itself
|
|
106
|
+
// (the throw still happens; the audit row is just missing).
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Wrap any viem {@link LocalAccount} with a per-transaction ETH-value
|
|
111
|
+
* cap. The cap is enforced BEFORE signing: a `signTransaction` call
|
|
112
|
+
* with `value > capWei` throws {@link SpendCapExceededError} and the
|
|
113
|
+
* HSM / KMS never sees the digest.
|
|
114
|
+
*
|
|
115
|
+
* `signMessage` and `signTypedData` are forwarded verbatim — they
|
|
116
|
+
* don't carry an on-chain ETH value, so the cap doesn't apply.
|
|
117
|
+
*
|
|
118
|
+
* Composes with `createRelayerAccount`: wrap the relayer with the
|
|
119
|
+
* cap to get role-tagged audit emission AND a per-tx spend limit.
|
|
120
|
+
*
|
|
121
|
+
* Synchronous factory — the wrapper holds no async state. The inner
|
|
122
|
+
* account must already be resolved (it carries the address).
|
|
123
|
+
*
|
|
124
|
+
* @example
|
|
125
|
+
* ```ts
|
|
126
|
+
* const inner = await createRelayerAccount(backend, {
|
|
127
|
+
* role: 'paymaster-topup',
|
|
128
|
+
* auditSink,
|
|
129
|
+
* });
|
|
130
|
+
* const capped = createSpendCappedAccount(inner, {
|
|
131
|
+
* capWei: 10n ** 17n, // 0.1 ETH
|
|
132
|
+
* auditSink,
|
|
133
|
+
* });
|
|
134
|
+
* await walletClient.sendTransaction({ account: capped, to, value: 5n * 10n ** 16n }); // 0.05 ETH — OK
|
|
135
|
+
* await walletClient.sendTransaction({ account: capped, to, value: 10n ** 18n }); // throws SpendCapExceededError
|
|
136
|
+
* ```
|
|
137
|
+
*/
|
|
138
|
+
export function createSpendCappedAccount(inner, opts) {
|
|
139
|
+
if (opts.capWei < 0n) {
|
|
140
|
+
throw new Error(`[key-custody] createSpendCappedAccount: capWei must be >= 0; got ${opts.capWei.toString()}`);
|
|
141
|
+
}
|
|
142
|
+
const { capWei, auditSink } = opts;
|
|
143
|
+
return {
|
|
144
|
+
address: inner.address,
|
|
145
|
+
type: 'local',
|
|
146
|
+
source: 'kms-spend-capped',
|
|
147
|
+
publicKey: inner.publicKey,
|
|
148
|
+
async signMessage({ message }) {
|
|
149
|
+
// Messages carry no on-chain value; forward verbatim.
|
|
150
|
+
return inner.signMessage({ message });
|
|
151
|
+
},
|
|
152
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
153
|
+
async signTransaction(transaction, options) {
|
|
154
|
+
const requestedValue = readTxValue(transaction);
|
|
155
|
+
if (requestedValue > capWei) {
|
|
156
|
+
const to = transaction.to ?? null;
|
|
157
|
+
await emitCapReject(auditSink, {
|
|
158
|
+
capWei,
|
|
159
|
+
requestedValue,
|
|
160
|
+
to,
|
|
161
|
+
signerAddress: inner.address,
|
|
162
|
+
});
|
|
163
|
+
throw new SpendCapExceededError({
|
|
164
|
+
capWei,
|
|
165
|
+
requestedValue,
|
|
166
|
+
to,
|
|
167
|
+
signerAddress: inner.address,
|
|
168
|
+
});
|
|
169
|
+
}
|
|
170
|
+
// Under or at cap → delegate. (At-cap is intentionally permitted;
|
|
171
|
+
// `cap == requested` is the boundary, not a violation.)
|
|
172
|
+
return inner.signTransaction(transaction, options);
|
|
173
|
+
},
|
|
174
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
175
|
+
async signTypedData(args) {
|
|
176
|
+
// Typed data carries no on-chain value; forward verbatim.
|
|
177
|
+
return inner.signTypedData(args);
|
|
178
|
+
},
|
|
179
|
+
};
|
|
180
|
+
}
|
|
181
|
+
//# sourceMappingURL=spend-capped-account.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"spend-capped-account.js","sourceRoot":"","sources":["../src/spend-capped-account.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@agenticprimitives/key-custody",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "1.0.0-alpha.10",
|
|
4
4
|
"description": "Pluggable envelope encryption + signers + HMAC providers (local-AES / AWS KMS / GCP KMS). Pure crypto primitives; no session lifecycle (that's in delegation).",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -15,6 +15,9 @@
|
|
|
15
15
|
"type": "module",
|
|
16
16
|
"main": "./dist/index.js",
|
|
17
17
|
"types": "./dist/index.d.ts",
|
|
18
|
+
"bin": {
|
|
19
|
+
"ap-provision-gcp": "./bin/ap-provision-gcp.mjs"
|
|
20
|
+
},
|
|
18
21
|
"exports": {
|
|
19
22
|
".": {
|
|
20
23
|
"types": "./dist/index.d.ts",
|
|
@@ -32,6 +35,14 @@
|
|
|
32
35
|
"types": "./dist/providers/gcp.d.ts",
|
|
33
36
|
"import": "./dist/providers/gcp.js"
|
|
34
37
|
},
|
|
38
|
+
"./kms-core": {
|
|
39
|
+
"types": "./dist/kms/kms-core.d.ts",
|
|
40
|
+
"import": "./dist/kms/kms-core.js"
|
|
41
|
+
},
|
|
42
|
+
"./provision-gcp": {
|
|
43
|
+
"types": "./dist/kms/provision-gcp.d.ts",
|
|
44
|
+
"import": "./dist/kms/provision-gcp.js"
|
|
45
|
+
},
|
|
35
46
|
"./mac": {
|
|
36
47
|
"types": "./dist/mac.d.ts",
|
|
37
48
|
"import": "./dist/mac.js"
|
|
@@ -39,38 +50,49 @@
|
|
|
39
50
|
"./kms-viem": {
|
|
40
51
|
"types": "./dist/kms-viem-account.d.ts",
|
|
41
52
|
"import": "./dist/kms-viem-account.js"
|
|
53
|
+
},
|
|
54
|
+
"./relayer": {
|
|
55
|
+
"types": "./dist/relayer-account.d.ts",
|
|
56
|
+
"import": "./dist/relayer-account.js"
|
|
57
|
+
},
|
|
58
|
+
"./spend-cap": {
|
|
59
|
+
"types": "./dist/spend-capped-account.d.ts",
|
|
60
|
+
"import": "./dist/spend-capped-account.js"
|
|
42
61
|
}
|
|
43
62
|
},
|
|
44
63
|
"files": [
|
|
45
64
|
"LICENSE",
|
|
65
|
+
"bin",
|
|
46
66
|
"dist",
|
|
47
67
|
"spec.md",
|
|
48
68
|
"README.md"
|
|
49
69
|
],
|
|
50
|
-
"scripts": {
|
|
51
|
-
"build": "tsc -p tsconfig.build.json",
|
|
52
|
-
"typecheck": "tsc -p tsconfig.json --noEmit",
|
|
53
|
-
"test": "vitest run",
|
|
54
|
-
"test:unit": "vitest run test/unit",
|
|
55
|
-
"test:integration": "vitest run test/integration --passWithNoTests",
|
|
56
|
-
"test:watch": "vitest",
|
|
57
|
-
"clean": "rm -rf dist"
|
|
58
|
-
},
|
|
59
70
|
"publishConfig": {
|
|
60
71
|
"access": "public"
|
|
61
72
|
},
|
|
62
73
|
"dependencies": {
|
|
63
|
-
"@noble/curves": "^
|
|
64
|
-
"@noble/hashes": "^
|
|
74
|
+
"@noble/curves": "^2.2.0",
|
|
75
|
+
"@noble/hashes": "^2.2.0"
|
|
65
76
|
},
|
|
66
77
|
"peerDependencies": {
|
|
67
|
-
"
|
|
68
|
-
"@agenticprimitives/
|
|
69
|
-
"@agenticprimitives/types": "
|
|
70
|
-
"
|
|
78
|
+
"viem": "^2.52.2",
|
|
79
|
+
"@agenticprimitives/audit": "1.0.0-alpha.10",
|
|
80
|
+
"@agenticprimitives/types": "1.0.0-alpha.10",
|
|
81
|
+
"@agenticprimitives/connect-auth": "1.0.0-alpha.10"
|
|
82
|
+
},
|
|
83
|
+
"peerDependenciesMeta": {
|
|
84
|
+
"@agenticprimitives/audit": {
|
|
85
|
+
"optional": true
|
|
86
|
+
},
|
|
87
|
+
"@agenticprimitives/connect-auth": {
|
|
88
|
+
"optional": true
|
|
89
|
+
},
|
|
90
|
+
"viem": {
|
|
91
|
+
"optional": true
|
|
92
|
+
}
|
|
71
93
|
},
|
|
72
94
|
"devDependencies": {
|
|
73
|
-
"vitest": "^
|
|
95
|
+
"vitest": "^4.1.8"
|
|
74
96
|
},
|
|
75
97
|
"keywords": [
|
|
76
98
|
"kms",
|
|
@@ -80,5 +102,14 @@
|
|
|
80
102
|
"secp256k1",
|
|
81
103
|
"hmac",
|
|
82
104
|
"agentic"
|
|
83
|
-
]
|
|
84
|
-
|
|
105
|
+
],
|
|
106
|
+
"scripts": {
|
|
107
|
+
"build": "tsc -p tsconfig.build.json",
|
|
108
|
+
"typecheck": "tsc -p tsconfig.json --noEmit",
|
|
109
|
+
"test": "vitest run",
|
|
110
|
+
"test:unit": "vitest run test/unit --passWithNoTests",
|
|
111
|
+
"test:integration": "vitest run test/integration --passWithNoTests",
|
|
112
|
+
"test:watch": "vitest",
|
|
113
|
+
"clean": "rm -rf dist"
|
|
114
|
+
}
|
|
115
|
+
}
|