183 lines
4.7 KiB
TypeScript
183 lines
4.7 KiB
TypeScript
import { constructTake, extractRead, GRead, GTake, ResolvedOperation, ResolvedRead } from '@coinweb/contract-kit';
|
|
import { CwebTake } from '@coinweb/contract-kit/dist/types/operations/take';
|
|
|
|
import { ResolvedOp, TypedClaim } from '../../types';
|
|
import { resultKey } from '../claims';
|
|
import { mutexBlockLockKey, mutexBlockUnlockKey, mutexExecOpsKey, MutexExecOpsResult } from '../mutex';
|
|
import { isResolvedBlockOp, isResolvedReadOp, isResolvedTakeOp } from '../utils';
|
|
|
|
const extractFunds = (fundsOp: GRead<ResolvedRead>, takenFundsIds: string[]) => {
|
|
if (!fundsOp) {
|
|
return {
|
|
takeOps: [],
|
|
amount: 0n,
|
|
};
|
|
}
|
|
|
|
const claims = extractRead(fundsOp);
|
|
|
|
const newClaims = claims?.filter(({ content }) => !takenFundsIds.includes((content.key.second_part as [string])[0]));
|
|
|
|
if (!newClaims?.length) {
|
|
return {
|
|
takeOps: [],
|
|
amount: 0n,
|
|
};
|
|
}
|
|
|
|
return {
|
|
takeOps: newClaims.map(({ content }) => constructTake(content.key)),
|
|
amount: newClaims.reduce((acc, { content }) => acc + BigInt(content.fees_stored), 0n),
|
|
};
|
|
};
|
|
|
|
export const extractOps = ({
|
|
contractArgs,
|
|
takenFundsIds,
|
|
execOpsIndexes,
|
|
}: {
|
|
contractArgs: ResolvedOperation[];
|
|
takenFundsIds: string[];
|
|
execOpsIndexes: number[];
|
|
}) => {
|
|
if (!contractArgs.length) {
|
|
return {
|
|
extractedOps: [],
|
|
fundsTakeOps: [],
|
|
storedCweb: 0n,
|
|
executionOpsTakeOp: null,
|
|
};
|
|
}
|
|
|
|
const [fundsOp, ...resolvedOps] = contractArgs;
|
|
|
|
if (!isResolvedReadOp(fundsOp)) {
|
|
throw new Error('Wrong funds claims');
|
|
}
|
|
|
|
const extractedOps: ResolvedOp[] = [];
|
|
let executedOps: MutexExecOpsResult = [];
|
|
let executionOpsProfit: bigint = 0n;
|
|
let executionOpsTakeOp: GTake<CwebTake> | null = null;
|
|
|
|
let i = 0;
|
|
|
|
while (i < resolvedOps.length) {
|
|
const op = resolvedOps[i];
|
|
|
|
if (isResolvedBlockOp(op)) {
|
|
const { first } = op.BlockOp.blocks_on[0][0];
|
|
|
|
console.log('first >>>', JSON.stringify(first));
|
|
|
|
//Maybe it is needed to check more conditions here
|
|
if (Array.isArray(first)) {
|
|
switch (first[0]) {
|
|
case resultKey: {
|
|
const nextAfterBlock = resolvedOps[i + 1];
|
|
|
|
if (!isResolvedTakeOp(nextAfterBlock)) {
|
|
throw new Error('Wrong subcall result');
|
|
}
|
|
|
|
extractedOps.push({ ChildOp: 0 }, ...(nextAfterBlock.TakeOp.result as TypedClaim<ResolvedOp[]>).body);
|
|
|
|
i += 2;
|
|
continue;
|
|
}
|
|
case mutexBlockLockKey: {
|
|
const nextAfterBlock = resolvedOps[i + 1];
|
|
|
|
if (!isResolvedTakeOp(nextAfterBlock)) {
|
|
throw new Error('Wrong mutex lock result');
|
|
}
|
|
|
|
extractedOps.push({ SlotOp: { ok: true } });
|
|
|
|
i += 2;
|
|
continue;
|
|
}
|
|
case mutexBlockUnlockKey: {
|
|
const nextAfterBlock = resolvedOps[i + 1];
|
|
|
|
if (!isResolvedTakeOp(nextAfterBlock)) {
|
|
throw new Error('Wrong mutex unlock result');
|
|
}
|
|
|
|
extractedOps.push({ SlotOp: { ok: true } });
|
|
|
|
i += 2;
|
|
continue;
|
|
}
|
|
case mutexExecOpsKey: {
|
|
const nextAfterBlock = resolvedOps[i + 1];
|
|
|
|
const execOpResultClaim = extractRead(nextAfterBlock)?.[0]?.content;
|
|
|
|
if (!execOpResultClaim) {
|
|
throw new Error('Wrong mutex exec result claim');
|
|
}
|
|
|
|
executedOps = execOpResultClaim.body as MutexExecOpsResult;
|
|
executionOpsProfit = BigInt(execOpResultClaim.fees_stored);
|
|
executionOpsTakeOp = constructTake(execOpResultClaim.key);
|
|
i += 2;
|
|
continue;
|
|
}
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (isResolvedTakeOp(op)) {
|
|
const keyFirstPart = op.TakeOp.result.key.first_part;
|
|
if (Array.isArray(keyFirstPart) && keyFirstPart[0] === mutexExecOpsKey) {
|
|
i++;
|
|
continue;
|
|
}
|
|
}
|
|
|
|
extractedOps.push(op);
|
|
i++;
|
|
}
|
|
|
|
const allOps: ResolvedOp[] = [];
|
|
|
|
const totalOpsCount = extractedOps.length + executedOps.length;
|
|
|
|
for (let i = 0; i < totalOpsCount; i++) {
|
|
if (execOpsIndexes.includes(i)) {
|
|
const op = executedOps.shift();
|
|
|
|
if (!op) {
|
|
throw new Error('Wrong mutex exec result place');
|
|
}
|
|
|
|
if (op.ok) {
|
|
allOps.push(op.resolved);
|
|
} else {
|
|
allOps.push({ SlotOp: { ok: false, error: op.error } });
|
|
}
|
|
} else {
|
|
const op = extractedOps.shift();
|
|
|
|
if (!op) {
|
|
throw new Error('Contract call args parsing error');
|
|
}
|
|
|
|
allOps.push(op);
|
|
}
|
|
}
|
|
|
|
const { takeOps, amount } = extractFunds(fundsOp, takenFundsIds);
|
|
|
|
return {
|
|
fundsTakeOps: takeOps,
|
|
storedCweb: amount + executionOpsProfit,
|
|
extractedOps: allOps,
|
|
executionOpsTakeOp,
|
|
};
|
|
};
|