@wiimdy/openfunderse-sdk 0.1.1
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 +43 -0
- package/dist/attestation-verifier.d.ts +11 -0
- package/dist/attestation-verifier.js +60 -0
- package/dist/attestation.d.ts +4 -0
- package/dist/attestation.js +16 -0
- package/dist/canonical.d.ts +3 -0
- package/dist/canonical.js +37 -0
- package/dist/dist_bak_vercel_repro/attestation-verifier.d.ts +11 -0
- package/dist/dist_bak_vercel_repro/attestation-verifier.js +60 -0
- package/dist/dist_bak_vercel_repro/attestation.d.ts +4 -0
- package/dist/dist_bak_vercel_repro/attestation.js +16 -0
- package/dist/dist_bak_vercel_repro/canonical.d.ts +3 -0
- package/dist/dist_bak_vercel_repro/canonical.js +37 -0
- package/dist/dist_bak_vercel_repro/eip712.d.ts +112 -0
- package/dist/dist_bak_vercel_repro/eip712.js +74 -0
- package/dist/dist_bak_vercel_repro/erc1271.d.ts +4 -0
- package/dist/dist_bak_vercel_repro/erc1271.js +24 -0
- package/dist/dist_bak_vercel_repro/execution-data.d.ts +3 -0
- package/dist/dist_bak_vercel_repro/execution-data.js +66 -0
- package/dist/dist_bak_vercel_repro/hash.d.ts +16 -0
- package/dist/dist_bak_vercel_repro/hash.js +67 -0
- package/dist/dist_bak_vercel_repro/index.d.ts +14 -0
- package/dist/dist_bak_vercel_repro/index.js +14 -0
- package/dist/dist_bak_vercel_repro/nadfun-types.d.ts +29 -0
- package/dist/dist_bak_vercel_repro/nadfun-types.js +1 -0
- package/dist/dist_bak_vercel_repro/ordering.d.ts +5 -0
- package/dist/dist_bak_vercel_repro/ordering.js +22 -0
- package/dist/dist_bak_vercel_repro/relayer-utils.d.ts +29 -0
- package/dist/dist_bak_vercel_repro/relayer-utils.js +108 -0
- package/dist/dist_bak_vercel_repro/scope.d.ts +5 -0
- package/dist/dist_bak_vercel_repro/scope.js +26 -0
- package/dist/dist_bak_vercel_repro/types.d.ts +106 -0
- package/dist/dist_bak_vercel_repro/types.js +1 -0
- package/dist/dist_bak_vercel_repro/validate.d.ts +2 -0
- package/dist/dist_bak_vercel_repro/validate.js +12 -0
- package/dist/dist_bak_vercel_repro/weighted-attestation.d.ts +19 -0
- package/dist/dist_bak_vercel_repro/weighted-attestation.js +62 -0
- package/dist/eip712.d.ts +112 -0
- package/dist/eip712.js +74 -0
- package/dist/erc1271.d.ts +4 -0
- package/dist/erc1271.js +24 -0
- package/dist/execution-data.d.ts +3 -0
- package/dist/execution-data.js +66 -0
- package/dist/hash.d.ts +16 -0
- package/dist/hash.js +67 -0
- package/dist/index.d.ts +14 -0
- package/dist/index.js +14 -0
- package/dist/nadfun-types.d.ts +29 -0
- package/dist/nadfun-types.js +1 -0
- package/dist/ordering.d.ts +5 -0
- package/dist/ordering.js +22 -0
- package/dist/relayer-utils.d.ts +29 -0
- package/dist/relayer-utils.js +108 -0
- package/dist/scope.d.ts +5 -0
- package/dist/scope.js +26 -0
- package/dist/types.d.ts +106 -0
- package/dist/types.js +1 -0
- package/dist/validate.d.ts +2 -0
- package/dist/validate.js +12 -0
- package/dist/weighted-attestation.d.ts +19 -0
- package/dist/weighted-attestation.js +62 -0
- package/package.json +32 -0
package/dist/eip712.js
ADDED
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { hashTypedData, recoverTypedDataAddress, verifyTypedData } from "viem";
|
|
2
|
+
export const CLAIM_ATTESTATION_TYPES = {
|
|
3
|
+
ClaimAttestation: [
|
|
4
|
+
{ name: "claimHash", type: "bytes32" },
|
|
5
|
+
{ name: "epochId", type: "uint64" },
|
|
6
|
+
{ name: "verifier", type: "address" },
|
|
7
|
+
{ name: "expiresAt", type: "uint64" },
|
|
8
|
+
{ name: "nonce", type: "uint256" }
|
|
9
|
+
]
|
|
10
|
+
};
|
|
11
|
+
export const INTENT_ATTESTATION_TYPES = {
|
|
12
|
+
IntentAttestation: [
|
|
13
|
+
{ name: "intentHash", type: "bytes32" },
|
|
14
|
+
{ name: "verifier", type: "address" },
|
|
15
|
+
{ name: "expiresAt", type: "uint64" },
|
|
16
|
+
{ name: "nonce", type: "uint256" }
|
|
17
|
+
]
|
|
18
|
+
};
|
|
19
|
+
export function toEip712Domain(input) {
|
|
20
|
+
return {
|
|
21
|
+
name: input.name,
|
|
22
|
+
version: input.version,
|
|
23
|
+
chainId: input.chainId,
|
|
24
|
+
verifyingContract: input.verifyingContract
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
export function claimAttestationTypedData(domain, message) {
|
|
28
|
+
return {
|
|
29
|
+
domain: toEip712Domain(domain),
|
|
30
|
+
types: CLAIM_ATTESTATION_TYPES,
|
|
31
|
+
primaryType: "ClaimAttestation",
|
|
32
|
+
message
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
export function intentAttestationTypedData(domain, message) {
|
|
36
|
+
return {
|
|
37
|
+
domain: toEip712Domain(domain),
|
|
38
|
+
types: INTENT_ATTESTATION_TYPES,
|
|
39
|
+
primaryType: "IntentAttestation",
|
|
40
|
+
message
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
export function claimAttestationDigest(domain, message) {
|
|
44
|
+
return hashTypedData(claimAttestationTypedData(domain, message));
|
|
45
|
+
}
|
|
46
|
+
export function intentAttestationDigest(domain, message) {
|
|
47
|
+
return hashTypedData(intentAttestationTypedData(domain, message));
|
|
48
|
+
}
|
|
49
|
+
export async function verifyClaimAttestation(domain, message, signature) {
|
|
50
|
+
return verifyTypedData({
|
|
51
|
+
...claimAttestationTypedData(domain, message),
|
|
52
|
+
address: message.verifier,
|
|
53
|
+
signature
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
export async function verifyIntentAttestation(domain, message, signature) {
|
|
57
|
+
return verifyTypedData({
|
|
58
|
+
...intentAttestationTypedData(domain, message),
|
|
59
|
+
address: message.verifier,
|
|
60
|
+
signature
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
export async function recoverClaimAttester(domain, message, signature) {
|
|
64
|
+
return recoverTypedDataAddress({
|
|
65
|
+
...claimAttestationTypedData(domain, message),
|
|
66
|
+
signature
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
export async function recoverIntentAttester(domain, message, signature) {
|
|
70
|
+
return recoverTypedDataAddress({
|
|
71
|
+
...intentAttestationTypedData(domain, message),
|
|
72
|
+
signature
|
|
73
|
+
});
|
|
74
|
+
}
|
package/dist/erc1271.js
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { encodeFunctionData } from "viem";
|
|
2
|
+
export const ERC1271_MAGIC_VALUE = "0x1626ba7e";
|
|
3
|
+
const ERC1271_ABI = [
|
|
4
|
+
{
|
|
5
|
+
type: "function",
|
|
6
|
+
name: "isValidSignature",
|
|
7
|
+
stateMutability: "view",
|
|
8
|
+
inputs: [
|
|
9
|
+
{ name: "hash", type: "bytes32" },
|
|
10
|
+
{ name: "signature", type: "bytes" }
|
|
11
|
+
],
|
|
12
|
+
outputs: [{ name: "magicValue", type: "bytes4" }]
|
|
13
|
+
}
|
|
14
|
+
];
|
|
15
|
+
export function encodeErc1271IsValidSignatureCall(hash, signature) {
|
|
16
|
+
return encodeFunctionData({
|
|
17
|
+
abi: ERC1271_ABI,
|
|
18
|
+
functionName: "isValidSignature",
|
|
19
|
+
args: [hash, signature]
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
export function isValidErc1271Result(result) {
|
|
23
|
+
return result.slice(0, 10).toLowerCase() === ERC1271_MAGIC_VALUE;
|
|
24
|
+
}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { decodeAbiParameters, encodeAbiParameters, parseAbiParameters } from "viem";
|
|
2
|
+
import { assertUint64 } from "./validate.js";
|
|
3
|
+
const NADFUN_V1_ABI = parseAbiParameters("uint8 version,uint8 action,uint8 venue,address router,address recipient,address token,uint64 deadline,uint256 amountOutMin,bytes extra");
|
|
4
|
+
const ACTION_TO_ID = {
|
|
5
|
+
BUY: 1,
|
|
6
|
+
SELL: 2
|
|
7
|
+
};
|
|
8
|
+
const VENUE_TO_ID = {
|
|
9
|
+
NADFUN_BONDING_CURVE: 1,
|
|
10
|
+
NADFUN_DEX: 2
|
|
11
|
+
};
|
|
12
|
+
const ID_TO_ACTION = {
|
|
13
|
+
1: "BUY",
|
|
14
|
+
2: "SELL"
|
|
15
|
+
};
|
|
16
|
+
const ID_TO_VENUE = {
|
|
17
|
+
1: "NADFUN_BONDING_CURVE",
|
|
18
|
+
2: "NADFUN_DEX"
|
|
19
|
+
};
|
|
20
|
+
function assertVersion(version) {
|
|
21
|
+
if (version !== 1) {
|
|
22
|
+
throw new Error(`unsupported execution-data version: ${version}`);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
function assertKnownAction(actionId) {
|
|
26
|
+
const action = ID_TO_ACTION[actionId];
|
|
27
|
+
if (!action)
|
|
28
|
+
throw new Error(`unsupported action id: ${actionId}`);
|
|
29
|
+
return action;
|
|
30
|
+
}
|
|
31
|
+
function assertKnownVenue(venueId) {
|
|
32
|
+
const venue = ID_TO_VENUE[venueId];
|
|
33
|
+
if (!venue)
|
|
34
|
+
throw new Error(`unsupported venue id: ${venueId}`);
|
|
35
|
+
return venue;
|
|
36
|
+
}
|
|
37
|
+
export function encodeNadfunExecutionDataV1(data) {
|
|
38
|
+
assertUint64(data.deadline, "deadline");
|
|
39
|
+
return encodeAbiParameters(NADFUN_V1_ABI, [
|
|
40
|
+
data.version,
|
|
41
|
+
ACTION_TO_ID[data.action],
|
|
42
|
+
VENUE_TO_ID[data.venue],
|
|
43
|
+
data.router,
|
|
44
|
+
data.recipient,
|
|
45
|
+
data.token,
|
|
46
|
+
data.deadline,
|
|
47
|
+
data.amountOutMin,
|
|
48
|
+
data.extra
|
|
49
|
+
]);
|
|
50
|
+
}
|
|
51
|
+
export function decodeNadfunExecutionDataV1(raw) {
|
|
52
|
+
const [version, actionId, venueId, router, recipient, token, deadline, amountOutMin, extra] = decodeAbiParameters(NADFUN_V1_ABI, raw);
|
|
53
|
+
const v = Number(version);
|
|
54
|
+
assertVersion(v);
|
|
55
|
+
return {
|
|
56
|
+
version: 1,
|
|
57
|
+
action: assertKnownAction(Number(actionId)),
|
|
58
|
+
venue: assertKnownVenue(Number(venueId)),
|
|
59
|
+
router,
|
|
60
|
+
recipient,
|
|
61
|
+
token,
|
|
62
|
+
deadline,
|
|
63
|
+
amountOutMin,
|
|
64
|
+
extra
|
|
65
|
+
};
|
|
66
|
+
}
|
package/dist/hash.d.ts
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { Address, ClaimPayload, Hex, TradeIntent } from "./types.js";
|
|
2
|
+
export declare function claimHash(payload: ClaimPayload): Hex;
|
|
3
|
+
export declare function intentHash(intent: TradeIntent): Hex;
|
|
4
|
+
export declare function snapshotHash(epochId: bigint, orderedClaimHashes: Hex[]): Hex;
|
|
5
|
+
export declare function canonicalOrderedClaimHashes(claimHashes: Hex[]): Hex[];
|
|
6
|
+
export declare function snapshotHashFromUnordered(epochId: bigint, claimHashes: Hex[]): Hex;
|
|
7
|
+
export declare function reasonHash(reason: string): Hex;
|
|
8
|
+
/**
|
|
9
|
+
* Canonical allowlist hash for intent execution route.
|
|
10
|
+
* Must match ClawCore allowlist verification logic.
|
|
11
|
+
*/
|
|
12
|
+
export declare function intentExecutionAllowlistHash(tokenIn: Address, tokenOut: Address, quoteAmountOut: bigint, minAmountOut: bigint, adapter: Address, adapterDataHash: Hex): Hex;
|
|
13
|
+
/**
|
|
14
|
+
* Helper that hashes raw adapter calldata before building the allowlist hash.
|
|
15
|
+
*/
|
|
16
|
+
export declare function intentExecutionCallHash(tokenIn: Address, tokenOut: Address, quoteAmountOut: bigint, minAmountOut: bigint, adapter: Address, adapterData: Hex): Hex;
|
package/dist/hash.js
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { encodeAbiParameters, keccak256, parseAbiParameters, toHex } from "viem";
|
|
2
|
+
import { canonicalClaim, canonicalIntent } from "./canonical.js";
|
|
3
|
+
import { assertStrictlySortedHex, uniqueSortedBytes32Hex } from "./ordering.js";
|
|
4
|
+
import { assertUint16, assertUint64 } from "./validate.js";
|
|
5
|
+
export function claimHash(payload) {
|
|
6
|
+
const v = canonicalClaim(payload);
|
|
7
|
+
assertUint64(v.timestamp, "timestamp");
|
|
8
|
+
return keccak256(encodeAbiParameters(parseAbiParameters("string schemaId,string sourceType,string sourceRef,string selector,string extracted,string extractedType,uint64 timestamp,bytes32 responseHash,string evidenceType,string evidenceURI,address crawler,string notes"), [
|
|
9
|
+
v.schemaId,
|
|
10
|
+
v.sourceType,
|
|
11
|
+
v.sourceRef,
|
|
12
|
+
v.selector,
|
|
13
|
+
v.extracted,
|
|
14
|
+
v.extractedType,
|
|
15
|
+
v.timestamp,
|
|
16
|
+
v.responseHash,
|
|
17
|
+
v.evidenceType,
|
|
18
|
+
v.evidenceURI,
|
|
19
|
+
v.crawler,
|
|
20
|
+
v.notes ?? ""
|
|
21
|
+
]));
|
|
22
|
+
}
|
|
23
|
+
export function intentHash(intent) {
|
|
24
|
+
const v = canonicalIntent(intent);
|
|
25
|
+
assertUint64(v.deadline, "deadline");
|
|
26
|
+
assertUint16(v.maxSlippageBps, "maxSlippageBps");
|
|
27
|
+
return keccak256(encodeAbiParameters(parseAbiParameters("string intentVersion,address vault,string action,address tokenIn,address tokenOut,uint256 amountIn,uint256 minAmountOut,uint64 deadline,uint16 maxSlippageBps,bytes32 snapshotHash"), [
|
|
28
|
+
v.intentVersion,
|
|
29
|
+
v.vault,
|
|
30
|
+
v.action,
|
|
31
|
+
v.tokenIn,
|
|
32
|
+
v.tokenOut,
|
|
33
|
+
v.amountIn,
|
|
34
|
+
v.minAmountOut,
|
|
35
|
+
v.deadline,
|
|
36
|
+
Number(v.maxSlippageBps),
|
|
37
|
+
v.snapshotHash
|
|
38
|
+
]));
|
|
39
|
+
}
|
|
40
|
+
export function snapshotHash(epochId, orderedClaimHashes) {
|
|
41
|
+
assertUint64(epochId, "epochId");
|
|
42
|
+
assertStrictlySortedHex(orderedClaimHashes);
|
|
43
|
+
return keccak256(encodeAbiParameters(parseAbiParameters("uint64 epochId,bytes32[] orderedClaimHashes"), [epochId, orderedClaimHashes]));
|
|
44
|
+
}
|
|
45
|
+
export function canonicalOrderedClaimHashes(claimHashes) {
|
|
46
|
+
return uniqueSortedBytes32Hex(claimHashes);
|
|
47
|
+
}
|
|
48
|
+
export function snapshotHashFromUnordered(epochId, claimHashes) {
|
|
49
|
+
const orderedClaimHashes = canonicalOrderedClaimHashes(claimHashes);
|
|
50
|
+
return snapshotHash(epochId, orderedClaimHashes);
|
|
51
|
+
}
|
|
52
|
+
export function reasonHash(reason) {
|
|
53
|
+
return keccak256(toHex(reason.normalize("NFC").trim()));
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Canonical allowlist hash for intent execution route.
|
|
57
|
+
* Must match ClawCore allowlist verification logic.
|
|
58
|
+
*/
|
|
59
|
+
export function intentExecutionAllowlistHash(tokenIn, tokenOut, quoteAmountOut, minAmountOut, adapter, adapterDataHash) {
|
|
60
|
+
return keccak256(encodeAbiParameters(parseAbiParameters("address tokenIn,address tokenOut,uint256 quoteAmountOut,uint256 minAmountOut,address adapter,bytes32 adapterDataHash"), [tokenIn, tokenOut, quoteAmountOut, minAmountOut, adapter, adapterDataHash]));
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Helper that hashes raw adapter calldata before building the allowlist hash.
|
|
64
|
+
*/
|
|
65
|
+
export function intentExecutionCallHash(tokenIn, tokenOut, quoteAmountOut, minAmountOut, adapter, adapterData) {
|
|
66
|
+
return intentExecutionAllowlistHash(tokenIn, tokenOut, quoteAmountOut, minAmountOut, adapter, keccak256(adapterData));
|
|
67
|
+
}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export * from "./types.js";
|
|
2
|
+
export * from "./nadfun-types.js";
|
|
3
|
+
export * from "./canonical.js";
|
|
4
|
+
export * from "./hash.js";
|
|
5
|
+
export * from "./eip712.js";
|
|
6
|
+
export * from "./erc1271.js";
|
|
7
|
+
export * from "./ordering.js";
|
|
8
|
+
export * from "./scope.js";
|
|
9
|
+
export * from "./attestation.js";
|
|
10
|
+
export * from "./validate.js";
|
|
11
|
+
export * from "./attestation-verifier.js";
|
|
12
|
+
export * from "./weighted-attestation.js";
|
|
13
|
+
export * from "./execution-data.js";
|
|
14
|
+
export * from "./relayer-utils.js";
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export * from "./types.js";
|
|
2
|
+
export * from "./nadfun-types.js";
|
|
3
|
+
export * from "./canonical.js";
|
|
4
|
+
export * from "./hash.js";
|
|
5
|
+
export * from "./eip712.js";
|
|
6
|
+
export * from "./erc1271.js";
|
|
7
|
+
export * from "./ordering.js";
|
|
8
|
+
export * from "./scope.js";
|
|
9
|
+
export * from "./attestation.js";
|
|
10
|
+
export * from "./validate.js";
|
|
11
|
+
export * from "./attestation-verifier.js";
|
|
12
|
+
export * from "./weighted-attestation.js";
|
|
13
|
+
export * from "./execution-data.js";
|
|
14
|
+
export * from "./relayer-utils.js";
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { Address, TradeIntent } from "./types.js";
|
|
2
|
+
/**
|
|
3
|
+
* NadFun-specific metadata for offchain intent context.
|
|
4
|
+
* These fields are NOT included in intentHash computation.
|
|
5
|
+
* They provide additional context for strategy/verifier agents.
|
|
6
|
+
*/
|
|
7
|
+
export interface NadFunIntentMeta {
|
|
8
|
+
/** Token symbol (e.g., "ABC") */
|
|
9
|
+
tokenSymbol: string;
|
|
10
|
+
/** Bonding curve state: BONDING (pre-graduation) or GRADUATED (post-graduation) */
|
|
11
|
+
curveState: "BONDING" | "GRADUATED";
|
|
12
|
+
/** Bonding curve contract address (valid when curveState === "BONDING") */
|
|
13
|
+
curveAddress: Address;
|
|
14
|
+
/** DEX pool address (valid when curveState === "GRADUATED") */
|
|
15
|
+
dexPoolAddress: Address;
|
|
16
|
+
/** NadFun platform token ID */
|
|
17
|
+
nadfunTokenId: string;
|
|
18
|
+
/** Graduation progress in basis points (0-10000) */
|
|
19
|
+
graduationProgress: bigint;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Extended trade intent combining canonical TradeIntent with NadFun metadata.
|
|
23
|
+
* The intentHash is computed only from TradeIntent fields.
|
|
24
|
+
* Metadata fields are for offchain context and agent decision-making.
|
|
25
|
+
*/
|
|
26
|
+
export interface NadFunTradeIntent extends TradeIntent {
|
|
27
|
+
/** NadFun-specific metadata (not included in hash) */
|
|
28
|
+
nadfunMeta: NadFunIntentMeta;
|
|
29
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { Hex } from "./types.js";
|
|
2
|
+
export declare function sortBytes32Hex(values: Hex[]): Hex[];
|
|
3
|
+
export declare function uniqueSortedBytes32Hex(values: Hex[]): Hex[];
|
|
4
|
+
export declare function isStrictlySortedHex(values: Hex[]): boolean;
|
|
5
|
+
export declare function assertStrictlySortedHex(values: Hex[], label?: string): void;
|
package/dist/ordering.js
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
function normalizeHex(value) {
|
|
2
|
+
return value.toLowerCase();
|
|
3
|
+
}
|
|
4
|
+
export function sortBytes32Hex(values) {
|
|
5
|
+
return [...values].map(normalizeHex).sort((a, b) => (a < b ? -1 : a > b ? 1 : 0));
|
|
6
|
+
}
|
|
7
|
+
export function uniqueSortedBytes32Hex(values) {
|
|
8
|
+
return [...new Set(sortBytes32Hex(values))];
|
|
9
|
+
}
|
|
10
|
+
export function isStrictlySortedHex(values) {
|
|
11
|
+
for (let i = 1; i < values.length; i += 1) {
|
|
12
|
+
if (values[i - 1].toLowerCase() >= values[i].toLowerCase()) {
|
|
13
|
+
return false;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
return true;
|
|
17
|
+
}
|
|
18
|
+
export function assertStrictlySortedHex(values, label = "orderedClaimHashes") {
|
|
19
|
+
if (!isStrictlySortedHex(values)) {
|
|
20
|
+
throw new Error(`${label} must be strictly sorted ascending with no duplicates`);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { CanonicalClaimRecord, CanonicalIntentRecord, ClaimPayload, CoreExecutionRequestInput, Hex, IntentExecutionRouteInput, IntentConstraints, TradeIntent } from "./types.js";
|
|
2
|
+
export declare function buildCanonicalClaimRecord(input: {
|
|
3
|
+
payload: ClaimPayload;
|
|
4
|
+
epochId: bigint;
|
|
5
|
+
}): CanonicalClaimRecord;
|
|
6
|
+
export declare function buildIntentConstraints(input: {
|
|
7
|
+
allowlistHash: Hex;
|
|
8
|
+
maxSlippageBps: bigint;
|
|
9
|
+
maxNotional: bigint;
|
|
10
|
+
deadline: bigint;
|
|
11
|
+
}): IntentConstraints;
|
|
12
|
+
export declare function buildCanonicalIntentRecord(input: {
|
|
13
|
+
intent: TradeIntent;
|
|
14
|
+
allowlistHash: Hex;
|
|
15
|
+
maxNotional: bigint;
|
|
16
|
+
now?: bigint;
|
|
17
|
+
}): CanonicalIntentRecord;
|
|
18
|
+
export declare function buildCanonicalSnapshotRecord(input: {
|
|
19
|
+
epochId: bigint;
|
|
20
|
+
claimHashes: Hex[];
|
|
21
|
+
}): {
|
|
22
|
+
epochId: bigint;
|
|
23
|
+
snapshotHash: `0x${string}`;
|
|
24
|
+
};
|
|
25
|
+
export declare function buildIntentAllowlistHashFromRoute(route: IntentExecutionRouteInput): Hex;
|
|
26
|
+
export declare function buildCoreExecutionRequestFromIntent(input: {
|
|
27
|
+
intent: TradeIntent;
|
|
28
|
+
executionRoute: IntentExecutionRouteInput;
|
|
29
|
+
}): CoreExecutionRequestInput;
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import { keccak256 } from "viem";
|
|
2
|
+
import { canonicalClaim, canonicalIntent } from "./canonical.js";
|
|
3
|
+
import { claimHash, intentExecutionAllowlistHash, intentHash, snapshotHashFromUnordered } from "./hash.js";
|
|
4
|
+
import { assertUint16, assertUint64 } from "./validate.js";
|
|
5
|
+
function assertPositive(value, label) {
|
|
6
|
+
if (value <= 0n) {
|
|
7
|
+
throw new Error(`${label} must be positive`);
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
function assertHex32(value, label) {
|
|
11
|
+
if (!/^0x[0-9a-fA-F]{64}$/.test(value)) {
|
|
12
|
+
throw new Error(`${label} must be 0x-prefixed 32-byte hex`);
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
export function buildCanonicalClaimRecord(input) {
|
|
16
|
+
assertUint64(input.epochId, "epochId");
|
|
17
|
+
assertUint64(input.payload.timestamp, "timestamp");
|
|
18
|
+
const payload = canonicalClaim(input.payload);
|
|
19
|
+
const hash = claimHash(payload);
|
|
20
|
+
return {
|
|
21
|
+
payload,
|
|
22
|
+
epochId: input.epochId,
|
|
23
|
+
claimHash: hash
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
export function buildIntentConstraints(input) {
|
|
27
|
+
assertHex32(input.allowlistHash, "allowlistHash");
|
|
28
|
+
assertUint16(input.maxSlippageBps, "maxSlippageBps");
|
|
29
|
+
assertUint64(input.deadline, "deadline");
|
|
30
|
+
assertPositive(input.maxNotional, "maxNotional");
|
|
31
|
+
return {
|
|
32
|
+
allowlistHash: input.allowlistHash,
|
|
33
|
+
maxSlippageBps: input.maxSlippageBps,
|
|
34
|
+
maxNotional: input.maxNotional,
|
|
35
|
+
deadline: input.deadline
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
export function buildCanonicalIntentRecord(input) {
|
|
39
|
+
const intent = canonicalIntent(input.intent);
|
|
40
|
+
assertUint64(intent.deadline, "deadline");
|
|
41
|
+
assertUint16(intent.maxSlippageBps, "maxSlippageBps");
|
|
42
|
+
assertPositive(intent.amountIn, "amountIn");
|
|
43
|
+
assertPositive(intent.minAmountOut, "minAmountOut");
|
|
44
|
+
if (intent.deadline <= (input.now ?? BigInt(Math.floor(Date.now() / 1000)))) {
|
|
45
|
+
throw new Error("intent deadline is expired");
|
|
46
|
+
}
|
|
47
|
+
const constraints = buildIntentConstraints({
|
|
48
|
+
allowlistHash: input.allowlistHash,
|
|
49
|
+
maxSlippageBps: intent.maxSlippageBps,
|
|
50
|
+
maxNotional: input.maxNotional,
|
|
51
|
+
deadline: intent.deadline
|
|
52
|
+
});
|
|
53
|
+
return {
|
|
54
|
+
intent,
|
|
55
|
+
intentHash: intentHash(intent),
|
|
56
|
+
constraints
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
export function buildCanonicalSnapshotRecord(input) {
|
|
60
|
+
assertUint64(input.epochId, "epochId");
|
|
61
|
+
if (input.claimHashes.length === 0) {
|
|
62
|
+
throw new Error("claimHashes must not be empty");
|
|
63
|
+
}
|
|
64
|
+
const hash = snapshotHashFromUnordered(input.epochId, input.claimHashes);
|
|
65
|
+
return {
|
|
66
|
+
epochId: input.epochId,
|
|
67
|
+
snapshotHash: hash
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
export function buildIntentAllowlistHashFromRoute(route) {
|
|
71
|
+
assertPositive(route.quoteAmountOut, "quoteAmountOut");
|
|
72
|
+
assertPositive(route.minAmountOut, "minAmountOut");
|
|
73
|
+
const adapterDataHash = route.adapterDataHash ??
|
|
74
|
+
(route.adapterData ? keccak256(route.adapterData) : undefined);
|
|
75
|
+
if (!adapterDataHash) {
|
|
76
|
+
throw new Error("adapterData or adapterDataHash is required");
|
|
77
|
+
}
|
|
78
|
+
assertHex32(adapterDataHash, "adapterDataHash");
|
|
79
|
+
return intentExecutionAllowlistHash(route.tokenIn, route.tokenOut, route.quoteAmountOut, route.minAmountOut, route.adapter, adapterDataHash);
|
|
80
|
+
}
|
|
81
|
+
export function buildCoreExecutionRequestFromIntent(input) {
|
|
82
|
+
const { intent, executionRoute } = input;
|
|
83
|
+
assertPositive(intent.amountIn, "amountIn");
|
|
84
|
+
assertPositive(intent.minAmountOut, "minAmountOut");
|
|
85
|
+
assertPositive(executionRoute.quoteAmountOut, "quoteAmountOut");
|
|
86
|
+
assertPositive(executionRoute.minAmountOut, "route.minAmountOut");
|
|
87
|
+
if (executionRoute.tokenIn.toLowerCase() !== intent.tokenIn.toLowerCase()) {
|
|
88
|
+
throw new Error("executionRoute.tokenIn must match intent.tokenIn");
|
|
89
|
+
}
|
|
90
|
+
if (executionRoute.tokenOut.toLowerCase() !== intent.tokenOut.toLowerCase()) {
|
|
91
|
+
throw new Error("executionRoute.tokenOut must match intent.tokenOut");
|
|
92
|
+
}
|
|
93
|
+
if (executionRoute.minAmountOut !== intent.minAmountOut) {
|
|
94
|
+
throw new Error("executionRoute.minAmountOut must match intent.minAmountOut");
|
|
95
|
+
}
|
|
96
|
+
if (!executionRoute.adapterData) {
|
|
97
|
+
throw new Error("executionRoute.adapterData is required for execution");
|
|
98
|
+
}
|
|
99
|
+
return {
|
|
100
|
+
tokenIn: executionRoute.tokenIn,
|
|
101
|
+
tokenOut: executionRoute.tokenOut,
|
|
102
|
+
amountIn: intent.amountIn,
|
|
103
|
+
quoteAmountOut: executionRoute.quoteAmountOut,
|
|
104
|
+
minAmountOut: executionRoute.minAmountOut,
|
|
105
|
+
adapter: executionRoute.adapter,
|
|
106
|
+
adapterData: executionRoute.adapterData
|
|
107
|
+
};
|
|
108
|
+
}
|
package/dist/scope.d.ts
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { Hex, ProtocolScope } from "./types.js";
|
|
2
|
+
export declare function canonicalScope(input: ProtocolScope): ProtocolScope;
|
|
3
|
+
export declare function scopeKey(input: ProtocolScope): string;
|
|
4
|
+
export declare function assertSameScope(expected: ProtocolScope, received: ProtocolScope): void;
|
|
5
|
+
export declare function scopedSnapshotHash(scope: ProtocolScope, snapshotHash: Hex): Hex;
|
package/dist/scope.js
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { encodeAbiParameters, keccak256, parseAbiParameters } from "viem";
|
|
2
|
+
function normalizeScopeText(value) {
|
|
3
|
+
return value.normalize("NFC").trim();
|
|
4
|
+
}
|
|
5
|
+
export function canonicalScope(input) {
|
|
6
|
+
return {
|
|
7
|
+
fundId: normalizeScopeText(input.fundId),
|
|
8
|
+
roomId: normalizeScopeText(input.roomId),
|
|
9
|
+
epochId: input.epochId
|
|
10
|
+
};
|
|
11
|
+
}
|
|
12
|
+
export function scopeKey(input) {
|
|
13
|
+
const v = canonicalScope(input);
|
|
14
|
+
return `${v.fundId}:${v.roomId}:${v.epochId.toString(10)}`;
|
|
15
|
+
}
|
|
16
|
+
export function assertSameScope(expected, received) {
|
|
17
|
+
const left = scopeKey(expected);
|
|
18
|
+
const right = scopeKey(received);
|
|
19
|
+
if (left !== right) {
|
|
20
|
+
throw new Error(`scope mismatch: expected=${left}, received=${right}`);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
export function scopedSnapshotHash(scope, snapshotHash) {
|
|
24
|
+
const v = canonicalScope(scope);
|
|
25
|
+
return keccak256(encodeAbiParameters(parseAbiParameters("string fundId,string roomId,uint64 epochId,bytes32 snapshotHash"), [v.fundId, v.roomId, v.epochId, snapshotHash]));
|
|
26
|
+
}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
export type Hex = `0x${string}`;
|
|
2
|
+
export type Address = `0x${string}`;
|
|
3
|
+
export interface ClaimPayload {
|
|
4
|
+
schemaId: string;
|
|
5
|
+
sourceType: string;
|
|
6
|
+
sourceRef: string;
|
|
7
|
+
selector: string;
|
|
8
|
+
extracted: string;
|
|
9
|
+
extractedType: string;
|
|
10
|
+
timestamp: bigint;
|
|
11
|
+
responseHash: Hex;
|
|
12
|
+
evidenceType: string;
|
|
13
|
+
evidenceURI: string;
|
|
14
|
+
crawler: Address;
|
|
15
|
+
notes?: string;
|
|
16
|
+
}
|
|
17
|
+
export interface TradeIntent {
|
|
18
|
+
intentVersion: string;
|
|
19
|
+
vault: Address;
|
|
20
|
+
action: "BUY" | "SELL";
|
|
21
|
+
tokenIn: Address;
|
|
22
|
+
tokenOut: Address;
|
|
23
|
+
amountIn: bigint;
|
|
24
|
+
minAmountOut: bigint;
|
|
25
|
+
deadline: bigint;
|
|
26
|
+
maxSlippageBps: bigint;
|
|
27
|
+
snapshotHash: Hex;
|
|
28
|
+
reason?: string;
|
|
29
|
+
}
|
|
30
|
+
export interface Eip712DomainInput {
|
|
31
|
+
name: string;
|
|
32
|
+
version: string;
|
|
33
|
+
chainId: bigint;
|
|
34
|
+
verifyingContract: Address;
|
|
35
|
+
}
|
|
36
|
+
export interface ProtocolScope {
|
|
37
|
+
fundId: string;
|
|
38
|
+
roomId: string;
|
|
39
|
+
epochId: bigint;
|
|
40
|
+
}
|
|
41
|
+
export type SubjectType = "CLAIM" | "INTENT";
|
|
42
|
+
export interface AttestationMeta {
|
|
43
|
+
verifier: Address;
|
|
44
|
+
expiresAt: bigint;
|
|
45
|
+
nonce: bigint;
|
|
46
|
+
}
|
|
47
|
+
export interface ClaimAttestationDraft extends AttestationMeta {
|
|
48
|
+
claimHash: Hex;
|
|
49
|
+
epochId: bigint;
|
|
50
|
+
}
|
|
51
|
+
export interface IntentAttestationDraft extends AttestationMeta {
|
|
52
|
+
intentHash: Hex;
|
|
53
|
+
}
|
|
54
|
+
export interface SignedAttestation<TSubject extends SubjectType, TMessage> {
|
|
55
|
+
subjectType: TSubject;
|
|
56
|
+
subjectHash: Hex;
|
|
57
|
+
message: TMessage;
|
|
58
|
+
signature: Hex;
|
|
59
|
+
}
|
|
60
|
+
export type ExecutionAction = "BUY" | "SELL";
|
|
61
|
+
export type ExecutionVenue = "NADFUN_BONDING_CURVE" | "NADFUN_DEX";
|
|
62
|
+
export interface NadfunExecutionDataV1 {
|
|
63
|
+
version: 1;
|
|
64
|
+
action: ExecutionAction;
|
|
65
|
+
venue: ExecutionVenue;
|
|
66
|
+
router: Address;
|
|
67
|
+
recipient: Address;
|
|
68
|
+
token: Address;
|
|
69
|
+
deadline: bigint;
|
|
70
|
+
amountOutMin: bigint;
|
|
71
|
+
extra: Hex;
|
|
72
|
+
}
|
|
73
|
+
export interface IntentConstraints {
|
|
74
|
+
allowlistHash: Hex;
|
|
75
|
+
maxSlippageBps: bigint;
|
|
76
|
+
maxNotional: bigint;
|
|
77
|
+
deadline: bigint;
|
|
78
|
+
}
|
|
79
|
+
export interface IntentExecutionRouteInput {
|
|
80
|
+
tokenIn: Address;
|
|
81
|
+
tokenOut: Address;
|
|
82
|
+
quoteAmountOut: bigint;
|
|
83
|
+
minAmountOut: bigint;
|
|
84
|
+
adapter: Address;
|
|
85
|
+
adapterData?: Hex;
|
|
86
|
+
adapterDataHash?: Hex;
|
|
87
|
+
}
|
|
88
|
+
export interface CoreExecutionRequestInput {
|
|
89
|
+
tokenIn: Address;
|
|
90
|
+
tokenOut: Address;
|
|
91
|
+
amountIn: bigint;
|
|
92
|
+
quoteAmountOut: bigint;
|
|
93
|
+
minAmountOut: bigint;
|
|
94
|
+
adapter: Address;
|
|
95
|
+
adapterData: Hex;
|
|
96
|
+
}
|
|
97
|
+
export interface CanonicalClaimRecord {
|
|
98
|
+
payload: ClaimPayload;
|
|
99
|
+
epochId: bigint;
|
|
100
|
+
claimHash: Hex;
|
|
101
|
+
}
|
|
102
|
+
export interface CanonicalIntentRecord {
|
|
103
|
+
intent: TradeIntent;
|
|
104
|
+
intentHash: Hex;
|
|
105
|
+
constraints: IntentConstraints;
|
|
106
|
+
}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/dist/validate.js
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
const UINT16_MAX = (1n << 16n) - 1n;
|
|
2
|
+
const UINT64_MAX = (1n << 64n) - 1n;
|
|
3
|
+
export function assertUint16(value, label) {
|
|
4
|
+
if (value < 0n || value > UINT16_MAX) {
|
|
5
|
+
throw new Error(`${label} must be uint16`);
|
|
6
|
+
}
|
|
7
|
+
}
|
|
8
|
+
export function assertUint64(value, label) {
|
|
9
|
+
if (value < 0n || value > UINT64_MAX) {
|
|
10
|
+
throw new Error(`${label} must be uint64`);
|
|
11
|
+
}
|
|
12
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { Address } from "./types.js";
|
|
2
|
+
export interface ValidatorWeight {
|
|
3
|
+
validator: Address;
|
|
4
|
+
weight: bigint;
|
|
5
|
+
}
|
|
6
|
+
export interface WeightMapOptions {
|
|
7
|
+
allowZeroWeight?: boolean;
|
|
8
|
+
}
|
|
9
|
+
export interface WeightedThresholdState {
|
|
10
|
+
totalWeight: bigint;
|
|
11
|
+
attestedWeight: bigint;
|
|
12
|
+
thresholdWeight: bigint;
|
|
13
|
+
met: boolean;
|
|
14
|
+
}
|
|
15
|
+
export declare function buildValidatorWeightMap(entries: ValidatorWeight[], options?: WeightMapOptions): Map<string, bigint>;
|
|
16
|
+
export declare function totalValidatorWeight(weightMap: Map<string, bigint>): bigint;
|
|
17
|
+
export declare function attestedWeight(attesters: Address[], weightMap: Map<string, bigint>): bigint;
|
|
18
|
+
export declare function reachedWeightedThreshold(attesters: Address[], weightMap: Map<string, bigint>, thresholdWeight: bigint): boolean;
|
|
19
|
+
export declare function weightedThresholdState(attesters: Address[], weightMap: Map<string, bigint>, thresholdWeight: bigint): WeightedThresholdState;
|