@tollxyz/guard 0.2.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 +225 -16
- package/dist/check.d.ts +26 -2
- package/dist/check.js +28 -2
- package/dist/index.d.ts +10 -6
- package/dist/index.js +6 -4
- package/dist/policy.d.ts +154 -9
- package/dist/policy.js +399 -14
- package/dist/spend.d.ts +48 -0
- package/dist/spend.js +239 -0
- package/dist/store.d.ts +46 -0
- package/dist/store.js +78 -0
- package/dist/wallets.d.ts +20 -11
- package/dist/wallets.js +269 -61
- package/dist/x402.d.ts +12 -0
- package/dist/x402.js +148 -7
- package/package.json +2 -2
package/dist/spend.js
ADDED
|
@@ -0,0 +1,239 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What a request spends, read locally (calldata, typed data, an x402 requirement) and, when Toll's answer carries one,
|
|
3
|
+
* from its simulation (x-toll.simulation). Only outflows of the spend assets count (default: native ETH, WETH and USDG
|
|
4
|
+
* on Robinhood Chain), so selling a coin that is not a spend asset is never capped.
|
|
5
|
+
*/
|
|
6
|
+
import { isAddress } from "./check.js";
|
|
7
|
+
/** native ETH as a spend-asset key */
|
|
8
|
+
export const NATIVE = "native";
|
|
9
|
+
/** USDG on Robinhood Chain */
|
|
10
|
+
export const USDG = "0x5fc5360d0400a0fd4f2af552add042d716f1d168";
|
|
11
|
+
/** WETH on Robinhood Chain */
|
|
12
|
+
export const WETH = "0x0bd7d308f8e1639fab988df18a8011f41eacad73";
|
|
13
|
+
/** the spend assets when none are given */
|
|
14
|
+
export const DEFAULT_SPEND_ASSETS = [NATIVE, WETH, USDG];
|
|
15
|
+
/** an unlimited allowance (type(uint256).max): larger than any cap */
|
|
16
|
+
export const UNLIMITED = (1n << 256n) - 1n;
|
|
17
|
+
/** Permit2 (same address on every chain) */
|
|
18
|
+
const PERMIT2 = "0x000000000022d473030f116ddee9f6b43ac78ba3";
|
|
19
|
+
/** native ETH as the simulation names it */
|
|
20
|
+
const SIM_NATIVE = "0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee";
|
|
21
|
+
const lc = (x) => String(x ?? "").toLowerCase();
|
|
22
|
+
const big = (x) => {
|
|
23
|
+
try {
|
|
24
|
+
if (typeof x === "bigint")
|
|
25
|
+
return x;
|
|
26
|
+
if (typeof x === "number")
|
|
27
|
+
return Number.isSafeInteger(x) ? BigInt(x) : null;
|
|
28
|
+
if (typeof x === "string" && /^(0x[0-9a-fA-F]+|\d+)$/.test(x.trim()))
|
|
29
|
+
return BigInt(x.trim());
|
|
30
|
+
}
|
|
31
|
+
catch {
|
|
32
|
+
/* unreadable */
|
|
33
|
+
}
|
|
34
|
+
return null;
|
|
35
|
+
};
|
|
36
|
+
const SEL = {
|
|
37
|
+
transfer: "0xa9059cbb",
|
|
38
|
+
transferFrom: "0x23b872dd",
|
|
39
|
+
approve: "0x095ea7b3",
|
|
40
|
+
increaseAllowance: "0x39509351",
|
|
41
|
+
deposit: "0xd0e30db0",
|
|
42
|
+
withdraw: "0x2e1a7d4d",
|
|
43
|
+
};
|
|
44
|
+
function words(data) {
|
|
45
|
+
const body = data.slice(10);
|
|
46
|
+
const out = [];
|
|
47
|
+
for (let i = 0; i + 64 <= body.length; i += 64)
|
|
48
|
+
out.push(body.slice(i, i + 64));
|
|
49
|
+
return out;
|
|
50
|
+
}
|
|
51
|
+
const wAddr = (w) => (w ? "0x" + w.slice(24).toLowerCase() : "");
|
|
52
|
+
const wInt = (w) => (w ? BigInt("0x" + w) : 0n);
|
|
53
|
+
class Acc {
|
|
54
|
+
assets;
|
|
55
|
+
items = [];
|
|
56
|
+
declared = {};
|
|
57
|
+
simOut = {};
|
|
58
|
+
approvals = {};
|
|
59
|
+
to = new Set();
|
|
60
|
+
spender = new Set();
|
|
61
|
+
payTo = new Set();
|
|
62
|
+
unknown = false;
|
|
63
|
+
simulated = false;
|
|
64
|
+
constructor(assets) {
|
|
65
|
+
this.assets = assets;
|
|
66
|
+
}
|
|
67
|
+
out(asset, amount, item, max = false) {
|
|
68
|
+
if (!this.assets.has(asset) || amount <= 0n)
|
|
69
|
+
return;
|
|
70
|
+
const cur = this.declared[asset] ?? 0n;
|
|
71
|
+
this.declared[asset] = max ? (amount > cur ? amount : cur) : cur + amount;
|
|
72
|
+
this.items.push({ ...item, asset, amount });
|
|
73
|
+
}
|
|
74
|
+
approve(asset, amount, spender) {
|
|
75
|
+
if (spender)
|
|
76
|
+
this.spender.add(spender);
|
|
77
|
+
if (!this.assets.has(asset))
|
|
78
|
+
return;
|
|
79
|
+
const cur = this.approvals[asset] ?? 0n;
|
|
80
|
+
if (amount > cur)
|
|
81
|
+
this.approvals[asset] = amount;
|
|
82
|
+
this.items.push({ kind: "approve", asset, amount, spender });
|
|
83
|
+
}
|
|
84
|
+
done() {
|
|
85
|
+
const outflow = {};
|
|
86
|
+
for (const a of new Set([...Object.keys(this.declared), ...Object.keys(this.simOut)])) {
|
|
87
|
+
const d = this.declared[a] ?? 0n;
|
|
88
|
+
const s = this.simOut[a] ?? 0n;
|
|
89
|
+
outflow[a] = s > d ? s : d;
|
|
90
|
+
}
|
|
91
|
+
return { items: this.items, outflow, approvals: this.approvals, to: [...this.to], spender: [...this.spender], payTo: [...this.payTo], unknown: this.unknown && !this.simulated, simulated: this.simulated };
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
function decodeTx(i, acc) {
|
|
95
|
+
const from = isAddress(i.from) ? lc(i.from) : null;
|
|
96
|
+
const target = lc(i.to);
|
|
97
|
+
const value = big(i.value ?? 0) ?? 0n;
|
|
98
|
+
const data = typeof i.data === "string" ? i.data : "0x";
|
|
99
|
+
if (value > 0n)
|
|
100
|
+
acc.out(NATIVE, value, { kind: "value", to: target });
|
|
101
|
+
if (data.length < 10) {
|
|
102
|
+
if (target)
|
|
103
|
+
acc.to.add(target);
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
106
|
+
const sel = data.slice(0, 10).toLowerCase();
|
|
107
|
+
const w = words(data);
|
|
108
|
+
if (sel === SEL.transfer && w.length >= 2) {
|
|
109
|
+
const to = wAddr(w[0]);
|
|
110
|
+
acc.to.add(to);
|
|
111
|
+
acc.out(target, wInt(w[1]), { kind: "transfer", to });
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
114
|
+
if (sel === SEL.transferFrom && w.length >= 3) {
|
|
115
|
+
const src = wAddr(w[0]);
|
|
116
|
+
const to = wAddr(w[2]);
|
|
117
|
+
acc.to.add(to);
|
|
118
|
+
// only the signer's own tokens are its spend
|
|
119
|
+
if (!from || src === from)
|
|
120
|
+
acc.out(target, wInt(w[2]), { kind: "transfer", to });
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
123
|
+
if ((sel === SEL.approve || sel === SEL.increaseAllowance) && w.length >= 2) {
|
|
124
|
+
acc.approve(target, wInt(w[1]), wAddr(w[0]));
|
|
125
|
+
return;
|
|
126
|
+
}
|
|
127
|
+
acc.to.add(target);
|
|
128
|
+
// WETH deposit (the value is already counted) and withdraw (WETH back to ETH): no new spend
|
|
129
|
+
if (target === WETH && (sel === SEL.deposit || sel === SEL.withdraw))
|
|
130
|
+
return;
|
|
131
|
+
acc.unknown = true;
|
|
132
|
+
}
|
|
133
|
+
function decodeTyped(td, acc, signer) {
|
|
134
|
+
const vc = lc(td.domain?.verifyingContract);
|
|
135
|
+
const m = (td.message ?? {});
|
|
136
|
+
const p = String(td.primaryType ?? "");
|
|
137
|
+
if (vc === PERMIT2) {
|
|
138
|
+
const spender = lc(m.spender);
|
|
139
|
+
if (p === "PermitSingle")
|
|
140
|
+
acc.approve(lc(m.details?.token), big(m.details?.amount) ?? UNLIMITED, spender);
|
|
141
|
+
else if (p === "PermitBatch")
|
|
142
|
+
for (const d of Array.isArray(m.details) ? m.details : [])
|
|
143
|
+
acc.approve(lc(d?.token), big(d?.amount) ?? UNLIMITED, spender);
|
|
144
|
+
else if (p === "PermitTransferFrom" || p === "PermitWitnessTransferFrom")
|
|
145
|
+
acc.approve(lc(m.permitted?.token), big(m.permitted?.amount) ?? UNLIMITED, spender);
|
|
146
|
+
else if (p === "PermitBatchTransferFrom" || p === "PermitBatchWitnessTransferFrom")
|
|
147
|
+
for (const d of Array.isArray(m.permitted) ? m.permitted : [])
|
|
148
|
+
acc.approve(lc(d?.token), big(d?.amount) ?? UNLIMITED, spender);
|
|
149
|
+
return;
|
|
150
|
+
}
|
|
151
|
+
if (p === "Permit" && m.spender !== undefined) {
|
|
152
|
+
acc.approve(vc, big(m.value) ?? UNLIMITED, lc(m.spender));
|
|
153
|
+
return;
|
|
154
|
+
}
|
|
155
|
+
if ((p === "TransferWithAuthorization" || p === "ReceiveWithAuthorization") && (!signer || lc(m.from) === signer || m.from === undefined)) {
|
|
156
|
+
const to = lc(m.to);
|
|
157
|
+
acc.to.add(to);
|
|
158
|
+
acc.out(vc, big(m.value) ?? 0n, { kind: "transfer", to });
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
function typedOf(i) {
|
|
162
|
+
if (i.typedData)
|
|
163
|
+
return i.typedData;
|
|
164
|
+
if (i.rpc?.method !== "eth_signTypedData_v4")
|
|
165
|
+
return null;
|
|
166
|
+
let td = i.rpc.params?.[1];
|
|
167
|
+
if (typeof td === "string") {
|
|
168
|
+
try {
|
|
169
|
+
td = JSON.parse(td);
|
|
170
|
+
}
|
|
171
|
+
catch {
|
|
172
|
+
return null;
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
return td && typeof td === "object" ? td : null;
|
|
176
|
+
}
|
|
177
|
+
function decodeX402(x, acc) {
|
|
178
|
+
const entries = Array.isArray(x.accepts) ? x.accepts : [x];
|
|
179
|
+
for (const raw of entries) {
|
|
180
|
+
const e = (raw && typeof raw === "object" ? raw : {});
|
|
181
|
+
const payTo = lc(e.payTo);
|
|
182
|
+
if (payTo)
|
|
183
|
+
acc.payTo.add(payTo);
|
|
184
|
+
const amt = big(e.amount ?? e.maxAmountRequired);
|
|
185
|
+
// the client pays one entry: the largest per asset counts
|
|
186
|
+
if (amt !== null)
|
|
187
|
+
acc.out(lc(e.asset), amt, { kind: "x402", payTo }, true);
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
function readSim(a, from, acc) {
|
|
191
|
+
const s = a?.["x-toll"]?.simulation;
|
|
192
|
+
if (!s || !from)
|
|
193
|
+
return;
|
|
194
|
+
const eff = s.status === "success" || s.status === "reverted" ? s : s.status === "insufficient-eth" ? s.effects : null;
|
|
195
|
+
if (!eff || !Array.isArray(eff.deltas))
|
|
196
|
+
return;
|
|
197
|
+
acc.simulated = true;
|
|
198
|
+
for (const d of eff.deltas) {
|
|
199
|
+
if (lc(d?.holder) !== from)
|
|
200
|
+
continue;
|
|
201
|
+
const delta = big(String(d?.delta ?? "").replace(/^-/, ""));
|
|
202
|
+
if (delta === null || !String(d?.delta).startsWith("-"))
|
|
203
|
+
continue;
|
|
204
|
+
const tok = lc(d?.token);
|
|
205
|
+
const asset = tok === SIM_NATIVE || tok === "0x0000000000000000000000000000000000000000" ? NATIVE : tok;
|
|
206
|
+
if (!acc.assets.has(asset))
|
|
207
|
+
continue;
|
|
208
|
+
acc.simOut[asset] = (acc.simOut[asset] ?? 0n) + delta;
|
|
209
|
+
acc.items.push({ kind: "simulation", asset, amount: delta });
|
|
210
|
+
}
|
|
211
|
+
for (const ap of Array.isArray(eff.approvals) ? eff.approvals : []) {
|
|
212
|
+
if (lc(ap?.owner) !== from || ap?.kind === "nft-all")
|
|
213
|
+
continue;
|
|
214
|
+
acc.approve(lc(ap?.token), ap?.amount === null || ap?.amount === undefined ? UNLIMITED : (big(ap.amount) ?? UNLIMITED), lc(ap?.spender));
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
/**
|
|
218
|
+
* What a request spends. `assessment` is Toll's answer (null when Toll was not asked or could not answer): its
|
|
219
|
+
* simulation, when read, beats the declared amounts upward. `assets` are the spend assets ("native" or token addresses).
|
|
220
|
+
*/
|
|
221
|
+
export function spendOf(input, assessment, assets = DEFAULT_SPEND_ASSETS) {
|
|
222
|
+
const acc = new Acc(new Set(assets.map(lc)));
|
|
223
|
+
const isTx = input.to !== undefined || input.data !== undefined;
|
|
224
|
+
const signer = isAddress(input.from) ? lc(input.from) : isAddress(input.message?.from) ? lc(input.message?.from) : null;
|
|
225
|
+
if (isTx)
|
|
226
|
+
decodeTx(input, acc);
|
|
227
|
+
else if (input.authorizationList && input.authorizationList.length)
|
|
228
|
+
acc.unknown = true; // a delegation can move anything
|
|
229
|
+
if (input.userOp)
|
|
230
|
+
acc.unknown = true; // raw callData is not decoded here
|
|
231
|
+
const td = typedOf(input);
|
|
232
|
+
if (td)
|
|
233
|
+
decodeTyped(td, acc, signer);
|
|
234
|
+
if (input.x402)
|
|
235
|
+
decodeX402(input.x402, acc);
|
|
236
|
+
if (isTx)
|
|
237
|
+
readSim(assessment, signer, acc);
|
|
238
|
+
return acc.done();
|
|
239
|
+
}
|
package/dist/store.d.ts
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Where the guard keeps its spend counters and the x402 payment ids it has paid. The default MemorySpendStore lives in
|
|
3
|
+
* this process: it resets on restart and is not shared between processes. Pass your own SpendStore (Redis, a database)
|
|
4
|
+
* for counters that survive restarts or span several workers.
|
|
5
|
+
*/
|
|
6
|
+
export interface SpendStore {
|
|
7
|
+
/**
|
|
8
|
+
* Reserves `amt` under key `k` in the window starting at `windowStart` (ms, UTC). ok when committed + pending + amt
|
|
9
|
+
* stays within `limit`; `used` is committed + pending after the call. Must be atomic per key.
|
|
10
|
+
*/
|
|
11
|
+
reserve(k: string, amt: bigint, limit: bigint, windowStart: number): Promise<{
|
|
12
|
+
ok: boolean;
|
|
13
|
+
id: string;
|
|
14
|
+
used: bigint;
|
|
15
|
+
}>;
|
|
16
|
+
/** the reservation was spent: it stays counted */
|
|
17
|
+
commit(id: string): Promise<void>;
|
|
18
|
+
/** the reservation was not spent (refused, the send threw): it no longer counts */
|
|
19
|
+
release(id: string): Promise<void>;
|
|
20
|
+
/** true when this x402 payment id was paid within its TTL */
|
|
21
|
+
paymentSeen(id: string): Promise<boolean>;
|
|
22
|
+
markPaid(id: string, ttlS: number): Promise<void>;
|
|
23
|
+
}
|
|
24
|
+
/** the start of the UTC day holding `t` (ms) */
|
|
25
|
+
export declare const dayStart: (t: number) => number;
|
|
26
|
+
/** an in-process SpendStore: resets on restart, not shared between processes */
|
|
27
|
+
export declare class MemorySpendStore implements SpendStore {
|
|
28
|
+
private readonly buckets;
|
|
29
|
+
private readonly where;
|
|
30
|
+
private readonly paid;
|
|
31
|
+
private readonly now;
|
|
32
|
+
private seq;
|
|
33
|
+
constructor(o?: {
|
|
34
|
+
now?: () => number;
|
|
35
|
+
});
|
|
36
|
+
private prune;
|
|
37
|
+
reserve(k: string, amt: bigint, limit: bigint, windowStart: number): Promise<{
|
|
38
|
+
ok: boolean;
|
|
39
|
+
id: string;
|
|
40
|
+
used: bigint;
|
|
41
|
+
}>;
|
|
42
|
+
commit(id: string): Promise<void>;
|
|
43
|
+
release(id: string): Promise<void>;
|
|
44
|
+
paymentSeen(id: string): Promise<boolean>;
|
|
45
|
+
markPaid(id: string, ttlS: number): Promise<void>;
|
|
46
|
+
}
|
package/dist/store.js
ADDED
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Where the guard keeps its spend counters and the x402 payment ids it has paid. The default MemorySpendStore lives in
|
|
3
|
+
* this process: it resets on restart and is not shared between processes. Pass your own SpendStore (Redis, a database)
|
|
4
|
+
* for counters that survive restarts or span several workers.
|
|
5
|
+
*/
|
|
6
|
+
/** the start of the UTC day holding `t` (ms) */
|
|
7
|
+
export const dayStart = (t) => t - (((t % 86_400_000) + 86_400_000) % 86_400_000);
|
|
8
|
+
/** an in-process SpendStore: resets on restart, not shared between processes */
|
|
9
|
+
export class MemorySpendStore {
|
|
10
|
+
buckets = new Map();
|
|
11
|
+
where = new Map();
|
|
12
|
+
paid = new Map();
|
|
13
|
+
now;
|
|
14
|
+
seq = 0;
|
|
15
|
+
constructor(o = {}) {
|
|
16
|
+
this.now = o.now ?? Date.now;
|
|
17
|
+
}
|
|
18
|
+
prune(windowStart) {
|
|
19
|
+
// windows older than the previous day are dropped
|
|
20
|
+
for (const b of this.buckets.keys()) {
|
|
21
|
+
const ws = Number(b.slice(b.lastIndexOf("@") + 1));
|
|
22
|
+
if (ws < windowStart - 86_400_000)
|
|
23
|
+
this.buckets.delete(b);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
async reserve(k, amt, limit, windowStart) {
|
|
27
|
+
// no await before the check and the write: atomic within this process
|
|
28
|
+
const bk = `${k}@${windowStart}`;
|
|
29
|
+
let b = this.buckets.get(bk);
|
|
30
|
+
if (!b) {
|
|
31
|
+
this.prune(windowStart);
|
|
32
|
+
b = { committed: 0n, pending: new Map() };
|
|
33
|
+
this.buckets.set(bk, b);
|
|
34
|
+
}
|
|
35
|
+
let used = b.committed;
|
|
36
|
+
for (const v of b.pending.values())
|
|
37
|
+
used += v;
|
|
38
|
+
if (amt < 0n || used + amt > limit)
|
|
39
|
+
return { ok: false, id: "", used };
|
|
40
|
+
const id = `r${++this.seq}`;
|
|
41
|
+
b.pending.set(id, amt);
|
|
42
|
+
this.where.set(id, bk);
|
|
43
|
+
return { ok: true, id, used: used + amt };
|
|
44
|
+
}
|
|
45
|
+
async commit(id) {
|
|
46
|
+
const bk = this.where.get(id);
|
|
47
|
+
const b = bk ? this.buckets.get(bk) : undefined;
|
|
48
|
+
this.where.delete(id);
|
|
49
|
+
const v = b?.pending.get(id);
|
|
50
|
+
if (!b || v === undefined)
|
|
51
|
+
return;
|
|
52
|
+
b.pending.delete(id);
|
|
53
|
+
b.committed += v;
|
|
54
|
+
}
|
|
55
|
+
async release(id) {
|
|
56
|
+
const bk = this.where.get(id);
|
|
57
|
+
this.where.delete(id);
|
|
58
|
+
if (bk)
|
|
59
|
+
this.buckets.get(bk)?.pending.delete(id);
|
|
60
|
+
}
|
|
61
|
+
async paymentSeen(id) {
|
|
62
|
+
const until = this.paid.get(id);
|
|
63
|
+
if (until === undefined)
|
|
64
|
+
return false;
|
|
65
|
+
if (until <= this.now()) {
|
|
66
|
+
this.paid.delete(id);
|
|
67
|
+
return false;
|
|
68
|
+
}
|
|
69
|
+
return true;
|
|
70
|
+
}
|
|
71
|
+
async markPaid(id, ttlS) {
|
|
72
|
+
const t = this.now();
|
|
73
|
+
for (const [k, until] of this.paid)
|
|
74
|
+
if (until <= t)
|
|
75
|
+
this.paid.delete(k);
|
|
76
|
+
this.paid.set(id, t + ttlS * 1000);
|
|
77
|
+
}
|
|
78
|
+
}
|
package/dist/wallets.d.ts
CHANGED
|
@@ -6,8 +6,8 @@ import { type Hex } from "./check.js";
|
|
|
6
6
|
import { type GuardOptions } from "./policy.js";
|
|
7
7
|
export interface ViemGuardOptions extends GuardOptions {
|
|
8
8
|
/**
|
|
9
|
-
* Encodes writeContract calldata. Default: viem's own encodeFunctionData, loaded on first
|
|
10
|
-
* wherever a viem
|
|
9
|
+
* Encodes writeContract (and contract-call batch) calldata. Default: viem's own encodeFunctionData, loaded on first
|
|
10
|
+
* use (viem is installed wherever a viem client is).
|
|
11
11
|
*/
|
|
12
12
|
encodeFunctionData?: (args: {
|
|
13
13
|
abi: unknown;
|
|
@@ -16,27 +16,36 @@ export interface ViemGuardOptions extends GuardOptions {
|
|
|
16
16
|
}) => Hex | string;
|
|
17
17
|
}
|
|
18
18
|
/**
|
|
19
|
-
* Wraps a viem WalletClient: sendTransaction, writeContract, signTransaction
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
19
|
+
* Wraps a viem WalletClient. Asks Toll first: sendTransaction, writeContract, signTransaction, signTypedData,
|
|
20
|
+
* signMessage, sendCalls (EIP-5792, each call), signAuthorization, and request() for eth_sendTransaction,
|
|
21
|
+
* eth_signTransaction, personal_sign, eth_sign, eth_signTypedData_v4 and wallet_sendCalls. An EIP-7702 authorization
|
|
22
|
+
* goes to onAuthorization (default "check"). Wrap last: `client.extend(...)` on the wrapped client returns an unguarded
|
|
23
|
+
* client, and the account's own sign methods (client.account.sign*) are not wrapped.
|
|
23
24
|
*/
|
|
24
25
|
export declare function guardViem<T extends object>(client: T, opts?: ViemGuardOptions): T;
|
|
26
|
+
/**
|
|
27
|
+
* Wraps a viem bundler client (account abstraction): sendUserOperation and prepareUserOperation ask Toll first.
|
|
28
|
+
* `calls` are checked one by one as transactions from the smart account's address; a ready `callData` is sent as a
|
|
29
|
+
* user operation with the account's EntryPoint. An EIP-7702 `authorization` goes to onAuthorization.
|
|
30
|
+
*/
|
|
31
|
+
export declare function guardSmartAccount<T extends object>(client: T, sopts?: ViemGuardOptions): T;
|
|
25
32
|
/** the EIP-712 primary type: the one type no other type refers to (as ethers' TypedDataEncoder.getPrimaryType) */
|
|
26
33
|
export declare function primaryTypeOf(types: Record<string, Array<{
|
|
27
34
|
name: string;
|
|
28
35
|
type: string;
|
|
29
36
|
}>>): string;
|
|
30
37
|
/**
|
|
31
|
-
* Wraps an ethers v6 Signer: sendTransaction, signTransaction and
|
|
32
|
-
* authorization (a transaction's authorizationList, or authorize()) goes to onAuthorization
|
|
33
|
-
* `signer.connect(provider)` returns an unguarded signer: wrap the connected one.
|
|
38
|
+
* Wraps an ethers v6 Signer: sendTransaction, signTransaction, signTypedData, signMessage and authorize() ask Toll
|
|
39
|
+
* first. An EIP-7702 authorization (a transaction's authorizationList, or authorize()) goes to onAuthorization
|
|
40
|
+
* (default "check"). `signer.connect(provider)` returns an unguarded signer: wrap the connected one.
|
|
34
41
|
*/
|
|
35
42
|
export declare function guardEthers<T extends object>(signer: T, opts?: GuardOptions): T;
|
|
36
43
|
/** true for a viem WalletClient (has `extend` and `request`), false for an ethers Signer */
|
|
37
44
|
export declare const isViemClient: (x: unknown) => boolean;
|
|
45
|
+
/** true for a viem bundler client (account abstraction): it has sendUserOperation */
|
|
46
|
+
export declare const isBundlerClient: (x: unknown) => boolean;
|
|
38
47
|
/**
|
|
39
|
-
* Puts Toll's pre-sign check in front of a wallet
|
|
40
|
-
* the same type and methods.
|
|
48
|
+
* Puts Toll's pre-sign check in front of a wallet: a viem bundler client (smart account), a viem WalletClient or an
|
|
49
|
+
* ethers v6 Signer; the wrapped wallet has the same type and methods.
|
|
41
50
|
*/
|
|
42
51
|
export declare function guard<T extends object>(wallet: T, opts?: ViemGuardOptions): T;
|