uvd-x402-sdk 2.69.0 → 2.71.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 +80 -0
- package/dist/backend/index.d.mts +220 -1
- package/dist/backend/index.d.ts +220 -1
- package/dist/backend/index.js +157 -0
- package/dist/backend/index.js.map +1 -1
- package/dist/backend/index.mjs +156 -1
- package/dist/backend/index.mjs.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
- package/src/backend/index.ts +317 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "uvd-x402-sdk",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.71.0",
|
|
4
4
|
"description": "x402 Payment SDK - Gasless crypto payments across 25 blockchains via Ultravioleta facilitator. Supports EVM (including Scroll, SKALE Base, Robinhood Chain), Solana, Fogo, Stellar, NEAR, Algorand, Sui, and XRP Ledger. Features: ERC-8004 Trustless Agents, Escrow/Refunds, multi-stablecoin (USDC, EURC, AUSD, PYUSD, USDT, USDG).",
|
|
5
5
|
"author": "Ultravioleta DAO <ultravioletadao@gmail.com>",
|
|
6
6
|
"license": "MIT",
|
package/src/backend/index.ts
CHANGED
|
@@ -3071,6 +3071,166 @@ export type Erc8004Network =
|
|
|
3071
3071
|
// Solana (uses QuantuLabs 8004-solana Anchor program + ATOM Engine)
|
|
3072
3072
|
| 'solana' | 'solana-devnet';
|
|
3073
3073
|
|
|
3074
|
+
/**
|
|
3075
|
+
* Networks where the facilitator serves the RELAYED feedback rail, i.e. where
|
|
3076
|
+
* Execution Market has deployed a `FeedbackDelegate` and the facilitator
|
|
3077
|
+
* verified it on-chain (code present, and its `REPUTATION_REGISTRY()` reads
|
|
3078
|
+
* back that network's registry).
|
|
3079
|
+
*
|
|
3080
|
+
* Anywhere else `POST /feedback/evm/prepare` answers 400 — and it should. An
|
|
3081
|
+
* invented delegate address would send a type-4 transaction to an account with
|
|
3082
|
+
* no code behind it, and in the EVM a `.call()` to an address with no code
|
|
3083
|
+
* RETURNS SUCCESS. The failure would look exactly like a rating that rated
|
|
3084
|
+
* nobody.
|
|
3085
|
+
*
|
|
3086
|
+
* `avalanche` is absent and is not waiting to join: the C-Chain rejects the
|
|
3087
|
+
* transaction type itself (`-32000 transaction type not supported`), so there
|
|
3088
|
+
* is nothing to deploy against. Anchor the rating on a chain that supports
|
|
3089
|
+
* EIP-7702; the payment stays where it was made.
|
|
3090
|
+
*/
|
|
3091
|
+
export const RELAYED_FEEDBACK_NETWORKS: readonly Erc8004Network[] = [
|
|
3092
|
+
'base',
|
|
3093
|
+
'ethereum',
|
|
3094
|
+
'polygon',
|
|
3095
|
+
'arbitrum',
|
|
3096
|
+
'optimism',
|
|
3097
|
+
'celo',
|
|
3098
|
+
'bsc',
|
|
3099
|
+
'monad',
|
|
3100
|
+
'base-sepolia',
|
|
3101
|
+
] as const;
|
|
3102
|
+
|
|
3103
|
+
/**
|
|
3104
|
+
* Whether `network` serves the rater-authored feedback rail.
|
|
3105
|
+
*
|
|
3106
|
+
* Lets a caller route without paying a round trip for a 400. The facilitator
|
|
3107
|
+
* re-checks the delegate on-chain on every request regardless — this list is a
|
|
3108
|
+
* routing hint, never the authority.
|
|
3109
|
+
*/
|
|
3110
|
+
export function supportsRelayedFeedback(network: string): boolean {
|
|
3111
|
+
return (RELAYED_FEEDBACK_NETWORKS as readonly string[]).includes(wireNetwork(network));
|
|
3112
|
+
}
|
|
3113
|
+
|
|
3114
|
+
/**
|
|
3115
|
+
* An EIP-7702 authorization, as a wallet produces it.
|
|
3116
|
+
*
|
|
3117
|
+
* Needed only the first time a rater rates: it points their EOA at the
|
|
3118
|
+
* `FeedbackDelegate`. Once delegated, `prepare` answers `delegated: true` and
|
|
3119
|
+
* the submission carries no authorization at all.
|
|
3120
|
+
*/
|
|
3121
|
+
export interface RelayAuthorizationParams {
|
|
3122
|
+
/**
|
|
3123
|
+
* Chain the authorization is for.
|
|
3124
|
+
*
|
|
3125
|
+
* `0` is EIP-7702's wildcard and is valid on EVERY chain — a far broader
|
|
3126
|
+
* grant than pinning this one. Send the chain id `prepare` returned.
|
|
3127
|
+
*/
|
|
3128
|
+
chainId: number;
|
|
3129
|
+
/**
|
|
3130
|
+
* The delegate the account is pointed at. Must be the address `prepare`
|
|
3131
|
+
* offered; the facilitator refuses anything else before it pays for a
|
|
3132
|
+
* transaction.
|
|
3133
|
+
*/
|
|
3134
|
+
address: string;
|
|
3135
|
+
/** The rater account's nonce at the moment the authorization executes */
|
|
3136
|
+
nonce: number;
|
|
3137
|
+
yParity: number;
|
|
3138
|
+
r: string;
|
|
3139
|
+
s: string;
|
|
3140
|
+
}
|
|
3141
|
+
|
|
3142
|
+
/**
|
|
3143
|
+
* Request body for `POST /feedback/evm/prepare`.
|
|
3144
|
+
*
|
|
3145
|
+
* `rater` is the address that will appear on-chain as the author, which is the
|
|
3146
|
+
* whole point of this rail.
|
|
3147
|
+
*/
|
|
3148
|
+
export interface PrepareRelayFeedbackRequest {
|
|
3149
|
+
x402Version: 1 | 2;
|
|
3150
|
+
network: Erc8004Network;
|
|
3151
|
+
feedback: FeedbackParams & { rater: string };
|
|
3152
|
+
}
|
|
3153
|
+
|
|
3154
|
+
/**
|
|
3155
|
+
* Response from `POST /feedback/evm/prepare`.
|
|
3156
|
+
*
|
|
3157
|
+
* Everything the rater has to sign so the CHAIN records them as the author
|
|
3158
|
+
* while the facilitator pays the gas.
|
|
3159
|
+
*/
|
|
3160
|
+
export interface PrepareRelayFeedbackResponse {
|
|
3161
|
+
success: boolean;
|
|
3162
|
+
/** The `FeedbackDelegate` the rater's EOA must be delegated to */
|
|
3163
|
+
delegate?: string;
|
|
3164
|
+
/** Registry calldata the rater is authorising, hex-encoded */
|
|
3165
|
+
data?: string;
|
|
3166
|
+
/**
|
|
3167
|
+
* The value the rater's signature must recover against.
|
|
3168
|
+
*
|
|
3169
|
+
* **The EIP-191 envelope is already applied here.** A holder of a raw key
|
|
3170
|
+
* signs this directly as a prehash (viem's `sign({ hash })`, ethers'
|
|
3171
|
+
* `signingKey.sign`). A WALLET must not be handed this value: `personal_sign`
|
|
3172
|
+
* applies the envelope itself, so it gets wrapped twice and recovers an
|
|
3173
|
+
* address that is not the rater. Wallets sign {@link signingPayload}.
|
|
3174
|
+
*/
|
|
3175
|
+
digest?: string;
|
|
3176
|
+
/**
|
|
3177
|
+
* The same hash with the envelope still OFF — what a wallet signs.
|
|
3178
|
+
*
|
|
3179
|
+
* `keccak256('\x19Ethereum Signed Message:\n32' || signingPayload)` is
|
|
3180
|
+
* exactly {@link digest}, so a client can check the two against each other
|
|
3181
|
+
* rather than rebuilding the preimage from `data`.
|
|
3182
|
+
*
|
|
3183
|
+
* Requires facilitator v1.95.0+. Older facilitators omit it; a client that
|
|
3184
|
+
* needs it should fail loudly rather than fall back to signing `digest`
|
|
3185
|
+
* through a wallet, which produces a well-formed signature that authorises
|
|
3186
|
+
* nobody.
|
|
3187
|
+
*/
|
|
3188
|
+
signingPayload?: string;
|
|
3189
|
+
/**
|
|
3190
|
+
* Unix seconds after which the authorisation is void. Short on purpose:
|
|
3191
|
+
* relaying is permissionless, so a signed authorisation is live in the wild
|
|
3192
|
+
* until it expires.
|
|
3193
|
+
*/
|
|
3194
|
+
deadline?: number;
|
|
3195
|
+
/** Single-use value binding this authorisation. Echo it back on submit */
|
|
3196
|
+
nonce?: string;
|
|
3197
|
+
/**
|
|
3198
|
+
* Whether the account is already delegated. When `false` the submission MUST
|
|
3199
|
+
* carry an `authorization`.
|
|
3200
|
+
*/
|
|
3201
|
+
delegated: boolean;
|
|
3202
|
+
/** The account nonce to put in the EIP-7702 authorization, when needed */
|
|
3203
|
+
accountNonce?: number;
|
|
3204
|
+
chainId: number;
|
|
3205
|
+
error?: string;
|
|
3206
|
+
network: Erc8004Network;
|
|
3207
|
+
}
|
|
3208
|
+
|
|
3209
|
+
/**
|
|
3210
|
+
* Request body for `POST /feedback/evm/submit`.
|
|
3211
|
+
*
|
|
3212
|
+
* The feedback parameters are not redundant with `prepare`: the facilitator
|
|
3213
|
+
* rebuilds the registry calldata from them and requires the rater's signature
|
|
3214
|
+
* to cover exactly that. It does not relay calldata it was handed.
|
|
3215
|
+
*/
|
|
3216
|
+
export interface SubmitRelayFeedbackRequest {
|
|
3217
|
+
x402Version: 1 | 2;
|
|
3218
|
+
network: Erc8004Network;
|
|
3219
|
+
feedback: FeedbackParams & { rater: string };
|
|
3220
|
+
/** The deadline `prepare` returned */
|
|
3221
|
+
deadline: number;
|
|
3222
|
+
/** The single-use nonce `prepare` returned */
|
|
3223
|
+
nonce: string;
|
|
3224
|
+
/**
|
|
3225
|
+
* The rater's signature. It must recover to `rater` over `digest` — so
|
|
3226
|
+
* either a raw-key prehash signature over `digest`, or a wallet
|
|
3227
|
+
* `personal_sign` over `signingPayload`. Not `personal_sign` over `digest`.
|
|
3228
|
+
*/
|
|
3229
|
+
signature: string;
|
|
3230
|
+
/** Required only when `prepare` answered `delegated: false` */
|
|
3231
|
+
authorization?: RelayAuthorizationParams;
|
|
3232
|
+
}
|
|
3233
|
+
|
|
3074
3234
|
/**
|
|
3075
3235
|
* Proof of payment returned when settling with ERC-8004 extension
|
|
3076
3236
|
*/
|
|
@@ -3759,6 +3919,14 @@ export class Erc8004Client {
|
|
|
3759
3919
|
*
|
|
3760
3920
|
* Requires proof of payment for authorized feedback submission.
|
|
3761
3921
|
*
|
|
3922
|
+
* @deprecated On this route the facilitator is the AUTHOR: the registry
|
|
3923
|
+
* records `msg.sender`, and that is the facilitator's wallet — which can also
|
|
3924
|
+
* revoke what it wrote. On the networks in {@link RELAYED_FEEDBACK_NETWORKS}
|
|
3925
|
+
* use {@link Erc8004Client.prepareRelayedFeedback} +
|
|
3926
|
+
* {@link Erc8004Client.submitRelayedFeedback} instead, which record the RATER
|
|
3927
|
+
* as author. This route still works and is not going away without notice: it
|
|
3928
|
+
* is the only one available where no `FeedbackDelegate` is deployed.
|
|
3929
|
+
*
|
|
3762
3930
|
* @param request - Feedback request with agent ID, value, and proof
|
|
3763
3931
|
* @returns Feedback response with transaction hash
|
|
3764
3932
|
*
|
|
@@ -3824,6 +3992,155 @@ export class Erc8004Client {
|
|
|
3824
3992
|
}
|
|
3825
3993
|
}
|
|
3826
3994
|
|
|
3995
|
+
/**
|
|
3996
|
+
* Ask the facilitator what the rater must sign to author a rating.
|
|
3997
|
+
*
|
|
3998
|
+
* Step 1 of the rater-authored rail. Writes nothing on-chain and costs
|
|
3999
|
+
* nothing: it reads the delegate, the rater's delegation state and their
|
|
4000
|
+
* account nonce, then hands back a digest, a deadline and a single-use nonce.
|
|
4001
|
+
*
|
|
4002
|
+
* Why this exists: the ERC-8004 Reputation Registry records `msg.sender` as
|
|
4003
|
+
* the author, and the deployed implementation has no delegation path — no
|
|
4004
|
+
* `giveFeedbackWithSignature`, no ERC-2771 forwarder. So a rating the
|
|
4005
|
+
* facilitator relays the ordinary way is a rating attributed to the
|
|
4006
|
+
* FACILITATOR. EIP-7702 fixes it without touching the registry: the rater
|
|
4007
|
+
* delegates their own EOA to the `FeedbackDelegate` and the transaction is
|
|
4008
|
+
* sent TO THE RATER'S ADDRESS, so the registry sees the rater while the
|
|
4009
|
+
* facilitator pays.
|
|
4010
|
+
*
|
|
4011
|
+
* What to do with the answer:
|
|
4012
|
+
* 1. Produce the rater's signature. **Which value you sign depends on how you
|
|
4013
|
+
* sign it**, and getting it wrong yields a well-formed signature that
|
|
4014
|
+
* authorises nobody:
|
|
4015
|
+
* - raw key: sign `digest` as a **prehash**. It already carries the
|
|
4016
|
+
* EIP-191 envelope.
|
|
4017
|
+
* - wallet: `personal_sign` over `signingPayload`. `personal_sign` adds the
|
|
4018
|
+
* envelope itself, so signing `digest` with it wraps the value TWICE and
|
|
4019
|
+
* recovers a stranger — the only symptom is `relay_bad_signature`.
|
|
4020
|
+
* 2. If `delegated` is `false`, also produce an EIP-7702 authorization over
|
|
4021
|
+
* `(chainId, delegate, accountNonce)`.
|
|
4022
|
+
* 3. Hand both to {@link submitRelayedFeedback} with the SAME feedback
|
|
4023
|
+
* parameters, `deadline` and `nonce`.
|
|
4024
|
+
*
|
|
4025
|
+
* @param request - Network, rater address and feedback parameters
|
|
4026
|
+
* @returns Everything needed to sign, including whether an EIP-7702
|
|
4027
|
+
* authorization is still required
|
|
4028
|
+
*
|
|
4029
|
+
* @example
|
|
4030
|
+
* ```ts
|
|
4031
|
+
* const prep = await erc8004.prepareRelayedFeedback({
|
|
4032
|
+
* x402Version: 1,
|
|
4033
|
+
* network: 'base',
|
|
4034
|
+
* feedback: { agentId: 18896, value: 95, tag1: 'quality', rater: raterAddress },
|
|
4035
|
+
* });
|
|
4036
|
+
* // prep.delegated === false -> an EIP-7702 authorization is required
|
|
4037
|
+
* ```
|
|
4038
|
+
*/
|
|
4039
|
+
async prepareRelayedFeedback(
|
|
4040
|
+
request: PrepareRelayFeedbackRequest,
|
|
4041
|
+
): Promise<PrepareRelayFeedbackResponse> {
|
|
4042
|
+
const url = `${this.baseUrl}/feedback/evm/prepare`;
|
|
4043
|
+
|
|
4044
|
+
const controller = new AbortController();
|
|
4045
|
+
const timeoutId = setTimeout(() => controller.abort(), this.timeout);
|
|
4046
|
+
|
|
4047
|
+
try {
|
|
4048
|
+
const response = await fetch(url, {
|
|
4049
|
+
method: 'POST',
|
|
4050
|
+
headers: {
|
|
4051
|
+
'Content-Type': 'application/json',
|
|
4052
|
+
'Accept': 'application/json',
|
|
4053
|
+
},
|
|
4054
|
+
body: JSON.stringify({ ...request, network: wireNetwork(request.network) }),
|
|
4055
|
+
signal: controller.signal,
|
|
4056
|
+
});
|
|
4057
|
+
|
|
4058
|
+
clearTimeout(timeoutId);
|
|
4059
|
+
|
|
4060
|
+
if (!response.ok) {
|
|
4061
|
+
const errorText = await response.text();
|
|
4062
|
+
return {
|
|
4063
|
+
success: false,
|
|
4064
|
+
delegated: false,
|
|
4065
|
+
chainId: 0,
|
|
4066
|
+
error: `Facilitator error: ${response.status} - ${errorText}`,
|
|
4067
|
+
network: request.network,
|
|
4068
|
+
};
|
|
4069
|
+
}
|
|
4070
|
+
|
|
4071
|
+
return await response.json();
|
|
4072
|
+
} catch (error) {
|
|
4073
|
+
clearTimeout(timeoutId);
|
|
4074
|
+
return {
|
|
4075
|
+
success: false,
|
|
4076
|
+
delegated: false,
|
|
4077
|
+
chainId: 0,
|
|
4078
|
+
error: error instanceof Error ? error.message : 'Unknown error',
|
|
4079
|
+
network: request.network,
|
|
4080
|
+
};
|
|
4081
|
+
}
|
|
4082
|
+
}
|
|
4083
|
+
|
|
4084
|
+
/**
|
|
4085
|
+
* Relay a rater-authored rating; the facilitator pays the gas.
|
|
4086
|
+
*
|
|
4087
|
+
* Step 2 of the rater-authored rail. The on-chain record that comes out of it
|
|
4088
|
+
* has the RATER as `msg.sender`, so `getClients(agentId)` shows the rater
|
|
4089
|
+
* rather than the facilitator.
|
|
4090
|
+
*
|
|
4091
|
+
* Pass back the same feedback parameters, `deadline` and `nonce` that
|
|
4092
|
+
* {@link prepareRelayedFeedback} returned. They are not redundant: the
|
|
4093
|
+
* facilitator rebuilds the registry calldata from them and requires the
|
|
4094
|
+
* rater's signature to cover exactly that.
|
|
4095
|
+
*
|
|
4096
|
+
* `authorization` is required only when `prepare` answered
|
|
4097
|
+
* `delegated: false`. One that names a different delegate than the one
|
|
4098
|
+
* `prepare` offered is refused before any gas is spent.
|
|
4099
|
+
*
|
|
4100
|
+
* @param request - Feedback parameters plus the rater's signature
|
|
4101
|
+
* @returns Feedback response with the transaction hash
|
|
4102
|
+
*/
|
|
4103
|
+
async submitRelayedFeedback(
|
|
4104
|
+
request: SubmitRelayFeedbackRequest,
|
|
4105
|
+
): Promise<FeedbackResponse> {
|
|
4106
|
+
const url = `${this.baseUrl}/feedback/evm/submit`;
|
|
4107
|
+
|
|
4108
|
+
const controller = new AbortController();
|
|
4109
|
+
const timeoutId = setTimeout(() => controller.abort(), this.timeout);
|
|
4110
|
+
|
|
4111
|
+
try {
|
|
4112
|
+
const response = await fetch(url, {
|
|
4113
|
+
method: 'POST',
|
|
4114
|
+
headers: {
|
|
4115
|
+
'Content-Type': 'application/json',
|
|
4116
|
+
'Accept': 'application/json',
|
|
4117
|
+
},
|
|
4118
|
+
body: JSON.stringify({ ...request, network: wireNetwork(request.network) }),
|
|
4119
|
+
signal: controller.signal,
|
|
4120
|
+
});
|
|
4121
|
+
|
|
4122
|
+
clearTimeout(timeoutId);
|
|
4123
|
+
|
|
4124
|
+
if (!response.ok) {
|
|
4125
|
+
const errorText = await response.text();
|
|
4126
|
+
return {
|
|
4127
|
+
success: false,
|
|
4128
|
+
error: `Facilitator error: ${response.status} - ${errorText}`,
|
|
4129
|
+
network: request.network,
|
|
4130
|
+
};
|
|
4131
|
+
}
|
|
4132
|
+
|
|
4133
|
+
return await response.json();
|
|
4134
|
+
} catch (error) {
|
|
4135
|
+
clearTimeout(timeoutId);
|
|
4136
|
+
return {
|
|
4137
|
+
success: false,
|
|
4138
|
+
error: error instanceof Error ? error.message : 'Unknown error',
|
|
4139
|
+
network: request.network,
|
|
4140
|
+
};
|
|
4141
|
+
}
|
|
4142
|
+
}
|
|
4143
|
+
|
|
3827
4144
|
/**
|
|
3828
4145
|
* Revoke previously submitted feedback
|
|
3829
4146
|
*
|