@aifinpay/agent 1.8.2 → 2.0.0-rc.7
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 +7 -9
- package/dist/agentPassport.d.ts +35 -0
- package/dist/agentPassport.d.ts.map +1 -0
- package/dist/agentPassport.js +87 -0
- package/dist/agentPassport.js.map +1 -0
- package/dist/aifp1.d.ts +20 -9
- package/dist/aifp1.d.ts.map +1 -1
- package/dist/aifp1.js +51 -2
- package/dist/aifp1.js.map +1 -1
- package/dist/chains.d.ts +4 -0
- package/dist/chains.d.ts.map +1 -0
- package/dist/chains.js +24 -0
- package/dist/chains.js.map +1 -0
- package/dist/facilitators/detect.d.ts +3 -3
- package/dist/facilitators/detect.d.ts.map +1 -1
- package/dist/facilitators/detect.js +3 -22
- package/dist/facilitators/detect.js.map +1 -1
- package/dist/facilitators/standard-x402.d.ts +4 -8
- package/dist/facilitators/standard-x402.d.ts.map +1 -1
- package/dist/facilitators/standard-x402.js +202 -92
- package/dist/facilitators/standard-x402.js.map +1 -1
- package/dist/index.d.ts +14 -16
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +15 -30
- package/dist/index.js.map +1 -1
- package/dist/settlement.d.ts +172 -0
- package/dist/settlement.d.ts.map +1 -0
- package/dist/settlement.js +355 -0
- package/dist/settlement.js.map +1 -0
- package/dist/settlementV14.d.ts +135 -0
- package/dist/settlementV14.d.ts.map +1 -0
- package/dist/settlementV14.js +203 -0
- package/dist/settlementV14.js.map +1 -0
- package/dist/splitterRoutes.d.ts +116 -0
- package/dist/splitterRoutes.d.ts.map +1 -0
- package/dist/splitterRoutes.generated.d.ts +22 -0
- package/dist/splitterRoutes.generated.d.ts.map +1 -0
- package/dist/splitterRoutes.generated.js +399 -0
- package/dist/splitterRoutes.generated.js.map +1 -0
- package/dist/splitterRoutes.js +70 -0
- package/dist/splitterRoutes.js.map +1 -0
- package/dist/unifiedAgent.d.ts +77 -5
- package/dist/unifiedAgent.d.ts.map +1 -1
- package/dist/unifiedAgent.js +51 -81
- package/dist/unifiedAgent.js.map +1 -1
- package/dist/wallet.d.ts +28 -0
- package/dist/wallet.d.ts.map +1 -0
- package/dist/wallet.js +97 -0
- package/dist/wallet.js.map +1 -0
- package/package.json +41 -9
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* B2BSplitter v1.4 settlement — the client half.
|
|
3
|
+
*
|
|
4
|
+
* v1.4 inverts who authorises a payment. Through v1.3 the agent built its own
|
|
5
|
+
* calldata and settled unilaterally; the backend verified afterwards. In v1.4
|
|
6
|
+
* both entrypoints go through `_verifyQuote`, which requires a 65-byte ECDSA
|
|
7
|
+
* signature from a SIGN_OPERATOR_ROLE holder. The agent cannot produce one, so
|
|
8
|
+
* the quote arrives already signed and the agent's job is to CHECK it and
|
|
9
|
+
* submit it — never to construct it.
|
|
10
|
+
*
|
|
11
|
+
* That makes this module mostly refusals, and deliberately so. Spec:
|
|
12
|
+
* evm-contract@feat/v14_migration docs/V14_QUOTE_FORMAT.md §8, "SDK / Frontend
|
|
13
|
+
* Responsibilities". Each check below cites the clause it implements, because
|
|
14
|
+
* a check nobody can trace back to a requirement is a check somebody deletes.
|
|
15
|
+
*/
|
|
16
|
+
import { type PublicClient, type WalletClient, type Address, type Hex } from "viem";
|
|
17
|
+
/** The Quote struct, exactly as B2BSplitterV14 declares it. Field ORDER is part
|
|
18
|
+
* of the EIP-712 hash — this mirrors _QUOTE_TYPEHASH and must not be reordered. */
|
|
19
|
+
export interface V14Quote {
|
|
20
|
+
payer: Address;
|
|
21
|
+
merchant: Address;
|
|
22
|
+
token: Address;
|
|
23
|
+
grossAmount: string;
|
|
24
|
+
ipCreator: Address;
|
|
25
|
+
validUntil: string;
|
|
26
|
+
orderIdHash: Hex;
|
|
27
|
+
nonce: string;
|
|
28
|
+
routeId: Hex;
|
|
29
|
+
}
|
|
30
|
+
/** What `/v1/quote` returns under `settlement_call` when settlement_version is 1.4. */
|
|
31
|
+
export interface V14SettlementCall {
|
|
32
|
+
chain: string;
|
|
33
|
+
contract: Address;
|
|
34
|
+
splitter_version: "1.4";
|
|
35
|
+
route: string;
|
|
36
|
+
asset: string;
|
|
37
|
+
function: string;
|
|
38
|
+
arg_encoding: "struct+signature";
|
|
39
|
+
field_order: string[];
|
|
40
|
+
value_wei: string;
|
|
41
|
+
args: {
|
|
42
|
+
quote: V14Quote;
|
|
43
|
+
signature: Hex;
|
|
44
|
+
};
|
|
45
|
+
bound_to_payer?: Address;
|
|
46
|
+
nonce_at_signing?: string;
|
|
47
|
+
}
|
|
48
|
+
export declare class V14SettlementError extends Error {
|
|
49
|
+
readonly code: string;
|
|
50
|
+
constructor(code: string, message: string);
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Routes this SDK understands, by NAME.
|
|
54
|
+
*
|
|
55
|
+
* §8.7 requires an allow-list and says old SDKs must refuse routes added after
|
|
56
|
+
* they shipped rather than guess. Names rather than hashes because the contract
|
|
57
|
+
* derives one from the other — Profiles.routeId(name) == keccak256(bytes(name)),
|
|
58
|
+
* verified against the deployed Amoy Profiles on 2026-09-02 for both entries —
|
|
59
|
+
* so hardcoding the hashes would be storing a derived value and inviting the
|
|
60
|
+
* two to disagree.
|
|
61
|
+
*/
|
|
62
|
+
export declare const KNOWN_V14_ROUTES: readonly ["merchant-aifp1", "agent-x402"];
|
|
63
|
+
export type KnownV14Route = (typeof KNOWN_V14_ROUTES)[number];
|
|
64
|
+
export declare function routeIdOf(name: string): Hex;
|
|
65
|
+
/** name → routeId, for every route this SDK will submit. */
|
|
66
|
+
export declare function knownRouteIds(): Record<Hex, KnownV14Route>;
|
|
67
|
+
export interface V14ValidateOptions {
|
|
68
|
+
/** The off-chain order id, when the caller knows it (§8.3). Omitted means the
|
|
69
|
+
* orderIdHash cannot be checked, and this module says so rather than
|
|
70
|
+
* pretending it verified something. */
|
|
71
|
+
orderId?: string;
|
|
72
|
+
/** The wallet that will send the transaction. §8.2 and the contract's own
|
|
73
|
+
* `payer == msg.sender` make this the difference between a quote that
|
|
74
|
+
* settles and one that reverts after gas. */
|
|
75
|
+
payer?: Address;
|
|
76
|
+
/** Seconds of headroom required before validUntil. A quote that expires while
|
|
77
|
+
* the transaction is in the mempool reverts SignatureExpired and the agent
|
|
78
|
+
* pays for the attempt. */
|
|
79
|
+
minSecondsRemaining?: number;
|
|
80
|
+
nowMs?: number;
|
|
81
|
+
/** Extra route names this deployment understands. Additive only. */
|
|
82
|
+
allowRoutes?: readonly string[];
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Every check §8 requires, before anything is broadcast.
|
|
86
|
+
*
|
|
87
|
+
* Throws on the first failure with a code, because these are not equivalent:
|
|
88
|
+
* an expired quote should be re-requested, a foreign payer is a caller bug, and
|
|
89
|
+
* an unknown route means this SDK is older than the deployment.
|
|
90
|
+
*/
|
|
91
|
+
export declare function validateV14SettlementCall(call: V14SettlementCall, opts?: V14ValidateOptions): {
|
|
92
|
+
route: string;
|
|
93
|
+
expiresInSeconds: number;
|
|
94
|
+
orderIdChecked: boolean;
|
|
95
|
+
};
|
|
96
|
+
/**
|
|
97
|
+
* §8.6 — never re-broadcast a settled quote.
|
|
98
|
+
*
|
|
99
|
+
* The contract keeps two things and they answer different questions:
|
|
100
|
+
* consumedNonce[payer][nonce] has THIS nonce already been spent
|
|
101
|
+
* payerNonce[payer] which nonce the contract will accept next
|
|
102
|
+
*
|
|
103
|
+
* A quote is submittable only if its nonce is unspent AND is the one the
|
|
104
|
+
* contract expects. Two outstanding quotes for one wallet cannot both settle:
|
|
105
|
+
* the second carries a stale nonce and reverts InvalidNonce. That is a property
|
|
106
|
+
* of the contract, so it is reported here rather than discovered on-chain.
|
|
107
|
+
*/
|
|
108
|
+
export declare function checkV14Submittable(publicClient: PublicClient, call: V14SettlementCall): Promise<{
|
|
109
|
+
submittable: true;
|
|
110
|
+
} | {
|
|
111
|
+
submittable: false;
|
|
112
|
+
reason: string;
|
|
113
|
+
code: string;
|
|
114
|
+
}>;
|
|
115
|
+
/**
|
|
116
|
+
* Validate, check submittability, then send.
|
|
117
|
+
*
|
|
118
|
+
* The order matters and is not stylistic: every check that can be made without
|
|
119
|
+
* the chain runs before the one that costs a round trip, and all of them run
|
|
120
|
+
* before anything is broadcast. Once `writeContract` is called the agent has
|
|
121
|
+
* spent gas whatever happens next.
|
|
122
|
+
*/
|
|
123
|
+
export declare function executeV14Settlement(call: V14SettlementCall, ctx: {
|
|
124
|
+
publicClient: PublicClient;
|
|
125
|
+
walletClient: WalletClient;
|
|
126
|
+
account: Address;
|
|
127
|
+
orderId?: string;
|
|
128
|
+
minSecondsRemaining?: number;
|
|
129
|
+
/** Skip the on-chain pre-flight. Only for a caller that has just done it. */
|
|
130
|
+
skipPreflight?: boolean;
|
|
131
|
+
}): Promise<{
|
|
132
|
+
hash: Hex;
|
|
133
|
+
route: string;
|
|
134
|
+
}>;
|
|
135
|
+
//# sourceMappingURL=settlementV14.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"settlementV14.d.ts","sourceRoot":"","sources":["../src/settlementV14.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* B2BSplitter v1.4 settlement — the client half.
|
|
3
|
+
*
|
|
4
|
+
* v1.4 inverts who authorises a payment. Through v1.3 the agent built its own
|
|
5
|
+
* calldata and settled unilaterally; the backend verified afterwards. In v1.4
|
|
6
|
+
* both entrypoints go through `_verifyQuote`, which requires a 65-byte ECDSA
|
|
7
|
+
* signature from a SIGN_OPERATOR_ROLE holder. The agent cannot produce one, so
|
|
8
|
+
* the quote arrives already signed and the agent's job is to CHECK it and
|
|
9
|
+
* submit it — never to construct it.
|
|
10
|
+
*
|
|
11
|
+
* That makes this module mostly refusals, and deliberately so. Spec:
|
|
12
|
+
* evm-contract@feat/v14_migration docs/V14_QUOTE_FORMAT.md §8, "SDK / Frontend
|
|
13
|
+
* Responsibilities". Each check below cites the clause it implements, because
|
|
14
|
+
* a check nobody can trace back to a requirement is a check somebody deletes.
|
|
15
|
+
*/
|
|
16
|
+
import { keccak256, stringToHex, parseAbi, } from "viem";
|
|
17
|
+
export class V14SettlementError extends Error {
|
|
18
|
+
code;
|
|
19
|
+
constructor(code, message) {
|
|
20
|
+
super(message);
|
|
21
|
+
this.name = "V14SettlementError";
|
|
22
|
+
this.code = code;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Routes this SDK understands, by NAME.
|
|
27
|
+
*
|
|
28
|
+
* §8.7 requires an allow-list and says old SDKs must refuse routes added after
|
|
29
|
+
* they shipped rather than guess. Names rather than hashes because the contract
|
|
30
|
+
* derives one from the other — Profiles.routeId(name) == keccak256(bytes(name)),
|
|
31
|
+
* verified against the deployed Amoy Profiles on 2026-09-02 for both entries —
|
|
32
|
+
* so hardcoding the hashes would be storing a derived value and inviting the
|
|
33
|
+
* two to disagree.
|
|
34
|
+
*/
|
|
35
|
+
export const KNOWN_V14_ROUTES = ["merchant-aifp1", "agent-x402"];
|
|
36
|
+
export function routeIdOf(name) {
|
|
37
|
+
return keccak256(stringToHex(name));
|
|
38
|
+
}
|
|
39
|
+
/** name → routeId, for every route this SDK will submit. */
|
|
40
|
+
export function knownRouteIds() {
|
|
41
|
+
const out = {};
|
|
42
|
+
for (const n of KNOWN_V14_ROUTES)
|
|
43
|
+
out[routeIdOf(n).toLowerCase()] = n;
|
|
44
|
+
return out;
|
|
45
|
+
}
|
|
46
|
+
const ZERO = "0x0000000000000000000000000000000000000000";
|
|
47
|
+
const lc = (s) => String(s || "").toLowerCase();
|
|
48
|
+
/**
|
|
49
|
+
* Every check §8 requires, before anything is broadcast.
|
|
50
|
+
*
|
|
51
|
+
* Throws on the first failure with a code, because these are not equivalent:
|
|
52
|
+
* an expired quote should be re-requested, a foreign payer is a caller bug, and
|
|
53
|
+
* an unknown route means this SDK is older than the deployment.
|
|
54
|
+
*/
|
|
55
|
+
export function validateV14SettlementCall(call, opts = {}) {
|
|
56
|
+
const fail = (code, msg) => { throw new V14SettlementError(code, msg); };
|
|
57
|
+
if (!call || typeof call !== "object")
|
|
58
|
+
fail("V14_MALFORMED", "no settlement call");
|
|
59
|
+
if (call.splitter_version !== "1.4") {
|
|
60
|
+
fail("V14_WRONG_VERSION", `expected a v1.4 settlement call, got ${String(call.splitter_version)} — v1.2 and v1.3 settle through a different path`);
|
|
61
|
+
}
|
|
62
|
+
const q = call.args && call.args.quote;
|
|
63
|
+
const sig = call.args && call.args.signature;
|
|
64
|
+
if (!q || !sig)
|
|
65
|
+
fail("V14_MALFORMED", "settlement call carries no quote or no signature");
|
|
66
|
+
// §8.1 — the signature is the whole point. The contract requires exactly 65
|
|
67
|
+
// bytes and reverts InvalidSignatureLength on anything else, after gas.
|
|
68
|
+
if (!/^0x[0-9a-fA-F]{130}$/.test(sig)) {
|
|
69
|
+
fail("V14_BAD_SIGNATURE", `signature must be 65 bytes, got ${(String(sig).length - 2) / 2}`);
|
|
70
|
+
}
|
|
71
|
+
// §8.7 — refuse routes this SDK does not understand rather than submit blind.
|
|
72
|
+
const allowed = { ...knownRouteIds() };
|
|
73
|
+
for (const extra of opts.allowRoutes || [])
|
|
74
|
+
allowed[routeIdOf(extra).toLowerCase()] = extra;
|
|
75
|
+
const route = allowed[lc(q.routeId)];
|
|
76
|
+
if (!route) {
|
|
77
|
+
fail("V14_UNKNOWN_ROUTE", `routeId ${q.routeId} is not one this SDK understands (${Object.values(allowed).join(", ")}). ` +
|
|
78
|
+
`A route added after this SDK shipped is expected — upgrade rather than force it.`);
|
|
79
|
+
}
|
|
80
|
+
// §8.2 — the contract enforces payer == msg.sender. Catching it here costs
|
|
81
|
+
// nothing; catching it on-chain costs the gas of a reverted transaction.
|
|
82
|
+
if (opts.payer && lc(opts.payer) !== lc(q.payer)) {
|
|
83
|
+
fail("V14_WRONG_PAYER", `this quote is signed for ${q.payer} and cannot be settled by ${opts.payer} — request one for your own address`);
|
|
84
|
+
}
|
|
85
|
+
if (call.bound_to_payer && lc(call.bound_to_payer) !== lc(q.payer)) {
|
|
86
|
+
fail("V14_MALFORMED", "bound_to_payer disagrees with the signed quote — do not submit this");
|
|
87
|
+
}
|
|
88
|
+
// §8.3 — hash the order id locally and compare. This is what stops a backend
|
|
89
|
+
// (or anything between it and here) from binding your payment to a different
|
|
90
|
+
// order than the one you asked about.
|
|
91
|
+
let orderIdChecked = false;
|
|
92
|
+
if (opts.orderId !== undefined) {
|
|
93
|
+
if (lc(keccak256(stringToHex(opts.orderId))) !== lc(q.orderIdHash)) {
|
|
94
|
+
fail("V14_ORDER_MISMATCH", `this quote settles a different order: orderIdHash does not match keccak256("${opts.orderId}")`);
|
|
95
|
+
}
|
|
96
|
+
orderIdChecked = true;
|
|
97
|
+
}
|
|
98
|
+
// §8.4 — expiry. Checked with headroom, because the relevant moment is when
|
|
99
|
+
// the transaction is MINED, not when it is signed.
|
|
100
|
+
const now = Math.floor((opts.nowMs ?? Date.now()) / 1000);
|
|
101
|
+
const expiresIn = Number(BigInt(q.validUntil) - BigInt(now));
|
|
102
|
+
const need = opts.minSecondsRemaining ?? 30;
|
|
103
|
+
if (expiresIn <= 0) {
|
|
104
|
+
fail("V14_EXPIRED", `quote expired ${-expiresIn}s ago — request a fresh one, do not submit this`);
|
|
105
|
+
}
|
|
106
|
+
if (expiresIn < need) {
|
|
107
|
+
fail("V14_EXPIRING", `quote expires in ${expiresIn}s, less than the ${need}s of headroom required — ` +
|
|
108
|
+
`it would likely revert SignatureExpired after you have paid gas`);
|
|
109
|
+
}
|
|
110
|
+
// §8.5 — msg.value must equal grossAmount exactly for native. The contract
|
|
111
|
+
// reverts IncorrectNativeValue on any difference, in either direction.
|
|
112
|
+
if (lc(q.token) === ZERO && String(call.value_wei) !== String(q.grossAmount)) {
|
|
113
|
+
fail("V14_VALUE_MISMATCH", `value_wei (${call.value_wei}) must equal the signed grossAmount (${q.grossAmount})`);
|
|
114
|
+
}
|
|
115
|
+
return { route: route, expiresInSeconds: expiresIn, orderIdChecked };
|
|
116
|
+
}
|
|
117
|
+
const NONCE_ABI = parseAbi([
|
|
118
|
+
"function consumedNonce(address,uint256) view returns (bool)",
|
|
119
|
+
"function payerNonce(address) view returns (uint256)",
|
|
120
|
+
"function paused() view returns (bool)",
|
|
121
|
+
]);
|
|
122
|
+
/**
|
|
123
|
+
* §8.6 — never re-broadcast a settled quote.
|
|
124
|
+
*
|
|
125
|
+
* The contract keeps two things and they answer different questions:
|
|
126
|
+
* consumedNonce[payer][nonce] has THIS nonce already been spent
|
|
127
|
+
* payerNonce[payer] which nonce the contract will accept next
|
|
128
|
+
*
|
|
129
|
+
* A quote is submittable only if its nonce is unspent AND is the one the
|
|
130
|
+
* contract expects. Two outstanding quotes for one wallet cannot both settle:
|
|
131
|
+
* the second carries a stale nonce and reverts InvalidNonce. That is a property
|
|
132
|
+
* of the contract, so it is reported here rather than discovered on-chain.
|
|
133
|
+
*/
|
|
134
|
+
export async function checkV14Submittable(publicClient, call) {
|
|
135
|
+
const q = call.args.quote;
|
|
136
|
+
const [spent, expected, paused] = await Promise.all([
|
|
137
|
+
publicClient.readContract({ address: call.contract, abi: NONCE_ABI, functionName: "consumedNonce", args: [q.payer, BigInt(q.nonce)] }),
|
|
138
|
+
publicClient.readContract({ address: call.contract, abi: NONCE_ABI, functionName: "payerNonce", args: [q.payer] }),
|
|
139
|
+
publicClient.readContract({ address: call.contract, abi: NONCE_ABI, functionName: "paused" }),
|
|
140
|
+
]);
|
|
141
|
+
if (paused) {
|
|
142
|
+
return { submittable: false, code: "V14_PAUSED",
|
|
143
|
+
reason: "the splitter is paused — every settlement reverts until it is unpaused" };
|
|
144
|
+
}
|
|
145
|
+
if (spent) {
|
|
146
|
+
return { submittable: false, code: "V14_ALREADY_SETTLED",
|
|
147
|
+
reason: `nonce ${q.nonce} has already been spent by ${q.payer} — this quote is settled, do not pay twice` };
|
|
148
|
+
}
|
|
149
|
+
if (BigInt(expected) !== BigInt(q.nonce)) {
|
|
150
|
+
return { submittable: false, code: "V14_STALE_NONCE",
|
|
151
|
+
reason: `this quote was signed at nonce ${q.nonce} but the contract now expects ${expected} — ` +
|
|
152
|
+
`another payment from this wallet settled first; request a fresh quote` };
|
|
153
|
+
}
|
|
154
|
+
return { submittable: true };
|
|
155
|
+
}
|
|
156
|
+
const SETTLE_ABI = parseAbi([
|
|
157
|
+
"function settleNative((address payer,address merchant,address token,uint256 grossAmount,address ipCreator,uint256 validUntil,bytes32 orderIdHash,uint256 nonce,bytes32 routeId) quote, bytes signature) payable",
|
|
158
|
+
"function settleStable((address payer,address merchant,address token,uint256 grossAmount,address ipCreator,uint256 validUntil,bytes32 orderIdHash,uint256 nonce,bytes32 routeId) quote, bytes signature)",
|
|
159
|
+
]);
|
|
160
|
+
const asTuple = (q) => ({
|
|
161
|
+
payer: q.payer, merchant: q.merchant, token: q.token,
|
|
162
|
+
grossAmount: BigInt(q.grossAmount), ipCreator: q.ipCreator,
|
|
163
|
+
validUntil: BigInt(q.validUntil), orderIdHash: q.orderIdHash,
|
|
164
|
+
nonce: BigInt(q.nonce), routeId: q.routeId,
|
|
165
|
+
});
|
|
166
|
+
/**
|
|
167
|
+
* Validate, check submittability, then send.
|
|
168
|
+
*
|
|
169
|
+
* The order matters and is not stylistic: every check that can be made without
|
|
170
|
+
* the chain runs before the one that costs a round trip, and all of them run
|
|
171
|
+
* before anything is broadcast. Once `writeContract` is called the agent has
|
|
172
|
+
* spent gas whatever happens next.
|
|
173
|
+
*/
|
|
174
|
+
export async function executeV14Settlement(call, ctx) {
|
|
175
|
+
const { route } = validateV14SettlementCall(call, {
|
|
176
|
+
orderId: ctx.orderId, payer: ctx.account, minSecondsRemaining: ctx.minSecondsRemaining,
|
|
177
|
+
});
|
|
178
|
+
if (!ctx.skipPreflight) {
|
|
179
|
+
const pre = await checkV14Submittable(ctx.publicClient, call);
|
|
180
|
+
if (!pre.submittable)
|
|
181
|
+
throw new V14SettlementError(pre.code, pre.reason);
|
|
182
|
+
}
|
|
183
|
+
const q = call.args.quote;
|
|
184
|
+
const native = lc(q.token) === ZERO;
|
|
185
|
+
if (!native) {
|
|
186
|
+
// §9.1 — settleStable needs an allowance first. Refused rather than
|
|
187
|
+
// silently attempted: approving on the agent's behalf is a decision the
|
|
188
|
+
// agent's own policy layer makes, not this function.
|
|
189
|
+
throw new V14SettlementError("V14_STABLE_NOT_SUPPORTED", "stablecoin settlement requires approve(splitter, grossAmount) first and is not yet wired here — " +
|
|
190
|
+
"quote in native for now");
|
|
191
|
+
}
|
|
192
|
+
const hash = await ctx.walletClient.writeContract({
|
|
193
|
+
address: call.contract,
|
|
194
|
+
abi: SETTLE_ABI,
|
|
195
|
+
functionName: "settleNative",
|
|
196
|
+
args: [asTuple(q), call.args.signature],
|
|
197
|
+
value: BigInt(q.grossAmount),
|
|
198
|
+
account: ctx.account,
|
|
199
|
+
chain: null,
|
|
200
|
+
});
|
|
201
|
+
return { hash, route };
|
|
202
|
+
}
|
|
203
|
+
//# sourceMappingURL=settlementV14.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"settlementV14.js","sourceRoot":"","sources":["../src/settlementV14.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AACH,OAAO,EACL,SAAS,EAAE,WAAW,EAAE,QAAQ,GAEjC,MAAM,MAAM,CAAC;AAgCd,MAAM,OAAO,kBAAmB,SAAQ,KAAK;IAClC,IAAI,CAAS;IACtB,YAAY,IAAY,EAAE,OAAe;QACvC,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,oBAAoB,CAAC;QACjC,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;IACnB,CAAC;CACF;AAED;;;;;;;;;GASG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,gBAAgB,EAAE,YAAY,CAAU,CAAC;AAG1E,MAAM,UAAU,SAAS,CAAC,IAAY;IACpC,OAAO,SAAS,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC;AACtC,CAAC;AAED,4DAA4D;AAC5D,MAAM,UAAU,aAAa;IAC3B,MAAM,GAAG,GAAkC,EAAE,CAAC;IAC9C,KAAK,MAAM,CAAC,IAAI,gBAAgB;QAAE,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC,GAAG,CAAC,CAAC;IACtE,OAAO,GAAiC,CAAC;AAC3C,CAAC;AAED,MAAM,IAAI,GAAG,4CAA4C,CAAC;AAC1D,MAAM,EAAE,GAAG,CAAC,CAAS,EAAE,EAAE,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,WAAW,EAAE,CAAC;AAoBxD;;;;;;GAMG;AACH,MAAM,UAAU,yBAAyB,CACvC,IAAuB,EACvB,OAA2B,EAAE;IAE7B,MAAM,IAAI,GAAG,CAAC,IAAY,EAAE,GAAW,EAAE,EAAE,GAAG,MAAM,IAAI,kBAAkB,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;IAEzF,IAAI,CAAC,IAAI,IAAI,OAAO,IAAI,KAAK,QAAQ;QAAE,IAAI,CAAC,eAAe,EAAE,oBAAoB,CAAC,CAAC;IACnF,IAAI,IAAI,CAAC,gBAAgB,KAAK,KAAK,EAAE,CAAC;QACpC,IAAI,CAAC,mBAAmB,EACtB,wCAAwC,MAAM,CAAC,IAAI,CAAC,gBAAgB,CAAC,kDAAkD,CAAC,CAAC;IAC7H,CAAC;IACD,MAAM,CAAC,GAAG,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC;IACvC,MAAM,GAAG,GAAG,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC;IAC7C,IAAI,CAAC,CAAC,IAAI,CAAC,GAAG;QAAE,IAAI,CAAC,eAAe,EAAE,kDAAkD,CAAC,CAAC;IAE1F,4EAA4E;IAC5E,wEAAwE;IACxE,IAAI,CAAC,sBAAsB,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;QACtC,IAAI,CAAC,mBAAmB,EAAE,mCAAmC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAC/F,CAAC;IAED,8EAA8E;IAC9E,MAAM,OAAO,GAAG,EAAE,GAAG,aAAa,EAAE,EAA4B,CAAC;IACjE,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,WAAW,IAAI,EAAE;QAAE,OAAO,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,WAAW,EAAE,CAAC,GAAG,KAAK,CAAC;IAC5F,MAAM,KAAK,GAAG,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC;IACrC,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,IAAI,CAAC,mBAAmB,EACtB,WAAW,CAAC,CAAC,OAAO,qCAAqC,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK;YAC/F,kFAAkF,CAAC,CAAC;IACxF,CAAC;IAED,2EAA2E;IAC3E,yEAAyE;IACzE,IAAI,IAAI,CAAC,KAAK,IAAI,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC;QACjD,IAAI,CAAC,iBAAiB,EACpB,4BAA4B,CAAC,CAAC,KAAK,6BAA6B,IAAI,CAAC,KAAK,qCAAqC,CAAC,CAAC;IACrH,CAAC;IACD,IAAI,IAAI,CAAC,cAAc,IAAI,EAAE,CAAC,IAAI,CAAC,cAAc,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC;QACnE,IAAI,CAAC,eAAe,EAAE,qEAAqE,CAAC,CAAC;IAC/F,CAAC;IAED,6EAA6E;IAC7E,6EAA6E;IAC7E,sCAAsC;IACtC,IAAI,cAAc,GAAG,KAAK,CAAC;IAC3B,IAAI,IAAI,CAAC,OAAO,KAAK,SAAS,EAAE,CAAC;QAC/B,IAAI,EAAE,CAAC,SAAS,CAAC,WAAW,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,WAAW,CAAC,EAAE,CAAC;YACnE,IAAI,CAAC,oBAAoB,EACvB,+EAA+E,IAAI,CAAC,OAAO,IAAI,CAAC,CAAC;QACrG,CAAC;QACD,cAAc,GAAG,IAAI,CAAC;IACxB,CAAC;IAED,4EAA4E;IAC5E,mDAAmD;IACnD,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,GAAG,EAAE,CAAC,GAAG,IAAI,CAAC,CAAC;IAC1D,MAAM,SAAS,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,UAAU,CAAC,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC;IAC7D,MAAM,IAAI,GAAG,IAAI,CAAC,mBAAmB,IAAI,EAAE,CAAC;IAC5C,IAAI,SAAS,IAAI,CAAC,EAAE,CAAC;QACnB,IAAI,CAAC,aAAa,EAAE,iBAAiB,CAAC,SAAS,iDAAiD,CAAC,CAAC;IACpG,CAAC;IACD,IAAI,SAAS,GAAG,IAAI,EAAE,CAAC;QACrB,IAAI,CAAC,cAAc,EACjB,oBAAoB,SAAS,oBAAoB,IAAI,2BAA2B;YAChF,iEAAiE,CAAC,CAAC;IACvE,CAAC;IAED,2EAA2E;IAC3E,uEAAuE;IACvE,IAAI,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,IAAI,IAAI,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,KAAK,MAAM,CAAC,CAAC,CAAC,WAAW,CAAC,EAAE,CAAC;QAC7E,IAAI,CAAC,oBAAoB,EACvB,cAAc,IAAI,CAAC,SAAS,wCAAwC,CAAC,CAAC,WAAW,GAAG,CAAC,CAAC;IAC1F,CAAC;IAED,OAAO,EAAE,KAAK,EAAE,KAAe,EAAE,gBAAgB,EAAE,SAAS,EAAE,cAAc,EAAE,CAAC;AACjF,CAAC;AAED,MAAM,SAAS,GAAG,QAAQ,CAAC;IACzB,6DAA6D;IAC7D,qDAAqD;IACrD,uCAAuC;CACxC,CAAC,CAAC;AAEH;;;;;;;;;;;GAWG;AACH,MAAM,CAAC,KAAK,UAAU,mBAAmB,CACvC,YAA0B,EAC1B,IAAuB;IAEvB,MAAM,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC;IAC1B,MAAM,CAAC,KAAK,EAAE,QAAQ,EAAE,MAAM,CAAC,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC;QAClD,YAAY,CAAC,YAAY,CAAC,EAAE,OAAO,EAAE,IAAI,CAAC,QAAQ,EAAE,GAAG,EAAE,SAAS,EAAE,YAAY,EAAE,eAAe,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC;QACtI,YAAY,CAAC,YAAY,CAAC,EAAE,OAAO,EAAE,IAAI,CAAC,QAAQ,EAAE,GAAG,EAAE,SAAS,EAAE,YAAY,EAAE,YAAY,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC;QAClH,YAAY,CAAC,YAAY,CAAC,EAAE,OAAO,EAAE,IAAI,CAAC,QAAQ,EAAE,GAAG,EAAE,SAAS,EAAE,YAAY,EAAE,QAAQ,EAAE,CAAC;KAC9F,CAAC,CAAC;IAEH,IAAI,MAAM,EAAE,CAAC;QACX,OAAO,EAAE,WAAW,EAAE,KAAK,EAAE,IAAI,EAAE,YAAY;YAC7C,MAAM,EAAE,wEAAwE,EAAE,CAAC;IACvF,CAAC;IACD,IAAI,KAAK,EAAE,CAAC;QACV,OAAO,EAAE,WAAW,EAAE,KAAK,EAAE,IAAI,EAAE,qBAAqB;YACtD,MAAM,EAAE,SAAS,CAAC,CAAC,KAAK,8BAA8B,CAAC,CAAC,KAAK,4CAA4C,EAAE,CAAC;IAChH,CAAC;IACD,IAAI,MAAM,CAAC,QAAQ,CAAC,KAAK,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC;QACzC,OAAO,EAAE,WAAW,EAAE,KAAK,EAAE,IAAI,EAAE,iBAAiB;YAClD,MAAM,EAAE,kCAAkC,CAAC,CAAC,KAAK,iCAAiC,QAAQ,KAAK;gBACvF,uEAAuE,EAAE,CAAC;IACtF,CAAC;IACD,OAAO,EAAE,WAAW,EAAE,IAAI,EAAE,CAAC;AAC/B,CAAC;AAED,MAAM,UAAU,GAAG,QAAQ,CAAC;IAC1B,iNAAiN;IACjN,yMAAyM;CAC1M,CAAC,CAAC;AAEH,MAAM,OAAO,GAAG,CAAC,CAAW,EAAE,EAAE,CAAC,CAAC;IAChC,KAAK,EAAE,CAAC,CAAC,KAAK,EAAE,QAAQ,EAAE,CAAC,CAAC,QAAQ,EAAE,KAAK,EAAE,CAAC,CAAC,KAAK;IACpD,WAAW,EAAE,MAAM,CAAC,CAAC,CAAC,WAAW,CAAC,EAAE,SAAS,EAAE,CAAC,CAAC,SAAS;IAC1D,UAAU,EAAE,MAAM,CAAC,CAAC,CAAC,UAAU,CAAC,EAAE,WAAW,EAAE,CAAC,CAAC,WAAW;IAC5D,KAAK,EAAE,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,OAAO,EAAE,CAAC,CAAC,OAAO;CAC3C,CAAC,CAAC;AAEH;;;;;;;GAOG;AACH,MAAM,CAAC,KAAK,UAAU,oBAAoB,CACxC,IAAuB,EACvB,GAQC;IAED,MAAM,EAAE,KAAK,EAAE,GAAG,yBAAyB,CAAC,IAAI,EAAE;QAChD,OAAO,EAAE,GAAG,CAAC,OAAO,EAAE,KAAK,EAAE,GAAG,CAAC,OAAO,EAAE,mBAAmB,EAAE,GAAG,CAAC,mBAAmB;KACvF,CAAC,CAAC;IAEH,IAAI,CAAC,GAAG,CAAC,aAAa,EAAE,CAAC;QACvB,MAAM,GAAG,GAAG,MAAM,mBAAmB,CAAC,GAAG,CAAC,YAAY,EAAE,IAAI,CAAC,CAAC;QAC9D,IAAI,CAAC,GAAG,CAAC,WAAW;YAAE,MAAM,IAAI,kBAAkB,CAAC,GAAG,CAAC,IAAI,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IAC3E,CAAC;IAED,MAAM,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC;IAC1B,MAAM,MAAM,GAAG,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,IAAI,CAAC;IACpC,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,oEAAoE;QACpE,wEAAwE;QACxE,qDAAqD;QACrD,MAAM,IAAI,kBAAkB,CAAC,0BAA0B,EACrD,kGAAkG;YAClG,yBAAyB,CAAC,CAAC;IAC/B,CAAC;IAED,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,YAAY,CAAC,aAAa,CAAC;QAChD,OAAO,EAAE,IAAI,CAAC,QAAQ;QACtB,GAAG,EAAE,UAAU;QACf,YAAY,EAAE,cAAc;QAC5B,IAAI,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC;QACvC,KAAK,EAAE,MAAM,CAAC,CAAC,CAAC,WAAW,CAAC;QAC5B,OAAO,EAAE,GAAG,CAAC,OAAO;QACpB,KAAK,EAAE,IAAI;KACZ,CAAC,CAAC;IACH,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC;AACzB,CAAC"}
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* v1.3 splitter selection, keyed by chain AND protocol route.
|
|
3
|
+
*
|
|
4
|
+
* From v1.3 a chain carries one splitter per protocol route, because the fee
|
|
5
|
+
* split is immutable at construction and the two protocols need different
|
|
6
|
+
* economics:
|
|
7
|
+
*
|
|
8
|
+
* merchant-aifp1 (100/0) — the agent pays the quoted gross amount, the
|
|
9
|
+
* AiFinPay treasury receives 1%, the merchant receives 99%.
|
|
10
|
+
* agent-x402 (0/0) — the provider receives 100% of the provider-defined
|
|
11
|
+
* price and the AiFinPay fee is 0% for now. This route is NOT fee-on-top;
|
|
12
|
+
* fee-on-top semantics arrive in a future contract version.
|
|
13
|
+
*
|
|
14
|
+
* Selection must use both chain and route, and must never fall back from one
|
|
15
|
+
* route to the other. That is not a style preference. The splitters were
|
|
16
|
+
* deployed with CREATE, so an address derives from deployer and nonce and the
|
|
17
|
+
* same address recurs on other chains for the other route:
|
|
18
|
+
*
|
|
19
|
+
* 0x1Fe2021336596655Fac72bC7bC40F7FFFA501d55
|
|
20
|
+
* is OP's merchant-aifp1 AND Base's agent-x402
|
|
21
|
+
* 0xF03B3387415D557b6ab709D06E8aF0b4ABD6Eb74
|
|
22
|
+
* is Unichain's merchant-aifp1, Avalanche's agent-x402, AND the legacy
|
|
23
|
+
* v1.2 splitter on Optimism
|
|
24
|
+
*
|
|
25
|
+
* An address on its own therefore says nothing about which economics apply.
|
|
26
|
+
* Resolving by chain alone would settle at the wrong fee split, silently,
|
|
27
|
+
* and the amounts would still look plausible in every log.
|
|
28
|
+
*
|
|
29
|
+
* The table itself is NOT in this file. It is generated into
|
|
30
|
+
* splitterRoutes.generated.ts from registry/splitter-table.json, a byte-for-byte
|
|
31
|
+
* copy of the canonical artifact in AiFinPay/evm-contract, where every
|
|
32
|
+
* payment-critical field — splitter, owner, treasury, both bps values, the
|
|
33
|
+
* runtime code hash — was read from the chain by verify-registry.mjs. Two
|
|
34
|
+
* repositories hand-maintaining the same payout addresses is the failure this
|
|
35
|
+
* split prevents; `npm run registry:check` fails CI if they disagree.
|
|
36
|
+
*
|
|
37
|
+
* What stays here is the part worth reading: the types, the errors, and the two
|
|
38
|
+
* resolvers. Logic belongs in a reviewed file, not in a generated one.
|
|
39
|
+
*/
|
|
40
|
+
import type { Chain } from "viem/chains";
|
|
41
|
+
export { SPLITTER_ROUTES, SPLITTER_GOVERNANCE, SPLITTER_REGISTRY_SOURCE, } from "./splitterRoutes.generated.js";
|
|
42
|
+
/** Protocol routes. A route is a fee profile fixed at construction. */
|
|
43
|
+
export type SplitterRoute = "merchant-aifp1" | "agent-x402";
|
|
44
|
+
/** Chains carrying v1.3 route splitters. */
|
|
45
|
+
export type SplitterRouteChain = "polygon" | "optimism" | "bnb" | "unichain" | "botchain" | "base" | "arbitrum" | "avalanche" | "xrplevm";
|
|
46
|
+
/** Key into SPLITTER_ROUTES. Both halves are required. */
|
|
47
|
+
export type SplitterRouteKey = `${SplitterRouteChain}:${SplitterRoute}`;
|
|
48
|
+
export interface SplitterRouteDeployment {
|
|
49
|
+
chain: SplitterRouteChain;
|
|
50
|
+
route: SplitterRoute;
|
|
51
|
+
chainId: number;
|
|
52
|
+
viemChain: Chain;
|
|
53
|
+
splitter: `0x${string}`;
|
|
54
|
+
/**
|
|
55
|
+
* The governance Safe, read from the contract's own owner(). It controls
|
|
56
|
+
* pause/unpause, the treasury address and the stablecoin whitelist, so it is
|
|
57
|
+
* carried here rather than assumed: every other field is only as trustworthy
|
|
58
|
+
* as whoever can change it.
|
|
59
|
+
*/
|
|
60
|
+
owner: `0x${string}`;
|
|
61
|
+
/** Owner and treasury are the same governance Safe on every chain. */
|
|
62
|
+
treasury: `0x${string}`;
|
|
63
|
+
/** Immutable, baked into runtime code. 100 = 1%. */
|
|
64
|
+
treasuryBps: number;
|
|
65
|
+
ipCreatorBps: number;
|
|
66
|
+
/** keccak-256 of the deployed runtime bytecode, read from chain. */
|
|
67
|
+
runtimeCodeHash: `0x${string}`;
|
|
68
|
+
/**
|
|
69
|
+
* Deployed and verified is not the same as payable. A route is enabled
|
|
70
|
+
* individually, and only after a successful mainnet paid end-to-end
|
|
71
|
+
* settlement on that exact route with verified balance deltas.
|
|
72
|
+
*/
|
|
73
|
+
settlementEnabled: boolean;
|
|
74
|
+
/**
|
|
75
|
+
* How many independent RPC providers agreed on every field above when the
|
|
76
|
+
* registry was verified. A route verified from one provider can never be
|
|
77
|
+
* enabled — BOT Chain and XRPL EVM have exactly one public provider each.
|
|
78
|
+
*/
|
|
79
|
+
rpcQuorum: number;
|
|
80
|
+
/**
|
|
81
|
+
* Stablecoins the splitter accepts, read live via whitelistedTokens() and
|
|
82
|
+
* owner-mutable, so pinned separately from the runtime hash. null = not
|
|
83
|
+
* accepted on this chain; a chain with both null settles native only.
|
|
84
|
+
*/
|
|
85
|
+
stablecoins: {
|
|
86
|
+
USDC: `0x${string}` | null;
|
|
87
|
+
USDT: `0x${string}` | null;
|
|
88
|
+
};
|
|
89
|
+
/** Policy review window. Outside it, a route must not settle. */
|
|
90
|
+
validFrom: string;
|
|
91
|
+
validUntil: string;
|
|
92
|
+
defaultRpc: string;
|
|
93
|
+
explorer: string;
|
|
94
|
+
/** The date the fields above were last read from the chain. */
|
|
95
|
+
verifiedAt: string;
|
|
96
|
+
}
|
|
97
|
+
export declare class UnknownSplitterRouteError extends Error {
|
|
98
|
+
constructor(chain: string, route: string);
|
|
99
|
+
}
|
|
100
|
+
export declare class SplitterRouteNotSettlingError extends Error {
|
|
101
|
+
constructor(key: string, reason: string);
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Resolve a splitter by chain AND route. Throws on an unknown pair rather
|
|
105
|
+
* than falling back, because the fallback is the bug: every route resolves to
|
|
106
|
+
* a real, deployed, working contract with the wrong economics.
|
|
107
|
+
*/
|
|
108
|
+
export declare function resolveSplitterRoute(chain: SplitterRouteChain | string, route: SplitterRoute | string): SplitterRouteDeployment;
|
|
109
|
+
/**
|
|
110
|
+
* Resolve a route that is cleared to move money. Separate from
|
|
111
|
+
* resolveSplitterRoute on purpose: reading the registry and being allowed to
|
|
112
|
+
* settle are different questions, and conflating them is how a disabled route
|
|
113
|
+
* ends up paying.
|
|
114
|
+
*/
|
|
115
|
+
export declare function resolveSettlingSplitterRoute(chain: SplitterRouteChain | string, route: SplitterRoute | string, now?: Date): SplitterRouteDeployment;
|
|
116
|
+
//# sourceMappingURL=splitterRoutes.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"splitterRoutes.d.ts","sourceRoot":"","sources":["../src/splitterRoutes.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsCG;AACH,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AAIzC,OAAO,EACL,eAAe,EACf,mBAAmB,EACnB,wBAAwB,GACzB,MAAM,+BAA+B,CAAC;AAEvC,uEAAuE;AACvE,MAAM,MAAM,aAAa,GAAG,gBAAgB,GAAG,YAAY,CAAC;AAE5D,4CAA4C;AAC5C,MAAM,MAAM,kBAAkB,GAC1B,SAAS,GACT,UAAU,GACV,KAAK,GACL,UAAU,GACV,UAAU,GACV,MAAM,GACN,UAAU,GACV,WAAW,GACX,SAAS,CAAC;AAEd,0DAA0D;AAC1D,MAAM,MAAM,gBAAgB,GAAG,GAAG,kBAAkB,IAAI,aAAa,EAAE,CAAC;AAExE,MAAM,WAAW,uBAAuB;IACtC,KAAK,EAAE,kBAAkB,CAAC;IAC1B,KAAK,EAAE,aAAa,CAAC;IACrB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,KAAK,CAAC;IACjB,QAAQ,EAAE,KAAK,MAAM,EAAE,CAAC;IACxB;;;;;OAKG;IACH,KAAK,EAAE,KAAK,MAAM,EAAE,CAAC;IACrB,sEAAsE;IACtE,QAAQ,EAAE,KAAK,MAAM,EAAE,CAAC;IACxB,oDAAoD;IACpD,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;IACrB,oEAAoE;IACpE,eAAe,EAAE,KAAK,MAAM,EAAE,CAAC;IAC/B;;;;OAIG;IACH,iBAAiB,EAAE,OAAO,CAAC;IAC3B;;;;OAIG;IACH,SAAS,EAAE,MAAM,CAAC;IAClB;;;;OAIG;IACH,WAAW,EAAE;QAAE,IAAI,EAAE,KAAK,MAAM,EAAE,GAAG,IAAI,CAAC;QAAC,IAAI,EAAE,KAAK,MAAM,EAAE,GAAG,IAAI,CAAA;KAAE,CAAC;IACxE,iEAAiE;IACjE,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,+DAA+D;IAC/D,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,qBAAa,yBAA0B,SAAQ,KAAK;gBACtC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM;CAUzC;AAED,qBAAa,6BAA8B,SAAQ,KAAK;gBAC1C,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM;CAIxC;AAED;;;;GAIG;AACH,wBAAgB,oBAAoB,CAClC,KAAK,EAAE,kBAAkB,GAAG,MAAM,EAClC,KAAK,EAAE,aAAa,GAAG,MAAM,GAC5B,uBAAuB,CAMzB;AAED;;;;;GAKG;AACH,wBAAgB,4BAA4B,CAC1C,KAAK,EAAE,kBAAkB,GAAG,MAAM,EAClC,KAAK,EAAE,aAAa,GAAG,MAAM,EAC7B,GAAG,GAAE,IAAiB,GACrB,uBAAuB,CAiDzB"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { SplitterRouteDeployment, SplitterRouteKey } from "./splitterRoutes.js";
|
|
2
|
+
/** Where this table came from, so a deployed build can be traced to a commit. */
|
|
3
|
+
export declare const SPLITTER_REGISTRY_SOURCE: {
|
|
4
|
+
readonly repo: "AiFinPay/evm-contract";
|
|
5
|
+
readonly path: "registry/generated/splitter-table.json";
|
|
6
|
+
readonly commit: "8577d568932cae1e551fc08c7e7f22202cdffeb1";
|
|
7
|
+
readonly artifactSha256: "ba556b411304c33861c778538d13921ecfbcec31937e0866a74f5e26e21e7a9f";
|
|
8
|
+
readonly schemaVersion: 4;
|
|
9
|
+
readonly registryUpdatedAt: "2026-08-28";
|
|
10
|
+
};
|
|
11
|
+
/**
|
|
12
|
+
* The governance Safe that owns every splitter below, and the exact signer
|
|
13
|
+
* shape it was verified under. Read from the chain by verify-registry.mjs, which
|
|
14
|
+
* compares the signer set and threshold exactly rather than as a floor.
|
|
15
|
+
*/
|
|
16
|
+
export declare const SPLITTER_GOVERNANCE: {
|
|
17
|
+
readonly safe: "0xFd936f75D9221949f2FEaB54Cd342F7527154eD5";
|
|
18
|
+
readonly threshold: 3;
|
|
19
|
+
readonly owners: readonly ["0x2118c57dEBD53f614DDfE464Ff2941BE6646cA82", "0x3C31dd9daCeC5473cC9B660CD69247A20701cF19", "0x25A834b6fEC79e9ee6ED04Ef5b97440149C6Cc24", "0x1D5eF769A024B3157c76884fbd10302d8d83fAB9", "0x849930eB20ED0a697c71BcE565f18702D202C0F8"];
|
|
20
|
+
};
|
|
21
|
+
export declare const SPLITTER_ROUTES: Record<SplitterRouteKey, SplitterRouteDeployment>;
|
|
22
|
+
//# sourceMappingURL=splitterRoutes.generated.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"splitterRoutes.generated.d.ts","sourceRoot":"","sources":["../src/splitterRoutes.generated.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,uBAAuB,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAErF,iFAAiF;AACjF,eAAO,MAAM,wBAAwB;;;;;;;CAO3B,CAAC;AAEX;;;;GAIG;AACH,eAAO,MAAM,mBAAmB;;;;CAUtB,CAAC;AAEX,eAAO,MAAM,eAAe,EAAE,MAAM,CAAC,gBAAgB,EAAE,uBAAuB,CAyW7E,CAAC"}
|