@opendatalabs/vana-sdk 3.4.1 → 3.5.1-pr.159.2d90789
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 +116 -0
- package/dist/account/personal-server-lite-owner-binding.cjs +3 -3
- package/dist/account/personal-server-lite-owner-binding.cjs.map +1 -1
- package/dist/account/personal-server-lite-owner-binding.d.ts +2 -2
- package/dist/account/personal-server-lite-owner-binding.js +1 -1
- package/dist/account/personal-server-lite-owner-binding.js.map +1 -1
- package/dist/direct/access-request-client.cjs +104 -0
- package/dist/direct/access-request-client.cjs.map +1 -0
- package/dist/direct/access-request-client.d.ts +51 -0
- package/dist/direct/access-request-client.js +79 -0
- package/dist/direct/access-request-client.js.map +1 -0
- package/dist/direct/access-request-client.test.d.ts +1 -0
- package/dist/direct/connect-flow.cjs +152 -0
- package/dist/direct/connect-flow.cjs.map +1 -0
- package/dist/direct/connect-flow.d.ts +85 -0
- package/dist/direct/connect-flow.js +128 -0
- package/dist/direct/connect-flow.js.map +1 -0
- package/dist/direct/connect-flow.test.d.ts +1 -0
- package/dist/direct/controller.cjs +129 -0
- package/dist/direct/controller.cjs.map +1 -0
- package/dist/direct/controller.d.ts +152 -0
- package/dist/direct/controller.js +109 -0
- package/dist/direct/controller.js.map +1 -0
- package/dist/direct/controller.test.d.ts +1 -0
- package/dist/direct/endpoints.cjs +45 -0
- package/dist/direct/endpoints.cjs.map +1 -0
- package/dist/direct/endpoints.d.ts +22 -0
- package/dist/direct/endpoints.js +19 -0
- package/dist/direct/endpoints.js.map +1 -0
- package/dist/direct/errors.cjs +65 -0
- package/dist/direct/errors.cjs.map +1 -0
- package/dist/direct/errors.d.ts +44 -0
- package/dist/direct/errors.js +38 -0
- package/dist/direct/errors.js.map +1 -0
- package/dist/direct/escrow-payment.cjs +96 -0
- package/dist/direct/escrow-payment.cjs.map +1 -0
- package/dist/direct/escrow-payment.d.ts +81 -0
- package/dist/direct/escrow-payment.js +72 -0
- package/dist/direct/escrow-payment.js.map +1 -0
- package/dist/direct/escrow-payment.test.d.ts +1 -0
- package/dist/direct/personal-server-read.cjs +149 -0
- package/dist/direct/personal-server-read.cjs.map +1 -0
- package/dist/direct/personal-server-read.d.ts +103 -0
- package/dist/direct/personal-server-read.js +124 -0
- package/dist/direct/personal-server-read.js.map +1 -0
- package/dist/direct/personal-server-read.test.d.ts +1 -0
- package/dist/direct/types.cjs +35 -0
- package/dist/direct/types.cjs.map +1 -0
- package/dist/direct/types.d.ts +205 -0
- package/dist/direct/types.js +11 -0
- package/dist/direct/types.js.map +1 -0
- package/dist/direct/use-direct-vana-connect.cjs +68 -0
- package/dist/direct/use-direct-vana-connect.cjs.map +1 -0
- package/dist/direct/use-direct-vana-connect.d.ts +45 -0
- package/dist/direct/use-direct-vana-connect.js +46 -0
- package/dist/direct/use-direct-vana-connect.js.map +1 -0
- package/dist/index.browser.d.ts +9 -4
- package/dist/index.browser.js +644 -178
- package/dist/index.browser.js.map +4 -4
- package/dist/index.node.cjs +672 -183
- package/dist/index.node.cjs.map +4 -4
- package/dist/index.node.d.ts +9 -4
- package/dist/index.node.js +644 -178
- package/dist/index.node.js.map +4 -4
- package/dist/personal-server-lite/owner-binding.cjs +93 -0
- package/dist/personal-server-lite/owner-binding.cjs.map +1 -0
- package/dist/personal-server-lite/owner-binding.d.ts +44 -0
- package/dist/personal-server-lite/owner-binding.js +65 -0
- package/dist/personal-server-lite/owner-binding.js.map +1 -0
- package/dist/personal-server-lite/owner-binding.test.d.ts +1 -0
- package/dist/protocol/data-point-status.cjs +80 -0
- package/dist/protocol/data-point-status.cjs.map +1 -0
- package/dist/protocol/data-point-status.d.ts +34 -0
- package/dist/protocol/data-point-status.js +51 -0
- package/dist/protocol/data-point-status.js.map +1 -0
- package/dist/protocol/data-point-status.test.d.ts +1 -0
- package/dist/protocol/eip712.cjs +53 -31
- package/dist/protocol/eip712.cjs.map +1 -1
- package/dist/protocol/eip712.d.ts +98 -43
- package/dist/protocol/eip712.js +47 -27
- package/dist/protocol/eip712.js.map +1 -1
- package/dist/protocol/escrow-deposit.cjs +89 -0
- package/dist/protocol/escrow-deposit.cjs.map +1 -0
- package/dist/protocol/escrow-deposit.d.ts +47 -0
- package/dist/protocol/escrow-deposit.js +60 -0
- package/dist/protocol/escrow-deposit.js.map +1 -0
- package/dist/protocol/escrow-deposit.test.d.ts +1 -0
- package/dist/protocol/escrow-flow.test.d.ts +21 -0
- package/dist/protocol/escrow.cjs +146 -0
- package/dist/protocol/escrow.cjs.map +1 -0
- package/dist/protocol/escrow.d.ts +336 -0
- package/dist/protocol/escrow.js +118 -0
- package/dist/protocol/escrow.js.map +1 -0
- package/dist/protocol/escrow.test.d.ts +1 -0
- package/dist/protocol/fee-registry.cjs +116 -0
- package/dist/protocol/fee-registry.cjs.map +1 -0
- package/dist/protocol/fee-registry.d.ts +151 -0
- package/dist/protocol/fee-registry.js +89 -0
- package/dist/protocol/fee-registry.js.map +1 -0
- package/dist/protocol/fee-registry.test.d.ts +1 -0
- package/dist/protocol/gateway.cjs +107 -37
- package/dist/protocol/gateway.cjs.map +1 -1
- package/dist/protocol/gateway.d.ts +223 -57
- package/dist/protocol/gateway.js +107 -37
- package/dist/protocol/gateway.js.map +1 -1
- package/dist/protocol/grants.cjs +27 -64
- package/dist/protocol/grants.cjs.map +1 -1
- package/dist/protocol/grants.d.ts +6 -13
- package/dist/protocol/grants.js +27 -63
- package/dist/protocol/grants.js.map +1 -1
- package/dist/protocol/personal-server-data.cjs +71 -0
- package/dist/protocol/personal-server-data.cjs.map +1 -0
- package/dist/protocol/personal-server-data.d.ts +16 -0
- package/dist/protocol/personal-server-data.js +47 -0
- package/dist/protocol/personal-server-data.js.map +1 -0
- package/dist/protocol/personal-server-data.test.d.ts +1 -0
- package/dist/protocol/personal-server-registration.cjs +16 -4
- package/dist/protocol/personal-server-registration.cjs.map +1 -1
- package/dist/protocol/personal-server-registration.d.ts +5 -2
- package/dist/protocol/personal-server-registration.js +16 -4
- package/dist/protocol/personal-server-registration.js.map +1 -1
- package/dist/react.cjs +32 -0
- package/dist/react.cjs.map +1 -0
- package/dist/react.d.ts +33 -0
- package/dist/react.js +11 -0
- package/dist/react.js.map +1 -0
- package/dist/server.cjs +73 -0
- package/dist/server.cjs.map +1 -0
- package/dist/server.d.ts +32 -0
- package/dist/server.js +55 -0
- package/dist/server.js.map +1 -0
- package/dist/storage/providers/vana-storage.cjs +75 -17
- package/dist/storage/providers/vana-storage.cjs.map +1 -1
- package/dist/storage/providers/vana-storage.js +75 -17
- package/dist/storage/providers/vana-storage.js.map +1 -1
- package/package.json +20 -1
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
var fee_registry_exports = {};
|
|
20
|
+
__export(fee_registry_exports, {
|
|
21
|
+
FEE_REGISTRY_ABI: () => FEE_REGISTRY_ABI,
|
|
22
|
+
REGISTRATION_KIND_FOR_OP: () => REGISTRATION_KIND_FOR_OP,
|
|
23
|
+
getFee: () => getFee,
|
|
24
|
+
getOpFee: () => getOpFee
|
|
25
|
+
});
|
|
26
|
+
module.exports = __toCommonJS(fee_registry_exports);
|
|
27
|
+
var import_viem = require("viem");
|
|
28
|
+
const FEE_REGISTRY_ABI = (0, import_viem.parseAbi)([
|
|
29
|
+
"struct Fee { uint256 amount; address asset; address payee; bool enabled; }",
|
|
30
|
+
"function fees(bytes32 operation) view returns (Fee)",
|
|
31
|
+
"function operationKey(string name) pure returns (bytes32)"
|
|
32
|
+
]);
|
|
33
|
+
const REGISTRATION_KIND_FOR_OP = {
|
|
34
|
+
grant: "grant_registration",
|
|
35
|
+
data: "data_registration",
|
|
36
|
+
server: "server_registration",
|
|
37
|
+
builder: "builder_registration"
|
|
38
|
+
};
|
|
39
|
+
function operationNameFor(kind, opts) {
|
|
40
|
+
switch (kind) {
|
|
41
|
+
case "grant_registration":
|
|
42
|
+
return opts?.grantRegistrationOpName ?? "grant_registration";
|
|
43
|
+
case "data_access":
|
|
44
|
+
return opts?.dataAccessOpName ?? "data_access";
|
|
45
|
+
case "data_registration":
|
|
46
|
+
return opts?.dataRegistrationOpName ?? "data_registration";
|
|
47
|
+
case "server_registration":
|
|
48
|
+
return opts?.serverRegistrationOpName ?? "server_registration";
|
|
49
|
+
case "builder_registration":
|
|
50
|
+
return opts?.builderRegistrationOpName ?? "builder_registration";
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
const ZERO_ADDRESS = "0x0000000000000000000000000000000000000000";
|
|
54
|
+
async function getFee(client, config, kind, opts) {
|
|
55
|
+
const address = config.contracts.feeRegistry;
|
|
56
|
+
const opName = operationNameFor(kind, opts);
|
|
57
|
+
const opKey = await client.readContract({
|
|
58
|
+
address,
|
|
59
|
+
abi: FEE_REGISTRY_ABI,
|
|
60
|
+
functionName: "operationKey",
|
|
61
|
+
args: [opName]
|
|
62
|
+
});
|
|
63
|
+
const fee = await client.readContract({
|
|
64
|
+
address,
|
|
65
|
+
abi: FEE_REGISTRY_ABI,
|
|
66
|
+
functionName: "fees",
|
|
67
|
+
args: [opKey]
|
|
68
|
+
});
|
|
69
|
+
if (fee.enabled && fee.payee === ZERO_ADDRESS) {
|
|
70
|
+
throw new Error(
|
|
71
|
+
`FeeRegistry: enabled operation "${opName}" has zero-address payee \u2014 contract pre-flight rejects payouts to 0x0`
|
|
72
|
+
);
|
|
73
|
+
}
|
|
74
|
+
return fee;
|
|
75
|
+
}
|
|
76
|
+
async function getOpFee(client, config, opType, opts) {
|
|
77
|
+
const registrationKind = REGISTRATION_KIND_FOR_OP[opType];
|
|
78
|
+
if (!registrationKind) {
|
|
79
|
+
throw new Error(
|
|
80
|
+
`getOpFee: unknown opType "${opType}" \u2014 supported types are ${Object.keys(REGISTRATION_KIND_FOR_OP).join(", ")}`
|
|
81
|
+
);
|
|
82
|
+
}
|
|
83
|
+
const includeDataAccess = opType === "grant";
|
|
84
|
+
const [registration, dataAccess] = await Promise.all([
|
|
85
|
+
getFee(client, config, registrationKind, opts),
|
|
86
|
+
includeDataAccess ? getFee(client, config, "data_access", opts) : Promise.resolve({
|
|
87
|
+
amount: 0n,
|
|
88
|
+
asset: ZERO_ADDRESS,
|
|
89
|
+
payee: ZERO_ADDRESS,
|
|
90
|
+
enabled: false
|
|
91
|
+
})
|
|
92
|
+
]);
|
|
93
|
+
if (registration.enabled && dataAccess.enabled && registration.asset.toLowerCase() !== dataAccess.asset.toLowerCase()) {
|
|
94
|
+
throw new Error(
|
|
95
|
+
`FeeRegistry asset mismatch for "${opType}": registration=${registration.asset} vs data_access=${dataAccess.asset}. The gateway requires both kinds to settle in the same asset when both are enabled.`
|
|
96
|
+
);
|
|
97
|
+
}
|
|
98
|
+
const asset = registration.enabled ? registration.asset : dataAccess.enabled ? dataAccess.asset : ZERO_ADDRESS;
|
|
99
|
+
return {
|
|
100
|
+
asset,
|
|
101
|
+
registrationFee: registration.enabled ? registration.amount : 0n,
|
|
102
|
+
dataAccessFee: dataAccess.enabled ? dataAccess.amount : 0n,
|
|
103
|
+
registrationEnabled: registration.enabled,
|
|
104
|
+
dataAccessEnabled: dataAccess.enabled,
|
|
105
|
+
registrationPayee: registration.enabled ? registration.payee : ZERO_ADDRESS,
|
|
106
|
+
dataAccessPayee: dataAccess.enabled ? dataAccess.payee : ZERO_ADDRESS
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
110
|
+
0 && (module.exports = {
|
|
111
|
+
FEE_REGISTRY_ABI,
|
|
112
|
+
REGISTRATION_KIND_FOR_OP,
|
|
113
|
+
getFee,
|
|
114
|
+
getOpFee
|
|
115
|
+
});
|
|
116
|
+
//# sourceMappingURL=fee-registry.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/protocol/fee-registry.ts"],"sourcesContent":["/**\n * Adapter for the on-chain FeeRegistry contract — the source of truth the\n * gateway re-reads on every /v1/escrow/pay to size the payment amount.\n *\n * The registry stores per-operation `{amount, asset, payee, enabled}`\n * records keyed on `keccak256(name)`. SDK consumers (builders sizing\n * payments) MUST read fees from this contract rather than hardcoding\n * them, or the signed `amount` won't match the gateway's expected total\n * and /v1/escrow/pay returns 400.\n *\n * Five operation kinds are wired up; each kind's name matches the\n * corresponding `payments.kind` column value on the gateway:\n *\n * - 'grant_registration' — one-time fee when a grant is first registered\n * (POST /v1/grants).\n * - 'data_access' — per-access surcharge on grant payments\n * (every accessRecord posted against a grant).\n * - 'data_registration' — one-time fee for registering a data point\n * (POST /v1/data → addDataWithSignature).\n * - 'server_registration' — one-time fee for registering a personal server\n * (POST /v1/servers).\n * - 'builder_registration' — one-time fee for registering a builder\n * (POST /v1/builders; gateway-only, no on-chain\n * submission).\n *\n * Disabled or unregistered fees skip enforcement: the corresponding\n * operation settles WITHOUT requiring a payment from escrow. `getFee`\n * surfaces this via `enabled: false` rather than throwing — the gateway\n * itself treats a disabled fee as a steady state, not a misconfig.\n *\n * Deployers can override the on-chain operation strings via\n * `FEE_REGISTRY_<KIND>_OP` env vars on the gateway side; the matching\n * SDK escape hatch is the `opts.<kind>OpName` arguments.\n *\n * This module is signer/transport-agnostic — callers pass in their own\n * `PublicClient` for the contract reads. No caching here; long-running\n * service consumers should wrap with their own TTL. Mirrors\n * data-gateway/lib/fee-registry.ts byte-for-byte.\n *\n * @category Protocol\n */\nimport { parseAbi, type Address, type Hex, type PublicClient } from \"viem\";\nimport type { DataPortabilityGatewayConfig } from \"./eip712\";\n\nexport const FEE_REGISTRY_ABI = parseAbi([\n \"struct Fee { uint256 amount; address asset; address payee; bool enabled; }\",\n \"function fees(bytes32 operation) view returns (Fee)\",\n \"function operationKey(string name) pure returns (bytes32)\",\n]);\n\nexport type FeeKind =\n | \"grant_registration\"\n | \"data_access\"\n | \"data_registration\"\n | \"server_registration\"\n | \"builder_registration\";\n\n/**\n * Map from a user-facing opType (POST /v1/escrow/pay body field, matches\n * the gateway's `payments.op_type` column) to the FeeKind that gates its\n * one-time registration fee.\n *\n * Data access is a per-call surcharge on grants only — it's not a\n * registration fee for any op, so it lives outside this map.\n */\nexport const REGISTRATION_KIND_FOR_OP: Record<string, FeeKind> = {\n grant: \"grant_registration\",\n data: \"data_registration\",\n server: \"server_registration\",\n builder: \"builder_registration\",\n};\n\nexport interface FeeEntry {\n amount: bigint;\n // Asset the fee is denominated in. 0x0000…0000 = native VANA; anything\n // else is an ERC-20 contract address.\n asset: Address;\n // The recipient the on-chain settle pass routes the fee to. Only\n // meaningful when `enabled` — disabled fees never land as a SettleOp `to`.\n payee: Address;\n enabled: boolean;\n}\n\n/**\n * Compound fee schedule for one op type, mirroring the gateway's\n * lib/op-fees.ts `OpFee`. For ANY op type, `registrationFee` is the\n * one-time fee charged at registration. For `'grant'` only, `dataAccessFee`\n * is the per-access surcharge — for any other op type it's always 0n with\n * `dataAccessEnabled: false`.\n *\n * `xxxEnabled` reflects the on-chain `Fee.enabled` flag. When OFF, the\n * corresponding amount is 0 and the pay handler should NOT require\n * payment for that kind. When both are off (for a grant) or registration\n * is off (for any other op type), the entire payment flow is skipped —\n * the op settles directly via the no-payment path.\n */\nexport interface OpFee {\n // Asset for whichever components are enabled. Falls back to native VANA\n // (0x0) when both components are disabled. The pay handler enforces that\n // the payer's `asset` matches.\n asset: Address;\n registrationFee: bigint;\n dataAccessFee: bigint;\n registrationEnabled: boolean;\n dataAccessEnabled: boolean;\n // Surfaced for the SDK's on-chain log-filter use case; the gateway's\n // OpFee type doesn't include these but the SDK keeps them since callers\n // sizing on-chain assertions need to know where the fee lands. Equal to\n // the zero address when the corresponding kind is disabled.\n registrationPayee: Address;\n dataAccessPayee: Address;\n}\n\nexport interface FeeRegistryOptions {\n grantRegistrationOpName?: string;\n dataAccessOpName?: string;\n dataRegistrationOpName?: string;\n serverRegistrationOpName?: string;\n builderRegistrationOpName?: string;\n}\n\nfunction operationNameFor(\n kind: FeeKind,\n opts: FeeRegistryOptions | undefined,\n): string {\n switch (kind) {\n case \"grant_registration\":\n return opts?.grantRegistrationOpName ?? \"grant_registration\";\n case \"data_access\":\n return opts?.dataAccessOpName ?? \"data_access\";\n case \"data_registration\":\n return opts?.dataRegistrationOpName ?? \"data_registration\";\n case \"server_registration\":\n return opts?.serverRegistrationOpName ?? \"server_registration\";\n case \"builder_registration\":\n return opts?.builderRegistrationOpName ?? \"builder_registration\";\n }\n}\n\nconst ZERO_ADDRESS = \"0x0000000000000000000000000000000000000000\" as Address;\n\n/**\n * Reads one fee kind from the FeeRegistry. Calls the contract's\n * `operationKey(name)` first to derive the bytes32 key — matches the\n * gateway's approach exactly (could compute locally via keccak256, but\n * going through the contract eliminates any chance of encoding drift).\n *\n * Returns `{enabled: false}` entries WITHOUT throwing — disabled is a\n * valid steady state on the gateway. The only validation is the\n * zero-payee check, and that only fires when the fee is enabled\n * (a disabled fee never lands as a SettleOp `to`).\n */\nexport async function getFee(\n client: PublicClient,\n config: DataPortabilityGatewayConfig,\n kind: FeeKind,\n opts?: FeeRegistryOptions,\n): Promise<FeeEntry> {\n const address = config.contracts.feeRegistry as Address;\n const opName = operationNameFor(kind, opts);\n\n const opKey = (await client.readContract({\n address,\n abi: FEE_REGISTRY_ABI,\n functionName: \"operationKey\",\n args: [opName],\n })) as Hex;\n\n const fee = (await client.readContract({\n address,\n abi: FEE_REGISTRY_ABI,\n functionName: \"fees\",\n args: [opKey],\n })) as FeeEntry;\n\n if (fee.enabled && fee.payee === ZERO_ADDRESS) {\n throw new Error(\n `FeeRegistry: enabled operation \"${opName}\" has zero-address payee — contract pre-flight rejects payouts to 0x0`,\n );\n }\n\n return fee;\n}\n\n/**\n * Convenience: combine the FeeRegistry reads for one op type into the\n * compound shape the pay handler validates against.\n *\n * For 'grant' opType the result includes both registration + data_access\n * components; for other op types data_access is always disabled with\n * amount=0. Disabled components contribute 0 to the signed total —\n * callers compute `amount = registrationFee + dataAccessFee` and the pay\n * handler accepts (or short-circuits with 'Payment not required' when\n * both are 0).\n *\n * Throws on asset mismatch ONLY when both components are enabled — a\n * disabled fee never lands as a SettleOp, so its asset is moot.\n */\nexport async function getOpFee(\n client: PublicClient,\n config: DataPortabilityGatewayConfig,\n opType: string,\n opts?: FeeRegistryOptions,\n): Promise<OpFee> {\n const registrationKind = REGISTRATION_KIND_FOR_OP[opType];\n if (!registrationKind) {\n throw new Error(\n `getOpFee: unknown opType \"${opType}\" — supported types are ${Object.keys(REGISTRATION_KIND_FOR_OP).join(\", \")}`,\n );\n }\n\n const includeDataAccess = opType === \"grant\";\n const [registration, dataAccess] = await Promise.all([\n getFee(client, config, registrationKind, opts),\n includeDataAccess\n ? getFee(client, config, \"data_access\", opts)\n : Promise.resolve<FeeEntry>({\n amount: 0n,\n asset: ZERO_ADDRESS,\n payee: ZERO_ADDRESS,\n enabled: false,\n }),\n ]);\n\n if (\n registration.enabled &&\n dataAccess.enabled &&\n registration.asset.toLowerCase() !== dataAccess.asset.toLowerCase()\n ) {\n throw new Error(\n `FeeRegistry asset mismatch for \"${opType}\": registration=${registration.asset} vs data_access=${dataAccess.asset}. The gateway requires both kinds to settle in the same asset when both are enabled.`,\n );\n }\n\n const asset = registration.enabled\n ? registration.asset\n : dataAccess.enabled\n ? dataAccess.asset\n : ZERO_ADDRESS;\n\n return {\n asset,\n registrationFee: registration.enabled ? registration.amount : 0n,\n dataAccessFee: dataAccess.enabled ? dataAccess.amount : 0n,\n registrationEnabled: registration.enabled,\n dataAccessEnabled: dataAccess.enabled,\n registrationPayee: registration.enabled ? registration.payee : ZERO_ADDRESS,\n dataAccessPayee: dataAccess.enabled ? dataAccess.payee : ZERO_ADDRESS,\n };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAyCA,kBAAoE;AAG7D,MAAM,uBAAmB,sBAAS;AAAA,EACvC;AAAA,EACA;AAAA,EACA;AACF,CAAC;AAiBM,MAAM,2BAAoD;AAAA,EAC/D,OAAO;AAAA,EACP,MAAM;AAAA,EACN,QAAQ;AAAA,EACR,SAAS;AACX;AAmDA,SAAS,iBACP,MACA,MACQ;AACR,UAAQ,MAAM;AAAA,IACZ,KAAK;AACH,aAAO,MAAM,2BAA2B;AAAA,IAC1C,KAAK;AACH,aAAO,MAAM,oBAAoB;AAAA,IACnC,KAAK;AACH,aAAO,MAAM,0BAA0B;AAAA,IACzC,KAAK;AACH,aAAO,MAAM,4BAA4B;AAAA,IAC3C,KAAK;AACH,aAAO,MAAM,6BAA6B;AAAA,EAC9C;AACF;AAEA,MAAM,eAAe;AAarB,eAAsB,OACpB,QACA,QACA,MACA,MACmB;AACnB,QAAM,UAAU,OAAO,UAAU;AACjC,QAAM,SAAS,iBAAiB,MAAM,IAAI;AAE1C,QAAM,QAAS,MAAM,OAAO,aAAa;AAAA,IACvC;AAAA,IACA,KAAK;AAAA,IACL,cAAc;AAAA,IACd,MAAM,CAAC,MAAM;AAAA,EACf,CAAC;AAED,QAAM,MAAO,MAAM,OAAO,aAAa;AAAA,IACrC;AAAA,IACA,KAAK;AAAA,IACL,cAAc;AAAA,IACd,MAAM,CAAC,KAAK;AAAA,EACd,CAAC;AAED,MAAI,IAAI,WAAW,IAAI,UAAU,cAAc;AAC7C,UAAM,IAAI;AAAA,MACR,mCAAmC,MAAM;AAAA,IAC3C;AAAA,EACF;AAEA,SAAO;AACT;AAgBA,eAAsB,SACpB,QACA,QACA,QACA,MACgB;AAChB,QAAM,mBAAmB,yBAAyB,MAAM;AACxD,MAAI,CAAC,kBAAkB;AACrB,UAAM,IAAI;AAAA,MACR,6BAA6B,MAAM,gCAA2B,OAAO,KAAK,wBAAwB,EAAE,KAAK,IAAI,CAAC;AAAA,IAChH;AAAA,EACF;AAEA,QAAM,oBAAoB,WAAW;AACrC,QAAM,CAAC,cAAc,UAAU,IAAI,MAAM,QAAQ,IAAI;AAAA,IACnD,OAAO,QAAQ,QAAQ,kBAAkB,IAAI;AAAA,IAC7C,oBACI,OAAO,QAAQ,QAAQ,eAAe,IAAI,IAC1C,QAAQ,QAAkB;AAAA,MACxB,QAAQ;AAAA,MACR,OAAO;AAAA,MACP,OAAO;AAAA,MACP,SAAS;AAAA,IACX,CAAC;AAAA,EACP,CAAC;AAED,MACE,aAAa,WACb,WAAW,WACX,aAAa,MAAM,YAAY,MAAM,WAAW,MAAM,YAAY,GAClE;AACA,UAAM,IAAI;AAAA,MACR,mCAAmC,MAAM,mBAAmB,aAAa,KAAK,mBAAmB,WAAW,KAAK;AAAA,IACnH;AAAA,EACF;AAEA,QAAM,QAAQ,aAAa,UACvB,aAAa,QACb,WAAW,UACT,WAAW,QACX;AAEN,SAAO;AAAA,IACL;AAAA,IACA,iBAAiB,aAAa,UAAU,aAAa,SAAS;AAAA,IAC9D,eAAe,WAAW,UAAU,WAAW,SAAS;AAAA,IACxD,qBAAqB,aAAa;AAAA,IAClC,mBAAmB,WAAW;AAAA,IAC9B,mBAAmB,aAAa,UAAU,aAAa,QAAQ;AAAA,IAC/D,iBAAiB,WAAW,UAAU,WAAW,QAAQ;AAAA,EAC3D;AACF;","names":[]}
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Adapter for the on-chain FeeRegistry contract — the source of truth the
|
|
3
|
+
* gateway re-reads on every /v1/escrow/pay to size the payment amount.
|
|
4
|
+
*
|
|
5
|
+
* The registry stores per-operation `{amount, asset, payee, enabled}`
|
|
6
|
+
* records keyed on `keccak256(name)`. SDK consumers (builders sizing
|
|
7
|
+
* payments) MUST read fees from this contract rather than hardcoding
|
|
8
|
+
* them, or the signed `amount` won't match the gateway's expected total
|
|
9
|
+
* and /v1/escrow/pay returns 400.
|
|
10
|
+
*
|
|
11
|
+
* Five operation kinds are wired up; each kind's name matches the
|
|
12
|
+
* corresponding `payments.kind` column value on the gateway:
|
|
13
|
+
*
|
|
14
|
+
* - 'grant_registration' — one-time fee when a grant is first registered
|
|
15
|
+
* (POST /v1/grants).
|
|
16
|
+
* - 'data_access' — per-access surcharge on grant payments
|
|
17
|
+
* (every accessRecord posted against a grant).
|
|
18
|
+
* - 'data_registration' — one-time fee for registering a data point
|
|
19
|
+
* (POST /v1/data → addDataWithSignature).
|
|
20
|
+
* - 'server_registration' — one-time fee for registering a personal server
|
|
21
|
+
* (POST /v1/servers).
|
|
22
|
+
* - 'builder_registration' — one-time fee for registering a builder
|
|
23
|
+
* (POST /v1/builders; gateway-only, no on-chain
|
|
24
|
+
* submission).
|
|
25
|
+
*
|
|
26
|
+
* Disabled or unregistered fees skip enforcement: the corresponding
|
|
27
|
+
* operation settles WITHOUT requiring a payment from escrow. `getFee`
|
|
28
|
+
* surfaces this via `enabled: false` rather than throwing — the gateway
|
|
29
|
+
* itself treats a disabled fee as a steady state, not a misconfig.
|
|
30
|
+
*
|
|
31
|
+
* Deployers can override the on-chain operation strings via
|
|
32
|
+
* `FEE_REGISTRY_<KIND>_OP` env vars on the gateway side; the matching
|
|
33
|
+
* SDK escape hatch is the `opts.<kind>OpName` arguments.
|
|
34
|
+
*
|
|
35
|
+
* This module is signer/transport-agnostic — callers pass in their own
|
|
36
|
+
* `PublicClient` for the contract reads. No caching here; long-running
|
|
37
|
+
* service consumers should wrap with their own TTL. Mirrors
|
|
38
|
+
* data-gateway/lib/fee-registry.ts byte-for-byte.
|
|
39
|
+
*
|
|
40
|
+
* @category Protocol
|
|
41
|
+
*/
|
|
42
|
+
import { type Address, type PublicClient } from "viem";
|
|
43
|
+
import type { DataPortabilityGatewayConfig } from "./eip712";
|
|
44
|
+
export declare const FEE_REGISTRY_ABI: readonly [{
|
|
45
|
+
readonly name: "fees";
|
|
46
|
+
readonly type: "function";
|
|
47
|
+
readonly stateMutability: "view";
|
|
48
|
+
readonly inputs: readonly [{
|
|
49
|
+
readonly type: "bytes32";
|
|
50
|
+
readonly name: "operation";
|
|
51
|
+
}];
|
|
52
|
+
readonly outputs: readonly [{
|
|
53
|
+
readonly type: "tuple";
|
|
54
|
+
readonly components: readonly [{
|
|
55
|
+
readonly type: "uint256";
|
|
56
|
+
readonly name: "amount";
|
|
57
|
+
}, {
|
|
58
|
+
readonly type: "address";
|
|
59
|
+
readonly name: "asset";
|
|
60
|
+
}, {
|
|
61
|
+
readonly type: "address";
|
|
62
|
+
readonly name: "payee";
|
|
63
|
+
}, {
|
|
64
|
+
readonly type: "bool";
|
|
65
|
+
readonly name: "enabled";
|
|
66
|
+
}];
|
|
67
|
+
}];
|
|
68
|
+
}, {
|
|
69
|
+
readonly name: "operationKey";
|
|
70
|
+
readonly type: "function";
|
|
71
|
+
readonly stateMutability: "pure";
|
|
72
|
+
readonly inputs: readonly [{
|
|
73
|
+
readonly type: "string";
|
|
74
|
+
readonly name: "name";
|
|
75
|
+
}];
|
|
76
|
+
readonly outputs: readonly [{
|
|
77
|
+
readonly type: "bytes32";
|
|
78
|
+
}];
|
|
79
|
+
}];
|
|
80
|
+
export type FeeKind = "grant_registration" | "data_access" | "data_registration" | "server_registration" | "builder_registration";
|
|
81
|
+
/**
|
|
82
|
+
* Map from a user-facing opType (POST /v1/escrow/pay body field, matches
|
|
83
|
+
* the gateway's `payments.op_type` column) to the FeeKind that gates its
|
|
84
|
+
* one-time registration fee.
|
|
85
|
+
*
|
|
86
|
+
* Data access is a per-call surcharge on grants only — it's not a
|
|
87
|
+
* registration fee for any op, so it lives outside this map.
|
|
88
|
+
*/
|
|
89
|
+
export declare const REGISTRATION_KIND_FOR_OP: Record<string, FeeKind>;
|
|
90
|
+
export interface FeeEntry {
|
|
91
|
+
amount: bigint;
|
|
92
|
+
asset: Address;
|
|
93
|
+
payee: Address;
|
|
94
|
+
enabled: boolean;
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Compound fee schedule for one op type, mirroring the gateway's
|
|
98
|
+
* lib/op-fees.ts `OpFee`. For ANY op type, `registrationFee` is the
|
|
99
|
+
* one-time fee charged at registration. For `'grant'` only, `dataAccessFee`
|
|
100
|
+
* is the per-access surcharge — for any other op type it's always 0n with
|
|
101
|
+
* `dataAccessEnabled: false`.
|
|
102
|
+
*
|
|
103
|
+
* `xxxEnabled` reflects the on-chain `Fee.enabled` flag. When OFF, the
|
|
104
|
+
* corresponding amount is 0 and the pay handler should NOT require
|
|
105
|
+
* payment for that kind. When both are off (for a grant) or registration
|
|
106
|
+
* is off (for any other op type), the entire payment flow is skipped —
|
|
107
|
+
* the op settles directly via the no-payment path.
|
|
108
|
+
*/
|
|
109
|
+
export interface OpFee {
|
|
110
|
+
asset: Address;
|
|
111
|
+
registrationFee: bigint;
|
|
112
|
+
dataAccessFee: bigint;
|
|
113
|
+
registrationEnabled: boolean;
|
|
114
|
+
dataAccessEnabled: boolean;
|
|
115
|
+
registrationPayee: Address;
|
|
116
|
+
dataAccessPayee: Address;
|
|
117
|
+
}
|
|
118
|
+
export interface FeeRegistryOptions {
|
|
119
|
+
grantRegistrationOpName?: string;
|
|
120
|
+
dataAccessOpName?: string;
|
|
121
|
+
dataRegistrationOpName?: string;
|
|
122
|
+
serverRegistrationOpName?: string;
|
|
123
|
+
builderRegistrationOpName?: string;
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Reads one fee kind from the FeeRegistry. Calls the contract's
|
|
127
|
+
* `operationKey(name)` first to derive the bytes32 key — matches the
|
|
128
|
+
* gateway's approach exactly (could compute locally via keccak256, but
|
|
129
|
+
* going through the contract eliminates any chance of encoding drift).
|
|
130
|
+
*
|
|
131
|
+
* Returns `{enabled: false}` entries WITHOUT throwing — disabled is a
|
|
132
|
+
* valid steady state on the gateway. The only validation is the
|
|
133
|
+
* zero-payee check, and that only fires when the fee is enabled
|
|
134
|
+
* (a disabled fee never lands as a SettleOp `to`).
|
|
135
|
+
*/
|
|
136
|
+
export declare function getFee(client: PublicClient, config: DataPortabilityGatewayConfig, kind: FeeKind, opts?: FeeRegistryOptions): Promise<FeeEntry>;
|
|
137
|
+
/**
|
|
138
|
+
* Convenience: combine the FeeRegistry reads for one op type into the
|
|
139
|
+
* compound shape the pay handler validates against.
|
|
140
|
+
*
|
|
141
|
+
* For 'grant' opType the result includes both registration + data_access
|
|
142
|
+
* components; for other op types data_access is always disabled with
|
|
143
|
+
* amount=0. Disabled components contribute 0 to the signed total —
|
|
144
|
+
* callers compute `amount = registrationFee + dataAccessFee` and the pay
|
|
145
|
+
* handler accepts (or short-circuits with 'Payment not required' when
|
|
146
|
+
* both are 0).
|
|
147
|
+
*
|
|
148
|
+
* Throws on asset mismatch ONLY when both components are enabled — a
|
|
149
|
+
* disabled fee never lands as a SettleOp, so its asset is moot.
|
|
150
|
+
*/
|
|
151
|
+
export declare function getOpFee(client: PublicClient, config: DataPortabilityGatewayConfig, opType: string, opts?: FeeRegistryOptions): Promise<OpFee>;
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { parseAbi } from "viem";
|
|
2
|
+
const FEE_REGISTRY_ABI = parseAbi([
|
|
3
|
+
"struct Fee { uint256 amount; address asset; address payee; bool enabled; }",
|
|
4
|
+
"function fees(bytes32 operation) view returns (Fee)",
|
|
5
|
+
"function operationKey(string name) pure returns (bytes32)"
|
|
6
|
+
]);
|
|
7
|
+
const REGISTRATION_KIND_FOR_OP = {
|
|
8
|
+
grant: "grant_registration",
|
|
9
|
+
data: "data_registration",
|
|
10
|
+
server: "server_registration",
|
|
11
|
+
builder: "builder_registration"
|
|
12
|
+
};
|
|
13
|
+
function operationNameFor(kind, opts) {
|
|
14
|
+
switch (kind) {
|
|
15
|
+
case "grant_registration":
|
|
16
|
+
return opts?.grantRegistrationOpName ?? "grant_registration";
|
|
17
|
+
case "data_access":
|
|
18
|
+
return opts?.dataAccessOpName ?? "data_access";
|
|
19
|
+
case "data_registration":
|
|
20
|
+
return opts?.dataRegistrationOpName ?? "data_registration";
|
|
21
|
+
case "server_registration":
|
|
22
|
+
return opts?.serverRegistrationOpName ?? "server_registration";
|
|
23
|
+
case "builder_registration":
|
|
24
|
+
return opts?.builderRegistrationOpName ?? "builder_registration";
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
const ZERO_ADDRESS = "0x0000000000000000000000000000000000000000";
|
|
28
|
+
async function getFee(client, config, kind, opts) {
|
|
29
|
+
const address = config.contracts.feeRegistry;
|
|
30
|
+
const opName = operationNameFor(kind, opts);
|
|
31
|
+
const opKey = await client.readContract({
|
|
32
|
+
address,
|
|
33
|
+
abi: FEE_REGISTRY_ABI,
|
|
34
|
+
functionName: "operationKey",
|
|
35
|
+
args: [opName]
|
|
36
|
+
});
|
|
37
|
+
const fee = await client.readContract({
|
|
38
|
+
address,
|
|
39
|
+
abi: FEE_REGISTRY_ABI,
|
|
40
|
+
functionName: "fees",
|
|
41
|
+
args: [opKey]
|
|
42
|
+
});
|
|
43
|
+
if (fee.enabled && fee.payee === ZERO_ADDRESS) {
|
|
44
|
+
throw new Error(
|
|
45
|
+
`FeeRegistry: enabled operation "${opName}" has zero-address payee \u2014 contract pre-flight rejects payouts to 0x0`
|
|
46
|
+
);
|
|
47
|
+
}
|
|
48
|
+
return fee;
|
|
49
|
+
}
|
|
50
|
+
async function getOpFee(client, config, opType, opts) {
|
|
51
|
+
const registrationKind = REGISTRATION_KIND_FOR_OP[opType];
|
|
52
|
+
if (!registrationKind) {
|
|
53
|
+
throw new Error(
|
|
54
|
+
`getOpFee: unknown opType "${opType}" \u2014 supported types are ${Object.keys(REGISTRATION_KIND_FOR_OP).join(", ")}`
|
|
55
|
+
);
|
|
56
|
+
}
|
|
57
|
+
const includeDataAccess = opType === "grant";
|
|
58
|
+
const [registration, dataAccess] = await Promise.all([
|
|
59
|
+
getFee(client, config, registrationKind, opts),
|
|
60
|
+
includeDataAccess ? getFee(client, config, "data_access", opts) : Promise.resolve({
|
|
61
|
+
amount: 0n,
|
|
62
|
+
asset: ZERO_ADDRESS,
|
|
63
|
+
payee: ZERO_ADDRESS,
|
|
64
|
+
enabled: false
|
|
65
|
+
})
|
|
66
|
+
]);
|
|
67
|
+
if (registration.enabled && dataAccess.enabled && registration.asset.toLowerCase() !== dataAccess.asset.toLowerCase()) {
|
|
68
|
+
throw new Error(
|
|
69
|
+
`FeeRegistry asset mismatch for "${opType}": registration=${registration.asset} vs data_access=${dataAccess.asset}. The gateway requires both kinds to settle in the same asset when both are enabled.`
|
|
70
|
+
);
|
|
71
|
+
}
|
|
72
|
+
const asset = registration.enabled ? registration.asset : dataAccess.enabled ? dataAccess.asset : ZERO_ADDRESS;
|
|
73
|
+
return {
|
|
74
|
+
asset,
|
|
75
|
+
registrationFee: registration.enabled ? registration.amount : 0n,
|
|
76
|
+
dataAccessFee: dataAccess.enabled ? dataAccess.amount : 0n,
|
|
77
|
+
registrationEnabled: registration.enabled,
|
|
78
|
+
dataAccessEnabled: dataAccess.enabled,
|
|
79
|
+
registrationPayee: registration.enabled ? registration.payee : ZERO_ADDRESS,
|
|
80
|
+
dataAccessPayee: dataAccess.enabled ? dataAccess.payee : ZERO_ADDRESS
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
export {
|
|
84
|
+
FEE_REGISTRY_ABI,
|
|
85
|
+
REGISTRATION_KIND_FOR_OP,
|
|
86
|
+
getFee,
|
|
87
|
+
getOpFee
|
|
88
|
+
};
|
|
89
|
+
//# sourceMappingURL=fee-registry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/protocol/fee-registry.ts"],"sourcesContent":["/**\n * Adapter for the on-chain FeeRegistry contract — the source of truth the\n * gateway re-reads on every /v1/escrow/pay to size the payment amount.\n *\n * The registry stores per-operation `{amount, asset, payee, enabled}`\n * records keyed on `keccak256(name)`. SDK consumers (builders sizing\n * payments) MUST read fees from this contract rather than hardcoding\n * them, or the signed `amount` won't match the gateway's expected total\n * and /v1/escrow/pay returns 400.\n *\n * Five operation kinds are wired up; each kind's name matches the\n * corresponding `payments.kind` column value on the gateway:\n *\n * - 'grant_registration' — one-time fee when a grant is first registered\n * (POST /v1/grants).\n * - 'data_access' — per-access surcharge on grant payments\n * (every accessRecord posted against a grant).\n * - 'data_registration' — one-time fee for registering a data point\n * (POST /v1/data → addDataWithSignature).\n * - 'server_registration' — one-time fee for registering a personal server\n * (POST /v1/servers).\n * - 'builder_registration' — one-time fee for registering a builder\n * (POST /v1/builders; gateway-only, no on-chain\n * submission).\n *\n * Disabled or unregistered fees skip enforcement: the corresponding\n * operation settles WITHOUT requiring a payment from escrow. `getFee`\n * surfaces this via `enabled: false` rather than throwing — the gateway\n * itself treats a disabled fee as a steady state, not a misconfig.\n *\n * Deployers can override the on-chain operation strings via\n * `FEE_REGISTRY_<KIND>_OP` env vars on the gateway side; the matching\n * SDK escape hatch is the `opts.<kind>OpName` arguments.\n *\n * This module is signer/transport-agnostic — callers pass in their own\n * `PublicClient` for the contract reads. No caching here; long-running\n * service consumers should wrap with their own TTL. Mirrors\n * data-gateway/lib/fee-registry.ts byte-for-byte.\n *\n * @category Protocol\n */\nimport { parseAbi, type Address, type Hex, type PublicClient } from \"viem\";\nimport type { DataPortabilityGatewayConfig } from \"./eip712\";\n\nexport const FEE_REGISTRY_ABI = parseAbi([\n \"struct Fee { uint256 amount; address asset; address payee; bool enabled; }\",\n \"function fees(bytes32 operation) view returns (Fee)\",\n \"function operationKey(string name) pure returns (bytes32)\",\n]);\n\nexport type FeeKind =\n | \"grant_registration\"\n | \"data_access\"\n | \"data_registration\"\n | \"server_registration\"\n | \"builder_registration\";\n\n/**\n * Map from a user-facing opType (POST /v1/escrow/pay body field, matches\n * the gateway's `payments.op_type` column) to the FeeKind that gates its\n * one-time registration fee.\n *\n * Data access is a per-call surcharge on grants only — it's not a\n * registration fee for any op, so it lives outside this map.\n */\nexport const REGISTRATION_KIND_FOR_OP: Record<string, FeeKind> = {\n grant: \"grant_registration\",\n data: \"data_registration\",\n server: \"server_registration\",\n builder: \"builder_registration\",\n};\n\nexport interface FeeEntry {\n amount: bigint;\n // Asset the fee is denominated in. 0x0000…0000 = native VANA; anything\n // else is an ERC-20 contract address.\n asset: Address;\n // The recipient the on-chain settle pass routes the fee to. Only\n // meaningful when `enabled` — disabled fees never land as a SettleOp `to`.\n payee: Address;\n enabled: boolean;\n}\n\n/**\n * Compound fee schedule for one op type, mirroring the gateway's\n * lib/op-fees.ts `OpFee`. For ANY op type, `registrationFee` is the\n * one-time fee charged at registration. For `'grant'` only, `dataAccessFee`\n * is the per-access surcharge — for any other op type it's always 0n with\n * `dataAccessEnabled: false`.\n *\n * `xxxEnabled` reflects the on-chain `Fee.enabled` flag. When OFF, the\n * corresponding amount is 0 and the pay handler should NOT require\n * payment for that kind. When both are off (for a grant) or registration\n * is off (for any other op type), the entire payment flow is skipped —\n * the op settles directly via the no-payment path.\n */\nexport interface OpFee {\n // Asset for whichever components are enabled. Falls back to native VANA\n // (0x0) when both components are disabled. The pay handler enforces that\n // the payer's `asset` matches.\n asset: Address;\n registrationFee: bigint;\n dataAccessFee: bigint;\n registrationEnabled: boolean;\n dataAccessEnabled: boolean;\n // Surfaced for the SDK's on-chain log-filter use case; the gateway's\n // OpFee type doesn't include these but the SDK keeps them since callers\n // sizing on-chain assertions need to know where the fee lands. Equal to\n // the zero address when the corresponding kind is disabled.\n registrationPayee: Address;\n dataAccessPayee: Address;\n}\n\nexport interface FeeRegistryOptions {\n grantRegistrationOpName?: string;\n dataAccessOpName?: string;\n dataRegistrationOpName?: string;\n serverRegistrationOpName?: string;\n builderRegistrationOpName?: string;\n}\n\nfunction operationNameFor(\n kind: FeeKind,\n opts: FeeRegistryOptions | undefined,\n): string {\n switch (kind) {\n case \"grant_registration\":\n return opts?.grantRegistrationOpName ?? \"grant_registration\";\n case \"data_access\":\n return opts?.dataAccessOpName ?? \"data_access\";\n case \"data_registration\":\n return opts?.dataRegistrationOpName ?? \"data_registration\";\n case \"server_registration\":\n return opts?.serverRegistrationOpName ?? \"server_registration\";\n case \"builder_registration\":\n return opts?.builderRegistrationOpName ?? \"builder_registration\";\n }\n}\n\nconst ZERO_ADDRESS = \"0x0000000000000000000000000000000000000000\" as Address;\n\n/**\n * Reads one fee kind from the FeeRegistry. Calls the contract's\n * `operationKey(name)` first to derive the bytes32 key — matches the\n * gateway's approach exactly (could compute locally via keccak256, but\n * going through the contract eliminates any chance of encoding drift).\n *\n * Returns `{enabled: false}` entries WITHOUT throwing — disabled is a\n * valid steady state on the gateway. The only validation is the\n * zero-payee check, and that only fires when the fee is enabled\n * (a disabled fee never lands as a SettleOp `to`).\n */\nexport async function getFee(\n client: PublicClient,\n config: DataPortabilityGatewayConfig,\n kind: FeeKind,\n opts?: FeeRegistryOptions,\n): Promise<FeeEntry> {\n const address = config.contracts.feeRegistry as Address;\n const opName = operationNameFor(kind, opts);\n\n const opKey = (await client.readContract({\n address,\n abi: FEE_REGISTRY_ABI,\n functionName: \"operationKey\",\n args: [opName],\n })) as Hex;\n\n const fee = (await client.readContract({\n address,\n abi: FEE_REGISTRY_ABI,\n functionName: \"fees\",\n args: [opKey],\n })) as FeeEntry;\n\n if (fee.enabled && fee.payee === ZERO_ADDRESS) {\n throw new Error(\n `FeeRegistry: enabled operation \"${opName}\" has zero-address payee — contract pre-flight rejects payouts to 0x0`,\n );\n }\n\n return fee;\n}\n\n/**\n * Convenience: combine the FeeRegistry reads for one op type into the\n * compound shape the pay handler validates against.\n *\n * For 'grant' opType the result includes both registration + data_access\n * components; for other op types data_access is always disabled with\n * amount=0. Disabled components contribute 0 to the signed total —\n * callers compute `amount = registrationFee + dataAccessFee` and the pay\n * handler accepts (or short-circuits with 'Payment not required' when\n * both are 0).\n *\n * Throws on asset mismatch ONLY when both components are enabled — a\n * disabled fee never lands as a SettleOp, so its asset is moot.\n */\nexport async function getOpFee(\n client: PublicClient,\n config: DataPortabilityGatewayConfig,\n opType: string,\n opts?: FeeRegistryOptions,\n): Promise<OpFee> {\n const registrationKind = REGISTRATION_KIND_FOR_OP[opType];\n if (!registrationKind) {\n throw new Error(\n `getOpFee: unknown opType \"${opType}\" — supported types are ${Object.keys(REGISTRATION_KIND_FOR_OP).join(\", \")}`,\n );\n }\n\n const includeDataAccess = opType === \"grant\";\n const [registration, dataAccess] = await Promise.all([\n getFee(client, config, registrationKind, opts),\n includeDataAccess\n ? getFee(client, config, \"data_access\", opts)\n : Promise.resolve<FeeEntry>({\n amount: 0n,\n asset: ZERO_ADDRESS,\n payee: ZERO_ADDRESS,\n enabled: false,\n }),\n ]);\n\n if (\n registration.enabled &&\n dataAccess.enabled &&\n registration.asset.toLowerCase() !== dataAccess.asset.toLowerCase()\n ) {\n throw new Error(\n `FeeRegistry asset mismatch for \"${opType}\": registration=${registration.asset} vs data_access=${dataAccess.asset}. The gateway requires both kinds to settle in the same asset when both are enabled.`,\n );\n }\n\n const asset = registration.enabled\n ? registration.asset\n : dataAccess.enabled\n ? dataAccess.asset\n : ZERO_ADDRESS;\n\n return {\n asset,\n registrationFee: registration.enabled ? registration.amount : 0n,\n dataAccessFee: dataAccess.enabled ? dataAccess.amount : 0n,\n registrationEnabled: registration.enabled,\n dataAccessEnabled: dataAccess.enabled,\n registrationPayee: registration.enabled ? registration.payee : ZERO_ADDRESS,\n dataAccessPayee: dataAccess.enabled ? dataAccess.payee : ZERO_ADDRESS,\n };\n}\n"],"mappings":"AAyCA,SAAS,gBAA2D;AAG7D,MAAM,mBAAmB,SAAS;AAAA,EACvC;AAAA,EACA;AAAA,EACA;AACF,CAAC;AAiBM,MAAM,2BAAoD;AAAA,EAC/D,OAAO;AAAA,EACP,MAAM;AAAA,EACN,QAAQ;AAAA,EACR,SAAS;AACX;AAmDA,SAAS,iBACP,MACA,MACQ;AACR,UAAQ,MAAM;AAAA,IACZ,KAAK;AACH,aAAO,MAAM,2BAA2B;AAAA,IAC1C,KAAK;AACH,aAAO,MAAM,oBAAoB;AAAA,IACnC,KAAK;AACH,aAAO,MAAM,0BAA0B;AAAA,IACzC,KAAK;AACH,aAAO,MAAM,4BAA4B;AAAA,IAC3C,KAAK;AACH,aAAO,MAAM,6BAA6B;AAAA,EAC9C;AACF;AAEA,MAAM,eAAe;AAarB,eAAsB,OACpB,QACA,QACA,MACA,MACmB;AACnB,QAAM,UAAU,OAAO,UAAU;AACjC,QAAM,SAAS,iBAAiB,MAAM,IAAI;AAE1C,QAAM,QAAS,MAAM,OAAO,aAAa;AAAA,IACvC;AAAA,IACA,KAAK;AAAA,IACL,cAAc;AAAA,IACd,MAAM,CAAC,MAAM;AAAA,EACf,CAAC;AAED,QAAM,MAAO,MAAM,OAAO,aAAa;AAAA,IACrC;AAAA,IACA,KAAK;AAAA,IACL,cAAc;AAAA,IACd,MAAM,CAAC,KAAK;AAAA,EACd,CAAC;AAED,MAAI,IAAI,WAAW,IAAI,UAAU,cAAc;AAC7C,UAAM,IAAI;AAAA,MACR,mCAAmC,MAAM;AAAA,IAC3C;AAAA,EACF;AAEA,SAAO;AACT;AAgBA,eAAsB,SACpB,QACA,QACA,QACA,MACgB;AAChB,QAAM,mBAAmB,yBAAyB,MAAM;AACxD,MAAI,CAAC,kBAAkB;AACrB,UAAM,IAAI;AAAA,MACR,6BAA6B,MAAM,gCAA2B,OAAO,KAAK,wBAAwB,EAAE,KAAK,IAAI,CAAC;AAAA,IAChH;AAAA,EACF;AAEA,QAAM,oBAAoB,WAAW;AACrC,QAAM,CAAC,cAAc,UAAU,IAAI,MAAM,QAAQ,IAAI;AAAA,IACnD,OAAO,QAAQ,QAAQ,kBAAkB,IAAI;AAAA,IAC7C,oBACI,OAAO,QAAQ,QAAQ,eAAe,IAAI,IAC1C,QAAQ,QAAkB;AAAA,MACxB,QAAQ;AAAA,MACR,OAAO;AAAA,MACP,OAAO;AAAA,MACP,SAAS;AAAA,IACX,CAAC;AAAA,EACP,CAAC;AAED,MACE,aAAa,WACb,WAAW,WACX,aAAa,MAAM,YAAY,MAAM,WAAW,MAAM,YAAY,GAClE;AACA,UAAM,IAAI;AAAA,MACR,mCAAmC,MAAM,mBAAmB,aAAa,KAAK,mBAAmB,WAAW,KAAK;AAAA,IACnH;AAAA,EACF;AAEA,QAAM,QAAQ,aAAa,UACvB,aAAa,QACb,WAAW,UACT,WAAW,QACX;AAEN,SAAO;AAAA,IACL;AAAA,IACA,iBAAiB,aAAa,UAAU,aAAa,SAAS;AAAA,IAC9D,eAAe,WAAW,UAAU,WAAW,SAAS;AAAA,IACxD,qBAAqB,aAAa;AAAA,IAClC,mBAAmB,WAAW;AAAA,IAC9B,mBAAmB,aAAa,UAAU,aAAa,QAAQ;AAAA,IAC/D,iBAAiB,WAAW,UAAU,WAAW,QAAQ;AAAA,EAC3D;AACF;","names":[]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -27,16 +27,6 @@ function createGatewayClient(baseUrl) {
|
|
|
27
27
|
const envelope = await res.json();
|
|
28
28
|
return envelope.data;
|
|
29
29
|
}
|
|
30
|
-
function normalizeFileRecord(record) {
|
|
31
|
-
return {
|
|
32
|
-
fileId: record.fileId ?? record.id ?? "",
|
|
33
|
-
owner: record.owner ?? record.ownerAddress ?? "",
|
|
34
|
-
url: record.url,
|
|
35
|
-
schemaId: record.schemaId,
|
|
36
|
-
createdAt: record.createdAt ?? record.addedAt ?? "",
|
|
37
|
-
deletedAt: record.deletedAt ?? null
|
|
38
|
-
};
|
|
39
|
-
}
|
|
40
30
|
function getMutationId(body, key) {
|
|
41
31
|
const value = body[key] ?? body["id"];
|
|
42
32
|
return typeof value === "string" ? value : void 0;
|
|
@@ -86,31 +76,33 @@ function createGatewayClient(baseUrl) {
|
|
|
86
76
|
}
|
|
87
77
|
return unwrapEnvelope(res);
|
|
88
78
|
},
|
|
89
|
-
async
|
|
90
|
-
const res = await fetch(`${base}/v1/
|
|
79
|
+
async getDataPoint(dataPointId) {
|
|
80
|
+
const res = await fetch(`${base}/v1/data/${dataPointId}`);
|
|
91
81
|
if (res.status === 404) return null;
|
|
92
82
|
if (!res.ok) {
|
|
93
83
|
throw new Error(`Gateway error: ${res.status} ${res.statusText}`);
|
|
94
84
|
}
|
|
95
|
-
return
|
|
85
|
+
return unwrapEnvelope(res);
|
|
96
86
|
},
|
|
97
|
-
async
|
|
87
|
+
async listDataPointsByOwner(owner, cursor, options) {
|
|
98
88
|
const params = new URLSearchParams({ user: owner });
|
|
99
89
|
if (cursor !== null) {
|
|
100
90
|
params.set("cursor", cursor);
|
|
101
91
|
}
|
|
102
|
-
if (options?.
|
|
103
|
-
params.set("
|
|
92
|
+
if (options?.since) {
|
|
93
|
+
params.set("since", options.since);
|
|
94
|
+
}
|
|
95
|
+
if (options?.limit !== void 0) {
|
|
96
|
+
params.set("limit", String(options.limit));
|
|
104
97
|
}
|
|
105
|
-
const res = await fetch(`${base}/v1/
|
|
98
|
+
const res = await fetch(`${base}/v1/data?${params.toString()}`);
|
|
106
99
|
if (!res.ok) {
|
|
107
100
|
throw new Error(`Gateway error: ${res.status} ${res.statusText}`);
|
|
108
101
|
}
|
|
109
102
|
const envelope = await res.json();
|
|
110
|
-
const
|
|
111
|
-
const nextCursor = pagination?.hasMore === false ? null : pagination?.nextCursor ?? envelope.data.cursor ?? null;
|
|
103
|
+
const nextCursor = envelope.pagination?.hasMore === false ? null : envelope.pagination?.nextCursor ?? null;
|
|
112
104
|
return {
|
|
113
|
-
|
|
105
|
+
dataPoints: envelope.data.dataPoints,
|
|
114
106
|
cursor: nextCursor
|
|
115
107
|
};
|
|
116
108
|
},
|
|
@@ -152,8 +144,8 @@ function createGatewayClient(baseUrl) {
|
|
|
152
144
|
alreadyRegistered: false
|
|
153
145
|
};
|
|
154
146
|
},
|
|
155
|
-
async
|
|
156
|
-
const res = await fetch(`${base}/v1/
|
|
147
|
+
async registerBuilder(params) {
|
|
148
|
+
const res = await fetch(`${base}/v1/builders`, {
|
|
157
149
|
method: "POST",
|
|
158
150
|
headers: {
|
|
159
151
|
"Content-Type": "application/json",
|
|
@@ -161,22 +153,57 @@ function createGatewayClient(baseUrl) {
|
|
|
161
153
|
},
|
|
162
154
|
body: JSON.stringify({
|
|
163
155
|
ownerAddress: params.ownerAddress,
|
|
164
|
-
|
|
165
|
-
|
|
156
|
+
granteeAddress: params.granteeAddress,
|
|
157
|
+
publicKey: params.publicKey,
|
|
158
|
+
appUrl: params.appUrl
|
|
166
159
|
})
|
|
167
160
|
});
|
|
168
161
|
if (res.status === 409) {
|
|
169
162
|
const body2 = await res.json().catch(() => ({}));
|
|
170
163
|
return {
|
|
171
|
-
|
|
164
|
+
builderId: getMutationId(
|
|
165
|
+
body2,
|
|
166
|
+
"builderId"
|
|
167
|
+
),
|
|
168
|
+
alreadyRegistered: true
|
|
172
169
|
};
|
|
173
170
|
}
|
|
174
171
|
if (!res.ok) {
|
|
175
172
|
throw new Error(`Gateway error: ${res.status} ${res.statusText}`);
|
|
176
173
|
}
|
|
177
|
-
const body = await res.json();
|
|
174
|
+
const body = await res.json().catch(() => ({}));
|
|
175
|
+
return {
|
|
176
|
+
builderId: getMutationId(body, "builderId"),
|
|
177
|
+
alreadyRegistered: false
|
|
178
|
+
};
|
|
179
|
+
},
|
|
180
|
+
async registerDataPoint(params) {
|
|
181
|
+
const res = await fetch(`${base}/v1/data`, {
|
|
182
|
+
method: "POST",
|
|
183
|
+
headers: {
|
|
184
|
+
"Content-Type": "application/json",
|
|
185
|
+
Authorization: `Web3Signed ${params.signature}`
|
|
186
|
+
},
|
|
187
|
+
body: JSON.stringify({
|
|
188
|
+
ownerAddress: params.ownerAddress,
|
|
189
|
+
scope: params.scope,
|
|
190
|
+
dataHash: params.dataHash,
|
|
191
|
+
metadataHash: params.metadataHash,
|
|
192
|
+
expectedVersion: params.expectedVersion
|
|
193
|
+
})
|
|
194
|
+
});
|
|
195
|
+
if (!res.ok) {
|
|
196
|
+
const body2 = await res.json().catch(() => ({}));
|
|
197
|
+
const detail = body2.error ?? res.statusText;
|
|
198
|
+
throw new Error(`Gateway error: ${res.status} ${detail}`);
|
|
199
|
+
}
|
|
200
|
+
const body = await res.json().catch(() => ({}));
|
|
178
201
|
return {
|
|
179
|
-
|
|
202
|
+
dataPointId: getMutationId(
|
|
203
|
+
body,
|
|
204
|
+
"dataPointId"
|
|
205
|
+
),
|
|
206
|
+
expectedVersion: body.expectedVersion
|
|
180
207
|
};
|
|
181
208
|
},
|
|
182
209
|
async createGrant(params) {
|
|
@@ -189,8 +216,9 @@ function createGatewayClient(baseUrl) {
|
|
|
189
216
|
body: JSON.stringify({
|
|
190
217
|
grantorAddress: params.grantorAddress,
|
|
191
218
|
granteeId: params.granteeId,
|
|
192
|
-
|
|
193
|
-
|
|
219
|
+
scopes: params.scopes,
|
|
220
|
+
grantVersion: params.grantVersion,
|
|
221
|
+
expiresAt: params.expiresAt
|
|
194
222
|
})
|
|
195
223
|
});
|
|
196
224
|
if (res.status === 409) {
|
|
@@ -215,7 +243,8 @@ function createGatewayClient(baseUrl) {
|
|
|
215
243
|
Authorization: `Web3Signed ${params.signature}`
|
|
216
244
|
},
|
|
217
245
|
body: JSON.stringify({
|
|
218
|
-
grantorAddress: params.grantorAddress
|
|
246
|
+
grantorAddress: params.grantorAddress,
|
|
247
|
+
grantVersion: params.grantVersion
|
|
219
248
|
})
|
|
220
249
|
});
|
|
221
250
|
if (res.status === 409) return;
|
|
@@ -223,21 +252,62 @@ function createGatewayClient(baseUrl) {
|
|
|
223
252
|
throw new Error(`Gateway error: ${res.status} ${res.statusText}`);
|
|
224
253
|
}
|
|
225
254
|
},
|
|
226
|
-
async
|
|
227
|
-
const res = await fetch(`${base}/v1/
|
|
228
|
-
|
|
255
|
+
async getEscrowBalance(account) {
|
|
256
|
+
const res = await fetch(`${base}/v1/escrow/balance?account=${account}`);
|
|
257
|
+
if (!res.ok) {
|
|
258
|
+
throw new Error(`Gateway error: ${res.status} ${res.statusText}`);
|
|
259
|
+
}
|
|
260
|
+
return await res.json();
|
|
261
|
+
},
|
|
262
|
+
async submitEscrowDeposit(params) {
|
|
263
|
+
const res = await fetch(`${base}/v1/escrow/deposit`, {
|
|
264
|
+
method: "POST",
|
|
265
|
+
headers: { "Content-Type": "application/json" },
|
|
266
|
+
body: JSON.stringify({ txHash: params.txHash })
|
|
267
|
+
});
|
|
268
|
+
if (res.status !== 200 && res.status !== 202) {
|
|
269
|
+
throw new Error(`Gateway error: ${res.status} ${res.statusText}`);
|
|
270
|
+
}
|
|
271
|
+
return await res.json();
|
|
272
|
+
},
|
|
273
|
+
async payForOperation(params) {
|
|
274
|
+
const body = {
|
|
275
|
+
payerAddress: params.payerAddress,
|
|
276
|
+
opType: params.opType,
|
|
277
|
+
opId: params.opId,
|
|
278
|
+
asset: params.asset,
|
|
279
|
+
amount: params.amount,
|
|
280
|
+
paymentNonce: params.paymentNonce
|
|
281
|
+
};
|
|
282
|
+
if (params.accessRecord) {
|
|
283
|
+
body["accessRecord"] = params.accessRecord;
|
|
284
|
+
}
|
|
285
|
+
const res = await fetch(`${base}/v1/escrow/pay`, {
|
|
286
|
+
method: "POST",
|
|
229
287
|
headers: {
|
|
230
288
|
"Content-Type": "application/json",
|
|
231
289
|
Authorization: `Web3Signed ${params.signature}`
|
|
232
290
|
},
|
|
233
|
-
body: JSON.stringify(
|
|
234
|
-
|
|
235
|
-
|
|
291
|
+
body: JSON.stringify(body)
|
|
292
|
+
});
|
|
293
|
+
if (!res.ok) {
|
|
294
|
+
throw new Error(`Gateway error: ${res.status} ${res.statusText}`);
|
|
295
|
+
}
|
|
296
|
+
return await res.json();
|
|
297
|
+
},
|
|
298
|
+
async settle(params) {
|
|
299
|
+
const res = await fetch(`${base}/v1/settle`, {
|
|
300
|
+
method: "POST",
|
|
301
|
+
headers: { "Content-Type": "application/json" },
|
|
302
|
+
// The gateway accepts an empty body; only `limit` is recognised.
|
|
303
|
+
// Always send a JSON body so the gateway's req.body shape parse
|
|
304
|
+
// doesn't have to deal with an undefined.
|
|
305
|
+
body: JSON.stringify(params ?? {})
|
|
236
306
|
});
|
|
237
|
-
if (res.status === 409) return;
|
|
238
307
|
if (!res.ok) {
|
|
239
308
|
throw new Error(`Gateway error: ${res.status} ${res.statusText}`);
|
|
240
309
|
}
|
|
310
|
+
return await res.json();
|
|
241
311
|
}
|
|
242
312
|
};
|
|
243
313
|
}
|