@haneullabs/wallet-sdk 0.1.0 → 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/CHANGELOG.md +47 -18
- package/dist/auto-approvals/analyzer.d.mts +83 -0
- package/dist/auto-approvals/analyzer.d.mts.map +1 -0
- package/dist/auto-approvals/analyzer.mjs +43 -0
- package/dist/auto-approvals/analyzer.mjs.map +1 -0
- package/dist/auto-approvals/index.d.mts +6 -0
- package/dist/auto-approvals/intent.d.mts +9 -0
- package/dist/auto-approvals/intent.d.mts.map +1 -0
- package/dist/auto-approvals/intent.mjs +40 -0
- package/dist/auto-approvals/intent.mjs.map +1 -0
- package/dist/auto-approvals/manager.d.mts +38 -0
- package/dist/auto-approvals/manager.d.mts.map +1 -0
- package/dist/auto-approvals/manager.mjs +192 -0
- package/dist/auto-approvals/manager.mjs.map +1 -0
- package/dist/auto-approvals/schemas/index.d.mts +2 -0
- package/dist/auto-approvals/schemas/policy.d.mts +149 -0
- package/dist/auto-approvals/schemas/policy.d.mts.map +1 -0
- package/dist/auto-approvals/schemas/policy.mjs +49 -0
- package/dist/auto-approvals/schemas/policy.mjs.map +1 -0
- package/dist/auto-approvals/schemas/state.d.mts +115 -0
- package/dist/auto-approvals/schemas/state.d.mts.map +1 -0
- package/dist/auto-approvals/schemas/state.mjs +20 -0
- package/dist/auto-approvals/schemas/state.mjs.map +1 -0
- package/dist/index.d.mts +16 -0
- package/dist/index.mjs +9 -0
- package/dist/transaction-analyzer/analyzer.d.mts +39 -0
- package/dist/transaction-analyzer/analyzer.d.mts.map +1 -0
- package/dist/transaction-analyzer/analyzer.mjs +46 -0
- package/dist/transaction-analyzer/analyzer.mjs.map +1 -0
- package/dist/transaction-analyzer/index.d.mts +8 -0
- package/dist/transaction-analyzer/rules/accessLevel.mjs +65 -0
- package/dist/transaction-analyzer/rules/accessLevel.mjs.map +1 -0
- package/dist/transaction-analyzer/rules/coin-flows.d.mts +12 -0
- package/dist/transaction-analyzer/rules/coin-flows.d.mts.map +1 -0
- package/dist/transaction-analyzer/rules/coin-flows.mjs +122 -0
- package/dist/transaction-analyzer/rules/coin-flows.mjs.map +1 -0
- package/dist/transaction-analyzer/rules/coin-value.d.mts +25 -0
- package/dist/transaction-analyzer/rules/coin-value.d.mts.map +1 -0
- package/dist/transaction-analyzer/rules/coin-value.mjs +36 -0
- package/dist/transaction-analyzer/rules/coin-value.mjs.map +1 -0
- package/dist/transaction-analyzer/rules/coins.d.mts +12 -0
- package/dist/transaction-analyzer/rules/coins.d.mts.map +1 -0
- package/dist/transaction-analyzer/rules/coins.mjs +48 -0
- package/dist/transaction-analyzer/rules/coins.mjs.map +1 -0
- package/dist/transaction-analyzer/rules/commands.d.mts +79 -0
- package/dist/transaction-analyzer/rules/commands.d.mts.map +1 -0
- package/dist/transaction-analyzer/rules/commands.mjs +141 -0
- package/dist/transaction-analyzer/rules/commands.mjs.map +1 -0
- package/dist/transaction-analyzer/rules/core.mjs +48 -0
- package/dist/transaction-analyzer/rules/core.mjs.map +1 -0
- package/dist/transaction-analyzer/rules/functions.mjs +31 -0
- package/dist/transaction-analyzer/rules/functions.mjs.map +1 -0
- package/dist/transaction-analyzer/rules/index.d.mts +2125 -0
- package/dist/transaction-analyzer/rules/index.d.mts.map +1 -0
- package/dist/transaction-analyzer/rules/index.mjs +34 -0
- package/dist/transaction-analyzer/rules/index.mjs.map +1 -0
- package/dist/transaction-analyzer/rules/inputs.d.mts +20 -0
- package/dist/transaction-analyzer/rules/inputs.d.mts.map +1 -0
- package/dist/transaction-analyzer/rules/inputs.mjs +38 -0
- package/dist/transaction-analyzer/rules/inputs.mjs.map +1 -0
- package/dist/transaction-analyzer/rules/objects.d.mts +12 -0
- package/dist/transaction-analyzer/rules/objects.d.mts.map +1 -0
- package/dist/transaction-analyzer/rules/objects.mjs +92 -0
- package/dist/transaction-analyzer/rules/objects.mjs.map +1 -0
- package/dist/util.d.mts +7 -0
- package/dist/util.d.mts.map +1 -0
- package/package.json +27 -25
- package/dist/cjs/auto-approvals/analyzer.d.ts +0 -71
- package/dist/cjs/auto-approvals/analyzer.js +0 -70
- package/dist/cjs/auto-approvals/analyzer.js.map +0 -7
- package/dist/cjs/auto-approvals/index.d.ts +0 -6
- package/dist/cjs/auto-approvals/index.js +0 -33
- package/dist/cjs/auto-approvals/index.js.map +0 -7
- package/dist/cjs/auto-approvals/intent.d.ts +0 -5
- package/dist/cjs/auto-approvals/intent.js +0 -65
- package/dist/cjs/auto-approvals/intent.js.map +0 -7
- package/dist/cjs/auto-approvals/manager.d.ts +0 -31
- package/dist/cjs/auto-approvals/manager.js +0 -328
- package/dist/cjs/auto-approvals/manager.js.map +0 -7
- package/dist/cjs/auto-approvals/schemas/index.d.ts +0 -4
- package/dist/cjs/auto-approvals/schemas/index.js +0 -28
- package/dist/cjs/auto-approvals/schemas/index.js.map +0 -7
- package/dist/cjs/auto-approvals/schemas/policy.d.ts +0 -145
- package/dist/cjs/auto-approvals/schemas/policy.js +0 -79
- package/dist/cjs/auto-approvals/schemas/policy.js.map +0 -7
- package/dist/cjs/auto-approvals/schemas/state.d.ts +0 -115
- package/dist/cjs/auto-approvals/schemas/state.js +0 -49
- package/dist/cjs/auto-approvals/schemas/state.js.map +0 -7
- package/dist/cjs/index.d.ts +0 -2
- package/dist/cjs/index.js +0 -20
- package/dist/cjs/index.js.map +0 -7
- package/dist/cjs/package.json +0 -5
- package/dist/cjs/transaction-analyzer/analyzer.d.ts +0 -34
- package/dist/cjs/transaction-analyzer/analyzer.js +0 -94
- package/dist/cjs/transaction-analyzer/analyzer.js.map +0 -7
- package/dist/cjs/transaction-analyzer/index.d.ts +0 -9
- package/dist/cjs/transaction-analyzer/index.js +0 -28
- package/dist/cjs/transaction-analyzer/index.js.map +0 -7
- package/dist/cjs/transaction-analyzer/rules/accessLevel.d.ts +0 -29
- package/dist/cjs/transaction-analyzer/rules/accessLevel.js +0 -106
- package/dist/cjs/transaction-analyzer/rules/accessLevel.js.map +0 -7
- package/dist/cjs/transaction-analyzer/rules/coin-flows.d.ts +0 -313
- package/dist/cjs/transaction-analyzer/rules/coin-flows.js +0 -179
- package/dist/cjs/transaction-analyzer/rules/coin-flows.js.map +0 -7
- package/dist/cjs/transaction-analyzer/rules/coin-value.d.ts +0 -42
- package/dist/cjs/transaction-analyzer/rules/coin-value.js +0 -60
- package/dist/cjs/transaction-analyzer/rules/coin-value.js.map +0 -7
- package/dist/cjs/transaction-analyzer/rules/coins.d.ts +0 -337
- package/dist/cjs/transaction-analyzer/rules/coins.js +0 -78
- package/dist/cjs/transaction-analyzer/rules/coins.js.map +0 -7
- package/dist/cjs/transaction-analyzer/rules/commands.d.ts +0 -366
- package/dist/cjs/transaction-analyzer/rules/commands.js +0 -148
- package/dist/cjs/transaction-analyzer/rules/commands.js.map +0 -7
- package/dist/cjs/transaction-analyzer/rules/core.d.ts +0 -314
- package/dist/cjs/transaction-analyzer/rules/core.js +0 -73
- package/dist/cjs/transaction-analyzer/rules/core.js.map +0 -7
- package/dist/cjs/transaction-analyzer/rules/functions.d.ts +0 -292
- package/dist/cjs/transaction-analyzer/rules/functions.js +0 -58
- package/dist/cjs/transaction-analyzer/rules/functions.js.map +0 -7
- package/dist/cjs/transaction-analyzer/rules/index.d.ts +0 -2244
- package/dist/cjs/transaction-analyzer/rules/index.js +0 -52
- package/dist/cjs/transaction-analyzer/rules/index.js.map +0 -7
- package/dist/cjs/transaction-analyzer/rules/inputs.d.ts +0 -313
- package/dist/cjs/transaction-analyzer/rules/inputs.js +0 -49
- package/dist/cjs/transaction-analyzer/rules/inputs.js.map +0 -7
- package/dist/cjs/transaction-analyzer/rules/objects.d.ts +0 -359
- package/dist/cjs/transaction-analyzer/rules/objects.js +0 -124
- package/dist/cjs/transaction-analyzer/rules/objects.js.map +0 -7
- package/dist/cjs/util.d.ts +0 -5
- package/dist/cjs/util.js +0 -17
- package/dist/cjs/util.js.map +0 -7
- package/dist/esm/auto-approvals/analyzer.d.ts +0 -71
- package/dist/esm/auto-approvals/analyzer.js +0 -50
- package/dist/esm/auto-approvals/analyzer.js.map +0 -7
- package/dist/esm/auto-approvals/index.d.ts +0 -6
- package/dist/esm/auto-approvals/index.js +0 -12
- package/dist/esm/auto-approvals/index.js.map +0 -7
- package/dist/esm/auto-approvals/intent.d.ts +0 -5
- package/dist/esm/auto-approvals/intent.js +0 -45
- package/dist/esm/auto-approvals/intent.js.map +0 -7
- package/dist/esm/auto-approvals/manager.d.ts +0 -31
- package/dist/esm/auto-approvals/manager.js +0 -308
- package/dist/esm/auto-approvals/manager.js.map +0 -7
- package/dist/esm/auto-approvals/schemas/index.d.ts +0 -4
- package/dist/esm/auto-approvals/schemas/index.js +0 -8
- package/dist/esm/auto-approvals/schemas/index.js.map +0 -7
- package/dist/esm/auto-approvals/schemas/policy.d.ts +0 -145
- package/dist/esm/auto-approvals/schemas/policy.js +0 -49
- package/dist/esm/auto-approvals/schemas/policy.js.map +0 -7
- package/dist/esm/auto-approvals/schemas/state.d.ts +0 -115
- package/dist/esm/auto-approvals/schemas/state.js +0 -19
- package/dist/esm/auto-approvals/schemas/state.js.map +0 -7
- package/dist/esm/index.d.ts +0 -2
- package/dist/esm/index.js +0 -3
- package/dist/esm/index.js.map +0 -7
- package/dist/esm/package.json +0 -5
- package/dist/esm/transaction-analyzer/analyzer.d.ts +0 -34
- package/dist/esm/transaction-analyzer/analyzer.js +0 -74
- package/dist/esm/transaction-analyzer/analyzer.js.map +0 -7
- package/dist/esm/transaction-analyzer/index.d.ts +0 -9
- package/dist/esm/transaction-analyzer/index.js +0 -8
- package/dist/esm/transaction-analyzer/index.js.map +0 -7
- package/dist/esm/transaction-analyzer/rules/accessLevel.d.ts +0 -29
- package/dist/esm/transaction-analyzer/rules/accessLevel.js +0 -86
- package/dist/esm/transaction-analyzer/rules/accessLevel.js.map +0 -7
- package/dist/esm/transaction-analyzer/rules/coin-flows.d.ts +0 -313
- package/dist/esm/transaction-analyzer/rules/coin-flows.js +0 -159
- package/dist/esm/transaction-analyzer/rules/coin-flows.js.map +0 -7
- package/dist/esm/transaction-analyzer/rules/coin-value.d.ts +0 -42
- package/dist/esm/transaction-analyzer/rules/coin-value.js +0 -40
- package/dist/esm/transaction-analyzer/rules/coin-value.js.map +0 -7
- package/dist/esm/transaction-analyzer/rules/coins.d.ts +0 -337
- package/dist/esm/transaction-analyzer/rules/coins.js +0 -58
- package/dist/esm/transaction-analyzer/rules/coins.js.map +0 -7
- package/dist/esm/transaction-analyzer/rules/commands.d.ts +0 -366
- package/dist/esm/transaction-analyzer/rules/commands.js +0 -128
- package/dist/esm/transaction-analyzer/rules/commands.js.map +0 -7
- package/dist/esm/transaction-analyzer/rules/core.d.ts +0 -314
- package/dist/esm/transaction-analyzer/rules/core.js +0 -53
- package/dist/esm/transaction-analyzer/rules/core.js.map +0 -7
- package/dist/esm/transaction-analyzer/rules/functions.d.ts +0 -292
- package/dist/esm/transaction-analyzer/rules/functions.js +0 -38
- package/dist/esm/transaction-analyzer/rules/functions.js.map +0 -7
- package/dist/esm/transaction-analyzer/rules/index.d.ts +0 -2244
- package/dist/esm/transaction-analyzer/rules/index.js +0 -32
- package/dist/esm/transaction-analyzer/rules/index.js.map +0 -7
- package/dist/esm/transaction-analyzer/rules/inputs.d.ts +0 -313
- package/dist/esm/transaction-analyzer/rules/inputs.js +0 -29
- package/dist/esm/transaction-analyzer/rules/inputs.js.map +0 -7
- package/dist/esm/transaction-analyzer/rules/objects.d.ts +0 -359
- package/dist/esm/transaction-analyzer/rules/objects.js +0 -104
- package/dist/esm/transaction-analyzer/rules/objects.js.map +0 -7
- package/dist/esm/util.d.ts +0 -5
- package/dist/esm/util.js +0 -1
- package/dist/esm/util.js.map +0 -7
- package/dist/tsconfig.esm.tsbuildinfo +0 -1
- package/dist/tsconfig.tsbuildinfo +0 -1
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import { createAnalyzer } from "../analyzer.mjs";
|
|
2
|
+
import { data } from "./core.mjs";
|
|
3
|
+
import { coins, gasCoins } from "./coins.mjs";
|
|
4
|
+
import { inputs } from "./inputs.mjs";
|
|
5
|
+
import { commands } from "./commands.mjs";
|
|
6
|
+
import { bcs } from "@haneullabs/haneul/bcs";
|
|
7
|
+
import { normalizeStructTag } from "@haneullabs/haneul/utils";
|
|
8
|
+
|
|
9
|
+
//#region src/transaction-analyzer/rules/coin-flows.ts
|
|
10
|
+
const coinFlows = createAnalyzer({
|
|
11
|
+
dependencies: {
|
|
12
|
+
data,
|
|
13
|
+
commands,
|
|
14
|
+
inputs,
|
|
15
|
+
coins,
|
|
16
|
+
gasCoins
|
|
17
|
+
},
|
|
18
|
+
analyze: () => async ({ data: data$1, commands: commands$1, inputs: inputs$1, coins: coins$1, gasCoins: gasCoins$1 }) => {
|
|
19
|
+
const getTrackedCoin = (ref) => {
|
|
20
|
+
switch (ref.$kind) {
|
|
21
|
+
case "GasCoin": return trackedCoins.get("gas") ?? null;
|
|
22
|
+
case "Object": return trackedCoins.get(`input:${ref.index}`) ?? null;
|
|
23
|
+
case "Result": return trackedCoins.get(`result:${ref.index[0]},${ref.index[1]}`) ?? null;
|
|
24
|
+
case "Unknown":
|
|
25
|
+
case "Pure": return null;
|
|
26
|
+
}
|
|
27
|
+
};
|
|
28
|
+
const splitCoin = (command) => {
|
|
29
|
+
const coin = getTrackedCoin(command.coin);
|
|
30
|
+
if (!coin) return;
|
|
31
|
+
if (!command.amounts.every((a) => a.$kind === "Pure")) {
|
|
32
|
+
coin.consume();
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
const amounts = command.amounts.map((a) => {
|
|
36
|
+
if (a.$kind !== "Pure") throw new Error("Expected pure value");
|
|
37
|
+
return BigInt(bcs.u64().fromBase64(a.bytes));
|
|
38
|
+
});
|
|
39
|
+
coin.remainingBalance -= amounts.reduce((a, b) => a + b, 0n);
|
|
40
|
+
amounts.forEach((amount, i) => {
|
|
41
|
+
trackedCoins.set(`result:${command.index},${i}`, new TrackedCoin(coin.coinType, amount, false));
|
|
42
|
+
});
|
|
43
|
+
};
|
|
44
|
+
const mergeCoins = (command) => {
|
|
45
|
+
const sources = command.sources.map(getTrackedCoin);
|
|
46
|
+
const amount = sources.reduce((a, c) => a + (c?.remainingBalance ?? 0n), 0n);
|
|
47
|
+
for (const src of sources) src?.consume();
|
|
48
|
+
const dest = getTrackedCoin(command.destination);
|
|
49
|
+
if (!dest) return;
|
|
50
|
+
dest.remainingBalance += amount;
|
|
51
|
+
};
|
|
52
|
+
const transferObjects = (command) => {
|
|
53
|
+
const address = command.address.$kind === "Pure" ? bcs.Address.fromBase64(command.address.bytes) : null;
|
|
54
|
+
for (const obj of command.objects) {
|
|
55
|
+
const tracked = getTrackedCoin(obj);
|
|
56
|
+
if (tracked && address && data$1.sender === address) trackedCoins.get("gas").remainingBalance += tracked.remainingBalance;
|
|
57
|
+
tracked?.consume();
|
|
58
|
+
}
|
|
59
|
+
};
|
|
60
|
+
const issues = [];
|
|
61
|
+
const trackedCoins = /* @__PURE__ */ new Map();
|
|
62
|
+
trackedCoins.set("gas", new TrackedCoin(normalizeStructTag("0x2::haneul::HANEUL"), gasCoins$1.reduce((a, c) => a + c.balance, 0n), true));
|
|
63
|
+
if (data$1.gasData.budget) trackedCoins.get("gas").remainingBalance -= BigInt(data$1.gasData.budget);
|
|
64
|
+
else issues.push({ message: "Gas budget not set in Transaction" });
|
|
65
|
+
for (const input of inputs$1) if (input.$kind === "Object" && coins$1[input.object.objectId]) {
|
|
66
|
+
const coin = coins$1[input.object.objectId];
|
|
67
|
+
trackedCoins.set(`input:${input.index}`, new TrackedCoin(coin.coinType, coin.balance, true));
|
|
68
|
+
}
|
|
69
|
+
for (const command of commands$1) switch (command.$kind) {
|
|
70
|
+
case "SplitCoins":
|
|
71
|
+
splitCoin(command);
|
|
72
|
+
break;
|
|
73
|
+
case "MergeCoins":
|
|
74
|
+
mergeCoins(command);
|
|
75
|
+
break;
|
|
76
|
+
case "TransferObjects":
|
|
77
|
+
transferObjects(command);
|
|
78
|
+
break;
|
|
79
|
+
case "MakeMoveVec":
|
|
80
|
+
command.elements.forEach((el) => {
|
|
81
|
+
getTrackedCoin(el)?.consume();
|
|
82
|
+
});
|
|
83
|
+
break;
|
|
84
|
+
case "MoveCall":
|
|
85
|
+
command.arguments.forEach((arg) => {
|
|
86
|
+
getTrackedCoin(arg)?.consume();
|
|
87
|
+
});
|
|
88
|
+
break;
|
|
89
|
+
case "Upgrade":
|
|
90
|
+
case "Publish": break;
|
|
91
|
+
default: throw new Error(`Unsupported command type: ${command.$kind}`);
|
|
92
|
+
}
|
|
93
|
+
const outflows = {};
|
|
94
|
+
for (const coin of trackedCoins.values()) {
|
|
95
|
+
if (!coin.owned) continue;
|
|
96
|
+
if (!outflows[coin.coinType]) outflows[coin.coinType] = {
|
|
97
|
+
coinType: coin.coinType,
|
|
98
|
+
amount: 0n
|
|
99
|
+
};
|
|
100
|
+
outflows[coin.coinType].amount += coin.initialBalance - coin.remainingBalance;
|
|
101
|
+
}
|
|
102
|
+
if (issues.length) return { issues };
|
|
103
|
+
return { result: { outflows: Object.values(outflows) } };
|
|
104
|
+
}
|
|
105
|
+
});
|
|
106
|
+
var TrackedCoin = class {
|
|
107
|
+
constructor(coinType, balance, owned) {
|
|
108
|
+
this.consumed = false;
|
|
109
|
+
this.coinType = coinType;
|
|
110
|
+
this.initialBalance = balance;
|
|
111
|
+
this.remainingBalance = balance;
|
|
112
|
+
this.owned = owned;
|
|
113
|
+
}
|
|
114
|
+
consume() {
|
|
115
|
+
this.remainingBalance = 0n;
|
|
116
|
+
this.consumed = true;
|
|
117
|
+
}
|
|
118
|
+
};
|
|
119
|
+
|
|
120
|
+
//#endregion
|
|
121
|
+
export { coinFlows };
|
|
122
|
+
//# sourceMappingURL=coin-flows.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"coin-flows.mjs","names":["data","gasCoins","inputs","coins","commands"],"sources":["../../../src/transaction-analyzer/rules/coin-flows.ts"],"sourcesContent":["// Copyright (c) Mysten Labs, Inc.\n// SPDX-License-Identifier: Apache-2.0\n\nimport { normalizeStructTag } from '@haneullabs/haneul/utils';\nimport type { TransactionAnalysisIssue } from '../analyzer.js';\nimport { createAnalyzer } from '../analyzer.js';\nimport { bcs } from '@haneullabs/haneul/bcs';\nimport { commands } from './commands.js';\nimport type { AnalyzedCommand, AnalyzedCommandArgument } from './commands.js';\nimport { data } from './core.js';\nimport { inputs } from './inputs.js';\nimport { coins, gasCoins } from './coins.js';\n\nexport interface CoinFlow {\n\tcoinType: string;\n\tamount: bigint;\n}\n\nexport const coinFlows = createAnalyzer({\n\tdependencies: { data, commands, inputs, coins, gasCoins },\n\tanalyze:\n\t\t() =>\n\t\tasync ({ data, commands, inputs, coins, gasCoins }) => {\n\t\t\tconst getTrackedCoin = (ref: AnalyzedCommandArgument): TrackedCoin | null => {\n\t\t\t\tswitch (ref.$kind) {\n\t\t\t\t\tcase 'GasCoin':\n\t\t\t\t\t\treturn trackedCoins.get('gas') ?? null;\n\t\t\t\t\tcase 'Object':\n\t\t\t\t\t\treturn trackedCoins.get(`input:${ref.index}`) ?? null;\n\t\t\t\t\tcase 'Result':\n\t\t\t\t\t\treturn trackedCoins.get(`result:${ref.index[0]},${ref.index[1]}`) ?? null;\n\t\t\t\t\tcase 'Unknown':\n\t\t\t\t\tcase 'Pure':\n\t\t\t\t\t\treturn null;\n\t\t\t\t}\n\t\t\t};\n\n\t\t\tconst splitCoin = (command: Extract<AnalyzedCommand, { $kind: 'SplitCoins' }>) => {\n\t\t\t\tconst coin = getTrackedCoin(command.coin);\n\n\t\t\t\tif (!coin) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\t// If any amounts are dynamic we need to assume the coin is fully consumed\n\t\t\t\tif (!command.amounts.every((a) => a.$kind === 'Pure')) {\n\t\t\t\t\tcoin.consume();\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tconst amounts = command.amounts.map((a) => {\n\t\t\t\t\tif (a.$kind !== 'Pure') {\n\t\t\t\t\t\tthrow new Error('Expected pure value');\n\t\t\t\t\t}\n\t\t\t\t\treturn BigInt(bcs.u64().fromBase64(a.bytes));\n\t\t\t\t});\n\n\t\t\t\tcoin.remainingBalance -= amounts.reduce((a, b) => a + b, 0n);\n\n\t\t\t\tamounts.forEach((amount, i) => {\n\t\t\t\t\ttrackedCoins.set(\n\t\t\t\t\t\t`result:${command.index},${i}`,\n\t\t\t\t\t\tnew TrackedCoin(coin.coinType, amount, false),\n\t\t\t\t\t);\n\t\t\t\t});\n\t\t\t};\n\n\t\t\tconst mergeCoins = (command: Extract<AnalyzedCommand, { $kind: 'MergeCoins' }>) => {\n\t\t\t\tconst sources = command.sources.map(getTrackedCoin);\n\t\t\t\tconst amount = sources.reduce((a, c) => a + (c?.remainingBalance ?? 0n), 0n);\n\n\t\t\t\tfor (const src of sources) {\n\t\t\t\t\tsrc?.consume();\n\t\t\t\t}\n\n\t\t\t\tconst dest = getTrackedCoin(command.destination);\n\n\t\t\t\tif (!dest) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tdest.remainingBalance += amount;\n\t\t\t};\n\n\t\t\tconst transferObjects = (command: Extract<AnalyzedCommand, { $kind: 'TransferObjects' }>) => {\n\t\t\t\tconst address =\n\t\t\t\t\tcommand.address.$kind === 'Pure' ? bcs.Address.fromBase64(command.address.bytes) : null;\n\n\t\t\t\tfor (const obj of command.objects) {\n\t\t\t\t\tconst tracked = getTrackedCoin(obj);\n\n\t\t\t\t\t// If coin is transferred to the sender, we can track the transfer in the gas coin\n\t\t\t\t\tif (tracked && address && data.sender === address) {\n\t\t\t\t\t\ttrackedCoins.get('gas')!.remainingBalance += tracked.remainingBalance;\n\t\t\t\t\t}\n\n\t\t\t\t\ttracked?.consume();\n\t\t\t\t}\n\t\t\t};\n\n\t\t\tconst issues: TransactionAnalysisIssue[] = [];\n\n\t\t\tconst trackedCoins = new Map<string, TrackedCoin>();\n\n\t\t\ttrackedCoins.set(\n\t\t\t\t'gas',\n\t\t\t\tnew TrackedCoin(\n\t\t\t\t\tnormalizeStructTag('0x2::haneul::HANEUL'),\n\t\t\t\t\tgasCoins.reduce((a, c) => a + c.balance, 0n),\n\t\t\t\t\ttrue,\n\t\t\t\t),\n\t\t\t);\n\n\t\t\tif (data.gasData.budget) {\n\t\t\t\ttrackedCoins.get('gas')!.remainingBalance -= BigInt(data.gasData.budget);\n\t\t\t} else {\n\t\t\t\tissues.push({ message: 'Gas budget not set in Transaction' });\n\t\t\t}\n\n\t\t\tfor (const input of inputs) {\n\t\t\t\tif (input.$kind === 'Object' && coins[input.object.objectId]) {\n\t\t\t\t\tconst coin = coins[input.object.objectId];\n\t\t\t\t\ttrackedCoins.set(\n\t\t\t\t\t\t`input:${input.index}`,\n\t\t\t\t\t\tnew TrackedCoin(coin.coinType, coin.balance, true),\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tfor (const command of commands) {\n\t\t\t\tswitch (command.$kind) {\n\t\t\t\t\tcase 'SplitCoins':\n\t\t\t\t\t\tsplitCoin(command);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 'MergeCoins':\n\t\t\t\t\t\tmergeCoins(command);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 'TransferObjects':\n\t\t\t\t\t\ttransferObjects(command);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 'MakeMoveVec':\n\t\t\t\t\t\tcommand.elements.forEach((el) => {\n\t\t\t\t\t\t\tconst tracked = getTrackedCoin(el);\n\t\t\t\t\t\t\ttracked?.consume();\n\t\t\t\t\t\t});\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 'MoveCall':\n\t\t\t\t\t\tcommand.arguments.forEach((arg) => {\n\t\t\t\t\t\t\tconst tracked = getTrackedCoin(arg);\n\t\t\t\t\t\t\ttracked?.consume();\n\t\t\t\t\t\t});\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 'Upgrade':\n\t\t\t\t\tcase 'Publish':\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tdefault:\n\t\t\t\t\t\tthrow new Error(`Unsupported command type: ${command.$kind}`);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tconst outflows: Record<string, CoinFlow> = {};\n\n\t\t\tfor (const coin of trackedCoins.values()) {\n\t\t\t\tif (!coin.owned) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tif (!outflows[coin.coinType]) {\n\t\t\t\t\toutflows[coin.coinType] = { coinType: coin.coinType, amount: 0n };\n\t\t\t\t}\n\n\t\t\t\toutflows[coin.coinType].amount += coin.initialBalance - coin.remainingBalance;\n\t\t\t}\n\n\t\t\tif (issues.length) {\n\t\t\t\treturn { issues };\n\t\t\t}\n\n\t\t\treturn {\n\t\t\t\tresult: {\n\t\t\t\t\toutflows: Object.values(outflows),\n\t\t\t\t},\n\t\t\t};\n\t\t},\n});\n\nclass TrackedCoin {\n\tcoinType: string;\n\tinitialBalance: bigint;\n\tremainingBalance: bigint;\n\towned: boolean;\n\tconsumed = false;\n\n\tconstructor(coinType: string, balance: bigint, owned: boolean) {\n\t\tthis.coinType = coinType;\n\t\tthis.initialBalance = balance;\n\t\tthis.remainingBalance = balance;\n\t\tthis.owned = owned;\n\t}\n\n\tconsume() {\n\t\tthis.remainingBalance = 0n;\n\t\tthis.consumed = true;\n\t}\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import "../analyzer.mjs";
|
|
2
|
+
import "./coin-flows.mjs";
|
|
3
|
+
|
|
4
|
+
//#region src/transaction-analyzer/rules/coin-value.d.ts
|
|
5
|
+
interface CoinValueAnalyzerOptions {
|
|
6
|
+
getCoinPrices: (coinTypes: string[]) => Promise<{
|
|
7
|
+
coinType: string;
|
|
8
|
+
decimals: number;
|
|
9
|
+
price: number | null;
|
|
10
|
+
}[]>;
|
|
11
|
+
}
|
|
12
|
+
interface CoinValueAnalysis {
|
|
13
|
+
coinTypesWithoutPrice: string[];
|
|
14
|
+
total: number;
|
|
15
|
+
coinTypes: {
|
|
16
|
+
coinType: string;
|
|
17
|
+
decimals: number;
|
|
18
|
+
price: number;
|
|
19
|
+
amount: bigint;
|
|
20
|
+
convertedAmount: number;
|
|
21
|
+
}[];
|
|
22
|
+
}
|
|
23
|
+
//#endregion
|
|
24
|
+
export { CoinValueAnalysis, CoinValueAnalyzerOptions };
|
|
25
|
+
//# sourceMappingURL=coin-value.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"coin-value.d.mts","names":[],"sources":["../../../src/transaction-analyzer/rules/coin-value.ts"],"sourcesContent":[],"mappings":";;;;UAMiB,wBAAA;0CACwB;;;IADxB,KAAA,EAAA,MAAA,GAAA,IAAA;EAUA,CAAA,EAAA,CAAA;;UAAA,iBAAA"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { createAnalyzer } from "../analyzer.mjs";
|
|
2
|
+
import { coinFlows } from "./coin-flows.mjs";
|
|
3
|
+
|
|
4
|
+
//#region src/transaction-analyzer/rules/coin-value.ts
|
|
5
|
+
const coinValues = createAnalyzer({
|
|
6
|
+
dependencies: { coinFlows },
|
|
7
|
+
analyze: ({ getCoinPrices }) => async ({ coinFlows: coinFlows$1 }) => {
|
|
8
|
+
const prices = await getCoinPrices(coinFlows$1.outflows.map((cf) => cf.coinType));
|
|
9
|
+
let total = 0;
|
|
10
|
+
const coinTypesWithoutPrice = [];
|
|
11
|
+
const coinTypes = [];
|
|
12
|
+
for (const flow of coinFlows$1.outflows) if (flow.amount > 0n) {
|
|
13
|
+
const result = prices.find((p) => p.coinType === flow.coinType);
|
|
14
|
+
if (result?.price != null) {
|
|
15
|
+
const amount = Number(flow.amount) / 10 ** result.decimals * result.price;
|
|
16
|
+
total += amount;
|
|
17
|
+
coinTypes.push({
|
|
18
|
+
coinType: flow.coinType,
|
|
19
|
+
decimals: result.decimals,
|
|
20
|
+
price: result.price,
|
|
21
|
+
amount: flow.amount,
|
|
22
|
+
convertedAmount: amount
|
|
23
|
+
});
|
|
24
|
+
} else coinTypesWithoutPrice.push(flow.coinType);
|
|
25
|
+
}
|
|
26
|
+
return { result: {
|
|
27
|
+
total,
|
|
28
|
+
coinTypesWithoutPrice,
|
|
29
|
+
coinTypes
|
|
30
|
+
} };
|
|
31
|
+
}
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
//#endregion
|
|
35
|
+
export { coinValues };
|
|
36
|
+
//# sourceMappingURL=coin-value.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"coin-value.mjs","names":["coinFlows"],"sources":["../../../src/transaction-analyzer/rules/coin-value.ts"],"sourcesContent":["// Copyright (c) Mysten Labs, Inc.\n// SPDX-License-Identifier: Apache-2.0\n\nimport { createAnalyzer } from '../analyzer.js';\nimport { coinFlows } from './coin-flows.js';\n\nexport interface CoinValueAnalyzerOptions {\n\tgetCoinPrices: (coinTypes: string[]) => Promise<\n\t\t{\n\t\t\tcoinType: string;\n\t\t\tdecimals: number;\n\t\t\tprice: number | null;\n\t\t}[]\n\t>;\n}\n\nexport interface CoinValueAnalysis {\n\tcoinTypesWithoutPrice: string[];\n\ttotal: number;\n\tcoinTypes: {\n\t\tcoinType: string;\n\t\tdecimals: number;\n\t\tprice: number;\n\t\tamount: bigint;\n\t\tconvertedAmount: number;\n\t}[];\n}\n\nexport const coinValues = createAnalyzer({\n\tdependencies: { coinFlows },\n\tanalyze:\n\t\t({ getCoinPrices }: CoinValueAnalyzerOptions) =>\n\t\tasync ({ coinFlows }) => {\n\t\t\tconst prices = await getCoinPrices(coinFlows.outflows.map((cf) => cf.coinType));\n\n\t\t\tlet total = 0;\n\t\t\tconst coinTypesWithoutPrice: string[] = [];\n\n\t\t\tconst coinTypes: {\n\t\t\t\tcoinType: string;\n\t\t\t\tdecimals: number;\n\t\t\t\tprice: number;\n\t\t\t\tamount: bigint;\n\t\t\t\tconvertedAmount: number;\n\t\t\t}[] = [];\n\n\t\t\tfor (const flow of coinFlows.outflows) {\n\t\t\t\tif (flow.amount > 0n) {\n\t\t\t\t\tconst result = prices.find((p) => p.coinType === flow.coinType);\n\n\t\t\t\t\tif (result?.price != null) {\n\t\t\t\t\t\tconst amount = (Number(flow.amount) / 10 ** result.decimals) * result.price;\n\t\t\t\t\t\ttotal += amount;\n\t\t\t\t\t\tcoinTypes.push({\n\t\t\t\t\t\t\tcoinType: flow.coinType,\n\t\t\t\t\t\t\tdecimals: result.decimals,\n\t\t\t\t\t\t\tprice: result.price,\n\t\t\t\t\t\t\tamount: flow.amount,\n\t\t\t\t\t\t\tconvertedAmount: amount,\n\t\t\t\t\t\t});\n\t\t\t\t\t} else {\n\t\t\t\t\t\tcoinTypesWithoutPrice.push(flow.coinType);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn {\n\t\t\t\tresult: {\n\t\t\t\t\ttotal: total,\n\t\t\t\t\tcoinTypesWithoutPrice,\n\t\t\t\t\tcoinTypes: coinTypes,\n\t\t\t\t},\n\t\t\t};\n\t\t},\n});\n"],"mappings":";;;;AA4BA,MAAa,aAAa,eAAe;CACxC,cAAc,EAAE,WAAW;CAC3B,UACE,EAAE,oBACH,OAAO,EAAE,6BAAgB;EACxB,MAAM,SAAS,MAAM,cAAcA,YAAU,SAAS,KAAK,OAAO,GAAG,SAAS,CAAC;EAE/E,IAAI,QAAQ;EACZ,MAAM,wBAAkC,EAAE;EAE1C,MAAM,YAMA,EAAE;AAER,OAAK,MAAM,QAAQA,YAAU,SAC5B,KAAI,KAAK,SAAS,IAAI;GACrB,MAAM,SAAS,OAAO,MAAM,MAAM,EAAE,aAAa,KAAK,SAAS;AAE/D,OAAI,QAAQ,SAAS,MAAM;IAC1B,MAAM,SAAU,OAAO,KAAK,OAAO,GAAG,MAAM,OAAO,WAAY,OAAO;AACtE,aAAS;AACT,cAAU,KAAK;KACd,UAAU,KAAK;KACf,UAAU,OAAO;KACjB,OAAO,OAAO;KACd,QAAQ,KAAK;KACb,iBAAiB;KACjB,CAAC;SAEF,uBAAsB,KAAK,KAAK,SAAS;;AAK5C,SAAO,EACN,QAAQ;GACA;GACP;GACW;GACX,EACD;;CAEH,CAAC"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import "../analyzer.mjs";
|
|
2
|
+
import { AnalyzedObject } from "./objects.mjs";
|
|
3
|
+
import "@haneullabs/haneul/bcs";
|
|
4
|
+
|
|
5
|
+
//#region src/transaction-analyzer/rules/coins.d.ts
|
|
6
|
+
type AnalyzedCoin = AnalyzedObject & {
|
|
7
|
+
balance: bigint;
|
|
8
|
+
coinType: string;
|
|
9
|
+
};
|
|
10
|
+
//#endregion
|
|
11
|
+
export { AnalyzedCoin };
|
|
12
|
+
//# sourceMappingURL=coins.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"coins.d.mts","names":[],"sources":["../../../src/transaction-analyzer/rules/coins.ts"],"sourcesContent":[],"mappings":";;;;;KAUY,YAAA,GAAe"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { createAnalyzer } from "../analyzer.mjs";
|
|
2
|
+
import { data } from "./core.mjs";
|
|
3
|
+
import { objects, objectsById } from "./objects.mjs";
|
|
4
|
+
import { bcs } from "@haneullabs/haneul/bcs";
|
|
5
|
+
import { normalizeStructTag, parseStructTag } from "@haneullabs/haneul/utils";
|
|
6
|
+
|
|
7
|
+
//#region src/transaction-analyzer/rules/coins.ts
|
|
8
|
+
const Coin = bcs.struct("Coin", {
|
|
9
|
+
id: bcs.Address,
|
|
10
|
+
balance: bcs.U64
|
|
11
|
+
});
|
|
12
|
+
const parsedCoinStruct = parseStructTag("0x2::coin::Coin<0x2::haneul::HANEUL>");
|
|
13
|
+
const coins = createAnalyzer({
|
|
14
|
+
dependencies: { objects },
|
|
15
|
+
analyze: () => async ({ objects: objects$1 }) => {
|
|
16
|
+
return { result: Object.fromEntries(await Promise.all(objects$1.filter((obj) => {
|
|
17
|
+
const parsed = parseStructTag(obj.type);
|
|
18
|
+
return parsed.address === parsedCoinStruct.address && parsed.module === parsedCoinStruct.module && parsed.name === parsedCoinStruct.name && parsed.typeParams.length === 1;
|
|
19
|
+
}).map(async (obj) => {
|
|
20
|
+
return [obj.objectId, {
|
|
21
|
+
...obj,
|
|
22
|
+
coinType: normalizeStructTag(parseStructTag(obj.type).typeParams[0]),
|
|
23
|
+
balance: BigInt(Coin.parse(obj.content).balance)
|
|
24
|
+
}];
|
|
25
|
+
}))) };
|
|
26
|
+
}
|
|
27
|
+
});
|
|
28
|
+
const gasCoins = createAnalyzer({
|
|
29
|
+
dependencies: {
|
|
30
|
+
objectsById,
|
|
31
|
+
data
|
|
32
|
+
},
|
|
33
|
+
analyze: () => async ({ objectsById: objectsById$1, data: data$1 }) => {
|
|
34
|
+
return { result: await Promise.all((data$1.gasData.payment ?? []).map(async (coin) => {
|
|
35
|
+
const obj = objectsById$1.get(coin.objectId);
|
|
36
|
+
const content = Coin.parse(obj.content);
|
|
37
|
+
return {
|
|
38
|
+
...obj,
|
|
39
|
+
coinType: normalizeStructTag(parseStructTag(obj.type).typeParams[0]),
|
|
40
|
+
balance: BigInt(content.balance)
|
|
41
|
+
};
|
|
42
|
+
})) };
|
|
43
|
+
}
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
//#endregion
|
|
47
|
+
export { coins, gasCoins };
|
|
48
|
+
//# sourceMappingURL=coins.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"coins.mjs","names":["objects","data","objectsById"],"sources":["../../../src/transaction-analyzer/rules/coins.ts"],"sourcesContent":["// Copyright (c) Mysten Labs, Inc.\n// SPDX-License-Identifier: Apache-2.0\n\nimport { bcs } from '@haneullabs/haneul/bcs';\nimport { objects, objectsById } from './objects.js';\nimport type { AnalyzedObject } from './objects.js';\nimport { createAnalyzer } from '../analyzer.js';\nimport { normalizeStructTag, parseStructTag } from '@haneullabs/haneul/utils';\nimport { data } from './core.js';\n\nexport type AnalyzedCoin = AnalyzedObject & { balance: bigint; coinType: string };\n\nexport const Coin = bcs.struct('Coin', {\n\tid: bcs.Address,\n\tbalance: bcs.U64,\n});\nconst parsedCoinStruct = parseStructTag('0x2::coin::Coin<0x2::haneul::HANEUL>');\n\nexport const coins = createAnalyzer({\n\tdependencies: { objects },\n\tanalyze:\n\t\t() =>\n\t\tasync ({ objects }) => {\n\t\t\treturn {\n\t\t\t\tresult: Object.fromEntries(\n\t\t\t\t\tawait Promise.all(\n\t\t\t\t\t\tobjects\n\t\t\t\t\t\t\t.filter((obj) => {\n\t\t\t\t\t\t\t\tconst parsed = parseStructTag(obj.type);\n\t\t\t\t\t\t\t\treturn (\n\t\t\t\t\t\t\t\t\tparsed.address === parsedCoinStruct.address &&\n\t\t\t\t\t\t\t\t\tparsed.module === parsedCoinStruct.module &&\n\t\t\t\t\t\t\t\t\tparsed.name === parsedCoinStruct.name &&\n\t\t\t\t\t\t\t\t\tparsed.typeParams.length === 1\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t})\n\t\t\t\t\t\t\t.map(async (obj) => {\n\t\t\t\t\t\t\t\treturn [\n\t\t\t\t\t\t\t\t\tobj.objectId,\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t...obj,\n\t\t\t\t\t\t\t\t\t\tcoinType: normalizeStructTag(parseStructTag(obj.type).typeParams[0]),\n\t\t\t\t\t\t\t\t\t\tbalance: BigInt(Coin.parse(obj.content).balance),\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t];\n\t\t\t\t\t\t\t}),\n\t\t\t\t\t),\n\t\t\t\t),\n\t\t\t};\n\t\t},\n});\n\nexport const gasCoins = createAnalyzer({\n\tdependencies: { objectsById, data },\n\tanalyze:\n\t\t() =>\n\t\tasync ({ objectsById, data }) => {\n\t\t\treturn {\n\t\t\t\tresult: await Promise.all(\n\t\t\t\t\t(data.gasData.payment ?? []).map(async (coin) => {\n\t\t\t\t\t\tconst obj = objectsById.get(coin.objectId)!;\n\t\t\t\t\t\tconst content = Coin.parse(obj.content);\n\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\t...obj,\n\t\t\t\t\t\t\tcoinType: normalizeStructTag(parseStructTag(obj.type).typeParams[0]),\n\t\t\t\t\t\t\tbalance: BigInt(content.balance),\n\t\t\t\t\t\t};\n\t\t\t\t\t}),\n\t\t\t\t),\n\t\t\t};\n\t\t},\n});\n"],"mappings":";;;;;;;AAYA,MAAa,OAAO,IAAI,OAAO,QAAQ;CACtC,IAAI,IAAI;CACR,SAAS,IAAI;CACb,CAAC;AACF,MAAM,mBAAmB,eAAe,uCAAuC;AAE/E,MAAa,QAAQ,eAAe;CACnC,cAAc,EAAE,SAAS;CACzB,eAEC,OAAO,EAAE,yBAAc;AACtB,SAAO,EACN,QAAQ,OAAO,YACd,MAAM,QAAQ,IACbA,UACE,QAAQ,QAAQ;GAChB,MAAM,SAAS,eAAe,IAAI,KAAK;AACvC,UACC,OAAO,YAAY,iBAAiB,WACpC,OAAO,WAAW,iBAAiB,UACnC,OAAO,SAAS,iBAAiB,QACjC,OAAO,WAAW,WAAW;IAE7B,CACD,IAAI,OAAO,QAAQ;AACnB,UAAO,CACN,IAAI,UACJ;IACC,GAAG;IACH,UAAU,mBAAmB,eAAe,IAAI,KAAK,CAAC,WAAW,GAAG;IACpE,SAAS,OAAO,KAAK,MAAM,IAAI,QAAQ,CAAC,QAAQ;IAChD,CACD;IACA,CACH,CACD,EACD;;CAEH,CAAC;AAEF,MAAa,WAAW,eAAe;CACtC,cAAc;EAAE;EAAa;EAAM;CACnC,eAEC,OAAO,EAAE,4BAAa,mBAAW;AAChC,SAAO,EACN,QAAQ,MAAM,QAAQ,KACpBC,OAAK,QAAQ,WAAW,EAAE,EAAE,IAAI,OAAO,SAAS;GAChD,MAAM,MAAMC,cAAY,IAAI,KAAK,SAAS;GAC1C,MAAM,UAAU,KAAK,MAAM,IAAI,QAAQ;AACvC,UAAO;IACN,GAAG;IACH,UAAU,mBAAmB,eAAe,IAAI,KAAK,CAAC,WAAW,GAAG;IACpE,SAAS,OAAO,QAAQ,QAAQ;IAChC;IACA,CACF,EACD;;CAEH,CAAC"}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import "../analyzer.mjs";
|
|
2
|
+
import { AnalyzedCommandInput } from "./inputs.mjs";
|
|
3
|
+
import { Command } from "@haneullabs/haneul/transactions";
|
|
4
|
+
import { HaneulClientTypes } from "@haneullabs/haneul/client";
|
|
5
|
+
|
|
6
|
+
//#region src/transaction-analyzer/rules/commands.d.ts
|
|
7
|
+
type AnalyzedCommandArgument = AnalyzedCommandInput | {
|
|
8
|
+
$kind: 'Unknown';
|
|
9
|
+
accessLevel: 'read' | 'mutate' | 'transfer';
|
|
10
|
+
} | {
|
|
11
|
+
$kind: 'GasCoin';
|
|
12
|
+
accessLevel: 'read' | 'mutate' | 'transfer';
|
|
13
|
+
} | {
|
|
14
|
+
$kind: 'Result';
|
|
15
|
+
index: [number, number];
|
|
16
|
+
accessLevel: 'read' | 'mutate' | 'transfer';
|
|
17
|
+
};
|
|
18
|
+
type AnalyzedCommand = {
|
|
19
|
+
$kind: 'MoveCall';
|
|
20
|
+
index: number;
|
|
21
|
+
arguments: AnalyzedCommandArgument[];
|
|
22
|
+
function: HaneulClientTypes.FunctionResponse;
|
|
23
|
+
command: Extract<Command, {
|
|
24
|
+
$kind: 'MoveCall';
|
|
25
|
+
}>['MoveCall'];
|
|
26
|
+
} | {
|
|
27
|
+
$kind: 'TransferObjects';
|
|
28
|
+
index: number;
|
|
29
|
+
objects: AnalyzedCommandArgument[];
|
|
30
|
+
address: AnalyzedCommandArgument;
|
|
31
|
+
command: Extract<Command, {
|
|
32
|
+
$kind: 'TransferObjects';
|
|
33
|
+
}>['TransferObjects'];
|
|
34
|
+
} | {
|
|
35
|
+
$kind: 'MergeCoins';
|
|
36
|
+
index: number;
|
|
37
|
+
sources: AnalyzedCommandArgument[];
|
|
38
|
+
destination: AnalyzedCommandArgument;
|
|
39
|
+
command: Extract<Command, {
|
|
40
|
+
$kind: 'MergeCoins';
|
|
41
|
+
}>['MergeCoins'];
|
|
42
|
+
} | {
|
|
43
|
+
$kind: 'SplitCoins';
|
|
44
|
+
index: number;
|
|
45
|
+
coin: AnalyzedCommandArgument;
|
|
46
|
+
amounts: AnalyzedCommandArgument[];
|
|
47
|
+
command: Extract<Command, {
|
|
48
|
+
$kind: 'SplitCoins';
|
|
49
|
+
}>['SplitCoins'];
|
|
50
|
+
} | {
|
|
51
|
+
$kind: 'MakeMoveVec';
|
|
52
|
+
index: number;
|
|
53
|
+
elements: AnalyzedCommandArgument[];
|
|
54
|
+
command: Extract<Command, {
|
|
55
|
+
$kind: 'MakeMoveVec';
|
|
56
|
+
}>['MakeMoveVec'];
|
|
57
|
+
} | {
|
|
58
|
+
$kind: 'Upgrade';
|
|
59
|
+
index: number;
|
|
60
|
+
ticket: AnalyzedCommandArgument;
|
|
61
|
+
command: Extract<Command, {
|
|
62
|
+
$kind: 'Upgrade';
|
|
63
|
+
}>['Upgrade'];
|
|
64
|
+
} | {
|
|
65
|
+
$kind: 'Publish';
|
|
66
|
+
index: number;
|
|
67
|
+
command: Extract<Command, {
|
|
68
|
+
$kind: 'Publish';
|
|
69
|
+
}>['Publish'];
|
|
70
|
+
} | {
|
|
71
|
+
$kind: 'Unknown';
|
|
72
|
+
index: number;
|
|
73
|
+
command: Extract<Command, {
|
|
74
|
+
$kind: 'Unknown';
|
|
75
|
+
}>['Unknown'];
|
|
76
|
+
};
|
|
77
|
+
//#endregion
|
|
78
|
+
export { AnalyzedCommand, AnalyzedCommandArgument };
|
|
79
|
+
//# sourceMappingURL=commands.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"commands.d.mts","names":[],"sources":["../../../src/transaction-analyzer/rules/commands.ts"],"sourcesContent":[],"mappings":";;;;;;KAYY,uBAAA,GACT;;;AADH,CAAA,GAAY;EAgBA,KAAA,EAAA,SAAA;EAIE,WAAA,EAAA,MAAA,GAAA,QAAA,GAAA,UAAA;CACD,GAAA;EACO,KAAA,EAAA,QAAA;EAAR,KAAA,EAAA,CAAA,MAAA,EAAA,MAAA,CAAA;EAKA,WAAA,EAAA,MAAA,GAAA,QAAA,GAAA,UAAA;CACA;AACQ,KAbR,eAAA,GAaQ;EAAR,KAAA,EAAA,UAAA;EAKA,KAAA,EAAA,MAAA;EACI,SAAA,EAfF,uBAeE,EAAA;EACI,QAAA,EAfP,iBAAA,CAAkB,gBAeX;EAAR,OAAA,EAdA,OAcA,CAdQ,OAcR,EAAA;IAKH,KAAA,EAAA,UAAA;EACG,CAAA,CAAA,CAAA,UAAA,CAAA;CACQ,GAAA;EAAR,KAAA,EAAA,iBAAA;EAKC,KAAA,EAAA,MAAA;EACO,OAAA,EAtBR,uBAsBQ,EAAA;EAAR,OAAA,EArBA,uBAqBA;EAKD,OAAA,EAzBC,OAyBD,CAzBS,OAyBT,EAAA;IACS,KAAA,EAAA,iBAAA;EAAR,CAAA,CAAA,CAAA,iBAAA,CAAA;CAKQ,GAAA;EAAR,KAAA,EAAA,YAAA;EAKQ,KAAA,EAAA,MAAA;EAAR,OAAA,EA/BA,uBA+BA,EAAA;EAAO,WAAA,EA9BH,uBA8BG;WA7BP,QAAQ;;;;;;QAKX;WACG;WACA,QAAQ;;;;;;YAKP;WACD,QAAQ;;;;;;UAKT;WACC,QAAQ;;;;;;WAKR,QAAQ;;;;;;WAKR,QAAQ"}
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
import { createAnalyzer } from "../analyzer.mjs";
|
|
2
|
+
import { data } from "./core.mjs";
|
|
3
|
+
import { inputs } from "./inputs.mjs";
|
|
4
|
+
import { moveFunctions } from "./functions.mjs";
|
|
5
|
+
|
|
6
|
+
//#region src/transaction-analyzer/rules/commands.ts
|
|
7
|
+
const commands = createAnalyzer({
|
|
8
|
+
dependencies: {
|
|
9
|
+
data,
|
|
10
|
+
moveFunctions,
|
|
11
|
+
inputs
|
|
12
|
+
},
|
|
13
|
+
analyze: () => ({ data: data$1, moveFunctions: moveFunctions$1, inputs: inputs$1 }) => {
|
|
14
|
+
const issues = [];
|
|
15
|
+
const commands$1 = [];
|
|
16
|
+
const mapInput = (arg, accessLevel = "transfer") => {
|
|
17
|
+
switch (arg.$kind) {
|
|
18
|
+
case "Input": break;
|
|
19
|
+
case "GasCoin": return {
|
|
20
|
+
$kind: "GasCoin",
|
|
21
|
+
accessLevel
|
|
22
|
+
};
|
|
23
|
+
case "Result": return {
|
|
24
|
+
$kind: "Result",
|
|
25
|
+
index: [arg.Result, 0],
|
|
26
|
+
accessLevel
|
|
27
|
+
};
|
|
28
|
+
case "NestedResult": return {
|
|
29
|
+
$kind: "Result",
|
|
30
|
+
index: arg.NestedResult,
|
|
31
|
+
accessLevel
|
|
32
|
+
};
|
|
33
|
+
default:
|
|
34
|
+
issues.push({ message: `Unexpected input type: ${JSON.stringify(arg)}` });
|
|
35
|
+
return {
|
|
36
|
+
$kind: "Unknown",
|
|
37
|
+
accessLevel
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
const input = inputs$1[arg.Input];
|
|
41
|
+
if (!input) {
|
|
42
|
+
issues.push({ message: `Missing input for index ${arg.Input}` });
|
|
43
|
+
return {
|
|
44
|
+
$kind: "Unknown",
|
|
45
|
+
accessLevel
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
return {
|
|
49
|
+
...input,
|
|
50
|
+
accessLevel
|
|
51
|
+
};
|
|
52
|
+
};
|
|
53
|
+
for (let index = 0; index < data$1.commands.length; index++) {
|
|
54
|
+
const command = data$1.commands[index];
|
|
55
|
+
switch (command.$kind) {
|
|
56
|
+
case "$Intent":
|
|
57
|
+
issues.push({ message: `Unexpected $Intent command: ${JSON.stringify(command)}` });
|
|
58
|
+
break;
|
|
59
|
+
case "MakeMoveVec":
|
|
60
|
+
commands$1.push({
|
|
61
|
+
$kind: "MakeMoveVec",
|
|
62
|
+
index,
|
|
63
|
+
elements: command.MakeMoveVec.elements.map((el) => mapInput(el)),
|
|
64
|
+
command: command.MakeMoveVec
|
|
65
|
+
});
|
|
66
|
+
break;
|
|
67
|
+
case "TransferObjects":
|
|
68
|
+
commands$1.push({
|
|
69
|
+
$kind: "TransferObjects",
|
|
70
|
+
index,
|
|
71
|
+
address: mapInput(command.TransferObjects.address),
|
|
72
|
+
objects: command.TransferObjects.objects.map((obj) => mapInput(obj)),
|
|
73
|
+
command: command.TransferObjects
|
|
74
|
+
});
|
|
75
|
+
break;
|
|
76
|
+
case "MergeCoins":
|
|
77
|
+
commands$1.push({
|
|
78
|
+
$kind: "MergeCoins",
|
|
79
|
+
index,
|
|
80
|
+
sources: command.MergeCoins.sources.map((src) => mapInput(src)),
|
|
81
|
+
destination: mapInput(command.MergeCoins.destination, "mutate"),
|
|
82
|
+
command: command.MergeCoins
|
|
83
|
+
});
|
|
84
|
+
break;
|
|
85
|
+
case "SplitCoins":
|
|
86
|
+
commands$1.push({
|
|
87
|
+
$kind: "SplitCoins",
|
|
88
|
+
index,
|
|
89
|
+
coin: mapInput(command.SplitCoins.coin, "mutate"),
|
|
90
|
+
amounts: command.SplitCoins.amounts.map((amt) => mapInput(amt, "transfer")),
|
|
91
|
+
command: command.SplitCoins
|
|
92
|
+
});
|
|
93
|
+
break;
|
|
94
|
+
case "MoveCall": {
|
|
95
|
+
const func = moveFunctions$1.find((fn) => fn.packageId === command.MoveCall.package && fn.moduleName === command.MoveCall.module && fn.name === command.MoveCall.function);
|
|
96
|
+
commands$1.push({
|
|
97
|
+
$kind: "MoveCall",
|
|
98
|
+
index,
|
|
99
|
+
arguments: command.MoveCall.arguments.map((arg, i) => {
|
|
100
|
+
let accessLevel = "transfer";
|
|
101
|
+
switch (func.parameters[i].reference) {
|
|
102
|
+
case "mutable":
|
|
103
|
+
accessLevel = "mutate";
|
|
104
|
+
break;
|
|
105
|
+
case "immutable":
|
|
106
|
+
accessLevel = "read";
|
|
107
|
+
break;
|
|
108
|
+
}
|
|
109
|
+
return mapInput(arg, accessLevel);
|
|
110
|
+
}),
|
|
111
|
+
command: command.MoveCall,
|
|
112
|
+
function: func
|
|
113
|
+
});
|
|
114
|
+
break;
|
|
115
|
+
}
|
|
116
|
+
case "Publish":
|
|
117
|
+
commands$1.push({
|
|
118
|
+
$kind: "Publish",
|
|
119
|
+
index,
|
|
120
|
+
command: command.Publish
|
|
121
|
+
});
|
|
122
|
+
break;
|
|
123
|
+
case "Upgrade":
|
|
124
|
+
commands$1.push({
|
|
125
|
+
$kind: "Upgrade",
|
|
126
|
+
index,
|
|
127
|
+
ticket: mapInput(command.Upgrade.ticket),
|
|
128
|
+
command: command.Upgrade
|
|
129
|
+
});
|
|
130
|
+
break;
|
|
131
|
+
default: throw new Error("Unknown command type: " + command.$kind);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
if (issues.length) return { issues };
|
|
135
|
+
return { result: commands$1 };
|
|
136
|
+
}
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
//#endregion
|
|
140
|
+
export { commands };
|
|
141
|
+
//# sourceMappingURL=commands.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"commands.mjs","names":["commands","inputs","data","moveFunctions"],"sources":["../../../src/transaction-analyzer/rules/commands.ts"],"sourcesContent":["// Copyright (c) Mysten Labs, Inc.\n// SPDX-License-Identifier: Apache-2.0\n\nimport type { Argument, Command } from '@haneullabs/haneul/transactions';\nimport type { HaneulClientTypes } from '@haneullabs/haneul/client';\nimport { inputs } from './inputs.js';\nimport type { AnalyzedCommandInput } from './inputs.js';\nimport type { TransactionAnalysisIssue } from '../analyzer.js';\nimport { createAnalyzer } from '../analyzer.js';\nimport { data } from './core.js';\nimport { moveFunctions } from './functions.js';\n\nexport type AnalyzedCommandArgument =\n\t| AnalyzedCommandInput\n\t| {\n\t\t\t$kind: 'Unknown';\n\t\t\taccessLevel: 'read' | 'mutate' | 'transfer';\n\t }\n\t| {\n\t\t\t$kind: 'GasCoin';\n\t\t\taccessLevel: 'read' | 'mutate' | 'transfer';\n\t }\n\t| {\n\t\t\t$kind: 'Result';\n\t\t\tindex: [number, number];\n\t\t\taccessLevel: 'read' | 'mutate' | 'transfer';\n\t };\n\nexport type AnalyzedCommand =\n\t| {\n\t\t\t$kind: 'MoveCall';\n\t\t\tindex: number;\n\t\t\targuments: AnalyzedCommandArgument[];\n\t\t\tfunction: HaneulClientTypes.FunctionResponse;\n\t\t\tcommand: Extract<Command, { $kind: 'MoveCall' }>['MoveCall'];\n\t }\n\t| {\n\t\t\t$kind: 'TransferObjects';\n\t\t\tindex: number;\n\t\t\tobjects: AnalyzedCommandArgument[];\n\t\t\taddress: AnalyzedCommandArgument;\n\t\t\tcommand: Extract<Command, { $kind: 'TransferObjects' }>['TransferObjects'];\n\t }\n\t| {\n\t\t\t$kind: 'MergeCoins';\n\t\t\tindex: number;\n\t\t\tsources: AnalyzedCommandArgument[];\n\t\t\tdestination: AnalyzedCommandArgument;\n\t\t\tcommand: Extract<Command, { $kind: 'MergeCoins' }>['MergeCoins'];\n\t }\n\t| {\n\t\t\t$kind: 'SplitCoins';\n\t\t\tindex: number;\n\t\t\tcoin: AnalyzedCommandArgument;\n\t\t\tamounts: AnalyzedCommandArgument[];\n\t\t\tcommand: Extract<Command, { $kind: 'SplitCoins' }>['SplitCoins'];\n\t }\n\t| {\n\t\t\t$kind: 'MakeMoveVec';\n\t\t\tindex: number;\n\t\t\telements: AnalyzedCommandArgument[];\n\t\t\tcommand: Extract<Command, { $kind: 'MakeMoveVec' }>['MakeMoveVec'];\n\t }\n\t| {\n\t\t\t$kind: 'Upgrade';\n\t\t\tindex: number;\n\t\t\tticket: AnalyzedCommandArgument;\n\t\t\tcommand: Extract<Command, { $kind: 'Upgrade' }>['Upgrade'];\n\t }\n\t| {\n\t\t\t$kind: 'Publish';\n\t\t\tindex: number;\n\t\t\tcommand: Extract<Command, { $kind: 'Publish' }>['Publish'];\n\t }\n\t| {\n\t\t\t$kind: 'Unknown';\n\t\t\tindex: number;\n\t\t\tcommand: Extract<Command, { $kind: 'Unknown' }>['Unknown'];\n\t };\n\nexport const commands = createAnalyzer({\n\tdependencies: {\n\t\tdata,\n\t\tmoveFunctions,\n\t\tinputs,\n\t},\n\tanalyze:\n\t\t() =>\n\t\t({ data, moveFunctions, inputs }) => {\n\t\t\tconst issues: TransactionAnalysisIssue[] = [];\n\t\t\tconst commands: AnalyzedCommand[] = [];\n\n\t\t\tconst mapInput = (\n\t\t\t\targ: Argument,\n\t\t\t\taccessLevel: 'read' | 'mutate' | 'transfer' = 'transfer',\n\t\t\t): AnalyzedCommandArgument => {\n\t\t\t\tswitch (arg.$kind) {\n\t\t\t\t\tcase 'Input':\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 'GasCoin':\n\t\t\t\t\t\treturn { $kind: 'GasCoin', accessLevel };\n\t\t\t\t\tcase 'Result':\n\t\t\t\t\t\treturn { $kind: 'Result', index: [arg.Result, 0], accessLevel };\n\t\t\t\t\tcase 'NestedResult':\n\t\t\t\t\t\treturn { $kind: 'Result', index: arg.NestedResult, accessLevel };\n\t\t\t\t\tdefault:\n\t\t\t\t\t\tissues.push({ message: `Unexpected input type: ${JSON.stringify(arg)}` });\n\t\t\t\t\t\treturn { $kind: 'Unknown', accessLevel };\n\t\t\t\t}\n\n\t\t\t\tconst input = inputs[arg.Input];\n\n\t\t\t\tif (!input) {\n\t\t\t\t\tissues.push({ message: `Missing input for index ${arg.Input}` });\n\t\t\t\t\treturn { $kind: 'Unknown', accessLevel };\n\t\t\t\t}\n\n\t\t\t\treturn { ...input, accessLevel };\n\t\t\t};\n\n\t\t\tfor (let index = 0; index < data.commands.length; index++) {\n\t\t\t\tconst command = data.commands[index];\n\t\t\t\tswitch (command.$kind) {\n\t\t\t\t\tcase '$Intent':\n\t\t\t\t\t\tissues.push({ message: `Unexpected $Intent command: ${JSON.stringify(command)}` });\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 'MakeMoveVec':\n\t\t\t\t\t\tcommands.push({\n\t\t\t\t\t\t\t$kind: 'MakeMoveVec',\n\t\t\t\t\t\t\tindex,\n\t\t\t\t\t\t\telements: command.MakeMoveVec.elements.map((el) => mapInput(el)),\n\t\t\t\t\t\t\tcommand: command.MakeMoveVec,\n\t\t\t\t\t\t});\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 'TransferObjects':\n\t\t\t\t\t\tcommands.push({\n\t\t\t\t\t\t\t$kind: 'TransferObjects',\n\t\t\t\t\t\t\tindex,\n\t\t\t\t\t\t\taddress: mapInput(command.TransferObjects.address),\n\t\t\t\t\t\t\tobjects: command.TransferObjects.objects.map((obj) => mapInput(obj)),\n\t\t\t\t\t\t\tcommand: command.TransferObjects,\n\t\t\t\t\t\t});\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 'MergeCoins':\n\t\t\t\t\t\tcommands.push({\n\t\t\t\t\t\t\t$kind: 'MergeCoins',\n\t\t\t\t\t\t\tindex,\n\t\t\t\t\t\t\tsources: command.MergeCoins.sources.map((src) => mapInput(src)),\n\t\t\t\t\t\t\tdestination: mapInput(command.MergeCoins.destination, 'mutate'),\n\t\t\t\t\t\t\tcommand: command.MergeCoins,\n\t\t\t\t\t\t});\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 'SplitCoins':\n\t\t\t\t\t\tcommands.push({\n\t\t\t\t\t\t\t$kind: 'SplitCoins',\n\t\t\t\t\t\t\tindex,\n\t\t\t\t\t\t\tcoin: mapInput(command.SplitCoins.coin, 'mutate'),\n\t\t\t\t\t\t\tamounts: command.SplitCoins.amounts.map((amt) => mapInput(amt, 'transfer')),\n\t\t\t\t\t\t\tcommand: command.SplitCoins,\n\t\t\t\t\t\t});\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 'MoveCall': {\n\t\t\t\t\t\tconst func = moveFunctions.find(\n\t\t\t\t\t\t\t(fn) =>\n\t\t\t\t\t\t\t\tfn.packageId === command.MoveCall.package &&\n\t\t\t\t\t\t\t\tfn.moduleName === command.MoveCall.module &&\n\t\t\t\t\t\t\t\tfn.name === command.MoveCall.function,\n\t\t\t\t\t\t)!;\n\t\t\t\t\t\tcommands.push({\n\t\t\t\t\t\t\t$kind: 'MoveCall',\n\t\t\t\t\t\t\tindex,\n\t\t\t\t\t\t\targuments: command.MoveCall.arguments.map((arg, i) => {\n\t\t\t\t\t\t\t\tlet accessLevel: 'read' | 'mutate' | 'transfer' = 'transfer';\n\t\t\t\t\t\t\t\tswitch (func.parameters[i].reference) {\n\t\t\t\t\t\t\t\t\tcase 'mutable':\n\t\t\t\t\t\t\t\t\t\taccessLevel = 'mutate';\n\t\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\t\tcase 'immutable':\n\t\t\t\t\t\t\t\t\t\taccessLevel = 'read';\n\t\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\treturn mapInput(arg, accessLevel);\n\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\tcommand: command.MoveCall,\n\t\t\t\t\t\t\tfunction: func,\n\t\t\t\t\t\t});\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\tcase 'Publish':\n\t\t\t\t\t\tcommands.push({\n\t\t\t\t\t\t\t$kind: 'Publish',\n\t\t\t\t\t\t\tindex,\n\t\t\t\t\t\t\tcommand: command.Publish,\n\t\t\t\t\t\t});\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 'Upgrade':\n\t\t\t\t\t\tcommands.push({\n\t\t\t\t\t\t\t$kind: 'Upgrade',\n\t\t\t\t\t\t\tindex,\n\t\t\t\t\t\t\tticket: mapInput(command.Upgrade.ticket),\n\t\t\t\t\t\t\tcommand: command.Upgrade,\n\t\t\t\t\t\t});\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tdefault:\n\t\t\t\t\t\tthrow new Error('Unknown command type: ' + (command as { $kind: string }).$kind);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (issues.length) {\n\t\t\t\treturn { issues };\n\t\t\t}\n\n\t\t\treturn { result: commands };\n\t\t},\n});\n"],"mappings":";;;;;;AAgFA,MAAa,WAAW,eAAe;CACtC,cAAc;EACb;EACA;EACA;EACA;CACD,gBAEE,EAAE,cAAM,gCAAe,uBAAa;EACpC,MAAM,SAAqC,EAAE;EAC7C,MAAMA,aAA8B,EAAE;EAEtC,MAAM,YACL,KACA,cAA8C,eACjB;AAC7B,WAAQ,IAAI,OAAZ;IACC,KAAK,QACJ;IACD,KAAK,UACJ,QAAO;KAAE,OAAO;KAAW;KAAa;IACzC,KAAK,SACJ,QAAO;KAAE,OAAO;KAAU,OAAO,CAAC,IAAI,QAAQ,EAAE;KAAE;KAAa;IAChE,KAAK,eACJ,QAAO;KAAE,OAAO;KAAU,OAAO,IAAI;KAAc;KAAa;IACjE;AACC,YAAO,KAAK,EAAE,SAAS,0BAA0B,KAAK,UAAU,IAAI,IAAI,CAAC;AACzE,YAAO;MAAE,OAAO;MAAW;MAAa;;GAG1C,MAAM,QAAQC,SAAO,IAAI;AAEzB,OAAI,CAAC,OAAO;AACX,WAAO,KAAK,EAAE,SAAS,2BAA2B,IAAI,SAAS,CAAC;AAChE,WAAO;KAAE,OAAO;KAAW;KAAa;;AAGzC,UAAO;IAAE,GAAG;IAAO;IAAa;;AAGjC,OAAK,IAAI,QAAQ,GAAG,QAAQC,OAAK,SAAS,QAAQ,SAAS;GAC1D,MAAM,UAAUA,OAAK,SAAS;AAC9B,WAAQ,QAAQ,OAAhB;IACC,KAAK;AACJ,YAAO,KAAK,EAAE,SAAS,+BAA+B,KAAK,UAAU,QAAQ,IAAI,CAAC;AAClF;IACD,KAAK;AACJ,gBAAS,KAAK;MACb,OAAO;MACP;MACA,UAAU,QAAQ,YAAY,SAAS,KAAK,OAAO,SAAS,GAAG,CAAC;MAChE,SAAS,QAAQ;MACjB,CAAC;AACF;IACD,KAAK;AACJ,gBAAS,KAAK;MACb,OAAO;MACP;MACA,SAAS,SAAS,QAAQ,gBAAgB,QAAQ;MAClD,SAAS,QAAQ,gBAAgB,QAAQ,KAAK,QAAQ,SAAS,IAAI,CAAC;MACpE,SAAS,QAAQ;MACjB,CAAC;AACF;IACD,KAAK;AACJ,gBAAS,KAAK;MACb,OAAO;MACP;MACA,SAAS,QAAQ,WAAW,QAAQ,KAAK,QAAQ,SAAS,IAAI,CAAC;MAC/D,aAAa,SAAS,QAAQ,WAAW,aAAa,SAAS;MAC/D,SAAS,QAAQ;MACjB,CAAC;AACF;IACD,KAAK;AACJ,gBAAS,KAAK;MACb,OAAO;MACP;MACA,MAAM,SAAS,QAAQ,WAAW,MAAM,SAAS;MACjD,SAAS,QAAQ,WAAW,QAAQ,KAAK,QAAQ,SAAS,KAAK,WAAW,CAAC;MAC3E,SAAS,QAAQ;MACjB,CAAC;AACF;IACD,KAAK,YAAY;KAChB,MAAM,OAAOC,gBAAc,MACzB,OACA,GAAG,cAAc,QAAQ,SAAS,WAClC,GAAG,eAAe,QAAQ,SAAS,UACnC,GAAG,SAAS,QAAQ,SAAS,SAC9B;AACD,gBAAS,KAAK;MACb,OAAO;MACP;MACA,WAAW,QAAQ,SAAS,UAAU,KAAK,KAAK,MAAM;OACrD,IAAI,cAA8C;AAClD,eAAQ,KAAK,WAAW,GAAG,WAA3B;QACC,KAAK;AACJ,uBAAc;AACd;QACD,KAAK;AACJ,uBAAc;AACd;;AAGF,cAAO,SAAS,KAAK,YAAY;QAChC;MACF,SAAS,QAAQ;MACjB,UAAU;MACV,CAAC;AACF;;IAED,KAAK;AACJ,gBAAS,KAAK;MACb,OAAO;MACP;MACA,SAAS,QAAQ;MACjB,CAAC;AACF;IACD,KAAK;AACJ,gBAAS,KAAK;MACb,OAAO;MACP;MACA,QAAQ,SAAS,QAAQ,QAAQ,OAAO;MACxC,SAAS,QAAQ;MACjB,CAAC;AACF;IACD,QACC,OAAM,IAAI,MAAM,2BAA4B,QAA8B,MAAM;;;AAInF,MAAI,OAAO,OACV,QAAO,EAAE,QAAQ;AAGlB,SAAO,EAAE,QAAQH,YAAU;;CAE7B,CAAC"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { createAnalyzer } from "../analyzer.mjs";
|
|
2
|
+
import { TransactionDataBuilder } from "@haneullabs/haneul/transactions";
|
|
3
|
+
|
|
4
|
+
//#region src/transaction-analyzer/rules/core.ts
|
|
5
|
+
const bytes = createAnalyzer({
|
|
6
|
+
cacheKey: "bytes@1.0.0",
|
|
7
|
+
analyze: (options, transaction) => async () => {
|
|
8
|
+
try {
|
|
9
|
+
return { result: await transaction.build({ client: options.client }) };
|
|
10
|
+
} catch {
|
|
11
|
+
return { issues: [{ message: "Failed to build transaction" }] };
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
});
|
|
15
|
+
const data = createAnalyzer({
|
|
16
|
+
dependencies: { bytes },
|
|
17
|
+
analyze: (_, tx) => () => {
|
|
18
|
+
return { result: tx.getData() };
|
|
19
|
+
}
|
|
20
|
+
});
|
|
21
|
+
const digest = createAnalyzer({
|
|
22
|
+
dependencies: { bytes },
|
|
23
|
+
analyze: () => ({ bytes: bytes$1 }) => {
|
|
24
|
+
return { result: TransactionDataBuilder.getDigestFromBytes(bytes$1) };
|
|
25
|
+
}
|
|
26
|
+
});
|
|
27
|
+
const transactionResponse = createAnalyzer({
|
|
28
|
+
cacheKey: "transactionResponse@1.0.0",
|
|
29
|
+
dependencies: { bytes },
|
|
30
|
+
analyze: (options) => async ({ bytes: bytes$1 }) => {
|
|
31
|
+
try {
|
|
32
|
+
const result = await options.client.core.simulateTransaction({ transaction: bytes$1 });
|
|
33
|
+
return { result: options.transactionResponse ?? result.Transaction ?? result.FailedTransaction };
|
|
34
|
+
} catch {
|
|
35
|
+
return { issues: [{ message: "Failed to dry run transaction" }] };
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
});
|
|
39
|
+
const balanceChanges = createAnalyzer({
|
|
40
|
+
dependencies: { transactionResponse },
|
|
41
|
+
analyze: () => ({ transactionResponse: transactionResponse$1 }) => {
|
|
42
|
+
return { result: transactionResponse$1.balanceChanges || [] };
|
|
43
|
+
}
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
//#endregion
|
|
47
|
+
export { balanceChanges, bytes, data, digest, transactionResponse };
|
|
48
|
+
//# sourceMappingURL=core.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"core.mjs","names":["bytes","transactionResponse"],"sources":["../../../src/transaction-analyzer/rules/core.ts"],"sourcesContent":["// Copyright (c) Mysten Labs, Inc.\n// SPDX-License-Identifier: Apache-2.0\n\nimport type { Transaction } from '@haneullabs/haneul/transactions';\nimport { TransactionDataBuilder } from '@haneullabs/haneul/transactions';\nimport type { ClientWithCoreApi, HaneulClientTypes } from '@haneullabs/haneul/client';\nimport type { AnalyzerResult } from '../analyzer.js';\nimport { createAnalyzer } from '../analyzer.js';\n\nexport const bytes = createAnalyzer({\n\tcacheKey: 'bytes@1.0.0',\n\tanalyze:\n\t\t(options: { client: ClientWithCoreApi }, transaction: Transaction) =>\n\t\tasync (): Promise<AnalyzerResult<Uint8Array>> => {\n\t\t\ttry {\n\t\t\t\treturn {\n\t\t\t\t\tresult: await transaction.build({ client: options.client }),\n\t\t\t\t};\n\t\t\t} catch {\n\t\t\t\treturn { issues: [{ message: 'Failed to build transaction' }] };\n\t\t\t}\n\t\t},\n});\n\nexport const data = createAnalyzer({\n\tdependencies: { bytes },\n\tanalyze: (_, tx) => () => {\n\t\treturn { result: tx.getData() };\n\t},\n});\n\nexport const digest = createAnalyzer({\n\tdependencies: { bytes },\n\tanalyze:\n\t\t() =>\n\t\t({ bytes }) => {\n\t\t\treturn { result: TransactionDataBuilder.getDigestFromBytes(bytes) };\n\t\t},\n});\n\nexport const transactionResponse = createAnalyzer({\n\tcacheKey: 'transactionResponse@1.0.0',\n\tdependencies: { bytes },\n\tanalyze:\n\t\t(options: { client: ClientWithCoreApi; transactionResponse?: HaneulClientTypes.Transaction }) =>\n\t\tasync ({ bytes }): Promise<AnalyzerResult<HaneulClientTypes.Transaction>> => {\n\t\t\ttry {\n\t\t\t\tconst result = await options.client.core.simulateTransaction({ transaction: bytes });\n\t\t\t\treturn {\n\t\t\t\t\tresult: options.transactionResponse ?? result.Transaction ?? result.FailedTransaction,\n\t\t\t\t};\n\t\t\t} catch {\n\t\t\t\treturn { issues: [{ message: 'Failed to dry run transaction' }] };\n\t\t\t}\n\t\t},\n});\n\nexport const balanceChanges = createAnalyzer({\n\tdependencies: { transactionResponse },\n\tanalyze:\n\t\t() =>\n\t\t({ transactionResponse }) => {\n\t\t\treturn { result: transactionResponse.balanceChanges || [] };\n\t\t},\n});\n"],"mappings":";;;;AASA,MAAa,QAAQ,eAAe;CACnC,UAAU;CACV,UACE,SAAwC,gBACzC,YAAiD;AAChD,MAAI;AACH,UAAO,EACN,QAAQ,MAAM,YAAY,MAAM,EAAE,QAAQ,QAAQ,QAAQ,CAAC,EAC3D;UACM;AACP,UAAO,EAAE,QAAQ,CAAC,EAAE,SAAS,+BAA+B,CAAC,EAAE;;;CAGlE,CAAC;AAEF,MAAa,OAAO,eAAe;CAClC,cAAc,EAAE,OAAO;CACvB,UAAU,GAAG,aAAa;AACzB,SAAO,EAAE,QAAQ,GAAG,SAAS,EAAE;;CAEhC,CAAC;AAEF,MAAa,SAAS,eAAe;CACpC,cAAc,EAAE,OAAO;CACvB,gBAEE,EAAE,qBAAY;AACd,SAAO,EAAE,QAAQ,uBAAuB,mBAAmBA,QAAM,EAAE;;CAErE,CAAC;AAEF,MAAa,sBAAsB,eAAe;CACjD,UAAU;CACV,cAAc,EAAE,OAAO;CACvB,UACE,YACD,OAAO,EAAE,qBAAoE;AAC5E,MAAI;GACH,MAAM,SAAS,MAAM,QAAQ,OAAO,KAAK,oBAAoB,EAAE,aAAaA,SAAO,CAAC;AACpF,UAAO,EACN,QAAQ,QAAQ,uBAAuB,OAAO,eAAe,OAAO,mBACpE;UACM;AACP,UAAO,EAAE,QAAQ,CAAC,EAAE,SAAS,iCAAiC,CAAC,EAAE;;;CAGpE,CAAC;AAEF,MAAa,iBAAiB,eAAe;CAC5C,cAAc,EAAE,qBAAqB;CACrC,gBAEE,EAAE,iDAA0B;AAC5B,SAAO,EAAE,QAAQC,sBAAoB,kBAAkB,EAAE,EAAE;;CAE7D,CAAC"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { createAnalyzer } from "../analyzer.mjs";
|
|
2
|
+
import { data } from "./core.mjs";
|
|
3
|
+
|
|
4
|
+
//#region src/transaction-analyzer/rules/functions.ts
|
|
5
|
+
const moveFunctions = createAnalyzer({
|
|
6
|
+
cacheKey: "moveFunctions@1.0.0",
|
|
7
|
+
dependencies: { data },
|
|
8
|
+
analyze: ({ client }) => async ({ data: data$1 }) => {
|
|
9
|
+
const issues = [];
|
|
10
|
+
const functions = new Set(data$1.commands.filter((cmd) => cmd.$kind === "MoveCall").map((cmd) => `${cmd.MoveCall.package}::${cmd.MoveCall.module}::${cmd.MoveCall.function}`));
|
|
11
|
+
const results = await Promise.all(Array.from(functions).map(async (functionId) => {
|
|
12
|
+
const [packageId, moduleName, name] = functionId.split("::");
|
|
13
|
+
try {
|
|
14
|
+
return (await client.core.getMoveFunction({
|
|
15
|
+
packageId,
|
|
16
|
+
moduleName,
|
|
17
|
+
name
|
|
18
|
+
})).function;
|
|
19
|
+
} catch {
|
|
20
|
+
issues.push({ message: `Failed to fetch Move function: ${functionId}` });
|
|
21
|
+
return null;
|
|
22
|
+
}
|
|
23
|
+
}));
|
|
24
|
+
if (issues.length) return { issues };
|
|
25
|
+
return { result: results.filter((fn) => fn !== null) };
|
|
26
|
+
}
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
//#endregion
|
|
30
|
+
export { moveFunctions };
|
|
31
|
+
//# sourceMappingURL=functions.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"functions.mjs","names":["data"],"sources":["../../../src/transaction-analyzer/rules/functions.ts"],"sourcesContent":["// Copyright (c) Mysten Labs, Inc.\n// SPDX-License-Identifier: Apache-2.0\n\nimport type { ClientWithCoreApi, HaneulClientTypes } from '@haneullabs/haneul/client';\nimport type { TransactionAnalysisIssue } from '../analyzer.js';\nimport { createAnalyzer } from '../analyzer.js';\nimport { data } from './core.js';\n\nexport const moveFunctions = createAnalyzer({\n\tcacheKey: 'moveFunctions@1.0.0',\n\tdependencies: { data },\n\tanalyze:\n\t\t({ client }: { client: ClientWithCoreApi }) =>\n\t\tasync ({ data }) => {\n\t\t\tconst issues: TransactionAnalysisIssue[] = [];\n\n\t\t\tconst functions = new Set(\n\t\t\t\tdata.commands\n\t\t\t\t\t.filter((cmd) => cmd.$kind === 'MoveCall')\n\t\t\t\t\t.map(\n\t\t\t\t\t\t(cmd) => `${cmd.MoveCall.package}::${cmd.MoveCall.module}::${cmd.MoveCall.function}`,\n\t\t\t\t\t),\n\t\t\t);\n\n\t\t\tconst results = await Promise.all(\n\t\t\t\tArray.from(functions).map(async (functionId) => {\n\t\t\t\t\tconst [packageId, moduleName, name] = functionId.split('::');\n\t\t\t\t\ttry {\n\t\t\t\t\t\tconst res = await client.core.getMoveFunction({ packageId, moduleName, name });\n\t\t\t\t\t\treturn res.function;\n\t\t\t\t\t} catch {\n\t\t\t\t\t\tissues.push({ message: `Failed to fetch Move function: ${functionId}` });\n\t\t\t\t\t\treturn null;\n\t\t\t\t\t}\n\t\t\t\t}),\n\t\t\t);\n\n\t\t\tif (issues.length) {\n\t\t\t\treturn { issues };\n\t\t\t}\n\n\t\t\treturn {\n\t\t\t\tresult: results.filter((fn): fn is HaneulClientTypes.FunctionResponse => fn !== null),\n\t\t\t};\n\t\t},\n});\n"],"mappings":";;;;AAQA,MAAa,gBAAgB,eAAe;CAC3C,UAAU;CACV,cAAc,EAAE,MAAM;CACtB,UACE,EAAE,aACH,OAAO,EAAE,mBAAW;EACnB,MAAM,SAAqC,EAAE;EAE7C,MAAM,YAAY,IAAI,IACrBA,OAAK,SACH,QAAQ,QAAQ,IAAI,UAAU,WAAW,CACzC,KACC,QAAQ,GAAG,IAAI,SAAS,QAAQ,IAAI,IAAI,SAAS,OAAO,IAAI,IAAI,SAAS,WAC1E,CACF;EAED,MAAM,UAAU,MAAM,QAAQ,IAC7B,MAAM,KAAK,UAAU,CAAC,IAAI,OAAO,eAAe;GAC/C,MAAM,CAAC,WAAW,YAAY,QAAQ,WAAW,MAAM,KAAK;AAC5D,OAAI;AAEH,YADY,MAAM,OAAO,KAAK,gBAAgB;KAAE;KAAW;KAAY;KAAM,CAAC,EACnE;WACJ;AACP,WAAO,KAAK,EAAE,SAAS,kCAAkC,cAAc,CAAC;AACxE,WAAO;;IAEP,CACF;AAED,MAAI,OAAO,OACV,QAAO,EAAE,QAAQ;AAGlB,SAAO,EACN,QAAQ,QAAQ,QAAQ,OAAiD,OAAO,KAAK,EACrF;;CAEH,CAAC"}
|