@opendatalabs/vana-sdk
Version:
A TypeScript library for interacting with Vana Network smart contracts.
123 lines • 3.82 kB
JavaScript
import { verifyTypedData } from "viem";
import {
GRANT_REGISTRATION_TYPES,
grantRegistrationDomain
} from "./eip712.js";
function isHexString(value) {
return typeof value === "string" && value.startsWith("0x");
}
function isDataPortabilityGatewayConfig(value) {
if (value === null || typeof value !== "object" || Array.isArray(value)) {
return false;
}
const config = value;
const contracts = config["contracts"];
if (typeof config["chainId"] !== "number" || !Number.isInteger(config["chainId"]) || config["chainId"] <= 0 || contracts === null || typeof contracts !== "object" || Array.isArray(contracts)) {
return false;
}
const c = contracts;
return isHexString(c["dataRegistry"]) && isHexString(c["dataPortabilityPermissions"]) && isHexString(c["dataPortabilityServer"]) && isHexString(c["dataPortabilityGrantees"]);
}
function parseGrantRegistrationPayload(grant) {
let parsed;
try {
parsed = JSON.parse(grant);
} catch {
return null;
}
if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
return null;
}
const value = parsed;
if (!Array.isArray(value["scopes"]) || value["scopes"].length === 0) {
return null;
}
if (!value["scopes"].every((scope) => typeof scope === "string")) {
return null;
}
if (typeof value["expiresAt"] !== "number" || !Number.isFinite(value["expiresAt"])) {
return null;
}
if (value["user"] !== void 0 && !isHexString(value["user"])) {
return null;
}
if (value["builder"] !== void 0 && !isHexString(value["builder"])) {
return null;
}
if (value["nonce"] !== void 0 && (typeof value["nonce"] !== "number" || !Number.isFinite(value["nonce"]))) {
return null;
}
return {
user: value["user"],
builder: value["builder"],
scopes: value["scopes"],
expiresAt: value["expiresAt"],
nonce: value["nonce"]
};
}
function parseFileIds(fileIds) {
try {
const values = (fileIds ?? []).map((fileId) => BigInt(fileId));
return {
values,
display: values.map((fileId) => fileId.toString())
};
} catch {
return null;
}
}
async function verifyGrantRegistration(input) {
const payload = parseGrantRegistrationPayload(input.grant);
if (!payload) {
return {
valid: false,
error: "Grant must be JSON with scopes and expiresAt"
};
}
const fileIds = parseFileIds(input.fileIds);
if (!fileIds) {
return { valid: false, error: "fileIds must contain integer values" };
}
let valid;
try {
valid = await verifyTypedData({
address: input.grantorAddress,
domain: grantRegistrationDomain(input.gatewayConfig),
types: GRANT_REGISTRATION_TYPES,
primaryType: "GrantRegistration",
message: {
grantorAddress: input.grantorAddress,
granteeId: input.granteeId,
grant: input.grant,
fileIds: fileIds.values
},
signature: input.signature
});
} catch {
return { valid: false, error: "EIP-712 signature verification failed" };
}
if (!valid) {
return { valid: false, error: "Grant signature does not match grantor" };
}
const nowSeconds = input.nowSeconds ?? Math.floor(Date.now() / 1e3);
if (payload.expiresAt > 0 && payload.expiresAt < nowSeconds) {
return { valid: false, error: "Grant has expired" };
}
if (payload.user !== void 0 && payload.user.toLowerCase() !== input.grantorAddress.toLowerCase()) {
return { valid: false, error: "Grant user does not match grantorAddress" };
}
return {
valid: true,
grantorAddress: input.grantorAddress,
granteeId: input.granteeId,
grant: input.grant,
payload,
fileIds: fileIds.display
};
}
export {
isDataPortabilityGatewayConfig,
parseGrantRegistrationPayload,
verifyGrantRegistration
};
//# sourceMappingURL=grants.js.map