@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/README.md
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# @claw/protocol-sdk
|
|
2
|
+
|
|
3
|
+
Claw의 공통 프로토콜 SDK (최소 범위):
|
|
4
|
+
|
|
5
|
+
## Role
|
|
6
|
+
- Monorepo canonical utility layer shared by contracts tests, relayer, and agents.
|
|
7
|
+
- Owns protocol hashing/typed-data rules so all components use identical verification logic.
|
|
8
|
+
|
|
9
|
+
- canonical hashing (`claimHash`, `intentHash`, `snapshotHash`)
|
|
10
|
+
- EIP-712 attestation typed data + verify/recover
|
|
11
|
+
- weighted threshold 유틸
|
|
12
|
+
- intent execution route 해시 유틸 (`intentExecutionAllowlistHash`, `intentExecutionCallHash`)
|
|
13
|
+
- NadFun adapter 실행데이터 인코딩/디코딩 (`encodeNadfunExecutionDataV1`)
|
|
14
|
+
|
|
15
|
+
## 목적
|
|
16
|
+
|
|
17
|
+
다른 서비스(릴레이어/봇/프론트/컨트랙트 테스트)가 **동일한 intent 규격과 해시 규칙**을 공유하도록 강제.
|
|
18
|
+
|
|
19
|
+
## 설치
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
npm install @claw/protocol-sdk
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## 로컬 개발
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
cd /Users/ham-yunsig/Documents/github/claw-validation-market/packages/sdk
|
|
29
|
+
npm install
|
|
30
|
+
npm test
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
## 핵심 사용 예
|
|
34
|
+
|
|
35
|
+
```ts
|
|
36
|
+
import {
|
|
37
|
+
intentHash,
|
|
38
|
+
intentExecutionCallHash,
|
|
39
|
+
encodeNadfunExecutionDataV1,
|
|
40
|
+
intentAttestationTypedData,
|
|
41
|
+
verifyIntentAttestation
|
|
42
|
+
} from "@claw/protocol-sdk";
|
|
43
|
+
```
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { type ClaimAttestationMessage, type IntentAttestationMessage } from "./eip712.js";
|
|
2
|
+
import type { Eip712DomainInput, Hex } from "./types.js";
|
|
3
|
+
export interface VerificationResult {
|
|
4
|
+
ok: boolean;
|
|
5
|
+
digest?: Hex;
|
|
6
|
+
recovered?: `0x${string}`;
|
|
7
|
+
error?: string;
|
|
8
|
+
}
|
|
9
|
+
export declare function verifyClaimAttestationEnvelope(domain: Eip712DomainInput, message: ClaimAttestationMessage, signature: Hex): Promise<VerificationResult>;
|
|
10
|
+
export declare function verifyIntentAttestationEnvelope(domain: Eip712DomainInput, message: IntentAttestationMessage, signature: Hex): Promise<VerificationResult>;
|
|
11
|
+
export declare function reachedThreshold(validCount: number, threshold: number): boolean;
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { claimAttestationDigest, intentAttestationDigest, recoverClaimAttester, recoverIntentAttester } from "./eip712.js";
|
|
2
|
+
import { assertNotExpired } from "./attestation.js";
|
|
3
|
+
async function verifyEnvelope(verifier, computeDigest, recoverAddress) {
|
|
4
|
+
try {
|
|
5
|
+
const digest = computeDigest();
|
|
6
|
+
const recovered = await recoverAddress();
|
|
7
|
+
if (recovered.toLowerCase() !== verifier.toLowerCase()) {
|
|
8
|
+
return {
|
|
9
|
+
ok: false,
|
|
10
|
+
digest,
|
|
11
|
+
recovered,
|
|
12
|
+
error: "signature does not recover claimed verifier"
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
return {
|
|
16
|
+
ok: true,
|
|
17
|
+
digest,
|
|
18
|
+
recovered
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
catch (error) {
|
|
22
|
+
return {
|
|
23
|
+
ok: false,
|
|
24
|
+
error: error instanceof Error ? error.message : String(error)
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
export async function verifyClaimAttestationEnvelope(domain, message, signature) {
|
|
29
|
+
try {
|
|
30
|
+
assertNotExpired(message.expiresAt);
|
|
31
|
+
}
|
|
32
|
+
catch (error) {
|
|
33
|
+
return {
|
|
34
|
+
ok: false,
|
|
35
|
+
error: error instanceof Error ? error.message : String(error)
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
return verifyEnvelope(message.verifier, () => claimAttestationDigest(domain, message), () => recoverClaimAttester(domain, message, signature));
|
|
39
|
+
}
|
|
40
|
+
export async function verifyIntentAttestationEnvelope(domain, message, signature) {
|
|
41
|
+
try {
|
|
42
|
+
assertNotExpired(message.expiresAt);
|
|
43
|
+
}
|
|
44
|
+
catch (error) {
|
|
45
|
+
return {
|
|
46
|
+
ok: false,
|
|
47
|
+
error: error instanceof Error ? error.message : String(error)
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
return verifyEnvelope(message.verifier, () => intentAttestationDigest(domain, message), () => recoverIntentAttester(domain, message, signature));
|
|
51
|
+
}
|
|
52
|
+
export function reachedThreshold(validCount, threshold) {
|
|
53
|
+
if (!Number.isInteger(validCount) || validCount < 0) {
|
|
54
|
+
throw new Error("validCount must be a non-negative integer");
|
|
55
|
+
}
|
|
56
|
+
if (!Number.isInteger(threshold) || threshold <= 0) {
|
|
57
|
+
throw new Error("threshold must be a positive integer");
|
|
58
|
+
}
|
|
59
|
+
return validCount >= threshold;
|
|
60
|
+
}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export declare function unixNow(): bigint;
|
|
2
|
+
export declare function isExpired(expiresAt: bigint, now?: bigint): boolean;
|
|
3
|
+
export declare function assertNotExpired(expiresAt: bigint, now?: bigint): void;
|
|
4
|
+
export declare function assertNonceStrictlyIncreases(lastNonce: bigint | null, incomingNonce: bigint): void;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export function unixNow() {
|
|
2
|
+
return BigInt(Math.floor(Date.now() / 1000));
|
|
3
|
+
}
|
|
4
|
+
export function isExpired(expiresAt, now = unixNow()) {
|
|
5
|
+
return expiresAt <= now;
|
|
6
|
+
}
|
|
7
|
+
export function assertNotExpired(expiresAt, now = unixNow()) {
|
|
8
|
+
if (isExpired(expiresAt, now)) {
|
|
9
|
+
throw new Error(`signature expired: expiresAt=${expiresAt.toString(10)}, now=${now.toString(10)}`);
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
export function assertNonceStrictlyIncreases(lastNonce, incomingNonce) {
|
|
13
|
+
if (lastNonce !== null && incomingNonce <= lastNonce) {
|
|
14
|
+
throw new Error(`nonce must strictly increase: last=${lastNonce.toString(10)}, incoming=${incomingNonce.toString(10)}`);
|
|
15
|
+
}
|
|
16
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { getAddress } from "viem";
|
|
2
|
+
function normalizeText(value) {
|
|
3
|
+
return value.normalize("NFC").trim();
|
|
4
|
+
}
|
|
5
|
+
function normalizeAddress(value) {
|
|
6
|
+
return getAddress(value);
|
|
7
|
+
}
|
|
8
|
+
export function canonicalClaim(input) {
|
|
9
|
+
return {
|
|
10
|
+
...input,
|
|
11
|
+
schemaId: normalizeText(input.schemaId),
|
|
12
|
+
sourceType: normalizeText(input.sourceType),
|
|
13
|
+
sourceRef: normalizeText(input.sourceRef),
|
|
14
|
+
selector: normalizeText(input.selector),
|
|
15
|
+
extracted: normalizeText(input.extracted),
|
|
16
|
+
extractedType: normalizeText(input.extractedType),
|
|
17
|
+
evidenceType: normalizeText(input.evidenceType),
|
|
18
|
+
evidenceURI: normalizeText(input.evidenceURI),
|
|
19
|
+
crawler: normalizeAddress(input.crawler),
|
|
20
|
+
notes: input.notes === undefined ? undefined : normalizeText(input.notes)
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
export function canonicalIntent(input) {
|
|
24
|
+
const normalizedAction = normalizeText(input.action).toUpperCase();
|
|
25
|
+
if (normalizedAction !== "BUY" && normalizedAction !== "SELL") {
|
|
26
|
+
throw new Error(`invalid action: ${input.action}`);
|
|
27
|
+
}
|
|
28
|
+
return {
|
|
29
|
+
...input,
|
|
30
|
+
intentVersion: normalizeText(input.intentVersion),
|
|
31
|
+
vault: normalizeAddress(input.vault),
|
|
32
|
+
action: normalizedAction,
|
|
33
|
+
tokenIn: normalizeAddress(input.tokenIn),
|
|
34
|
+
tokenOut: normalizeAddress(input.tokenOut),
|
|
35
|
+
reason: input.reason === undefined ? undefined : normalizeText(input.reason)
|
|
36
|
+
};
|
|
37
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { type ClaimAttestationMessage, type IntentAttestationMessage } from "./eip712.js";
|
|
2
|
+
import type { Eip712DomainInput, Hex } from "./types.js";
|
|
3
|
+
export interface VerificationResult {
|
|
4
|
+
ok: boolean;
|
|
5
|
+
digest?: Hex;
|
|
6
|
+
recovered?: `0x${string}`;
|
|
7
|
+
error?: string;
|
|
8
|
+
}
|
|
9
|
+
export declare function verifyClaimAttestationEnvelope(domain: Eip712DomainInput, message: ClaimAttestationMessage, signature: Hex): Promise<VerificationResult>;
|
|
10
|
+
export declare function verifyIntentAttestationEnvelope(domain: Eip712DomainInput, message: IntentAttestationMessage, signature: Hex): Promise<VerificationResult>;
|
|
11
|
+
export declare function reachedThreshold(validCount: number, threshold: number): boolean;
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { claimAttestationDigest, intentAttestationDigest, recoverClaimAttester, recoverIntentAttester } from "./eip712.js";
|
|
2
|
+
import { assertNotExpired } from "./attestation.js";
|
|
3
|
+
async function verifyEnvelope(verifier, computeDigest, recoverAddress) {
|
|
4
|
+
try {
|
|
5
|
+
const digest = computeDigest();
|
|
6
|
+
const recovered = await recoverAddress();
|
|
7
|
+
if (recovered.toLowerCase() !== verifier.toLowerCase()) {
|
|
8
|
+
return {
|
|
9
|
+
ok: false,
|
|
10
|
+
digest,
|
|
11
|
+
recovered,
|
|
12
|
+
error: "signature does not recover claimed verifier"
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
return {
|
|
16
|
+
ok: true,
|
|
17
|
+
digest,
|
|
18
|
+
recovered
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
catch (error) {
|
|
22
|
+
return {
|
|
23
|
+
ok: false,
|
|
24
|
+
error: error instanceof Error ? error.message : String(error)
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
export async function verifyClaimAttestationEnvelope(domain, message, signature) {
|
|
29
|
+
try {
|
|
30
|
+
assertNotExpired(message.expiresAt);
|
|
31
|
+
}
|
|
32
|
+
catch (error) {
|
|
33
|
+
return {
|
|
34
|
+
ok: false,
|
|
35
|
+
error: error instanceof Error ? error.message : String(error)
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
return verifyEnvelope(message.verifier, () => claimAttestationDigest(domain, message), () => recoverClaimAttester(domain, message, signature));
|
|
39
|
+
}
|
|
40
|
+
export async function verifyIntentAttestationEnvelope(domain, message, signature) {
|
|
41
|
+
try {
|
|
42
|
+
assertNotExpired(message.expiresAt);
|
|
43
|
+
}
|
|
44
|
+
catch (error) {
|
|
45
|
+
return {
|
|
46
|
+
ok: false,
|
|
47
|
+
error: error instanceof Error ? error.message : String(error)
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
return verifyEnvelope(message.verifier, () => intentAttestationDigest(domain, message), () => recoverIntentAttester(domain, message, signature));
|
|
51
|
+
}
|
|
52
|
+
export function reachedThreshold(validCount, threshold) {
|
|
53
|
+
if (!Number.isInteger(validCount) || validCount < 0) {
|
|
54
|
+
throw new Error("validCount must be a non-negative integer");
|
|
55
|
+
}
|
|
56
|
+
if (!Number.isInteger(threshold) || threshold <= 0) {
|
|
57
|
+
throw new Error("threshold must be a positive integer");
|
|
58
|
+
}
|
|
59
|
+
return validCount >= threshold;
|
|
60
|
+
}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export declare function unixNow(): bigint;
|
|
2
|
+
export declare function isExpired(expiresAt: bigint, now?: bigint): boolean;
|
|
3
|
+
export declare function assertNotExpired(expiresAt: bigint, now?: bigint): void;
|
|
4
|
+
export declare function assertNonceStrictlyIncreases(lastNonce: bigint | null, incomingNonce: bigint): void;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export function unixNow() {
|
|
2
|
+
return BigInt(Math.floor(Date.now() / 1000));
|
|
3
|
+
}
|
|
4
|
+
export function isExpired(expiresAt, now = unixNow()) {
|
|
5
|
+
return expiresAt <= now;
|
|
6
|
+
}
|
|
7
|
+
export function assertNotExpired(expiresAt, now = unixNow()) {
|
|
8
|
+
if (isExpired(expiresAt, now)) {
|
|
9
|
+
throw new Error(`signature expired: expiresAt=${expiresAt.toString(10)}, now=${now.toString(10)}`);
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
export function assertNonceStrictlyIncreases(lastNonce, incomingNonce) {
|
|
13
|
+
if (lastNonce !== null && incomingNonce <= lastNonce) {
|
|
14
|
+
throw new Error(`nonce must strictly increase: last=${lastNonce.toString(10)}, incoming=${incomingNonce.toString(10)}`);
|
|
15
|
+
}
|
|
16
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { getAddress } from "viem";
|
|
2
|
+
function normalizeText(value) {
|
|
3
|
+
return value.normalize("NFC").trim();
|
|
4
|
+
}
|
|
5
|
+
function normalizeAddress(value) {
|
|
6
|
+
return getAddress(value);
|
|
7
|
+
}
|
|
8
|
+
export function canonicalClaim(input) {
|
|
9
|
+
return {
|
|
10
|
+
...input,
|
|
11
|
+
schemaId: normalizeText(input.schemaId),
|
|
12
|
+
sourceType: normalizeText(input.sourceType),
|
|
13
|
+
sourceRef: normalizeText(input.sourceRef),
|
|
14
|
+
selector: normalizeText(input.selector),
|
|
15
|
+
extracted: normalizeText(input.extracted),
|
|
16
|
+
extractedType: normalizeText(input.extractedType),
|
|
17
|
+
evidenceType: normalizeText(input.evidenceType),
|
|
18
|
+
evidenceURI: normalizeText(input.evidenceURI),
|
|
19
|
+
crawler: normalizeAddress(input.crawler),
|
|
20
|
+
notes: input.notes === undefined ? undefined : normalizeText(input.notes)
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
export function canonicalIntent(input) {
|
|
24
|
+
const normalizedAction = normalizeText(input.action).toUpperCase();
|
|
25
|
+
if (normalizedAction !== "BUY" && normalizedAction !== "SELL") {
|
|
26
|
+
throw new Error(`invalid action: ${input.action}`);
|
|
27
|
+
}
|
|
28
|
+
return {
|
|
29
|
+
...input,
|
|
30
|
+
intentVersion: normalizeText(input.intentVersion),
|
|
31
|
+
vault: normalizeAddress(input.vault),
|
|
32
|
+
action: normalizedAction,
|
|
33
|
+
tokenIn: normalizeAddress(input.tokenIn),
|
|
34
|
+
tokenOut: normalizeAddress(input.tokenOut),
|
|
35
|
+
reason: input.reason === undefined ? undefined : normalizeText(input.reason)
|
|
36
|
+
};
|
|
37
|
+
}
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import type { Address, Eip712DomainInput, Hex } from "./types.js";
|
|
2
|
+
export declare const CLAIM_ATTESTATION_TYPES: {
|
|
3
|
+
readonly ClaimAttestation: readonly [{
|
|
4
|
+
readonly name: "claimHash";
|
|
5
|
+
readonly type: "bytes32";
|
|
6
|
+
}, {
|
|
7
|
+
readonly name: "epochId";
|
|
8
|
+
readonly type: "uint64";
|
|
9
|
+
}, {
|
|
10
|
+
readonly name: "verifier";
|
|
11
|
+
readonly type: "address";
|
|
12
|
+
}, {
|
|
13
|
+
readonly name: "expiresAt";
|
|
14
|
+
readonly type: "uint64";
|
|
15
|
+
}, {
|
|
16
|
+
readonly name: "nonce";
|
|
17
|
+
readonly type: "uint256";
|
|
18
|
+
}];
|
|
19
|
+
};
|
|
20
|
+
export declare const INTENT_ATTESTATION_TYPES: {
|
|
21
|
+
readonly IntentAttestation: readonly [{
|
|
22
|
+
readonly name: "intentHash";
|
|
23
|
+
readonly type: "bytes32";
|
|
24
|
+
}, {
|
|
25
|
+
readonly name: "verifier";
|
|
26
|
+
readonly type: "address";
|
|
27
|
+
}, {
|
|
28
|
+
readonly name: "expiresAt";
|
|
29
|
+
readonly type: "uint64";
|
|
30
|
+
}, {
|
|
31
|
+
readonly name: "nonce";
|
|
32
|
+
readonly type: "uint256";
|
|
33
|
+
}];
|
|
34
|
+
};
|
|
35
|
+
export interface ClaimAttestationMessage {
|
|
36
|
+
claimHash: Hex;
|
|
37
|
+
epochId: bigint;
|
|
38
|
+
verifier: Address;
|
|
39
|
+
expiresAt: bigint;
|
|
40
|
+
nonce: bigint;
|
|
41
|
+
}
|
|
42
|
+
export interface IntentAttestationMessage {
|
|
43
|
+
intentHash: Hex;
|
|
44
|
+
verifier: Address;
|
|
45
|
+
expiresAt: bigint;
|
|
46
|
+
nonce: bigint;
|
|
47
|
+
}
|
|
48
|
+
export declare function toEip712Domain(input: Eip712DomainInput): {
|
|
49
|
+
name: string;
|
|
50
|
+
version: string;
|
|
51
|
+
chainId: bigint;
|
|
52
|
+
verifyingContract: `0x${string}`;
|
|
53
|
+
};
|
|
54
|
+
export declare function claimAttestationTypedData(domain: Eip712DomainInput, message: ClaimAttestationMessage): {
|
|
55
|
+
domain: {
|
|
56
|
+
name: string;
|
|
57
|
+
version: string;
|
|
58
|
+
chainId: bigint;
|
|
59
|
+
verifyingContract: `0x${string}`;
|
|
60
|
+
};
|
|
61
|
+
types: {
|
|
62
|
+
readonly ClaimAttestation: readonly [{
|
|
63
|
+
readonly name: "claimHash";
|
|
64
|
+
readonly type: "bytes32";
|
|
65
|
+
}, {
|
|
66
|
+
readonly name: "epochId";
|
|
67
|
+
readonly type: "uint64";
|
|
68
|
+
}, {
|
|
69
|
+
readonly name: "verifier";
|
|
70
|
+
readonly type: "address";
|
|
71
|
+
}, {
|
|
72
|
+
readonly name: "expiresAt";
|
|
73
|
+
readonly type: "uint64";
|
|
74
|
+
}, {
|
|
75
|
+
readonly name: "nonce";
|
|
76
|
+
readonly type: "uint256";
|
|
77
|
+
}];
|
|
78
|
+
};
|
|
79
|
+
primaryType: "ClaimAttestation";
|
|
80
|
+
message: ClaimAttestationMessage;
|
|
81
|
+
};
|
|
82
|
+
export declare function intentAttestationTypedData(domain: Eip712DomainInput, message: IntentAttestationMessage): {
|
|
83
|
+
domain: {
|
|
84
|
+
name: string;
|
|
85
|
+
version: string;
|
|
86
|
+
chainId: bigint;
|
|
87
|
+
verifyingContract: `0x${string}`;
|
|
88
|
+
};
|
|
89
|
+
types: {
|
|
90
|
+
readonly IntentAttestation: readonly [{
|
|
91
|
+
readonly name: "intentHash";
|
|
92
|
+
readonly type: "bytes32";
|
|
93
|
+
}, {
|
|
94
|
+
readonly name: "verifier";
|
|
95
|
+
readonly type: "address";
|
|
96
|
+
}, {
|
|
97
|
+
readonly name: "expiresAt";
|
|
98
|
+
readonly type: "uint64";
|
|
99
|
+
}, {
|
|
100
|
+
readonly name: "nonce";
|
|
101
|
+
readonly type: "uint256";
|
|
102
|
+
}];
|
|
103
|
+
};
|
|
104
|
+
primaryType: "IntentAttestation";
|
|
105
|
+
message: IntentAttestationMessage;
|
|
106
|
+
};
|
|
107
|
+
export declare function claimAttestationDigest(domain: Eip712DomainInput, message: ClaimAttestationMessage): Hex;
|
|
108
|
+
export declare function intentAttestationDigest(domain: Eip712DomainInput, message: IntentAttestationMessage): Hex;
|
|
109
|
+
export declare function verifyClaimAttestation(domain: Eip712DomainInput, message: ClaimAttestationMessage, signature: Hex): Promise<boolean>;
|
|
110
|
+
export declare function verifyIntentAttestation(domain: Eip712DomainInput, message: IntentAttestationMessage, signature: Hex): Promise<boolean>;
|
|
111
|
+
export declare function recoverClaimAttester(domain: Eip712DomainInput, message: ClaimAttestationMessage, signature: Hex): Promise<Address>;
|
|
112
|
+
export declare function recoverIntentAttester(domain: Eip712DomainInput, message: IntentAttestationMessage, signature: Hex): Promise<Address>;
|
|
@@ -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
|
+
}
|
|
@@ -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
|
+
}
|
|
@@ -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;
|