@recta/client 0.1.0 → 0.1.2
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 +16 -1
- package/dist/client.d.ts +10 -0
- package/dist/client.js +13 -2
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -33,6 +33,7 @@ const recta = createRectaClient({
|
|
|
33
33
|
maxNativeValueWei: 10n ** 15n, // never attach more than 0.001 native to one route transaction
|
|
34
34
|
minOutputBps: 9900, // required, 1–10000: the route must guarantee the recipient at least 99 % of the amount sent
|
|
35
35
|
},
|
|
36
|
+
referrer: "0x…", // optional: the integrator that ships this agent (see "Referral for integrators")
|
|
36
37
|
});
|
|
37
38
|
|
|
38
39
|
// Dry run: evaluates and checks, signs no permit, sends no transaction.
|
|
@@ -49,6 +50,18 @@ your signer's address. Each step is also available alone: `evaluate`, `authorize
|
|
|
49
50
|
|
|
50
51
|
Your account must be an EOA: Recta's signed requests are EIP-191 signatures recovered to the sender's address.
|
|
51
52
|
|
|
53
|
+
## Referral for integrators
|
|
54
|
+
|
|
55
|
+
If you ship Recta inside a plugin, framework or agent template, set your own EVM address once as the `referrer` and
|
|
56
|
+
every agent that runs your integration carries it. Recta fixes it at the agent's first signed evaluation and never
|
|
57
|
+
changes it afterwards. You earn 20 % of the fees Recta actually collects from those agents (confirmed on chain) for
|
|
58
|
+
12 months, up to 200 USDC per agent, whether or not you pay fees yourself. One level only. The agent still pays exactly
|
|
59
|
+
5 % of its verified saving: your share comes out of Recta's 5 %, never on top of it.
|
|
60
|
+
|
|
61
|
+
The referrer travels in the query of the agent's own signed requests, so nobody relaying them can add, drop or change
|
|
62
|
+
it. It is ignored when it is the agent's own address. Terms and your balance: `GET /v1/referrals/balance`, signed by
|
|
63
|
+
your address, once Recta's referral program is on (it starts together with fee collection).
|
|
64
|
+
|
|
52
65
|
### Coinbase CDP accounts
|
|
53
66
|
|
|
54
67
|
A [Coinbase CDP](https://docs.cdp.coinbase.com) EVM server account (an EOA whose key stays in CDP) works through
|
|
@@ -78,7 +91,9 @@ anything that policy does not allow, and it allows sending only on those six cha
|
|
|
78
91
|
on any other chain is refused by CDP unless you add your own rule for it.
|
|
79
92
|
|
|
80
93
|
The saving is measured against `baseline_provider`: the route your agent would use without Recta. Declare the one it
|
|
81
|
-
really uses. If
|
|
94
|
+
really uses. If your agent bridges through LI.FI (its public API or an aggregator built on it), declare `lifi`
|
|
95
|
+
wherever the fit check (`GET /v1/golden-corridor/fit`) lists it in `declarable_baselines`; it is refused with
|
|
96
|
+
`latency_class` SECONDS or MINUTES. Recta reads LI.FI's own transaction, its fee included. If that route is already the cheapest, Recta answers with no saving and charges nothing.
|
|
82
97
|
|
|
83
98
|
## What is checked before signing
|
|
84
99
|
|
package/dist/client.d.ts
CHANGED
|
@@ -12,6 +12,14 @@ export interface RectaClientOptions {
|
|
|
12
12
|
/** The least the recipient must be guaranteed, in basis points of the amount sent (e.g. 9950 = 99.5 %). */
|
|
13
13
|
readonly minOutputBps: number;
|
|
14
14
|
};
|
|
15
|
+
/**
|
|
16
|
+
* Who referred this agent to Recta (OD-REF-1): an EVM address, usually the author of the plugin, framework or template
|
|
17
|
+
* that ships this client. Sent as `?referrer=` on the signed evaluation and fee-authorization requests, so it is part
|
|
18
|
+
* of what the agent's own key signs. Recta fixes it once, at the agent's first signed evaluation, and never changes it;
|
|
19
|
+
* the agent still pays exactly 5 % of its verified saving (the referrer's share comes out of Recta's 5 %). Ignored
|
|
20
|
+
* when it is the signer's own address (nobody can refer itself).
|
|
21
|
+
*/
|
|
22
|
+
readonly referrer?: string;
|
|
15
23
|
/** Defaults to the global fetch. */
|
|
16
24
|
readonly fetch?: typeof fetch;
|
|
17
25
|
/** Milliseconds since the epoch; defaults to Date.now. */
|
|
@@ -25,6 +33,8 @@ export declare function signedRequestMessage(f: {
|
|
|
25
33
|
readonly bodyKeccak256: string;
|
|
26
34
|
readonly issuedAt: number;
|
|
27
35
|
}): string;
|
|
36
|
+
/** The `?referrer=` suffix for a configured referrer: lower-cased, empty when none or when it is the payer itself. */
|
|
37
|
+
export declare function referrerQuery(referrer: string | undefined, payer: string): string;
|
|
28
38
|
export type FeeOutcome = {
|
|
29
39
|
readonly kind: "NOT_REQUIRED";
|
|
30
40
|
} | {
|
package/dist/client.js
CHANGED
|
@@ -16,6 +16,16 @@ export function signedRequestMessage(f) {
|
|
|
16
16
|
].join("\n");
|
|
17
17
|
}
|
|
18
18
|
const RESULT_ID = /^[A-Za-z0-9_-]+$/;
|
|
19
|
+
const ADDRESS = /^0x[0-9a-fA-F]{40}$/;
|
|
20
|
+
/** The `?referrer=` suffix for a configured referrer: lower-cased, empty when none or when it is the payer itself. */
|
|
21
|
+
export function referrerQuery(referrer, payer) {
|
|
22
|
+
if (referrer === undefined)
|
|
23
|
+
return "";
|
|
24
|
+
if (!ADDRESS.test(referrer))
|
|
25
|
+
throw new RectaCheckError("referrer", "the referrer must be a 0x-prefixed 20-byte EVM address");
|
|
26
|
+
const r = referrer.toLowerCase();
|
|
27
|
+
return r === payer.toLowerCase() ? "" : `?referrer=${r}`;
|
|
28
|
+
}
|
|
19
29
|
const field = (v, k) => (typeof v === "object" && v !== null ? v[k] : undefined);
|
|
20
30
|
const resultIdOf = (v) => {
|
|
21
31
|
if (!RESULT_ID.test(v))
|
|
@@ -33,6 +43,7 @@ export function createRectaClient(options) {
|
|
|
33
43
|
const now = options.now ?? Date.now;
|
|
34
44
|
const nowUnix = () => BigInt(Math.floor(now() / 1000));
|
|
35
45
|
const payer = signer.address.toLowerCase();
|
|
46
|
+
const referral = referrerQuery(options.referrer, payer);
|
|
36
47
|
let policyChecked = false;
|
|
37
48
|
async function call(method, path, body, idempotencyKey, signed = true) {
|
|
38
49
|
const bytes = body === undefined ? new Uint8Array() : new TextEncoder().encode(JSON.stringify(body));
|
|
@@ -72,7 +83,7 @@ export function createRectaClient(options) {
|
|
|
72
83
|
if (typeof request.sender !== "string" || request.sender.toLowerCase() !== payer)
|
|
73
84
|
throw new RectaCheckError("sender", "the request's sender must be the signer");
|
|
74
85
|
await walletPolicy();
|
|
75
|
-
const a = await call("POST", PATHS.evaluations
|
|
86
|
+
const a = await call("POST", `${PATHS.evaluations}${referral}`, request, opts.idempotencyKey ?? crypto.randomUUID());
|
|
76
87
|
if (a.status === 402)
|
|
77
88
|
throw new RectaDebtError(a.body, field(a.body, "debt_offer") ?? null);
|
|
78
89
|
if (a.status !== 200)
|
|
@@ -105,7 +116,7 @@ export function createRectaClient(options) {
|
|
|
105
116
|
if (opts.dryRun === true)
|
|
106
117
|
return { fee: { kind: "DRY_RUN", amountUsdcAtomic: checked.amount, typedData: checked.typedData }, artifact: undefined };
|
|
107
118
|
const signature = await signer.signTypedData(checked.typedData);
|
|
108
|
-
const s = await call("POST", `${PATHS.evaluations}/${id}/fee-authorization`, { signature, amount_usdc_atomic: checked.amount.toString() });
|
|
119
|
+
const s = await call("POST", `${PATHS.evaluations}/${id}/fee-authorization${referral}`, { signature, amount_usdc_atomic: checked.amount.toString() });
|
|
109
120
|
if (s.status === 200 || s.status === 201)
|
|
110
121
|
return { fee: { kind: "AUTHORIZED", amountUsdcAtomic: checked.amount, signature }, artifact: field(s.body, "artifact") };
|
|
111
122
|
if (!(s.status === 409 && field(s.body, "reason_code") === "OFFER_STALE"))
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { createRectaClient, signedRequestMessage, type RectaClient, type RectaClientOptions, type FeeOutcome } from "./client.js";
|
|
1
|
+
export { createRectaClient, signedRequestMessage, referrerQuery, type RectaClient, type RectaClientOptions, type FeeOutcome } from "./client.js";
|
|
2
2
|
export { checkFeePermit, type FeePermitLimits } from "./fee.js";
|
|
3
3
|
export { checkExecutionArtifact, pinnedRouteOf, type CheckedArtifact, type EvaluationRequestView, type ArtifactLimits } from "./artifact.js";
|
|
4
4
|
export { PINNED_ROUTES, type PinnedRoute } from "./pinned-routes.js";
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { createRectaClient, signedRequestMessage } from "./client.js";
|
|
1
|
+
export { createRectaClient, signedRequestMessage, referrerQuery } from "./client.js";
|
|
2
2
|
export { checkFeePermit } from "./fee.js";
|
|
3
3
|
export { checkExecutionArtifact, pinnedRouteOf } from "./artifact.js";
|
|
4
4
|
export { PINNED_ROUTES } from "./pinned-routes.js";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@recta/client",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.2",
|
|
4
4
|
"description": "Client for Recta (api.recta.build): evaluate a cross-chain stablecoin transfer, authorize Recta's 5 %-of-verified-saving fee, execute the committed route and report it, with local checks before every signature.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Recta (https://recta.build)",
|
|
@@ -45,7 +45,7 @@
|
|
|
45
45
|
"build": "tsc -p tsconfig.build.json"
|
|
46
46
|
},
|
|
47
47
|
"peerDependencies": {
|
|
48
|
-
"viem": ">=2.
|
|
48
|
+
"viem": ">=2.38.3 <3"
|
|
49
49
|
},
|
|
50
50
|
"publishConfig": {
|
|
51
51
|
"access": "public",
|