@integraledger/lcp-binding-evm-x402 0.9.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/CHANGELOG.md +13 -0
- package/LICENSE +202 -0
- package/NOTICE +14 -0
- package/README.md +115 -0
- package/dist/adapter.d.ts +42 -0
- package/dist/adapter.d.ts.map +1 -0
- package/dist/adapter.js +124 -0
- package/dist/adapter.js.map +1 -0
- package/dist/asset-transfer-method-filter.d.ts +82 -0
- package/dist/asset-transfer-method-filter.d.ts.map +1 -0
- package/dist/asset-transfer-method-filter.js +130 -0
- package/dist/asset-transfer-method-filter.js.map +1 -0
- package/dist/constants.d.ts +52 -0
- package/dist/constants.d.ts.map +1 -0
- package/dist/constants.js +54 -0
- package/dist/constants.js.map +1 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +5 -0
- package/dist/index.js.map +1 -0
- package/dist/manifest.d.ts +13 -0
- package/dist/manifest.d.ts.map +1 -0
- package/dist/manifest.js +36 -0
- package/dist/manifest.js.map +1 -0
- package/package.json +65 -0
- package/src/adapter.ts +187 -0
- package/src/asset-transfer-method-filter.ts +146 -0
- package/src/constants.ts +107 -0
- package/src/index.ts +20 -0
- package/src/manifest.ts +37 -0
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The two mandatory x402 checks.
|
|
3
|
+
*
|
|
4
|
+
* 1. **Asset-transfer-method filter.** The atrHash-as-nonce weld rides ONLY on EIP-3009
|
|
5
|
+
* `transferWithAuthorization`, whose `nonce` is a payer-controlled 32-byte field committed on-chain in
|
|
6
|
+
* `AuthorizationUsed`. x402's `exact` scheme on EVM defines **three** methods, verified at
|
|
7
|
+
* `x402-foundation/x402@1fec3aa04e41`:
|
|
8
|
+
*
|
|
9
|
+
* 1. `eip3009` — tokens with native `transferWithAuthorization` (the default when `extra` omits it)
|
|
10
|
+
* 2. `permit2` — tokens without it, via a proxy and the canonical Permit2 contract
|
|
11
|
+
* 3. `erc7710` — smart accounts with delegation support
|
|
12
|
+
*
|
|
13
|
+
* Only the first exposes a payer-controlled nonce. Under `permit2` the value rides an off-chain EIP-712
|
|
14
|
+
* witness, and under `erc7710` the payment is authorized by a delegation the payer's smart account
|
|
15
|
+
* granted — in neither case is there a 32-byte field on the settlement for the weld to occupy. An offer
|
|
16
|
+
* requesting either would settle a payment that silently DROPS the binding, so this refuses instead.
|
|
17
|
+
*
|
|
18
|
+
* The rule is not Permit2-specific and the naming here is deliberate: it is "the method must be the one
|
|
19
|
+
* that carries a payer nonce". A refusal naming only one of the two rejected methods would report a
|
|
20
|
+
* correct decision for the wrong reason, which is what an operator then debugs.
|
|
21
|
+
*
|
|
22
|
+
* The settlement-side spender/witness proxy detection is the on-chain extension that lands once a
|
|
23
|
+
* harness run closes it; it is NOT fabricated here.
|
|
24
|
+
*
|
|
25
|
+
* 2. **Payment-flow filter.** x402 §6.1 defines three flows and reserves `extra.paymentFlow` as a
|
|
26
|
+
* protocol key: `authorization` (verify → resource → settle), `upfront` (settle → resource) and
|
|
27
|
+
* `escrow` (settle → resource → settle). "When the resolved payment flow is not `authorization`,
|
|
28
|
+
* `PaymentRequired` `accepts[].extra.paymentFlow` MUST be present", and "Clients MUST NOT construct a
|
|
29
|
+
* payment for a `paymentFlow` they do not recognize."
|
|
30
|
+
*
|
|
31
|
+
* This weld survives `upfront` untouched — one settlement, one EIP-3009 authorization, one nonce.
|
|
32
|
+
*
|
|
33
|
+
* `escrow` settles TWICE, and the scheme's own table marks `eip3009` "One-time use", so a single nonce
|
|
34
|
+
* cannot carry both the deposit and the final charge. **That is a statement about THIS carrier, not a
|
|
35
|
+
* judgement about the flow.** A two-phase settlement is exactly the case the record is supposed to
|
|
36
|
+
* survive, and there is a binding for it: `@integraledger/lcp-binding-evm-escrow` welds
|
|
37
|
+
* `PaymentInfo.salt`, which is recoverable from BOTH the authorization and the capture artifact and
|
|
38
|
+
* joins them on `paymentInfoHash`. So this answers "not this binding, that one" and names it — it does
|
|
39
|
+
* not tell a deployment how to transact, which is not this project's business.
|
|
40
|
+
*
|
|
41
|
+
* 3. **Inbound `nonce == atrHash` re-challenge.** The seller-side verification that a presented
|
|
42
|
+
* authorization's nonce equals the atrHash it advertised. The primitive lives here; the re-challenge
|
|
43
|
+
* orchestration (re-issue the 402 on mismatch) belongs to the seller surface.
|
|
44
|
+
*/
|
|
45
|
+
|
|
46
|
+
import type { Outcome, Refusal } from "@integraledger/lcp-binding-core";
|
|
47
|
+
import { atrHashEquals } from "@integraledger/lcp-kernel";
|
|
48
|
+
|
|
49
|
+
/** The x402 asset-transfer method an offer may request. Only `eip3009` carries the payer nonce. */
|
|
50
|
+
export const EIP3009_TRANSFER_METHOD = "eip3009";
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* The methods x402's exact-EVM scheme defines, in the scheme's own order. Listed so the refusal can say
|
|
54
|
+
* whether it met a method the host defines or one nobody does — a typo and an unsupported-but-real method
|
|
55
|
+
* are different problems for the operator reading the message.
|
|
56
|
+
*/
|
|
57
|
+
export const X402_TRANSFER_METHODS: readonly string[] = [
|
|
58
|
+
"eip3009",
|
|
59
|
+
"permit2",
|
|
60
|
+
"erc7710",
|
|
61
|
+
];
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Refuse an asset-transfer method that carries no payer nonce. Returns a typed `policy-rejection`
|
|
65
|
+
* `Refusal` when the method is present and not `eip3009`; `null` when it is absent or `eip3009` (proceed).
|
|
66
|
+
*
|
|
67
|
+
* Absent is `null` because x402's scheme says so: "If no `assetTransferMethod` is specified in
|
|
68
|
+
* `PaymentRequired.extra`, clients should default to `eip3009`."
|
|
69
|
+
*/
|
|
70
|
+
export function filterAssetTransferMethod(
|
|
71
|
+
assetTransferMethod: string | undefined,
|
|
72
|
+
): Refusal | null {
|
|
73
|
+
if (
|
|
74
|
+
assetTransferMethod === undefined ||
|
|
75
|
+
assetTransferMethod === EIP3009_TRANSFER_METHOD
|
|
76
|
+
)
|
|
77
|
+
return null;
|
|
78
|
+
const known = X402_TRANSFER_METHODS.includes(assetTransferMethod);
|
|
79
|
+
return {
|
|
80
|
+
refused: true,
|
|
81
|
+
haltClass: "policy-rejection",
|
|
82
|
+
code: "x402/asset-transfer-method-unsupported",
|
|
83
|
+
detail: `the atrHash weld requires the eip3009 asset-transfer method, whose payer-controlled nonce carries it; got "${assetTransferMethod}"${
|
|
84
|
+
known
|
|
85
|
+
? " — a method x402 defines, but one that exposes no 32-byte payer field for the weld"
|
|
86
|
+
: " — not a method x402's exact-EVM scheme defines (eip3009, permit2, erc7710)"
|
|
87
|
+
}. Refusing rather than settling unwelded.`,
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/** The x402 payment flows, §6.1. `authorization` is the default when `extra.paymentFlow` is omitted. */
|
|
92
|
+
export const X402_PAYMENT_FLOWS: readonly string[] = [
|
|
93
|
+
"authorization",
|
|
94
|
+
"upfront",
|
|
95
|
+
"escrow",
|
|
96
|
+
];
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Report a payment flow this weld cannot ride. `null` means proceed.
|
|
100
|
+
*
|
|
101
|
+
* Absent is `null` because §6.1 makes `authorization` the resolved default, and it is also the flow whose
|
|
102
|
+
* ordering the rest of this package assumes: verify → resource → settle.
|
|
103
|
+
*
|
|
104
|
+
* The `escrow` answer is a ROUTING answer, not a policy one. Which settlement shape a party chooses is
|
|
105
|
+
* theirs; what this project owes them is a record that survives it, and for two-phase settlement that
|
|
106
|
+
* record is `binding-evm-escrow`'s, not this one's.
|
|
107
|
+
*/
|
|
108
|
+
export function filterPaymentFlow(
|
|
109
|
+
paymentFlow: string | undefined,
|
|
110
|
+
): Refusal | null {
|
|
111
|
+
if (paymentFlow === undefined || paymentFlow === "authorization") return null;
|
|
112
|
+
if (paymentFlow === "upfront") return null;
|
|
113
|
+
const known = X402_PAYMENT_FLOWS.includes(paymentFlow);
|
|
114
|
+
return {
|
|
115
|
+
refused: true,
|
|
116
|
+
haltClass: "policy-rejection",
|
|
117
|
+
code: known
|
|
118
|
+
? "x402/weld-not-carried-by-this-binding"
|
|
119
|
+
: "x402/payment-flow-unrecognized",
|
|
120
|
+
detail: known
|
|
121
|
+
? `the escrow payment flow settles twice (settle -> resource -> settle) and x402 marks eip3009 "One-time use", so this binding's nonce can carry only one of the two. Use @integraledger/lcp-binding-evm-escrow for a two-phase settlement: it welds PaymentInfo.salt, which is recoverable from BOTH the authorization and the capture artifact and joins them on paymentInfoHash. Which settlement shape you use is your choice; this is about which binding carries the record across it.`
|
|
122
|
+
: `unrecognized x402 paymentFlow "${paymentFlow}" — §6.1 defines ${X402_PAYMENT_FLOWS.join(", ")}, and clients MUST NOT construct a payment for a flow they do not recognize`,
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* The inbound re-challenge: does a presented authorization nonce equal the advertised atrHash?
|
|
128
|
+
* Compared as DECODED BYTES per LCP §2.5, so the two any-case spellings of one hash agree; returns the
|
|
129
|
+
* lowercased nonce on match, else a `verification-failure`
|
|
130
|
+
* `Refusal` (the caller re-issues the 402 — never settles an unwelded payment).
|
|
131
|
+
*/
|
|
132
|
+
export function verifyInboundNonce(
|
|
133
|
+
presentedNonce: string,
|
|
134
|
+
expectedAtrHash: string,
|
|
135
|
+
): Outcome<`0x${string}`> {
|
|
136
|
+
// Decoded-byte comparison per LCP §2.5. Fails CLOSED: a presented nonce that is not a well-formed
|
|
137
|
+
// atrHash is refused rather than case-folded into a string match against a malformed expectation.
|
|
138
|
+
if (!atrHashEquals(presentedNonce, expectedAtrHash))
|
|
139
|
+
return {
|
|
140
|
+
refused: true,
|
|
141
|
+
haltClass: "verification-failure",
|
|
142
|
+
code: "x402/nonce-mismatch",
|
|
143
|
+
detail: `presented nonce ${presentedNonce} does not equal the advertised atrHash ${expectedAtrHash}`,
|
|
144
|
+
};
|
|
145
|
+
return { ok: true, value: presentedNonce.toLowerCase() as `0x${string}` };
|
|
146
|
+
}
|
package/src/constants.ts
ADDED
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Verified per-deployment `X402AdapterConfig` values for the LCP canonical EVM binding
|
|
3
|
+
* `LCP-X402-EVM-NONCE-1`.
|
|
4
|
+
*
|
|
5
|
+
* **Why this file exists.** `tokenName` and `tokenVersion` are the EIP-712 domain of the USDC contract the
|
|
6
|
+
* authorization is signed against, and they are NOT constant across Circle's deployments: Base Sepolia and
|
|
7
|
+
* Monad report `name() = "USDC"`, while Base mainnet and Avalanche report `name() = "USD Coin"`. A config
|
|
8
|
+
* copied from one chain to another therefore produces a WRONG domain separator, and every authorization
|
|
9
|
+
* signed under it fails verification at the token — silently, from the seller's point of view, because the
|
|
10
|
+
* signature is well-formed and simply does not recover to the payer. That is the exact failure this file
|
|
11
|
+
* removes: each entry below was read from its own deployed contract, never inherited from a sibling.
|
|
12
|
+
*
|
|
13
|
+
* Every value here is reproducible in one call, and the pinned domain separators in
|
|
14
|
+
* the repository's pinned domain-separator tests are what hold them honest:
|
|
15
|
+
*
|
|
16
|
+
* cast call <asset> "name()(string)" --rpc-url <rpc>
|
|
17
|
+
* cast call <asset> "version()(string)" --rpc-url <rpc>
|
|
18
|
+
* cast call <asset> "DOMAIN_SEPARATOR()(bytes32)" --rpc-url <rpc>
|
|
19
|
+
*
|
|
20
|
+
* **AN UPSTREAM MISMATCH, RECORDED HERE BECAUSE IT IS THE KIND THAT FAILS SILENTLY.** x402's own Go
|
|
21
|
+
* implementation disagrees with the chain about Monad. Verified 2026-08-08 at
|
|
22
|
+
* `x402-foundation/x402@1fec3aa04e41`, `go/mechanisms/evm/constants.go`: the `"eip155:143"` entry names
|
|
23
|
+
* the SAME asset address as the `monad` entry below — `0x754704Bc059F8C67012fEd69BC8A327a5aafb603` — and
|
|
24
|
+
* gives it EIP-712 domain `Name: "USD Coin"`. The deployed contract's `name()` returns `"USDC"`, which is
|
|
25
|
+
* what the entry below carries and what the pinned `DOMAIN_SEPARATOR()` assertion in this repository holds
|
|
26
|
+
* it to.
|
|
27
|
+
*
|
|
28
|
+
* The chain is the authority: the domain separator is computed by the token contract, so a signer using
|
|
29
|
+
* "USD Coin" against a contract reporting "USDC" produces an authorization that simply does not recover to
|
|
30
|
+
* the payer. That is the silent failure this whole file exists to prevent, and here it is upstream.
|
|
31
|
+
*
|
|
32
|
+
* **REPORTED UPSTREAM 2026-08-08:** x402-foundation/x402#3102, with the `cast call` reproduction and the
|
|
33
|
+
* observation that USDC deployments are not uniform on this — Base Sepolia and Monad report "USDC" while
|
|
34
|
+
* Base mainnet and Avalanche report "USD Coin", so a value copied between chains yields a wrong domain
|
|
35
|
+
* separator rather than an obvious error. Our entry stays as measured whatever upstream does: the token
|
|
36
|
+
* contract computes the separator, so the chain is the authority.
|
|
37
|
+
*
|
|
38
|
+
* **What this file is not.** It is not an endorsement of a rail, an allowlist, or a supported-chain list.
|
|
39
|
+
* `createX402Adapter` takes any `X402AdapterConfig`, and a deployment absent here is not thereby refused —
|
|
40
|
+
* it simply has not been read off-chain by us. Adding a chain means adding a verified row, nothing more.
|
|
41
|
+
*/
|
|
42
|
+
import type { X402AdapterConfig } from "./adapter.js";
|
|
43
|
+
|
|
44
|
+
/** The deployments whose EIP-712 domain values have been read from their own USDC contract. */
|
|
45
|
+
export type X402DeploymentName =
|
|
46
|
+
| "base"
|
|
47
|
+
| "base-sepolia"
|
|
48
|
+
| "avalanche"
|
|
49
|
+
| "monad";
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Verified 2026-07-30. `fromBlock` is deliberately absent: an enumeration lower bound is an operational
|
|
53
|
+
* choice per deployment, not a property of the token, and defaulting one here would silently narrow a
|
|
54
|
+
* caller's history scan.
|
|
55
|
+
*/
|
|
56
|
+
const DEPLOYMENTS: Record<X402DeploymentName, X402AdapterConfig> = {
|
|
57
|
+
base: {
|
|
58
|
+
chainId: 8453,
|
|
59
|
+
asset: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
|
|
60
|
+
tokenName: "USD Coin",
|
|
61
|
+
tokenVersion: "2",
|
|
62
|
+
},
|
|
63
|
+
// The chain the x402 weld is live-proven on. Note the name differs from Base MAINNET above — the two
|
|
64
|
+
// Base deployments do not share an EIP-712 domain, which is the sharpest form of this file's hazard.
|
|
65
|
+
"base-sepolia": {
|
|
66
|
+
chainId: 84532,
|
|
67
|
+
asset: "0x036CbD53842c5426634e7929541eC2318f3dCF7e",
|
|
68
|
+
tokenName: "USDC",
|
|
69
|
+
tokenVersion: "2",
|
|
70
|
+
},
|
|
71
|
+
avalanche: {
|
|
72
|
+
chainId: 43114,
|
|
73
|
+
asset: "0xB97EF9Ef8734C71904D8002F8b6Bc66Dd9c48a6E",
|
|
74
|
+
tokenName: "USD Coin",
|
|
75
|
+
tokenVersion: "2",
|
|
76
|
+
},
|
|
77
|
+
monad: {
|
|
78
|
+
chainId: 143,
|
|
79
|
+
asset: "0x754704Bc059F8C67012fEd69BC8A327a5aafb603",
|
|
80
|
+
tokenName: "USDC",
|
|
81
|
+
tokenVersion: "2",
|
|
82
|
+
},
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* The verified config for a known deployment. Throws on an unknown name (fail-fast): there is no sane
|
|
87
|
+
* default, and guessing a domain would produce signatures that verify nowhere.
|
|
88
|
+
*/
|
|
89
|
+
export function getX402Deployment(name: string): X402AdapterConfig {
|
|
90
|
+
// The guard is folded INTO the lookup rather than sitting in front of it: a separate `hasOwn` early
|
|
91
|
+
// return would make the `=== undefined` check below unreachable, i.e. dead code.
|
|
92
|
+
const config = Object.hasOwn(DEPLOYMENTS, name)
|
|
93
|
+
? DEPLOYMENTS[name as X402DeploymentName]
|
|
94
|
+
: undefined;
|
|
95
|
+
if (config === undefined)
|
|
96
|
+
throw new Error(
|
|
97
|
+
`unknown x402 deployment "${name}" — known: ${Object.keys(DEPLOYMENTS).join(", ")}. ` +
|
|
98
|
+
"A deployment's tokenName/tokenVersion must be read from its own USDC contract (name()/version()); " +
|
|
99
|
+
"inheriting another chain's values yields a wrong EIP-712 domain and unverifiable signatures.",
|
|
100
|
+
);
|
|
101
|
+
return config;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/** The known deployment names, for callers that enumerate rather than look up. */
|
|
105
|
+
export function x402DeploymentNames(): X402DeploymentName[] {
|
|
106
|
+
return Object.keys(DEPLOYMENTS) as X402DeploymentName[];
|
|
107
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export {
|
|
2
|
+
createX402Adapter,
|
|
3
|
+
type X402AdapterConfig,
|
|
4
|
+
type X402Proposal,
|
|
5
|
+
type X402ProposalContext,
|
|
6
|
+
} from "./adapter.js";
|
|
7
|
+
export {
|
|
8
|
+
EIP3009_TRANSFER_METHOD,
|
|
9
|
+
filterAssetTransferMethod,
|
|
10
|
+
filterPaymentFlow,
|
|
11
|
+
verifyInboundNonce,
|
|
12
|
+
X402_PAYMENT_FLOWS,
|
|
13
|
+
X402_TRANSFER_METHODS,
|
|
14
|
+
} from "./asset-transfer-method-filter.js";
|
|
15
|
+
export {
|
|
16
|
+
getX402Deployment,
|
|
17
|
+
type X402DeploymentName,
|
|
18
|
+
x402DeploymentNames,
|
|
19
|
+
} from "./constants.js";
|
|
20
|
+
export { X402_MANIFEST } from "./manifest.js";
|
package/src/manifest.ts
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import type { BindingManifest } from "@integraledger/lcp-binding-core";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* The x402 `exact` / EIP-3009 binding manifest (LCP `LCP-X402-EVM-NONCE-1`).
|
|
5
|
+
*
|
|
6
|
+
* **pattern = "native-field"** — the atrHash rides the EIP-3009 `nonce`, an EXISTING protocol field
|
|
7
|
+
* the payer signs over; there is no derivation and no overlay contract. Off-canonical Native Field per
|
|
8
|
+
* LCP §8.3.1 / Appendix B.1. This is authored fresh and correct — an archived
|
|
9
|
+
* declaration says `id-reuse` / non-recoverable / non-indexable, a KNOWN-BAD artifact: it read MPP-EVM's
|
|
10
|
+
* Appendix-C.1 derivation-MUST (a property of MPP's method spec) onto the x402 path, where no derivation
|
|
11
|
+
* exists. Do NOT reconcile these values against that archive — "fixing" them reintroduces the bug.
|
|
12
|
+
*/
|
|
13
|
+
export const X402_MANIFEST: BindingManifest = {
|
|
14
|
+
rail: "evm:x402",
|
|
15
|
+
protocol: "x402",
|
|
16
|
+
pattern: "native-field",
|
|
17
|
+
nativeField: "eip3009.nonce",
|
|
18
|
+
recovery: {
|
|
19
|
+
onChain: true,
|
|
20
|
+
zeroPartyRecoverable: true,
|
|
21
|
+
forwardIndexable: true,
|
|
22
|
+
},
|
|
23
|
+
assetBinding: "filtered", // recover reads the token's own AuthorizationUsed log — the record proves THIS asset moved
|
|
24
|
+
successGate: "structural", // a reverted tx emits no logs, so the AuthorizationUsed weld event cannot exist
|
|
25
|
+
indexing: "nonce-topic:AuthorizationUsed",
|
|
26
|
+
finality: {
|
|
27
|
+
reversible: false,
|
|
28
|
+
note: "instant, final settlement (EIP-3009) — no on-rail reversal; recourse is the record's elected forum, and finality is never represented as dispute resolution (PAY-3/RCS-5) The atrHash welded as the EIP-3009 nonce MUST be per-transaction: an EIP-3009 nonce is one-time use, so one payer paying twice under the same ATR reproduces the same authorization and the token rejects the second with no LCP-level diagnostic. LCP §6.1 wants a per-transaction ATR anyway.",
|
|
29
|
+
},
|
|
30
|
+
// The payer's EIP-3009 signature commits to the nonce (= atrHash): signature-grade weld.
|
|
31
|
+
weldGrades: { ERC3009: "signature" },
|
|
32
|
+
offCanonical: { profile: "integra-x402-nonce-v1" }, // named profile
|
|
33
|
+
// "welded-settled", not "settled": on this rail the two are one event. The nonce IS the atrHash, so the
|
|
34
|
+
// settlement that fires `AuthorizationUsed` welds in the same log — there is no settled-but-unwelded
|
|
35
|
+
// state to name. Other rails say "settled" because their weld is a payload a settlement can lack.
|
|
36
|
+
lifecycleStates: ["proposed", "welded-settled"],
|
|
37
|
+
};
|