payid 0.2.7 → 0.2.8
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/package.json +3 -2
- package/index.ts +0 -1
- package/src/decision-proof/generate.ts +0 -41
- package/src/decision-proof/hash.ts +0 -26
- package/src/decision-proof/sign.ts +0 -42
- package/src/decision-proof/types.ts +0 -18
- package/src/erc4337/build.ts +0 -16
- package/src/erc4337/types.ts +0 -13
- package/src/erc4337/userop.ts +0 -30
- package/src/evaluate.ts +0 -63
- package/src/index.ts +0 -1
- package/src/normalize.ts +0 -13
- package/src/payid.ts +0 -167
- package/src/resolver/http.ts +0 -16
- package/src/resolver/ipfs.ts +0 -22
- package/src/resolver/resolver.ts +0 -24
- package/src/resolver/types.ts +0 -9
- package/src/resolver/utils.ts +0 -13
- package/src/rules/rule_generic_evaluator.wasm +0 -0
- package/tsconfig.json +0 -29
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "payid",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.8",
|
|
4
4
|
"private": false,
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -12,7 +12,8 @@
|
|
|
12
12
|
},
|
|
13
13
|
"scripts": {
|
|
14
14
|
"build:js": "bun build src/index.ts --outdir dist --target node",
|
|
15
|
-
"build": "
|
|
15
|
+
"build:build": "tsc -p tsconfig.build.json",
|
|
16
|
+
"build": "bun run build:js && bun run build:build"
|
|
16
17
|
},
|
|
17
18
|
"devDependencies": {
|
|
18
19
|
"@types/bun": "latest"
|
package/index.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export * from "./src";
|
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
import { randomBytes } from "crypto";
|
|
2
|
-
import type { DecisionPayload, DecisionProof } from "./types";
|
|
3
|
-
import { hashContext, hashRuleSet } from "./hash";
|
|
4
|
-
import { signDecision } from "./sign";
|
|
5
|
-
import { ethers } from "ethers";
|
|
6
|
-
|
|
7
|
-
export async function generateDecisionProof(params: {
|
|
8
|
-
payId: string;
|
|
9
|
-
owner: string;
|
|
10
|
-
decision: "ALLOW" | "REJECT";
|
|
11
|
-
context: any;
|
|
12
|
-
ruleConfig: any;
|
|
13
|
-
signer: ethers.Signer;
|
|
14
|
-
chainId: number;
|
|
15
|
-
verifyingContract: string;
|
|
16
|
-
ttlSeconds?: number;
|
|
17
|
-
}): Promise<DecisionProof> {
|
|
18
|
-
const issuedAt = Math.floor(Date.now() / 1000);
|
|
19
|
-
const expiresAt = issuedAt + (params.ttlSeconds ?? 60);
|
|
20
|
-
|
|
21
|
-
const payload: DecisionPayload = {
|
|
22
|
-
version: "payid.decision.v1",
|
|
23
|
-
payId: params.payId,
|
|
24
|
-
owner: params.owner,
|
|
25
|
-
decision: params.decision === "ALLOW" ? 1 : 0,
|
|
26
|
-
contextHash: hashContext(params.context),
|
|
27
|
-
ruleSetHash: hashRuleSet(params.ruleConfig),
|
|
28
|
-
issuedAt,
|
|
29
|
-
expiresAt,
|
|
30
|
-
nonce: `0x${randomBytes(32).toString("hex")}`
|
|
31
|
-
};
|
|
32
|
-
|
|
33
|
-
const signature = await signDecision(
|
|
34
|
-
params.signer,
|
|
35
|
-
params.chainId,
|
|
36
|
-
params.verifyingContract,
|
|
37
|
-
payload
|
|
38
|
-
);
|
|
39
|
-
|
|
40
|
-
return { payload, signature };
|
|
41
|
-
}
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
import { keccak256 } from "ethers";
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* NOTE:
|
|
5
|
-
* Untuk v1, JSON stringify yang sudah distabilkan
|
|
6
|
-
* (keys sorted). WAJIB untuk golden tests.
|
|
7
|
-
*/
|
|
8
|
-
function stableStringify(obj: any): string {
|
|
9
|
-
if (Array.isArray(obj)) {
|
|
10
|
-
return `[${obj.map(stableStringify).join(",")}]`;
|
|
11
|
-
}
|
|
12
|
-
if (obj && typeof obj === "object") {
|
|
13
|
-
return `{${Object.keys(obj).sort().map(
|
|
14
|
-
k => `"${k}":${stableStringify(obj[k])}`
|
|
15
|
-
).join(",")}}`;
|
|
16
|
-
}
|
|
17
|
-
return JSON.stringify(obj);
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
export function hashContext(context: any): string {
|
|
21
|
-
return keccak256(Buffer.from(stableStringify(context)));
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
export function hashRuleSet(ruleConfig: any): string {
|
|
25
|
-
return keccak256(Buffer.from(stableStringify(ruleConfig)));
|
|
26
|
-
}
|
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
import { ethers } from "ethers";
|
|
2
|
-
import type { DecisionPayload } from "./types";
|
|
3
|
-
|
|
4
|
-
export async function signDecision(
|
|
5
|
-
signer: ethers.Signer,
|
|
6
|
-
chainId: number,
|
|
7
|
-
verifyingContract: string,
|
|
8
|
-
payload: DecisionPayload
|
|
9
|
-
): Promise<string> {
|
|
10
|
-
const domain = {
|
|
11
|
-
name: "PAY.ID Decision",
|
|
12
|
-
version: "1",
|
|
13
|
-
chainId,
|
|
14
|
-
verifyingContract
|
|
15
|
-
};
|
|
16
|
-
|
|
17
|
-
const types = {
|
|
18
|
-
Decision: [
|
|
19
|
-
{ name: "version", type: "string" },
|
|
20
|
-
{ name: "payId", type: "string" },
|
|
21
|
-
{ name: "owner", type: "address" },
|
|
22
|
-
{ name: "decision", type: "uint8" },
|
|
23
|
-
{ name: "contextHash", type: "bytes32" },
|
|
24
|
-
{ name: "ruleSetHash", type: "bytes32" },
|
|
25
|
-
{ name: "issuedAt", type: "uint64" },
|
|
26
|
-
{ name: "expiresAt", type: "uint64" },
|
|
27
|
-
{ name: "nonce", type: "bytes32" }
|
|
28
|
-
]
|
|
29
|
-
};
|
|
30
|
-
|
|
31
|
-
if (typeof (signer as any).signTypedData === "function") {
|
|
32
|
-
return await (signer as any).signTypedData(domain, types, payload);
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
if (typeof (signer as any)._signTypedData === "function") {
|
|
36
|
-
return await (signer as any)._signTypedData(domain, types, payload);
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
throw new Error(
|
|
40
|
-
"Signer does not support EIP-712 signing (signTypedData)"
|
|
41
|
-
);
|
|
42
|
-
}
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
export type DecisionValue = 0 | 1; // 1=ALLOW, 0=REJECT
|
|
2
|
-
|
|
3
|
-
export interface DecisionPayload {
|
|
4
|
-
version: "payid.decision.v1";
|
|
5
|
-
payId: string;
|
|
6
|
-
owner: string; // authority address
|
|
7
|
-
decision: DecisionValue;
|
|
8
|
-
contextHash: string; // bytes32
|
|
9
|
-
ruleSetHash: string; // bytes32
|
|
10
|
-
issuedAt: number; // uint64
|
|
11
|
-
expiresAt: number; // uint64
|
|
12
|
-
nonce: string; // bytes32
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
export interface DecisionProof {
|
|
16
|
-
payload: DecisionPayload;
|
|
17
|
-
signature: string; // EIP-712 signature
|
|
18
|
-
}
|
package/src/erc4337/build.ts
DELETED
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
import { ethers } from "ethers";
|
|
2
|
-
import type { DecisionProof } from "../decision-proof/types";
|
|
3
|
-
|
|
4
|
-
export function buildPayCallData(
|
|
5
|
-
contractAddress: string,
|
|
6
|
-
proof: DecisionProof
|
|
7
|
-
): string {
|
|
8
|
-
const iface = new ethers.Interface([
|
|
9
|
-
"function pay(bytes payload, bytes signature)"
|
|
10
|
-
]);
|
|
11
|
-
|
|
12
|
-
return iface.encodeFunctionData("pay", [
|
|
13
|
-
ethers.toUtf8Bytes(JSON.stringify(proof.payload)),
|
|
14
|
-
proof.signature
|
|
15
|
-
]);
|
|
16
|
-
}
|
package/src/erc4337/types.ts
DELETED
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
export interface UserOperation {
|
|
2
|
-
sender: string;
|
|
3
|
-
nonce: string;
|
|
4
|
-
initCode: string;
|
|
5
|
-
callData: string;
|
|
6
|
-
callGasLimit: string;
|
|
7
|
-
verificationGasLimit: string;
|
|
8
|
-
preVerificationGas: string;
|
|
9
|
-
maxFeePerGas: string;
|
|
10
|
-
maxPriorityFeePerGas: string;
|
|
11
|
-
paymasterAndData: string;
|
|
12
|
-
signature: string;
|
|
13
|
-
}
|
package/src/erc4337/userop.ts
DELETED
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
import type { UserOperation } from "./types";
|
|
2
|
-
|
|
3
|
-
export function buildUserOperation(params: {
|
|
4
|
-
sender: string;
|
|
5
|
-
callData: string;
|
|
6
|
-
nonce: string;
|
|
7
|
-
gas: {
|
|
8
|
-
callGasLimit: string;
|
|
9
|
-
verificationGasLimit: string;
|
|
10
|
-
preVerificationGas: string;
|
|
11
|
-
maxFeePerGas: string;
|
|
12
|
-
maxPriorityFeePerGas: string;
|
|
13
|
-
};
|
|
14
|
-
initCode?: string;
|
|
15
|
-
paymasterAndData?: string;
|
|
16
|
-
}): UserOperation {
|
|
17
|
-
return {
|
|
18
|
-
sender: params.sender,
|
|
19
|
-
nonce: params.nonce,
|
|
20
|
-
initCode: params.initCode ?? "0x",
|
|
21
|
-
callData: params.callData,
|
|
22
|
-
callGasLimit: params.gas.callGasLimit,
|
|
23
|
-
verificationGasLimit: params.gas.verificationGasLimit,
|
|
24
|
-
preVerificationGas: params.gas.preVerificationGas,
|
|
25
|
-
maxFeePerGas: params.gas.maxFeePerGas,
|
|
26
|
-
maxPriorityFeePerGas: params.gas.maxPriorityFeePerGas,
|
|
27
|
-
paymasterAndData: params.paymasterAndData ?? "0x",
|
|
28
|
-
signature: "0x" // signed later by smart account
|
|
29
|
-
};
|
|
30
|
-
}
|
package/src/evaluate.ts
DELETED
|
@@ -1,63 +0,0 @@
|
|
|
1
|
-
import type { RuleContext, RuleResult, RuleConfig } from "payid-types";
|
|
2
|
-
import { executeRule } from "payid-rule-engine";
|
|
3
|
-
import { normalizeContext } from "./normalize";
|
|
4
|
-
import { preprocessContextV2 } from "payid-rule-engine";
|
|
5
|
-
|
|
6
|
-
export async function evaluate(
|
|
7
|
-
wasmBinary: Buffer,
|
|
8
|
-
context: RuleContext,
|
|
9
|
-
ruleConfig: RuleConfig,
|
|
10
|
-
options?: {
|
|
11
|
-
trustedIssuers?: Set<string>;
|
|
12
|
-
}
|
|
13
|
-
): Promise<RuleResult> {
|
|
14
|
-
// ---- basic validation (v1 behavior) ----
|
|
15
|
-
if (!context || typeof context !== "object") {
|
|
16
|
-
throw new Error("evaluate(): context is required");
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
if (!context.tx) {
|
|
20
|
-
throw new Error("evaluate(): context.tx is required");
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
if (!ruleConfig || typeof ruleConfig !== "object") {
|
|
24
|
-
throw new Error("evaluate(): ruleConfig is required");
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
let result: RuleResult;
|
|
28
|
-
|
|
29
|
-
try {
|
|
30
|
-
// ---- NEW: preprocess v2 context if enabled ----
|
|
31
|
-
const preparedContext =
|
|
32
|
-
options?.trustedIssuers
|
|
33
|
-
? preprocessContextV2(context, ruleConfig, options.trustedIssuers)
|
|
34
|
-
: context;
|
|
35
|
-
|
|
36
|
-
// ---- existing normalization ----
|
|
37
|
-
const normalized = normalizeContext(preparedContext);
|
|
38
|
-
|
|
39
|
-
// ---- execute WASM rule engine ----
|
|
40
|
-
result = await executeRule(wasmBinary, normalized, ruleConfig);
|
|
41
|
-
} catch (err: any) {
|
|
42
|
-
return {
|
|
43
|
-
decision: "REJECT",
|
|
44
|
-
code: "CONTEXT_OR_ENGINE_ERROR",
|
|
45
|
-
reason: err?.message ?? "rule evaluation failed"
|
|
46
|
-
};
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
// ---- output validation ----
|
|
50
|
-
if (result.decision !== "ALLOW" && result.decision !== "REJECT") {
|
|
51
|
-
return {
|
|
52
|
-
decision: "REJECT",
|
|
53
|
-
code: "INVALID_ENGINE_OUTPUT",
|
|
54
|
-
reason: "invalid decision value"
|
|
55
|
-
};
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
return {
|
|
59
|
-
decision: result.decision,
|
|
60
|
-
code: result.code || "UNKNOWN",
|
|
61
|
-
reason: result.reason
|
|
62
|
-
};
|
|
63
|
-
}
|
package/src/index.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export { PayID } from "./payid";
|
package/src/normalize.ts
DELETED
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import type { RuleContext } from "payid-types";
|
|
2
|
-
|
|
3
|
-
export function normalizeContext(ctx: RuleContext): RuleContext {
|
|
4
|
-
return {
|
|
5
|
-
...ctx,
|
|
6
|
-
tx: {
|
|
7
|
-
...ctx.tx,
|
|
8
|
-
sender: ctx.tx.sender?.toLowerCase(),
|
|
9
|
-
receiver: ctx.tx.receiver?.toLowerCase(),
|
|
10
|
-
asset: ctx.tx.asset.toUpperCase()
|
|
11
|
-
}
|
|
12
|
-
};
|
|
13
|
-
}
|
package/src/payid.ts
DELETED
|
@@ -1,167 +0,0 @@
|
|
|
1
|
-
import type { RuleContext, RuleResult, RuleConfig } from "payid-types";
|
|
2
|
-
import { evaluate as evaluatePolicy } from "./evaluate";
|
|
3
|
-
import { generateDecisionProof } from "./decision-proof/generate";
|
|
4
|
-
import { resolveRule } from "./resolver/resolver";
|
|
5
|
-
import type { RuleSource } from "./resolver/types";
|
|
6
|
-
import { ethers } from "ethers";
|
|
7
|
-
import fs from "fs";
|
|
8
|
-
import type { UserOperation } from "./erc4337/types";
|
|
9
|
-
import { buildPayCallData } from "./erc4337/build";
|
|
10
|
-
import { buildUserOperation } from "./erc4337/userop";
|
|
11
|
-
|
|
12
|
-
export class PayID {
|
|
13
|
-
private wasm: Buffer;
|
|
14
|
-
|
|
15
|
-
constructor(wasmPath: string) {
|
|
16
|
-
this.wasm = fs.readFileSync(wasmPath);
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
async evaluate(
|
|
20
|
-
context: RuleContext,
|
|
21
|
-
ruleConfig: RuleConfig
|
|
22
|
-
): Promise<RuleResult> {
|
|
23
|
-
return evaluatePolicy(this.wasm, context, ruleConfig);
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
async evaluateAndProve(params: {
|
|
28
|
-
context: RuleContext;
|
|
29
|
-
ruleConfig: RuleConfig;
|
|
30
|
-
payId: string;
|
|
31
|
-
owner: string;
|
|
32
|
-
signer: ethers.Signer;
|
|
33
|
-
chainId: number;
|
|
34
|
-
verifyingContract: string;
|
|
35
|
-
ttlSeconds?: number;
|
|
36
|
-
}) {
|
|
37
|
-
const result = await this.evaluate(params.context, params.ruleConfig);
|
|
38
|
-
|
|
39
|
-
const proof = await generateDecisionProof({
|
|
40
|
-
payId: params.payId,
|
|
41
|
-
owner: params.owner,
|
|
42
|
-
decision: result.decision,
|
|
43
|
-
context: params.context,
|
|
44
|
-
ruleConfig: params.ruleConfig,
|
|
45
|
-
signer: params.signer,
|
|
46
|
-
chainId: params.chainId,
|
|
47
|
-
verifyingContract: params.verifyingContract,
|
|
48
|
-
ttlSeconds: params.ttlSeconds
|
|
49
|
-
});
|
|
50
|
-
|
|
51
|
-
return { result, proof };
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
async evaluateWithRuleSource(
|
|
55
|
-
context: RuleContext,
|
|
56
|
-
ruleSource: RuleSource
|
|
57
|
-
): Promise<RuleResult> {
|
|
58
|
-
try {
|
|
59
|
-
const { config } = await resolveRule(ruleSource);
|
|
60
|
-
return await this.evaluate(context, config);
|
|
61
|
-
} catch (err: any) {
|
|
62
|
-
return {
|
|
63
|
-
decision: "REJECT",
|
|
64
|
-
code: "RULE_RESOLVE_ERROR",
|
|
65
|
-
reason: err?.message ?? "failed to resolve rule"
|
|
66
|
-
};
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
async evaluateAndProveFromSource(params: {
|
|
71
|
-
context: RuleContext;
|
|
72
|
-
ruleSource: RuleSource;
|
|
73
|
-
payId: string;
|
|
74
|
-
owner: string;
|
|
75
|
-
signer: ethers.Signer;
|
|
76
|
-
chainId: number;
|
|
77
|
-
verifyingContract: string;
|
|
78
|
-
ttlSeconds?: number;
|
|
79
|
-
}) {
|
|
80
|
-
try {
|
|
81
|
-
const { config } = await resolveRule(params.ruleSource);
|
|
82
|
-
|
|
83
|
-
const result = await this.evaluate(params.context, config);
|
|
84
|
-
|
|
85
|
-
const proof = await generateDecisionProof({
|
|
86
|
-
payId: params.payId,
|
|
87
|
-
owner: params.owner,
|
|
88
|
-
decision: result.decision,
|
|
89
|
-
context: params.context,
|
|
90
|
-
ruleConfig: config,
|
|
91
|
-
signer: params.signer,
|
|
92
|
-
chainId: params.chainId,
|
|
93
|
-
verifyingContract: params.verifyingContract,
|
|
94
|
-
ttlSeconds: params.ttlSeconds
|
|
95
|
-
});
|
|
96
|
-
|
|
97
|
-
return { result, proof };
|
|
98
|
-
} catch (err: any) {
|
|
99
|
-
return {
|
|
100
|
-
result: {
|
|
101
|
-
decision: "REJECT",
|
|
102
|
-
code: "RULE_RESOLVE_ERROR",
|
|
103
|
-
reason: err?.message ?? "rule resolve failed"
|
|
104
|
-
},
|
|
105
|
-
proof: null
|
|
106
|
-
};
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
async evaluateProveAndBuildUserOp(params: {
|
|
111
|
-
context: RuleContext;
|
|
112
|
-
ruleSource: { uri: string; hash?: string; };
|
|
113
|
-
payId: string;
|
|
114
|
-
owner: string;
|
|
115
|
-
signer: ethers.Signer;
|
|
116
|
-
|
|
117
|
-
// ERC-4337 specific
|
|
118
|
-
smartAccount: string;
|
|
119
|
-
targetContract: string;
|
|
120
|
-
nonce: string;
|
|
121
|
-
gas: {
|
|
122
|
-
callGasLimit: string;
|
|
123
|
-
verificationGasLimit: string;
|
|
124
|
-
preVerificationGas: string;
|
|
125
|
-
maxFeePerGas: string;
|
|
126
|
-
maxPriorityFeePerGas: string;
|
|
127
|
-
};
|
|
128
|
-
paymasterAndData?: string;
|
|
129
|
-
|
|
130
|
-
chainId: number;
|
|
131
|
-
verifyingContract: string;
|
|
132
|
-
}): Promise<{
|
|
133
|
-
result: RuleResult;
|
|
134
|
-
userOp: UserOperation | null;
|
|
135
|
-
proof: any;
|
|
136
|
-
}> {
|
|
137
|
-
const { result, proof } =
|
|
138
|
-
await this.evaluateAndProveFromSource({
|
|
139
|
-
context: params.context,
|
|
140
|
-
ruleSource: params.ruleSource,
|
|
141
|
-
payId: params.payId,
|
|
142
|
-
owner: params.owner,
|
|
143
|
-
signer: params.signer,
|
|
144
|
-
chainId: params.chainId,
|
|
145
|
-
verifyingContract: params.verifyingContract
|
|
146
|
-
});
|
|
147
|
-
|
|
148
|
-
if (result.decision !== "ALLOW" || !proof) {
|
|
149
|
-
return { result: (result as any), userOp: null, proof };
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
const callData = buildPayCallData(
|
|
153
|
-
params.targetContract,
|
|
154
|
-
proof
|
|
155
|
-
);
|
|
156
|
-
|
|
157
|
-
const userOp = buildUserOperation({
|
|
158
|
-
sender: params.smartAccount,
|
|
159
|
-
nonce: params.nonce,
|
|
160
|
-
callData,
|
|
161
|
-
gas: params.gas,
|
|
162
|
-
paymasterAndData: params.paymasterAndData
|
|
163
|
-
});
|
|
164
|
-
|
|
165
|
-
return { result, userOp, proof };
|
|
166
|
-
}
|
|
167
|
-
}
|
package/src/resolver/http.ts
DELETED
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
import { verifyHash } from "./utils";
|
|
2
|
-
|
|
3
|
-
export async function resolveHttpRule(
|
|
4
|
-
uri: string,
|
|
5
|
-
expectedHash?: string
|
|
6
|
-
): Promise<any> {
|
|
7
|
-
const res = await fetch(uri);
|
|
8
|
-
if (!res.ok) {
|
|
9
|
-
throw new Error(`HTTP_RULE_FETCH_FAILED: ${res.status}`);
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
const text = await res.text();
|
|
13
|
-
verifyHash(text, expectedHash);
|
|
14
|
-
|
|
15
|
-
return JSON.parse(text);
|
|
16
|
-
}
|
package/src/resolver/ipfs.ts
DELETED
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
import { verifyHash } from "./utils";
|
|
2
|
-
|
|
3
|
-
const DEFAULT_GATEWAY = "https://ipfs.io/ipfs/";
|
|
4
|
-
|
|
5
|
-
export async function resolveIpfsRule(
|
|
6
|
-
uri: string,
|
|
7
|
-
expectedHash?: string,
|
|
8
|
-
gateway = DEFAULT_GATEWAY
|
|
9
|
-
): Promise<any> {
|
|
10
|
-
const cid = uri.replace("ipfs://", "");
|
|
11
|
-
const url = `${gateway}${cid}`;
|
|
12
|
-
|
|
13
|
-
const res = await fetch(url);
|
|
14
|
-
if (!res.ok) {
|
|
15
|
-
throw new Error(`IPFS_RULE_FETCH_FAILED: ${res.status}`);
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
const text = await res.text();
|
|
19
|
-
verifyHash(text, expectedHash);
|
|
20
|
-
|
|
21
|
-
return JSON.parse(text);
|
|
22
|
-
}
|
package/src/resolver/resolver.ts
DELETED
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
import type { RuleSource, ResolvedRule } from "./types";
|
|
2
|
-
import { resolveHttpRule } from "./http";
|
|
3
|
-
import { resolveIpfsRule } from "./ipfs";
|
|
4
|
-
|
|
5
|
-
export async function resolveRule(
|
|
6
|
-
source: RuleSource
|
|
7
|
-
): Promise<ResolvedRule> {
|
|
8
|
-
const { uri, hash } = source;
|
|
9
|
-
|
|
10
|
-
let config: any;
|
|
11
|
-
|
|
12
|
-
if (uri.startsWith("ipfs://")) {
|
|
13
|
-
config = await resolveIpfsRule(uri, hash);
|
|
14
|
-
} else if (uri.startsWith("http://") || uri.startsWith("https://")) {
|
|
15
|
-
config = await resolveHttpRule(uri, hash);
|
|
16
|
-
} else {
|
|
17
|
-
throw new Error("UNSUPPORTED_RULE_URI");
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
return {
|
|
21
|
-
config,
|
|
22
|
-
source
|
|
23
|
-
};
|
|
24
|
-
}
|
package/src/resolver/types.ts
DELETED
package/src/resolver/utils.ts
DELETED
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import { keccak256 } from "ethers";
|
|
2
|
-
|
|
3
|
-
export function verifyHash(
|
|
4
|
-
content: string,
|
|
5
|
-
expectedHash?: string
|
|
6
|
-
) {
|
|
7
|
-
if (!expectedHash) return;
|
|
8
|
-
|
|
9
|
-
const actual = keccak256(Buffer.from(content));
|
|
10
|
-
if (actual !== expectedHash) {
|
|
11
|
-
throw new Error("RULE_HASH_MISMATCH");
|
|
12
|
-
}
|
|
13
|
-
}
|
|
Binary file
|
package/tsconfig.json
DELETED
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"compilerOptions": {
|
|
3
|
-
// Environment setup & latest features
|
|
4
|
-
"lib": ["ESNext"],
|
|
5
|
-
"target": "ESNext",
|
|
6
|
-
"module": "Preserve",
|
|
7
|
-
"moduleDetection": "force",
|
|
8
|
-
"jsx": "react-jsx",
|
|
9
|
-
"allowJs": true,
|
|
10
|
-
|
|
11
|
-
// Bundler mode
|
|
12
|
-
"moduleResolution": "bundler",
|
|
13
|
-
"allowImportingTsExtensions": true,
|
|
14
|
-
"verbatimModuleSyntax": true,
|
|
15
|
-
"noEmit": true,
|
|
16
|
-
|
|
17
|
-
// Best practices
|
|
18
|
-
"strict": true,
|
|
19
|
-
"skipLibCheck": true,
|
|
20
|
-
"noFallthroughCasesInSwitch": true,
|
|
21
|
-
"noUncheckedIndexedAccess": true,
|
|
22
|
-
"noImplicitOverride": true,
|
|
23
|
-
|
|
24
|
-
// Some stricter flags (disabled by default)
|
|
25
|
-
"noUnusedLocals": false,
|
|
26
|
-
"noUnusedParameters": false,
|
|
27
|
-
"noPropertyAccessFromIndexSignature": false
|
|
28
|
-
}
|
|
29
|
-
}
|