@wowok/agent-mcp 2.6.1 → 2.6.3
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/dist/customer/info-puzzle.d.ts +1 -1
- package/dist/customer/info-puzzle.js +4 -2
- package/dist/customer/risk-assessment.js +26 -4
- package/dist/customer/types.d.ts +2 -0
- package/dist/examples/guard-template-balance-check.json +38 -0
- package/dist/examples/guard-template-time-lock.json +39 -0
- package/dist/examples/machine-template-7node-rental.json +114 -0
- package/dist/examples/rental-ziroom-machine-create.json +137 -0
- package/dist/examples/rental-ziroom-permission-create.json +35 -0
- package/dist/examples/rental-ziroom-service-create.json +80 -0
- package/dist/examples/retail-myshop-service-create.json +88 -0
- package/dist/extensions/capability-manifest.js +24 -24
- package/dist/extensions/constraint-registry.js +18 -18
- package/dist/extensions/metric-registry.js +14 -14
- package/dist/extensions/mode-evaluator.js +16 -16
- package/dist/extensions/modes.js +131 -45
- package/dist/extensions/registry.d.ts +2 -0
- package/dist/extensions/registry.js +63 -30
- package/dist/extensions/types.d.ts +1 -0
- package/dist/index.js +50 -0
- package/dist/knowledge/deployment-scanner.js +1 -1
- package/dist/knowledge/fund-layer.d.ts +72 -0
- package/dist/knowledge/fund-layer.js +420 -0
- package/dist/knowledge/guard-render.d.ts +57 -0
- package/dist/knowledge/guard-render.js +700 -0
- package/dist/knowledge/guard-submission-prompt.d.ts +31 -0
- package/dist/knowledge/guard-submission-prompt.js +171 -0
- package/dist/knowledge/machine-ledger.js +1 -1
- package/dist/knowledge/machine-render.d.ts +41 -0
- package/dist/knowledge/machine-render.js +565 -0
- package/dist/knowledge/machine-templates.js +4 -4
- package/dist/knowledge/reward-confirm.js +2 -2
- package/dist/knowledge/reward-puzzle.js +1 -1
- package/dist/knowledge/reward-risk.js +9 -9
- package/dist/knowledge/reward-templates.js +2 -2
- package/dist/knowledge/service-confirm.d.ts +1 -1
- package/dist/knowledge/service-confirm.js +3 -3
- package/dist/knowledge/service-context.js +1 -1
- package/dist/knowledge/service-ledger.js +1 -1
- package/dist/knowledge/service-risk.d.ts +1 -1
- package/dist/knowledge/service-risk.js +3 -3
- package/dist/knowledge/service-templates.js +2 -2
- package/dist/knowledge/service-translation.d.ts +1 -1
- package/dist/knowledge/service-translation.js +7 -7
- package/dist/project/deployment-bridge.js +6 -5
- package/dist/project/deployment-doc.js +5 -5
- package/dist/project/edit-planner.d.ts +123 -0
- package/dist/project/edit-planner.js +1371 -0
- package/dist/project/evaluation.js +314 -14
- package/dist/project/graph-builder.js +6 -1
- package/dist/project/handlers.d.ts +99 -2
- package/dist/project/handlers.js +358 -16
- package/dist/project/stage-gate.js +4 -4
- package/dist/schema/call/allocation.js +2 -2
- package/dist/schema/call/arbitration.js +19 -6
- package/dist/schema/call/contact.js +2 -2
- package/dist/schema/call/demand.js +2 -2
- package/dist/schema/call/guard.js +1 -1
- package/dist/schema/call/machine.d.ts +1975 -777
- package/dist/schema/call/machine.js +50 -4
- package/dist/schema/call/order.js +3 -6
- package/dist/schema/call/permission.js +2 -2
- package/dist/schema/call/repository.js +2 -2
- package/dist/schema/call/reward.js +3 -3
- package/dist/schema/call/semantic.js +7 -1
- package/dist/schema/call/service.d.ts +180 -8
- package/dist/schema/call/service.js +82 -27
- package/dist/schema/call/treasury.js +3 -3
- package/dist/schema/common/index.d.ts +2 -0
- package/dist/schema/common/index.js +46 -10
- package/dist/schema/local/index.js +5 -1
- package/dist/schema/operations.d.ts +755 -176
- package/dist/schema/operations.js +43 -7
- package/dist/schema/project/index.d.ts +969 -6
- package/dist/schema/project/index.js +268 -4
- package/dist/schema/query/index.d.ts +217 -0
- package/dist/schema/query/index.js +63 -33
- package/dist/schema/schema-query/index.d.ts +53 -3
- package/dist/schema/schema-query/index.js +17 -2
- package/dist/schema/utils/node-parser.js +13 -0
- package/dist/schema/utils/object-type-utils.d.ts +12 -0
- package/dist/schema/utils/object-type-utils.js +35 -0
- package/dist/schema/utils/permission-machine-check.d.ts +49 -0
- package/dist/schema/utils/permission-machine-check.js +121 -0
- package/dist/schema/utils/skills-recommendation.d.ts +2 -0
- package/dist/schema/utils/skills-recommendation.js +76 -0
- package/dist/schema-query/index.d.ts +14 -1
- package/dist/schema-query/index.js +104 -2
- package/dist/schemas/account_operation.schema.json +1 -1
- package/dist/schemas/index.json +1 -1
- package/dist/schemas/onchain_events.output.json +1 -1
- package/dist/schemas/onchain_operations.output.json +2820 -0
- package/dist/schemas/onchain_operations.schema.json +115 -53
- package/dist/schemas/onchain_operations_allocation.schema.json +5 -5
- package/dist/schemas/onchain_operations_arbitration.schema.json +9 -7
- package/dist/schemas/onchain_operations_contact.schema.json +3 -3
- package/dist/schemas/onchain_operations_demand.schema.json +3 -3
- package/dist/schemas/onchain_operations_gen_passport.schema.json +2 -2
- package/dist/schemas/onchain_operations_guard.schema.json +1 -1
- package/dist/schemas/onchain_operations_machine.schema.json +4 -4
- package/dist/schemas/onchain_operations_order.schema.json +3 -3
- package/dist/schemas/onchain_operations_payment.schema.json +1 -1
- package/dist/schemas/onchain_operations_permission.schema.json +2 -2
- package/dist/schemas/onchain_operations_progress.schema.json +1 -1
- package/dist/schemas/onchain_operations_proof.schema.json +1 -1
- package/dist/schemas/onchain_operations_repository.schema.json +3 -3
- package/dist/schemas/onchain_operations_reward.schema.json +6 -6
- package/dist/schemas/onchain_operations_service.schema.json +77 -17
- package/dist/schemas/onchain_operations_treasury.schema.json +4 -4
- package/dist/schemas/onchain_table_data.output.json +1 -1
- package/dist/schemas/onchain_table_data.schema.json +10 -9
- package/dist/schemas/project_operation.output.json +1026 -7
- package/dist/schemas/project_operation.schema.json +46 -4
- package/dist/schemas/query_toolkit.output.json +15 -15
- package/dist/schemas/query_toolkit.schema.json +3 -3
- package/dist/schemas/schema_query.output.json +64 -1
- package/dist/schemas/schema_query.schema.json +3 -2
- package/dist/schemas/wowok_buildin_info.output.json +81 -8
- package/dist/schemas/wowok_buildin_info.schema.json +46 -2
- package/dist/tools/handlers/onchain.js +571 -6
- package/dist/tools/handlers/project.js +25 -2
- package/dist/tools/handlers/schema-query.js +24 -1
- package/dist/tools/index.d.ts +8 -0
- package/dist/tools/index.js +177 -6
- package/package.json +2 -2
|
@@ -1,10 +1,247 @@
|
|
|
1
1
|
import { readFileSync } from "fs";
|
|
2
2
|
import { resolve } from "path";
|
|
3
|
-
import { CallService, CallMachine, CallProgress, CallGuard, CallArbitration, CallRepository, CallContact, CallTreasury, CallReward, CallAllocation, CallPersonal, CallPayment, CallDemand, CallOrder, gen_passport, CallProof, gen_proof, ResponseData, LocalProject, parseGuardFile, formatGuardParseErrors, transformRewardInput, transformPersonalInput, } from "@wowok/wowok";
|
|
3
|
+
import { CallService, CallMachine, CallProgress, CallGuard, CallArbitration, CallRepository, CallContact, CallTreasury, CallReward, CallAllocation, CallPersonal, CallPayment, CallDemand, CallOrder, gen_passport, CallProof, gen_proof, ResponseData, LocalProject, LocalMark, query_objects, parseGuardFile, formatGuardParseErrors, transformRewardInput, transformPersonalInput, } from "@wowok/wowok";
|
|
4
4
|
import { OnchainOperationsSchema, strictParse, getEnvConfig, handleCallResult, checkClientSchemaCompatibility, parseMachineNodesFromText, formatNodeErrors as formatMachineNodeErrors, transformSubmission, } from "../../schema/index.js";
|
|
5
5
|
import { handlePermissionOperations } from "../../schema/call/permission-handler.js";
|
|
6
|
+
import { collectPermissionIndexes, checkPermissionAuthorization, formatPermissionWarning, } from "../../schema/utils/permission-machine-check.js";
|
|
6
7
|
import { isProjectServiceEnabled, normalize as projectNormalize, } from "../../project/index.js";
|
|
8
|
+
import { getSkillsHintForOnchain } from "../../schema/utils/skills-recommendation.js";
|
|
9
|
+
import { processFundOperation, generateSkillsHint as generateFundSkillsHint } from "../../knowledge/fund-layer.js";
|
|
10
|
+
import { generateGuardSubmissionPrompt, formatSubmissionPrompt } from "../../knowledge/guard-submission-prompt.js";
|
|
7
11
|
import { withHarness } from "../shared.js";
|
|
12
|
+
function formatRecipientLabel(recipient) {
|
|
13
|
+
if (!recipient)
|
|
14
|
+
return "unknown";
|
|
15
|
+
if (typeof recipient === "string")
|
|
16
|
+
return recipient;
|
|
17
|
+
if ("GuardIdentifier" in recipient) {
|
|
18
|
+
return `GuardIdentifier(${recipient.GuardIdentifier})`;
|
|
19
|
+
}
|
|
20
|
+
if ("Entity" in recipient) {
|
|
21
|
+
const addr = recipient.Entity;
|
|
22
|
+
if (typeof addr === "string" && addr.length > 16) {
|
|
23
|
+
return `Entity(${addr.slice(0, 8)}...${addr.slice(-4)})`;
|
|
24
|
+
}
|
|
25
|
+
return `Entity(${addr})`;
|
|
26
|
+
}
|
|
27
|
+
if ("Signer" in recipient) {
|
|
28
|
+
return "Signer (transaction signer)";
|
|
29
|
+
}
|
|
30
|
+
return JSON.stringify(recipient);
|
|
31
|
+
}
|
|
32
|
+
function formatMistAmount(amount) {
|
|
33
|
+
const wowEquivalent = Number(amount) / 1_000_000_000;
|
|
34
|
+
if (wowEquivalent === 0)
|
|
35
|
+
return "0 WOW";
|
|
36
|
+
const wowStr = wowEquivalent.toFixed(9).replace(/\.?0+$/, "");
|
|
37
|
+
return `${wowStr} WOW (${amount.toString()} MIST)`;
|
|
38
|
+
}
|
|
39
|
+
function extractNodesForCheck(data) {
|
|
40
|
+
if (!data?.node)
|
|
41
|
+
return [];
|
|
42
|
+
if (data.node.nodes && Array.isArray(data.node.nodes)) {
|
|
43
|
+
return data.node.nodes;
|
|
44
|
+
}
|
|
45
|
+
return [];
|
|
46
|
+
}
|
|
47
|
+
function resolvePermissionRef(data) {
|
|
48
|
+
if (!data?.object)
|
|
49
|
+
return null;
|
|
50
|
+
if (typeof data.object === "string")
|
|
51
|
+
return null;
|
|
52
|
+
const obj = data.object;
|
|
53
|
+
if (obj.permission) {
|
|
54
|
+
if (typeof obj.permission === "string")
|
|
55
|
+
return obj.permission;
|
|
56
|
+
return null;
|
|
57
|
+
}
|
|
58
|
+
return null;
|
|
59
|
+
}
|
|
60
|
+
async function checkMachinePermissionBeforePublish(data, env) {
|
|
61
|
+
if (data?.publish !== true)
|
|
62
|
+
return "";
|
|
63
|
+
const nodes = extractNodesForCheck(data);
|
|
64
|
+
if (nodes.length === 0)
|
|
65
|
+
return "";
|
|
66
|
+
const collection = collectPermissionIndexes(nodes);
|
|
67
|
+
if (collection.requiredIndexes.length === 0) {
|
|
68
|
+
return "";
|
|
69
|
+
}
|
|
70
|
+
let warning = "";
|
|
71
|
+
if (collection.missingRefs.length > 0) {
|
|
72
|
+
warning += "WARNING: Some forwards have NEITHER permissionIndex nor namedOperator. " +
|
|
73
|
+
"These forwards cannot be executed. Add one or the other:\n";
|
|
74
|
+
for (const ref of collection.missingRefs) {
|
|
75
|
+
warning += ` - Node "${ref.nodeName}", pair prev_node="${ref.prevNode}", forward "${ref.forwardName}"\n`;
|
|
76
|
+
}
|
|
77
|
+
warning += "\n";
|
|
78
|
+
}
|
|
79
|
+
const permRef = resolvePermissionRef(data);
|
|
80
|
+
if (!permRef) {
|
|
81
|
+
if (collection.requiredIndexes.length > 0) {
|
|
82
|
+
warning += "PRE-PUBLISH REMINDER: This Machine uses " + collection.requiredIndexes.length +
|
|
83
|
+
" custom permission index(es): [" + collection.requiredIndexes.join(", ") + "]. " +
|
|
84
|
+
"After creating the Permission object, grant entities for each index via " +
|
|
85
|
+
'permission.op="add perm by index" BEFORE publishing the Machine. ' +
|
|
86
|
+
"Otherwise, forwards using these indexes will be un-executable.\n";
|
|
87
|
+
}
|
|
88
|
+
return warning;
|
|
89
|
+
}
|
|
90
|
+
let permAddress = permRef;
|
|
91
|
+
if (!permRef.startsWith("0x")) {
|
|
92
|
+
try {
|
|
93
|
+
const mark = await LocalMark.Instance().get(permRef);
|
|
94
|
+
if (mark?.address) {
|
|
95
|
+
permAddress = mark.address;
|
|
96
|
+
}
|
|
97
|
+
else {
|
|
98
|
+
return warning + "PRE-PUBLISH: Could not resolve Permission name '" + permRef +
|
|
99
|
+
"' to an address. Ensure the Permission object exists and is marked. " +
|
|
100
|
+
"Required indexes: [" + collection.requiredIndexes.join(", ") + "]\n";
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
catch {
|
|
104
|
+
return warning + "PRE-PUBLISH: Failed to lookup Permission name '" + permRef +
|
|
105
|
+
"'. Required indexes: [" + collection.requiredIndexes.join(", ") + "]\n";
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
const network = env?.network ?? "testnet";
|
|
109
|
+
let permData = null;
|
|
110
|
+
try {
|
|
111
|
+
const queryResult = await query_objects({
|
|
112
|
+
objects: [permAddress],
|
|
113
|
+
network: network,
|
|
114
|
+
});
|
|
115
|
+
const permObj = queryResult?.objects?.[0];
|
|
116
|
+
if (permObj) {
|
|
117
|
+
permData = {
|
|
118
|
+
address: permAddress,
|
|
119
|
+
entity_count: permObj.entity_count,
|
|
120
|
+
perm_remark: permObj.perm_remark,
|
|
121
|
+
owner: permObj.owner ?? permObj.builder,
|
|
122
|
+
admin: permObj.admin,
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
catch {
|
|
127
|
+
return warning + "PRE-PUBLISH: Failed to query Permission object " + permAddress +
|
|
128
|
+
". Required indexes: [" + collection.requiredIndexes.join(", ") + "]\n";
|
|
129
|
+
}
|
|
130
|
+
if (!permData) {
|
|
131
|
+
return warning + "PRE-PUBLISH: Permission object " + permAddress +
|
|
132
|
+
" not found on-chain. Required indexes: [" + collection.requiredIndexes.join(", ") + "]\n";
|
|
133
|
+
}
|
|
134
|
+
const report = checkPermissionAuthorization(collection.requiredIndexes, permData);
|
|
135
|
+
if (!report.allAuthorized) {
|
|
136
|
+
warning += formatPermissionWarning(report) + "\n";
|
|
137
|
+
}
|
|
138
|
+
return warning;
|
|
139
|
+
}
|
|
140
|
+
async function detectServiceGuardCircularDependency(data) {
|
|
141
|
+
if (!data || typeof data.object !== "object" || data.object === null)
|
|
142
|
+
return null;
|
|
143
|
+
const orderAllocators = data.order_allocators;
|
|
144
|
+
if (!orderAllocators || typeof orderAllocators !== "object")
|
|
145
|
+
return null;
|
|
146
|
+
const allocators = Array.isArray(orderAllocators.allocators)
|
|
147
|
+
? orderAllocators.allocators
|
|
148
|
+
: [];
|
|
149
|
+
if (allocators.length === 0)
|
|
150
|
+
return null;
|
|
151
|
+
const unresolvedGuards = [];
|
|
152
|
+
const seen = new Set();
|
|
153
|
+
for (const alloc of allocators) {
|
|
154
|
+
const guardRef = alloc?.guard;
|
|
155
|
+
if (typeof guardRef === "string" && !guardRef.startsWith("0x")) {
|
|
156
|
+
if (seen.has(guardRef))
|
|
157
|
+
continue;
|
|
158
|
+
seen.add(guardRef);
|
|
159
|
+
try {
|
|
160
|
+
const addr = await LocalMark.Instance().get_address(guardRef);
|
|
161
|
+
if (!addr) {
|
|
162
|
+
unresolvedGuards.push(guardRef);
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
catch {
|
|
166
|
+
unresolvedGuards.push(guardRef);
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
if (unresolvedGuards.length === 0)
|
|
171
|
+
return null;
|
|
172
|
+
const guardList = unresolvedGuards.map(g => `'${g}'`).join(", ");
|
|
173
|
+
const serviceObj = data.object;
|
|
174
|
+
const serviceName = serviceObj.name ?? "<service_name>";
|
|
175
|
+
const recommended_steps = [
|
|
176
|
+
{
|
|
177
|
+
step: 1,
|
|
178
|
+
action: "onchain_operations",
|
|
179
|
+
operation_type: "service",
|
|
180
|
+
params: {
|
|
181
|
+
...data,
|
|
182
|
+
order_allocators: null,
|
|
183
|
+
publish: false,
|
|
184
|
+
},
|
|
185
|
+
purpose: `Create Service '${serviceName}' WITHOUT order_allocators to establish ` +
|
|
186
|
+
`its LocalMark entry. After this step, the name '${serviceName}' resolves ` +
|
|
187
|
+
`to an on-chain address.`,
|
|
188
|
+
},
|
|
189
|
+
{
|
|
190
|
+
step: 2,
|
|
191
|
+
action: "onchain_operations",
|
|
192
|
+
operation_type: "guard",
|
|
193
|
+
params: unresolvedGuards.map(name => ({
|
|
194
|
+
object: { name, type: "Guard" },
|
|
195
|
+
_hint: `Table items may reference Service '${serviceName}' by name`,
|
|
196
|
+
})),
|
|
197
|
+
purpose: `Create Guard(s) ${guardList}. Their table items can now resolve ` +
|
|
198
|
+
`Service '${serviceName}' by name (LocalMark entry from step 1).`,
|
|
199
|
+
},
|
|
200
|
+
{
|
|
201
|
+
step: 3,
|
|
202
|
+
action: "onchain_operations",
|
|
203
|
+
operation_type: "service",
|
|
204
|
+
params: {
|
|
205
|
+
object: serviceName,
|
|
206
|
+
order_allocators: orderAllocators,
|
|
207
|
+
publish: data.publish ?? true,
|
|
208
|
+
},
|
|
209
|
+
purpose: "Update Service with order_allocators (referencing Guards created in " +
|
|
210
|
+
"step 2) and publish. After publish, order_allocators becomes SDK-LOCKED.",
|
|
211
|
+
},
|
|
212
|
+
];
|
|
213
|
+
const guideText = `⚠️ Circular dependency detected: Service ↔ Guard\n\n` +
|
|
214
|
+
`Cannot create Service with order_allocators referencing non-existent Guard(s): ${guardList}.\n\n` +
|
|
215
|
+
`Explanation: Guard table items may reference the Service by name, creating a circular ` +
|
|
216
|
+
`dependency: the Service must exist as a LocalMark before the Guard can resolve it, ` +
|
|
217
|
+
`but the Guard must exist before the Service can reference it in order_allocators. ` +
|
|
218
|
+
`The SDK would fail with a BCS serialization error: "Expected valid Address for ` +
|
|
219
|
+
`ValueType.Address, but failed to resolve string: <name>".\n\n` +
|
|
220
|
+
`Recommended steps:\n` +
|
|
221
|
+
recommended_steps
|
|
222
|
+
.map(s => ` Step ${s.step} (${s.operation_type}): ${s.purpose}`)
|
|
223
|
+
.join("\n") +
|
|
224
|
+
`\n\nHint: This is the canonical Service↔Guard circular dependency. The 3-step ` +
|
|
225
|
+
`pattern above is the documented solution (see SCHEMA-03 / P0-01 fix in ` +
|
|
226
|
+
`schema/call/service.ts publish field description).`;
|
|
227
|
+
return {
|
|
228
|
+
content: [{
|
|
229
|
+
type: "text",
|
|
230
|
+
text: guideText,
|
|
231
|
+
}],
|
|
232
|
+
structuredContent: {
|
|
233
|
+
result: {
|
|
234
|
+
type: "error",
|
|
235
|
+
error: `Cannot create Service with order_allocators referencing non-existent Guard(s): ${guardList}. Circular dependency: Service↔Guard.`,
|
|
236
|
+
error_code: "circular_dependency_detected",
|
|
237
|
+
retryable: true,
|
|
238
|
+
recovery_hint: JSON.stringify(recommended_steps),
|
|
239
|
+
related_object: serviceName,
|
|
240
|
+
},
|
|
241
|
+
message: "Circular dependency detected: Service ↔ Guard. See recovery_hint for the 3-step creation pattern.",
|
|
242
|
+
},
|
|
243
|
+
};
|
|
244
|
+
}
|
|
8
245
|
export async function handleOnchainOperations(args) {
|
|
9
246
|
let validated;
|
|
10
247
|
let constraintWarnings = [];
|
|
@@ -34,12 +271,19 @@ export async function handleOnchainOperations(args) {
|
|
|
34
271
|
const rData = ResponseData(result);
|
|
35
272
|
const created = rData.filter((r) => r.change === "created" && r.object);
|
|
36
273
|
for (const obj of created) {
|
|
274
|
+
const isService = !!(obj.type_raw && obj.type_raw.includes("service::Service"));
|
|
37
275
|
await lp.addObject(project.id, {
|
|
38
276
|
objectAddress: obj.object,
|
|
39
277
|
objectType: obj.type_raw,
|
|
40
|
-
role: "reference",
|
|
278
|
+
role: isService ? "core" : "reference",
|
|
41
279
|
});
|
|
42
280
|
}
|
|
281
|
+
if (operationType === "service") {
|
|
282
|
+
const svc = created.find((o) => o.type_raw && o.type_raw.includes("service::Service"));
|
|
283
|
+
if (svc && svc.object) {
|
|
284
|
+
await lp.updateProject(project.id, { serviceAddress: svc.object }).catch(() => { });
|
|
285
|
+
}
|
|
286
|
+
}
|
|
43
287
|
}
|
|
44
288
|
catch {
|
|
45
289
|
}
|
|
@@ -95,13 +339,96 @@ export async function handleOnchainOperations(args) {
|
|
|
95
339
|
delete env.project;
|
|
96
340
|
delete env.client_schema_version;
|
|
97
341
|
delete env.schema_strict_mode;
|
|
342
|
+
const skillsHint = getSkillsHintForOnchain(validated.operation_type, validated.data);
|
|
343
|
+
if (skillsHint) {
|
|
344
|
+
constraintWarnings.push(skillsHint);
|
|
345
|
+
}
|
|
98
346
|
switch (validated.operation_type) {
|
|
99
347
|
case "service": {
|
|
100
|
-
const callService = new CallService(validated.data);
|
|
101
|
-
const result = validated.submission
|
|
102
|
-
? await callService.call_with_submission(env, await transformSubmission(validated.submission))
|
|
103
|
-
: await callService.call(env);
|
|
104
348
|
const data = validated.data;
|
|
349
|
+
const circularDepGuide = await detectServiceGuardCircularDependency(data);
|
|
350
|
+
if (circularDepGuide) {
|
|
351
|
+
return circularDepGuide;
|
|
352
|
+
}
|
|
353
|
+
const fundResult = await processFundOperation(data, "service", env?.network);
|
|
354
|
+
constraintWarnings.push(...fundResult.warnings);
|
|
355
|
+
if (fundResult.confirmation) {
|
|
356
|
+
constraintWarnings.push(fundResult.confirmation.message);
|
|
357
|
+
const fundHint = generateFundSkillsHint(fundResult.confirmation);
|
|
358
|
+
if (fundHint)
|
|
359
|
+
constraintWarnings.push(fundHint);
|
|
360
|
+
}
|
|
361
|
+
const orderAllocators = data?.order_allocators;
|
|
362
|
+
if (orderAllocators && typeof orderAllocators === "object") {
|
|
363
|
+
const allocators = Array.isArray(orderAllocators.allocators)
|
|
364
|
+
? orderAllocators.allocators : [];
|
|
365
|
+
for (let i = 0; i < allocators.length; i++) {
|
|
366
|
+
const alloc = allocators[i];
|
|
367
|
+
const sharing = Array.isArray(alloc?.sharing) ? alloc.sharing : [];
|
|
368
|
+
if (sharing.length <= 1)
|
|
369
|
+
continue;
|
|
370
|
+
const seen = new Map();
|
|
371
|
+
for (let j = 0; j < sharing.length; j++) {
|
|
372
|
+
const who = sharing[j]?.who;
|
|
373
|
+
let key = "";
|
|
374
|
+
if (typeof who === "string") {
|
|
375
|
+
key = who;
|
|
376
|
+
}
|
|
377
|
+
else if (who && typeof who === "object") {
|
|
378
|
+
if (who.Entity && typeof who.Entity === "object") {
|
|
379
|
+
key = "Entity:" + (who.Entity.name_or_address ?? "");
|
|
380
|
+
}
|
|
381
|
+
else if (who.Signer) {
|
|
382
|
+
key = "Signer";
|
|
383
|
+
}
|
|
384
|
+
else if (who.GuardIdentifier !== undefined) {
|
|
385
|
+
key = "Guard:" + who.GuardIdentifier;
|
|
386
|
+
}
|
|
387
|
+
else {
|
|
388
|
+
key = JSON.stringify(who);
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
if (!key)
|
|
392
|
+
continue;
|
|
393
|
+
const count = seen.get(key) ?? 0;
|
|
394
|
+
seen.set(key, count + 1);
|
|
395
|
+
}
|
|
396
|
+
for (const [key, count] of seen) {
|
|
397
|
+
if (count > 1) {
|
|
398
|
+
constraintWarnings.push(`DUPLICATE SHARING ENTITY: Allocator[${i}] has entity "${key}" appearing ${count} times ` +
|
|
399
|
+
`in the sharing array. This is likely a configuration error — each entity should appear ` +
|
|
400
|
+
`at most once per allocator. Total sharing: ${count * 100}% to the same entity. ` +
|
|
401
|
+
`If intentional, ignore this warning.`);
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
const callService = new CallService(validated.data);
|
|
407
|
+
let result;
|
|
408
|
+
try {
|
|
409
|
+
result = validated.submission
|
|
410
|
+
? await callService.call_with_submission(env, await transformSubmission(validated.submission))
|
|
411
|
+
: await callService.call(env);
|
|
412
|
+
}
|
|
413
|
+
catch (e) {
|
|
414
|
+
const errMsg = e.message ?? String(e);
|
|
415
|
+
if (/not found|GetObjectExisted|resolve|LocalMark|failed to resolve/i.test(errMsg)) {
|
|
416
|
+
const permRef = (typeof data?.object === 'object' && data?.object !== null)
|
|
417
|
+
? data.object.permission
|
|
418
|
+
: undefined;
|
|
419
|
+
throw new Error(`DEPENDENCY RESOLUTION FAILED: One or more referenced objects could not be resolved.\n` +
|
|
420
|
+
`Original error: ${errMsg}\n` +
|
|
421
|
+
`Common causes:\n` +
|
|
422
|
+
` 1. Object name typo — check spelling in LocalMark\n` +
|
|
423
|
+
` 2. Object not yet created — create dependencies first\n` +
|
|
424
|
+
` 3. Object on different network — check env.network\n` +
|
|
425
|
+
`Referenced objects in this call: machine=${data?.machine ?? "<none>"}, ` +
|
|
426
|
+
`buy_guard=${data?.buy_guard ?? "<none>"}, ` +
|
|
427
|
+
`permission=${permRef ?? "<inline/new>"}, ` +
|
|
428
|
+
`arbitrations=${Array.isArray(data?.arbitrations) ? data.arbitrations.length + " item(s)" : "<none>"}`);
|
|
429
|
+
}
|
|
430
|
+
throw e;
|
|
431
|
+
}
|
|
105
432
|
const intent = data?.publish ? "publish service" : data?.bPublished !== undefined ? "modify service" : "create service";
|
|
106
433
|
const isCreatingService = data?.object != null && typeof data.object === "object";
|
|
107
434
|
const hasCompensationFundAdd = data?.compensation_fund_add != null;
|
|
@@ -112,6 +439,30 @@ export async function handleOnchainOperations(args) {
|
|
|
112
439
|
"from this Service. (Note: some industries like freelance do not require this; " +
|
|
113
440
|
"the evaluation engine will check industry-specific requirements.)");
|
|
114
441
|
}
|
|
442
|
+
const isPublishing = data?.publish === true;
|
|
443
|
+
const hasArbitrations = Array.isArray(data?.arbitrations) && data.arbitrations.length > 0;
|
|
444
|
+
if (isPublishing && !hasArbitrations && hasCompensationFundAdd) {
|
|
445
|
+
throw new Error("HARD PRE-CHECK FAILED: Cannot publish Service with compensation_fund > 0 but no Arbitration bound.\n" +
|
|
446
|
+
"Contract (service.move:494): assert!(arbitration_count > 0, E_ARBITRATION_NOT_SET_WITH_COMPENSATION_FUND).\n" +
|
|
447
|
+
"The transaction WILL ABORT on-chain if you proceed.\n" +
|
|
448
|
+
"Fix: (1) Create an Arbitration object first (onchain_operations with operation_type='arbitration').\n" +
|
|
449
|
+
" (2) Set data.arbitrations=[<arbitration_name_or_id>] in this same call.\n" +
|
|
450
|
+
" (3) Then call publish=true.\n" +
|
|
451
|
+
"Note: After publish, arbitrations can still be ADDED (but not removed without pause+lock).");
|
|
452
|
+
}
|
|
453
|
+
if (isPublishing && !hasArbitrations && !hasCompensationFundAdd) {
|
|
454
|
+
constraintWarnings.push("WARNING: Publishing Service without arbitrations. If compensation_fund was " +
|
|
455
|
+
"deposited in a prior call, the contract (service.move:494) WILL ABORT with " +
|
|
456
|
+
"E_ARBITRATION_NOT_SET_WITH_COMPENSATION_FUND. If compensation_fund is 0, " +
|
|
457
|
+
"publish will succeed but buyers have no dispute resolution path. " +
|
|
458
|
+
"Recommended: bind arbitrations before publish.");
|
|
459
|
+
}
|
|
460
|
+
if (!isPublishing && hasCompensationFundAdd && !hasArbitrations) {
|
|
461
|
+
constraintWarnings.push("WARNING: Depositing compensation_fund on a Service without arbitrations bound. " +
|
|
462
|
+
"If this Service is already published, arbitration rulings will not be able to " +
|
|
463
|
+
"withdraw compensation from this Service. Recommended: bind arbitrations first, " +
|
|
464
|
+
"then deposit compensation_fund.");
|
|
465
|
+
}
|
|
115
466
|
const output = handleCallResult(result, withHarness(buildCtx(data), "service", intent));
|
|
116
467
|
autoAddToProject(projectEnvPrefix, validated.operation_type, result).catch(() => { });
|
|
117
468
|
return output;
|
|
@@ -141,6 +492,33 @@ export async function handleOnchainOperations(args) {
|
|
|
141
492
|
bReplace: true
|
|
142
493
|
};
|
|
143
494
|
}
|
|
495
|
+
const machineData = validated.data;
|
|
496
|
+
const permWarning = await checkMachinePermissionBeforePublish(machineData, env);
|
|
497
|
+
if (permWarning) {
|
|
498
|
+
constraintWarnings.push(permWarning);
|
|
499
|
+
}
|
|
500
|
+
const machineNodes = machineData?.node?.nodes ?? machineData?.node;
|
|
501
|
+
if (Array.isArray(machineNodes)) {
|
|
502
|
+
const arbPatterns = /^(dispute|disputed|arbitration|arb_|arb\.|resolve_dispute|start_arbitration|open_dispute)/i;
|
|
503
|
+
for (const node of machineNodes) {
|
|
504
|
+
const nodeName = typeof node === 'object' ? node?.name : '';
|
|
505
|
+
if (typeof nodeName === 'string' && arbPatterns.test(nodeName)) {
|
|
506
|
+
constraintWarnings.push(`ARBITRATION SEPARATION WARNING: Machine node "${nodeName}" appears to be an arbitration-related node.\n` +
|
|
507
|
+
`CORE PRINCIPLE: A merchant cannot handle disputes fairly — they would be 'both player and referee'.\n` +
|
|
508
|
+
`The WoWok smart contract design makes Arbitration a completely separate object:\n` +
|
|
509
|
+
` - Arbitration has its own Permission, voting_guard, usage_guard, and balance\n` +
|
|
510
|
+
` - Arb instances have a 7-state lifecycle managed by Arbitration, not by Machine\n` +
|
|
511
|
+
` - The Order object is the bridge: it has 'progress' (Machine) and 'dispute' (Arb list) fields\n` +
|
|
512
|
+
` - When Arb rules, it calls order::compensate() — the ONLY connection to the business flow\n\n` +
|
|
513
|
+
`CORRECT PATTERN:\n` +
|
|
514
|
+
` - Machine: business states only (ordered -> shipped -> delivered -> refunded -> completed)\n` +
|
|
515
|
+
` - Arbitration: separate object with its own Permission (NOT shared with Service)\n` +
|
|
516
|
+
` - Arb: 7-state lifecycle (Principal_confirming -> Arbitrator_confirming -> Voting -> Arbitrated -> Objectionable -> Finished -> Withdrawn)\n` +
|
|
517
|
+
` - Use 'refunded'/'cancelled' nodes for the BUSINESS OUTCOME of a dispute, not 'disputed'\n\n` +
|
|
518
|
+
`If this node name is a legitimate business state (not arbitration), ignore this warning.`);
|
|
519
|
+
}
|
|
520
|
+
}
|
|
521
|
+
}
|
|
144
522
|
const callMachine = new CallMachine(validated.data);
|
|
145
523
|
const result = validated.submission
|
|
146
524
|
? await callMachine.call_with_submission(env, await transformSubmission(validated.submission))
|
|
@@ -161,6 +539,65 @@ export async function handleOnchainOperations(args) {
|
|
|
161
539
|
const result = validated.submission
|
|
162
540
|
? await callProgress.call_with_submission(env, await transformSubmission(validated.submission))
|
|
163
541
|
: await callProgress.call(env);
|
|
542
|
+
if (!validated.submission && result && typeof result === 'object' && 'submission' in result) {
|
|
543
|
+
const submissionData = result.submission;
|
|
544
|
+
if (Array.isArray(submissionData) && submissionData.length > 0) {
|
|
545
|
+
const guardRef = submissionData[0]?.guard;
|
|
546
|
+
if (guardRef) {
|
|
547
|
+
const submissionCtx = {
|
|
548
|
+
operation: "progress_next",
|
|
549
|
+
network: env?.network,
|
|
550
|
+
signer: env?.account,
|
|
551
|
+
progress_address: validated.data?.object,
|
|
552
|
+
order_address: validated.data?.task,
|
|
553
|
+
};
|
|
554
|
+
const prompt = await generateGuardSubmissionPrompt(guardRef, submissionCtx);
|
|
555
|
+
if (prompt) {
|
|
556
|
+
constraintWarnings.push(formatSubmissionPrompt(prompt));
|
|
557
|
+
}
|
|
558
|
+
}
|
|
559
|
+
}
|
|
560
|
+
}
|
|
561
|
+
if (result && typeof result === 'object' && 'digest' in result
|
|
562
|
+
&& result?.effects?.status?.status === 'success') {
|
|
563
|
+
try {
|
|
564
|
+
const progressRef = validated.data?.object;
|
|
565
|
+
let progressAddr;
|
|
566
|
+
if (typeof progressRef === 'string') {
|
|
567
|
+
if (progressRef.startsWith('0x')) {
|
|
568
|
+
progressAddr = progressRef;
|
|
569
|
+
}
|
|
570
|
+
else {
|
|
571
|
+
progressAddr = await LocalMark.Instance().get_address(progressRef) ?? undefined;
|
|
572
|
+
}
|
|
573
|
+
}
|
|
574
|
+
if (progressAddr) {
|
|
575
|
+
const progressQuery = await query_objects({
|
|
576
|
+
objects: [progressAddr],
|
|
577
|
+
no_cache: true,
|
|
578
|
+
network: env?.network,
|
|
579
|
+
});
|
|
580
|
+
const progressObj = progressQuery?.objects?.[0];
|
|
581
|
+
if (progressObj?.type === "Progress") {
|
|
582
|
+
const currentNode = progressObj.current ?? "<unknown>";
|
|
583
|
+
const historyCount = Array.isArray(progressObj.session)
|
|
584
|
+
? progressObj.session.length : 0;
|
|
585
|
+
const machineAddr = progressObj.machine;
|
|
586
|
+
const previewLines = [
|
|
587
|
+
`PROGRESS PREVIEW:`,
|
|
588
|
+
` • current node: "${currentNode}"`,
|
|
589
|
+
` • history count: ${historyCount} session(s)`,
|
|
590
|
+
];
|
|
591
|
+
if (machineAddr) {
|
|
592
|
+
previewLines.push(` • machine: ${machineAddr}`);
|
|
593
|
+
}
|
|
594
|
+
constraintWarnings.push(previewLines.join("\n"));
|
|
595
|
+
}
|
|
596
|
+
}
|
|
597
|
+
}
|
|
598
|
+
catch {
|
|
599
|
+
}
|
|
600
|
+
}
|
|
164
601
|
const output = handleCallResult(result, buildCtx(validated.data));
|
|
165
602
|
autoAddToProject(projectEnvPrefix, validated.operation_type, result).catch(() => { });
|
|
166
603
|
return output;
|
|
@@ -175,6 +612,14 @@ export async function handleOnchainOperations(args) {
|
|
|
175
612
|
return output;
|
|
176
613
|
}
|
|
177
614
|
case "arbitration": {
|
|
615
|
+
const arbFundResult = await processFundOperation(validated.data, "arbitration", env?.network);
|
|
616
|
+
constraintWarnings.push(...arbFundResult.warnings);
|
|
617
|
+
if (arbFundResult.confirmation) {
|
|
618
|
+
constraintWarnings.push(arbFundResult.confirmation.message);
|
|
619
|
+
const fundHint = generateFundSkillsHint(arbFundResult.confirmation);
|
|
620
|
+
if (fundHint)
|
|
621
|
+
constraintWarnings.push(fundHint);
|
|
622
|
+
}
|
|
178
623
|
const callArbitration = new CallArbitration(validated.data);
|
|
179
624
|
const result = validated.submission
|
|
180
625
|
? await callArbitration.call_with_submission(env, await transformSubmission(validated.submission))
|
|
@@ -193,6 +638,14 @@ export async function handleOnchainOperations(args) {
|
|
|
193
638
|
return output;
|
|
194
639
|
}
|
|
195
640
|
case "treasury": {
|
|
641
|
+
const trFundResult = await processFundOperation(validated.data, "treasury", env?.network);
|
|
642
|
+
constraintWarnings.push(...trFundResult.warnings);
|
|
643
|
+
if (trFundResult.confirmation) {
|
|
644
|
+
constraintWarnings.push(trFundResult.confirmation.message);
|
|
645
|
+
const fundHint = generateFundSkillsHint(trFundResult.confirmation);
|
|
646
|
+
if (fundHint)
|
|
647
|
+
constraintWarnings.push(fundHint);
|
|
648
|
+
}
|
|
196
649
|
const callTreasury = new CallTreasury(validated.data);
|
|
197
650
|
const result = validated.submission
|
|
198
651
|
? await callTreasury.call_with_submission(env, await transformSubmission(validated.submission))
|
|
@@ -202,6 +655,14 @@ export async function handleOnchainOperations(args) {
|
|
|
202
655
|
return output;
|
|
203
656
|
}
|
|
204
657
|
case "reward": {
|
|
658
|
+
const rwFundResult = await processFundOperation(validated.data, "reward", env?.network);
|
|
659
|
+
constraintWarnings.push(...rwFundResult.warnings);
|
|
660
|
+
if (rwFundResult.confirmation) {
|
|
661
|
+
constraintWarnings.push(rwFundResult.confirmation.message);
|
|
662
|
+
const fundHint = generateFundSkillsHint(rwFundResult.confirmation);
|
|
663
|
+
if (fundHint)
|
|
664
|
+
constraintWarnings.push(fundHint);
|
|
665
|
+
}
|
|
205
666
|
const transformedData = transformRewardInput(validated.data);
|
|
206
667
|
const callReward = new CallReward(transformedData);
|
|
207
668
|
const result = validated.submission
|
|
@@ -216,6 +677,51 @@ export async function handleOnchainOperations(args) {
|
|
|
216
677
|
const result = validated.submission
|
|
217
678
|
? await callAllocation.call_with_submission(env, await transformSubmission(validated.submission))
|
|
218
679
|
: await callAllocation.call(env);
|
|
680
|
+
const allocData = validated.data;
|
|
681
|
+
if (allocData?.alloc_by_guard) {
|
|
682
|
+
const createdPayments = ResponseData(result).filter((e) => e?.type === "Payment" && e?.change === "created");
|
|
683
|
+
if (createdPayments.length > 0) {
|
|
684
|
+
const paymentAddrs = createdPayments.map((p) => p.object).join(", ");
|
|
685
|
+
try {
|
|
686
|
+
const paymentResult = await query_objects({
|
|
687
|
+
objects: createdPayments.map((p) => p.object),
|
|
688
|
+
no_cache: true,
|
|
689
|
+
network: env?.network,
|
|
690
|
+
});
|
|
691
|
+
const distributionLines = [];
|
|
692
|
+
let totalDistributed = BigInt(0);
|
|
693
|
+
for (const obj of paymentResult?.objects || []) {
|
|
694
|
+
if (obj?.type === "Payment" && obj?.record) {
|
|
695
|
+
for (const entry of obj.record) {
|
|
696
|
+
const recipientLabel = formatRecipientLabel(entry.recipient);
|
|
697
|
+
const amountStr = typeof entry.amount === 'string' ? entry.amount : String(entry.amount);
|
|
698
|
+
const amountBig = BigInt(amountStr);
|
|
699
|
+
totalDistributed += amountBig;
|
|
700
|
+
distributionLines.push(` • ${recipientLabel}: ${formatMistAmount(amountBig)}`);
|
|
701
|
+
}
|
|
702
|
+
if (obj.object) {
|
|
703
|
+
distributionLines.push(` • Payment object: ${obj.object}`);
|
|
704
|
+
}
|
|
705
|
+
}
|
|
706
|
+
}
|
|
707
|
+
if (distributionLines.length > 0) {
|
|
708
|
+
distributionLines.unshift(`DISTRIBUTION DETAILS (alloc_by_guard):`);
|
|
709
|
+
distributionLines.push(` ─────────────────`, ` • Total distributed: ${formatMistAmount(totalDistributed)}`);
|
|
710
|
+
const isEscrow = paymentResult?.objects?.some((obj) => obj?.type === "Payment" && obj?.info?.for_object);
|
|
711
|
+
if (isEscrow) {
|
|
712
|
+
distributionLines.push(``, `ESCROW MODE: Funds are held in escrow (Payment.for_object points to an Order). ` +
|
|
713
|
+
`The Order owner must call order_claim (or service_order_claim) to actually receive the funds. ` +
|
|
714
|
+
`This happens when the Guard's sharing config uses { GuardIdentifier: 0 }.`);
|
|
715
|
+
}
|
|
716
|
+
constraintWarnings.push(distributionLines.join("\n"));
|
|
717
|
+
}
|
|
718
|
+
}
|
|
719
|
+
catch {
|
|
720
|
+
constraintWarnings.push(`alloc_by_guard created Payment object(s) [${paymentAddrs}]. ` +
|
|
721
|
+
`Query these Payment objects to see the distribution details and check for_object for escrow mode.`);
|
|
722
|
+
}
|
|
723
|
+
}
|
|
724
|
+
}
|
|
219
725
|
const output = handleCallResult(result, buildCtx(validated.data));
|
|
220
726
|
autoAddToProject(projectEnvPrefix, validated.operation_type, result).catch(() => { });
|
|
221
727
|
return output;
|
|
@@ -277,6 +783,34 @@ export async function handleOnchainOperations(args) {
|
|
|
277
783
|
}
|
|
278
784
|
const callGuard = new CallGuard(validatedData);
|
|
279
785
|
const result = await callGuard.call(env);
|
|
786
|
+
if (result && typeof result === 'object' && 'digest' in result
|
|
787
|
+
&& result?.effects?.status?.status === 'success') {
|
|
788
|
+
try {
|
|
789
|
+
const rootType = validatedData.root?.type ?? "<unknown>";
|
|
790
|
+
const tableArr = Array.isArray(validatedData.table) ? validatedData.table : [];
|
|
791
|
+
const tableEntries = tableArr.length;
|
|
792
|
+
const submissionEntries = tableArr.filter((t) => t?.b_submission === true).length;
|
|
793
|
+
const relyGuards = validatedData.rely?.guards;
|
|
794
|
+
const relyCount = Array.isArray(relyGuards) ? relyGuards.length : 0;
|
|
795
|
+
const relyMode = validatedData.rely?.logic_or === true
|
|
796
|
+
? "OR" : validatedData.rely?.logic_or === false ? "AND" : "none";
|
|
797
|
+
const summaryLines = [
|
|
798
|
+
`GUARD LOGIC SUMMARY:`,
|
|
799
|
+
` • root type: ${rootType}`,
|
|
800
|
+
` • table entries: ${tableEntries} (${submissionEntries} require runtime submission)`,
|
|
801
|
+
];
|
|
802
|
+
if (relyCount > 0) {
|
|
803
|
+
summaryLines.push(` • relies on: ${relyCount} guard(s) (mode: ${relyMode})`);
|
|
804
|
+
}
|
|
805
|
+
if (validatedData.description) {
|
|
806
|
+
const desc = String(validatedData.description).slice(0, 80);
|
|
807
|
+
summaryLines.push(` • description: "${desc}"`);
|
|
808
|
+
}
|
|
809
|
+
constraintWarnings.push(summaryLines.join("\n"));
|
|
810
|
+
}
|
|
811
|
+
catch {
|
|
812
|
+
}
|
|
813
|
+
}
|
|
280
814
|
const output = handleCallResult(result, buildCtx(validated.data));
|
|
281
815
|
autoAddToProject(projectEnvPrefix, validated.operation_type, result).catch(() => { });
|
|
282
816
|
return output;
|
|
@@ -290,6 +824,37 @@ export async function handleOnchainOperations(args) {
|
|
|
290
824
|
return output;
|
|
291
825
|
}
|
|
292
826
|
case "payment": {
|
|
827
|
+
const payFundResult = await processFundOperation(validated.data, "payment", env?.network);
|
|
828
|
+
constraintWarnings.push(...payFundResult.warnings);
|
|
829
|
+
if (payFundResult.confirmation) {
|
|
830
|
+
constraintWarnings.push(payFundResult.confirmation.message);
|
|
831
|
+
const fundHint = generateFundSkillsHint(payFundResult.confirmation);
|
|
832
|
+
if (fundHint)
|
|
833
|
+
constraintWarnings.push(fundHint);
|
|
834
|
+
}
|
|
835
|
+
const paymentData = validated.data;
|
|
836
|
+
if (paymentData?.receive === true) {
|
|
837
|
+
constraintWarnings.push("RECEIVE MODE (order_claim): You are unwrapping a CoinWrapper to your wallet. " +
|
|
838
|
+
"This is the final step of the escrow flow:\n" +
|
|
839
|
+
" 1. Allocation's alloc_by_guard created a Payment object with your address as a recipient\n" +
|
|
840
|
+
" 2. The Payment's revenue split transferred a CoinWrapper to your wallet (owned but not spendable)\n" +
|
|
841
|
+
" 3. THIS operation unwraps the CoinWrapper via payment::unwrap_to_myself, deleting the " +
|
|
842
|
+
"CoinWrapper and transferring the underlying coin to tx_context::sender\n" +
|
|
843
|
+
"Requirements:\n" +
|
|
844
|
+
" - You MUST be the CoinWrapper's owner (the recipient specified in the Allocation)\n" +
|
|
845
|
+
" - type_parameter MUST match the coin type used when the Allocation created the Payment " +
|
|
846
|
+
"(e.g. '0x2::wow::WOW')\n" +
|
|
847
|
+
" - object can be a CoinWrapper ID (0x...) or a local mark name\n" +
|
|
848
|
+
"To find received CoinWrappers: call query_toolkit with query_type='onchain_received' " +
|
|
849
|
+
"and type='CoinWrapper' for your account.\n" +
|
|
850
|
+
"After success: verify your balance increased via account_balance query.");
|
|
851
|
+
}
|
|
852
|
+
else if (paymentData?.revenue) {
|
|
853
|
+
constraintWarnings.push("CREATE MODE: Creating a new Payment object. Payments are IMMUTABLE after creation — " +
|
|
854
|
+
"they cannot be modified. The 'revenue' array defines the recipients and amounts; " +
|
|
855
|
+
"ensure correctness before submitting. The 'info.for_guard' field (if set) binds this " +
|
|
856
|
+
"Payment to a Guard for conditional release (common in escrow workflows).");
|
|
857
|
+
}
|
|
293
858
|
const callPayment = new CallPayment(validated.data);
|
|
294
859
|
const result = await callPayment.call(env);
|
|
295
860
|
const output = handleCallResult(result, buildCtx(validated.data));
|