feat: add fee management
This commit is contained in:
parent
732ca0f292
commit
27cd1f50b6
34
packages/cwait/src/onchain/claims/funds.ts
Normal file
34
packages/cwait/src/onchain/claims/funds.ts
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
import {
|
||||||
|
constructClaim,
|
||||||
|
constructClaimKey,
|
||||||
|
constructRangeRead,
|
||||||
|
constructStore,
|
||||||
|
constructTake,
|
||||||
|
CwebStore,
|
||||||
|
GRead,
|
||||||
|
GStore,
|
||||||
|
} from '@coinweb/contract-kit';
|
||||||
|
import { CwebRead } from '@coinweb/contract-kit/dist/esm/operations/read';
|
||||||
|
import { toHex } from 'lib/shared';
|
||||||
|
|
||||||
|
import { context } from '../context';
|
||||||
|
import { uuid } from '../utils';
|
||||||
|
|
||||||
|
export const fundsKey = '_funds';
|
||||||
|
|
||||||
|
export const constructFundsClaimKeyFirstPart = (processId: string) => [fundsKey, processId];
|
||||||
|
|
||||||
|
export const constructFundsClaimKey = (processId: string, claimId?: string) =>
|
||||||
|
constructClaimKey(constructFundsClaimKeyFirstPart(processId), [claimId ?? uuid()]);
|
||||||
|
|
||||||
|
export const constructFundsClaim = (processId: string, amount: bigint) =>
|
||||||
|
constructClaim(constructFundsClaimKey(processId), {}, toHex(amount));
|
||||||
|
|
||||||
|
export const constructFundsClaimStore = (processId: string, amount: bigint): GStore<CwebStore> =>
|
||||||
|
constructStore(constructFundsClaim(processId, amount));
|
||||||
|
|
||||||
|
export const constructFundsClaimRangRead = (processId: string): GRead<CwebRead> =>
|
||||||
|
constructRangeRead(context.issuer, constructFundsClaimKeyFirstPart(processId), {}, 10000);
|
||||||
|
|
||||||
|
export const constructFundsClaimTakeOp = (processId: string, id: string) =>
|
||||||
|
constructTake(constructFundsClaimKey(processId, id));
|
||||||
@ -0,0 +1,2 @@
|
|||||||
|
export * from './funds';
|
||||||
|
export * from './result';
|
||||||
@ -3,16 +3,18 @@ import {
|
|||||||
constructClaim,
|
constructClaim,
|
||||||
constructClaimKey,
|
constructClaimKey,
|
||||||
constructStore,
|
constructStore,
|
||||||
|
constructTake,
|
||||||
CwebStore,
|
CwebStore,
|
||||||
GRead,
|
|
||||||
GStore,
|
GStore,
|
||||||
|
constructRead,
|
||||||
} from '@coinweb/contract-kit';
|
} from '@coinweb/contract-kit';
|
||||||
import { constructRead, CwebRead } from '@coinweb/contract-kit/dist/esm/operations/read';
|
|
||||||
|
|
||||||
import { ResolvedOp } from '../../types';
|
import { ResolvedOp } from '../../types';
|
||||||
import { context } from '../context';
|
import { context } from '../context';
|
||||||
|
|
||||||
export const constructResultClaimKey = (id: string) => constructClaimKey(['result'], [id]);
|
export const resultKey = '_result';
|
||||||
|
|
||||||
|
export const constructResultClaimKey = (id: string) => constructClaimKey([resultKey], [id]);
|
||||||
|
|
||||||
export const constructResultClaim = (id: string, result: ResolvedOp[]) =>
|
export const constructResultClaim = (id: string, result: ResolvedOp[]) =>
|
||||||
constructClaim(constructResultClaimKey(id), result, '0x0');
|
constructClaim(constructResultClaimKey(id), result, '0x0');
|
||||||
@ -20,8 +22,9 @@ export const constructResultClaim = (id: string, result: ResolvedOp[]) =>
|
|||||||
export const constructResultClaimStore = (id: string, result: ResolvedOp[]): GStore<CwebStore> =>
|
export const constructResultClaimStore = (id: string, result: ResolvedOp[]): GStore<CwebStore> =>
|
||||||
constructStore(constructResultClaim(id, result));
|
constructStore(constructResultClaim(id, result));
|
||||||
|
|
||||||
export const constructResultClaimRead = (id: string): GRead<CwebRead> =>
|
export const constructResultClaimRead = (id: string) => constructRead(context.issuer, constructResultClaimKey(id));
|
||||||
constructRead(context.issuer, constructResultClaimKey(id));
|
|
||||||
|
export const constructResultClaimTake = (id: string) => constructTake(constructResultClaimKey(id));
|
||||||
|
|
||||||
export const constructResultBlockFilter = (id: string): BlockFilter => {
|
export const constructResultBlockFilter = (id: string): BlockFilter => {
|
||||||
const { first_part: first, second_part: second } = constructResultClaimKey(id);
|
const { first_part: first, second_part: second } = constructResultClaimKey(id);
|
||||||
|
|||||||
@ -1,8 +1,11 @@
|
|||||||
import { Context, extractContractArgs, extractUser, getMethodArguments, User } from '@coinweb/contract-kit';
|
import { Context, extractUser, getMethodArguments } from '@coinweb/contract-kit';
|
||||||
import { getCallParameters, getContractIssuer } from 'lib/onchain';
|
import { getCallParameters, getContractIssuer } from 'lib/onchain';
|
||||||
|
|
||||||
import { ResolvedOp, TypedClaim } from '../../types';
|
import { ExecutorMethodArgs } from '../../types';
|
||||||
import { isResolvedBlockOp, isResolvedReadOp } from '../utils';
|
import { uuid } from '../utils';
|
||||||
|
|
||||||
|
import { extractFunds } from './extractFunds';
|
||||||
|
import { extractOps } from './extractOps';
|
||||||
|
|
||||||
let rawContext: Context | null = null;
|
let rawContext: Context | null = null;
|
||||||
|
|
||||||
@ -18,70 +21,50 @@ export const getRawContext = () => {
|
|||||||
return rawContext;
|
return rawContext;
|
||||||
};
|
};
|
||||||
|
|
||||||
const getMethodArgs = () => {
|
export const getMethodArgs = () => {
|
||||||
return getMethodArguments(getRawContext()) as [
|
return getMethodArguments(getRawContext()) as [methodName: string, ...ExecutorMethodArgs];
|
||||||
methodName: string,
|
|
||||||
initialArgs?: unknown[],
|
|
||||||
resolvedOps?: ResolvedOp[],
|
|
||||||
caller?: User,
|
|
||||||
isChild?: boolean,
|
|
||||||
];
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const extractResolvedOps = () => {
|
let thisId: string | undefined;
|
||||||
const resolvedOps = extractContractArgs(getRawContext().tx);
|
|
||||||
|
|
||||||
const extractedOps: ResolvedOp[] = [];
|
|
||||||
|
|
||||||
let i = 0;
|
|
||||||
|
|
||||||
while (i < resolvedOps.length) {
|
|
||||||
const op = resolvedOps[i];
|
|
||||||
|
|
||||||
if (isResolvedBlockOp(op)) {
|
|
||||||
const { first } = op.BlockOp.blocks_on[0][0];
|
|
||||||
|
|
||||||
//Maybe it is needed to check more conditions here
|
|
||||||
if (Array.isArray(first) && first[0] === 'result') {
|
|
||||||
const nextAfterBlock = resolvedOps[i + 1];
|
|
||||||
|
|
||||||
if (!isResolvedReadOp(nextAfterBlock)) {
|
|
||||||
throw new Error('Wrong subcall result');
|
|
||||||
}
|
|
||||||
|
|
||||||
extractedOps.push(
|
|
||||||
{ ChildOp: 0 },
|
|
||||||
...(nextAfterBlock.ReadOp.results[0].content as TypedClaim<ResolvedOp[]>).body
|
|
||||||
);
|
|
||||||
|
|
||||||
i += 2;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
extractedOps.push(op);
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
|
|
||||||
return extractedOps;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const context = {
|
export const context = {
|
||||||
get isChild() {
|
get isChild() {
|
||||||
return !!getMethodArgs()[4];
|
return !!getMethodArgs()[5];
|
||||||
|
},
|
||||||
|
get thisId() {
|
||||||
|
thisId = thisId ?? getMethodArgs()[4] ?? uuid();
|
||||||
|
return thisId;
|
||||||
|
},
|
||||||
|
get parentId() {
|
||||||
|
return getMethodArgs()[5];
|
||||||
},
|
},
|
||||||
get ops() {
|
get ops() {
|
||||||
console.log('Parse ops in context');
|
console.log('Parse ops in context');
|
||||||
|
|
||||||
const previousOps = getMethodArgs()[2] ?? [];
|
const previousOps = getMethodArgs()[2] ?? [];
|
||||||
const resolvedOps = extractResolvedOps();
|
const { extractedOps } = extractOps();
|
||||||
|
|
||||||
const allResolvedOps = [...previousOps, ...resolvedOps];
|
const allResolvedOps = [...previousOps, ...extractedOps];
|
||||||
|
|
||||||
console.log('new ops >>>', JSON.stringify(resolvedOps));
|
console.log('new ops >>>', JSON.stringify(extractedOps));
|
||||||
|
|
||||||
return allResolvedOps;
|
return allResolvedOps;
|
||||||
},
|
},
|
||||||
|
get funds() {
|
||||||
|
const { availableCweb } = getCallParameters(getRawContext());
|
||||||
|
|
||||||
|
const { amount: storedCweb, takeOps } = extractFunds();
|
||||||
|
|
||||||
|
console.log('Available Cweb: ', availableCweb);
|
||||||
|
console.log('Stored Cweb: ', storedCweb);
|
||||||
|
console.log('Take Ops: ', takeOps);
|
||||||
|
|
||||||
|
return {
|
||||||
|
availableCweb,
|
||||||
|
storedCweb,
|
||||||
|
takeOps,
|
||||||
|
};
|
||||||
|
},
|
||||||
get methodName() {
|
get methodName() {
|
||||||
return getMethodArguments(getRawContext())[0] as string;
|
return getMethodArguments(getRawContext())[0] as string;
|
||||||
},
|
},
|
||||||
@ -106,4 +89,7 @@ export const context = {
|
|||||||
get parentTxId() {
|
get parentTxId() {
|
||||||
return getRawContext().call.txid;
|
return getRawContext().call.txid;
|
||||||
},
|
},
|
||||||
|
get needSaveResult() {
|
||||||
|
return getMethodArgs()[6] ?? false;
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|||||||
34
packages/cwait/src/onchain/context/extractFunds.ts
Normal file
34
packages/cwait/src/onchain/context/extractFunds.ts
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
import { constructTake } from '@coinweb/contract-kit';
|
||||||
|
import { extractRead } from '@coinweb/contract-kit/dist/esm/operations/read';
|
||||||
|
|
||||||
|
import { getMethodArgs } from './context';
|
||||||
|
import { extractOps } from './extractOps';
|
||||||
|
|
||||||
|
export const extractFunds = () => {
|
||||||
|
const { fundsOp } = extractOps();
|
||||||
|
|
||||||
|
const takenFundsIds = getMethodArgs()[7] ?? [];
|
||||||
|
|
||||||
|
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),
|
||||||
|
};
|
||||||
|
};
|
||||||
58
packages/cwait/src/onchain/context/extractOps.ts
Normal file
58
packages/cwait/src/onchain/context/extractOps.ts
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
import { extractContractArgs } from '@coinweb/contract-kit';
|
||||||
|
|
||||||
|
import { ResolvedOp, TypedClaim } from '../../types';
|
||||||
|
import { resultKey } from '../claims/result';
|
||||||
|
import { isResolvedBlockOp, isResolvedReadOp, isResolvedTakeOp } from '../utils';
|
||||||
|
|
||||||
|
import { getRawContext } from './context';
|
||||||
|
|
||||||
|
export const extractOps = () => {
|
||||||
|
const contractArgs = extractContractArgs(getRawContext().tx);
|
||||||
|
|
||||||
|
if (!contractArgs.length) {
|
||||||
|
return {
|
||||||
|
extractedOps: [],
|
||||||
|
fundsOps: [],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const [fundsOp, ...resolvedOps] = contractArgs;
|
||||||
|
|
||||||
|
if (!isResolvedReadOp(fundsOp)) {
|
||||||
|
throw new Error('Wrong funds claims');
|
||||||
|
}
|
||||||
|
|
||||||
|
const extractedOps: ResolvedOp[] = [];
|
||||||
|
|
||||||
|
let i = 0;
|
||||||
|
|
||||||
|
while (i < resolvedOps.length) {
|
||||||
|
const op = resolvedOps[i];
|
||||||
|
|
||||||
|
if (isResolvedBlockOp(op)) {
|
||||||
|
const { first } = op.BlockOp.blocks_on[0][0];
|
||||||
|
|
||||||
|
//Maybe it is needed to check more conditions here
|
||||||
|
if (Array.isArray(first) && first[0] === 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extractedOps.push(op);
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
fundsOp,
|
||||||
|
extractedOps,
|
||||||
|
};
|
||||||
|
};
|
||||||
@ -1,9 +1,8 @@
|
|||||||
import { markTaskBatch } from './promisifiedOps/awaited';
|
import { markTaskBatch } from './promisifiedOps/awaited';
|
||||||
|
import { getBatchId } from './utils';
|
||||||
|
|
||||||
export const opMarker = Symbol('opMarker');
|
export const opMarker = Symbol('opMarker');
|
||||||
|
|
||||||
let batchId = 0;
|
|
||||||
|
|
||||||
const wrapPromiseUtil =
|
const wrapPromiseUtil =
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
<T extends (values: any) => any>(nativePromiseUtil: T): T =>
|
<T extends (values: any) => any>(nativePromiseUtil: T): T =>
|
||||||
@ -16,7 +15,7 @@ const wrapPromiseUtil =
|
|||||||
});
|
});
|
||||||
|
|
||||||
if (argsWithMarker > 0) {
|
if (argsWithMarker > 0) {
|
||||||
markTaskBatch(argsWithMarker, batchId++);
|
markTaskBatch(argsWithMarker, getBatchId());
|
||||||
}
|
}
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
|
||||||
|
|||||||
@ -76,7 +76,7 @@ export const cwait = <TAsyncCallback extends (...args: any[]) => Promise<unknown
|
|||||||
}
|
}
|
||||||
|
|
||||||
console.log('cwait-error');
|
console.log('cwait-error');
|
||||||
throw new Error('Exec operation not found');
|
throw new Error('Read operation not found');
|
||||||
}
|
}
|
||||||
}) as TAsyncCallback;
|
}) as TAsyncCallback;
|
||||||
};
|
};
|
||||||
|
|||||||
3
packages/cwait/src/onchain/utils/batchId.ts
Normal file
3
packages/cwait/src/onchain/utils/batchId.ts
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
let batchId = 0;
|
||||||
|
|
||||||
|
export const getBatchId = () => batchId++;
|
||||||
@ -3,7 +3,7 @@ import { prepareTx } from './prepareTxs';
|
|||||||
export const constructTx = (isFullyExecuted: boolean) => {
|
export const constructTx = (isFullyExecuted: boolean) => {
|
||||||
const { calls } = prepareTx(isFullyExecuted);
|
const { calls } = prepareTx(isFullyExecuted);
|
||||||
|
|
||||||
const { tx } = prepareTx(isFullyExecuted, calls);
|
const { txs } = prepareTx(isFullyExecuted, calls);
|
||||||
|
|
||||||
return tx;
|
return txs;
|
||||||
};
|
};
|
||||||
|
|||||||
@ -4,30 +4,59 @@ import {
|
|||||||
constructContractRef,
|
constructContractRef,
|
||||||
FullCallInfo,
|
FullCallInfo,
|
||||||
NewTx,
|
NewTx,
|
||||||
|
passCwebFrom,
|
||||||
PreparedOperation,
|
PreparedOperation,
|
||||||
|
sendCwebInterface,
|
||||||
} from '@coinweb/contract-kit';
|
} from '@coinweb/contract-kit';
|
||||||
import { CwebBlock } from '@coinweb/contract-kit/dist/esm/operations/block';
|
import { CwebBlock } from '@coinweb/contract-kit/dist/esm/operations/block';
|
||||||
import { GBlock } from '@coinweb/contract-kit/dist/types/operations/generics';
|
import { GBlock } from '@coinweb/contract-kit/dist/types/operations/generics';
|
||||||
|
|
||||||
import { ExecutorMethodArgs, ResolvedOp, ResolvedSlotOp, Task } from '../../../types';
|
import { ExecutorMethodArgs, ResolvedOp, ResolvedSlotOp, Task } from '../../../types';
|
||||||
import { constructResultBlockFilter, constructResultClaimRead } from '../../claims/result';
|
import { constructFundsClaimRangRead, constructFundsClaimStore } from '../../claims/funds';
|
||||||
|
import { constructResultBlockFilter, constructResultClaimTake, resultKey } from '../../claims/result';
|
||||||
import { context, getRawContext } from '../../context';
|
import { context, getRawContext } from '../../context';
|
||||||
import { isPreparedBlockOp, isPreparedExecOp } from '../typeGuards';
|
import { isPreparedBlockOp, isPreparedExecOp } from '../typeGuards';
|
||||||
|
|
||||||
export const prepareInThreadTxs = ({
|
export const prepareInThreadTxs = ({
|
||||||
cwebPerCall,
|
cwebPerCall,
|
||||||
outThread,
|
outThreadTasksCount,
|
||||||
outThreadFee,
|
outThreadFee,
|
||||||
tasks,
|
tasks,
|
||||||
}: {
|
}: {
|
||||||
tasks: Task[];
|
tasks: Task[];
|
||||||
cwebPerCall: bigint;
|
cwebPerCall: bigint;
|
||||||
outThread: number;
|
outThreadTasksCount: number;
|
||||||
outThreadFee: bigint;
|
outThreadFee: bigint;
|
||||||
}) => {
|
}): {
|
||||||
|
txs: NewTx[];
|
||||||
|
calls: number;
|
||||||
|
} => {
|
||||||
|
if (!tasks.length) {
|
||||||
|
const { constructSendCweb } = sendCwebInterface();
|
||||||
|
const { availableCweb, takeOps, storedCweb } = context.funds;
|
||||||
|
const { user } = context;
|
||||||
|
|
||||||
|
const restOfAvailableCweb = availableCweb - outThreadFee;
|
||||||
|
|
||||||
|
const restOfCweb = restOfAvailableCweb + storedCweb - BigInt(takeOps.length) * 100n - 3000n;
|
||||||
|
|
||||||
|
const txs =
|
||||||
|
restOfCweb > 0n
|
||||||
|
? [
|
||||||
|
constructContinueTx(getRawContext(), [
|
||||||
|
passCwebFrom(context.issuer, restOfAvailableCweb),
|
||||||
|
...takeOps,
|
||||||
|
...constructSendCweb(restOfCweb, user, null),
|
||||||
|
]),
|
||||||
|
]
|
||||||
|
: [];
|
||||||
|
|
||||||
|
return { txs, calls: 0 };
|
||||||
|
}
|
||||||
|
|
||||||
let txFee = 0n;
|
let txFee = 0n;
|
||||||
let callsPrepared = 0;
|
let callsPrepared = 0;
|
||||||
const resolvedSlotOps = new Array(outThread).fill({ SlotOp: 0 }) satisfies ResolvedSlotOp[];
|
const resolvedSlotOps = new Array(outThreadTasksCount).fill({ SlotOp: 0 }) satisfies ResolvedSlotOp[];
|
||||||
|
|
||||||
const resolvedChildOps: ResolvedOp[] = [...context.ops, ...resolvedSlotOps];
|
const resolvedChildOps: ResolvedOp[] = [...context.ops, ...resolvedSlotOps];
|
||||||
|
|
||||||
@ -47,7 +76,7 @@ export const prepareInThreadTxs = ({
|
|||||||
console.log('Child call info');
|
console.log('Child call info');
|
||||||
const id = task.op.ExecOp.id;
|
const id = task.op.ExecOp.id;
|
||||||
|
|
||||||
callArgs.push(constructBlock([constructResultBlockFilter(id)]), constructResultClaimRead(id));
|
callArgs.push(constructBlock([constructResultBlockFilter(id)]), constructResultClaimTake(id));
|
||||||
txFee += 200n;
|
txFee += 200n;
|
||||||
|
|
||||||
childCalls.push({
|
childCalls.push({
|
||||||
@ -59,6 +88,8 @@ export const prepareInThreadTxs = ({
|
|||||||
context.initialArgs,
|
context.initialArgs,
|
||||||
[...resolvedChildOps, { ExecOp: { id } }],
|
[...resolvedChildOps, { ExecOp: { id } }],
|
||||||
context.user,
|
context.user,
|
||||||
|
id,
|
||||||
|
context.thisId,
|
||||||
true,
|
true,
|
||||||
] satisfies ExecutorMethodArgs,
|
] satisfies ExecutorMethodArgs,
|
||||||
},
|
},
|
||||||
@ -82,22 +113,47 @@ export const prepareInThreadTxs = ({
|
|||||||
const returnTxs: NewTx[] = [];
|
const returnTxs: NewTx[] = [];
|
||||||
|
|
||||||
if (callArgs.length) {
|
if (callArgs.length) {
|
||||||
|
const { storedCweb, takeOps } = context.funds;
|
||||||
|
|
||||||
const latestCallArg = callArgs.at(-1)!;
|
const latestCallArg = callArgs.at(-1)!;
|
||||||
|
|
||||||
if ('StoreOp' in latestCallArg && (latestCallArg.StoreOp.key.first_part as [string])[0] === 'result') {
|
if ('StoreOp' in latestCallArg && (latestCallArg.StoreOp.key.first_part as [string])[0] === resultKey) {
|
||||||
|
//SAVE RESULT CLAIMS
|
||||||
|
console.log('SAVE RESULT CLAIMS', JSON.stringify(callArgs));
|
||||||
|
|
||||||
if (callArgs.length > 1) {
|
if (callArgs.length > 1) {
|
||||||
throw new Error('Unexpected count of result ops');
|
throw new Error('Unexpected count of result ops');
|
||||||
}
|
}
|
||||||
|
|
||||||
returnTxs.push(constructContinueTx(getRawContext(), [latestCallArg]));
|
const resultOps = [];
|
||||||
|
|
||||||
|
if (context.needSaveResult) {
|
||||||
|
resultOps.push(...callArgs);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (context.parentId) {
|
||||||
|
const { availableCweb, storedCweb, takeOps } = context.funds;
|
||||||
|
|
||||||
|
const cwebToStore = availableCweb + storedCweb - BigInt(takeOps.length) * 100n - 500n;
|
||||||
|
|
||||||
|
resultOps.push(
|
||||||
|
constructFundsClaimStore(context.parentId, cwebToStore),
|
||||||
|
...takeOps,
|
||||||
|
passCwebFrom(context.issuer, availableCweb)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (resultOps.length) {
|
||||||
|
returnTxs.push(constructContinueTx(getRawContext(), resultOps));
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
txFee += 700n + outThreadFee;
|
txFee += 800n + outThreadFee + BigInt(takeOps.length) * 100n;
|
||||||
callsPrepared++;
|
callsPrepared++;
|
||||||
|
|
||||||
returnTxs.push(
|
returnTxs.push(
|
||||||
constructContinueTx(
|
constructContinueTx(
|
||||||
getRawContext(),
|
getRawContext(),
|
||||||
[],
|
[passCwebFrom(context.issuer, cwebPerCall - outThreadFee), ...takeOps],
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
callInfo: {
|
callInfo: {
|
||||||
@ -108,14 +164,17 @@ export const prepareInThreadTxs = ({
|
|||||||
context.initialArgs,
|
context.initialArgs,
|
||||||
[...context.ops, ...resolvedSlotOps],
|
[...context.ops, ...resolvedSlotOps],
|
||||||
context.user,
|
context.user,
|
||||||
false,
|
context.thisId,
|
||||||
|
context.parentId,
|
||||||
|
context.needSaveResult,
|
||||||
|
takeOps.map((op) => (op.TakeOp.key.second_part as [string])[0]),
|
||||||
] satisfies ExecutorMethodArgs,
|
] satisfies ExecutorMethodArgs,
|
||||||
},
|
},
|
||||||
contractInfo: {
|
contractInfo: {
|
||||||
providedCweb: cwebPerCall - txFee,
|
providedCweb: cwebPerCall - txFee + storedCweb,
|
||||||
authenticated: null,
|
authenticated: null,
|
||||||
},
|
},
|
||||||
contractArgs: callArgs,
|
contractArgs: [constructFundsClaimRangRead(context.thisId), ...callArgs],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
|||||||
@ -1,10 +1,26 @@
|
|||||||
import { constructContinueTx, constructContractRef, FullCallInfo, PreparedOperation } from '@coinweb/contract-kit';
|
import {
|
||||||
|
constructContinueTx,
|
||||||
|
constructContractRef,
|
||||||
|
FullCallInfo,
|
||||||
|
NewTx,
|
||||||
|
PreparedOperation,
|
||||||
|
} from '@coinweb/contract-kit';
|
||||||
|
|
||||||
import { ExecutorMethodArgs, Task } from '../../../types';
|
import { ExecutorMethodArgs, Task } from '../../../types';
|
||||||
import { context, getRawContext } from '../../context';
|
import { context, getRawContext } from '../../context';
|
||||||
import { isPreparedExecOp } from '../typeGuards';
|
import { isPreparedExecOp } from '../typeGuards';
|
||||||
|
|
||||||
export const prepareOutThreadTxs = ({ tasks, cwebPerCall }: { tasks: Task[]; cwebPerCall: bigint }) => {
|
export const prepareOutThreadTxs = ({
|
||||||
|
tasks,
|
||||||
|
cwebPerCall,
|
||||||
|
}: {
|
||||||
|
tasks: Task[];
|
||||||
|
cwebPerCall: bigint;
|
||||||
|
}): {
|
||||||
|
txs: NewTx[];
|
||||||
|
fee: bigint;
|
||||||
|
calls: number;
|
||||||
|
} => {
|
||||||
const siblingCallResolvedOps = [...context.ops];
|
const siblingCallResolvedOps = [...context.ops];
|
||||||
|
|
||||||
const siblingTxInfo: {
|
const siblingTxInfo: {
|
||||||
@ -32,7 +48,9 @@ export const prepareOutThreadTxs = ({ tasks, cwebPerCall }: { tasks: Task[]; cwe
|
|||||||
context.initialArgs,
|
context.initialArgs,
|
||||||
[...siblingCallResolvedOps, { ExecOp: { id } }],
|
[...siblingCallResolvedOps, { ExecOp: { id } }],
|
||||||
context.user,
|
context.user,
|
||||||
true,
|
id,
|
||||||
|
context.parentId ?? context.thisId,
|
||||||
|
false,
|
||||||
] satisfies ExecutorMethodArgs,
|
] satisfies ExecutorMethodArgs,
|
||||||
},
|
},
|
||||||
contractInfo: {
|
contractInfo: {
|
||||||
@ -73,5 +91,7 @@ export const prepareOutThreadTxs = ({ tasks, cwebPerCall }: { tasks: Task[]; cwe
|
|||||||
constructContinueTx(getRawContext(), ops, calls)
|
constructContinueTx(getRawContext(), ops, calls)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
txFee += BigInt(siblingTxs.length) * 100n;
|
||||||
|
|
||||||
return { txs: siblingTxs, fee: txFee, calls: callsPrepared };
|
return { txs: siblingTxs, fee: txFee, calls: callsPrepared };
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,28 +1,48 @@
|
|||||||
import { constructContinueTx, constructDataUnverified } from '@coinweb/contract-kit';
|
import { constructContinueTx, NewTx, passCwebFrom, sendCwebInterface } from '@coinweb/contract-kit';
|
||||||
import { getCallParameters } from 'lib/onchain';
|
|
||||||
|
|
||||||
import { getRawContext } from '../../context';
|
import { context, getRawContext } from '../../context';
|
||||||
import { getAwaitedTasks } from '../../promisifiedOps';
|
import { getAwaitedTasks } from '../../promisifiedOps';
|
||||||
|
|
||||||
import { prepareInThreadTxs } from './prepareInThreadTxs';
|
import { prepareInThreadTxs } from './prepareInThreadTxs';
|
||||||
import { prepareOutThreadTxs } from './prepareOutThreadTxs';
|
import { prepareOutThreadTxs } from './prepareOutThreadTxs';
|
||||||
import { splitTasks } from './splitTasks';
|
import { splitTasks } from './splitTasks';
|
||||||
|
|
||||||
export const prepareTx = (isFullyExecuted: boolean, callsCount?: number) => {
|
export const prepareTx = (isFullyExecuted: boolean, callsCount?: number): { txs: NewTx[]; calls: number } => {
|
||||||
console.log('Calls Count: ', callsCount);
|
console.log('Calls Count: ', callsCount);
|
||||||
|
|
||||||
const ctx = getRawContext();
|
|
||||||
const awaitedTasks = getAwaitedTasks();
|
const awaitedTasks = getAwaitedTasks();
|
||||||
|
|
||||||
console.log('Awaited Tasks: ', JSON.stringify(awaitedTasks));
|
console.log('Awaited Tasks: ', JSON.stringify(awaitedTasks));
|
||||||
|
|
||||||
if (!awaitedTasks.length) {
|
if (!awaitedTasks.length) {
|
||||||
return { tx: [constructContinueTx(ctx, [constructDataUnverified({ isFullyExecuted })])], calls: 0 };
|
if (context.isChild) {
|
||||||
|
return { txs: [], calls: 0 };
|
||||||
|
}
|
||||||
|
|
||||||
|
const { constructSendCweb } = sendCwebInterface();
|
||||||
|
const { availableCweb, takeOps, storedCweb } = context.funds;
|
||||||
|
const { user } = context;
|
||||||
|
|
||||||
|
const restOfCweb = availableCweb + storedCweb - BigInt(takeOps.length) * 100n - 3000n;
|
||||||
|
|
||||||
|
const txs =
|
||||||
|
restOfCweb > 0n
|
||||||
|
? [
|
||||||
|
constructContinueTx(getRawContext(), [
|
||||||
|
passCwebFrom(context.issuer, availableCweb),
|
||||||
|
...takeOps,
|
||||||
|
...constructSendCweb(restOfCweb, user, null),
|
||||||
|
]),
|
||||||
|
]
|
||||||
|
: [];
|
||||||
|
|
||||||
|
return { txs, calls: 0 };
|
||||||
}
|
}
|
||||||
|
|
||||||
const { inThreadTasks, outThreadTasks } = splitTasks(awaitedTasks, isFullyExecuted);
|
const { inThreadTasks, outThreadTasks } = splitTasks(awaitedTasks, isFullyExecuted);
|
||||||
|
|
||||||
const { availableCweb } = getCallParameters(ctx);
|
const { availableCweb } = context.funds;
|
||||||
|
|
||||||
const cwebPerCall = availableCweb / BigInt(callsCount || 1);
|
const cwebPerCall = availableCweb / BigInt(callsCount || 1);
|
||||||
const {
|
const {
|
||||||
txs: outThreadTxs,
|
txs: outThreadTxs,
|
||||||
@ -33,9 +53,9 @@ export const prepareTx = (isFullyExecuted: boolean, callsCount?: number) => {
|
|||||||
const { txs: inThreadTxs, calls: inThreadCallsPrepared } = prepareInThreadTxs({
|
const { txs: inThreadTxs, calls: inThreadCallsPrepared } = prepareInThreadTxs({
|
||||||
tasks: inThreadTasks,
|
tasks: inThreadTasks,
|
||||||
cwebPerCall,
|
cwebPerCall,
|
||||||
outThread: outThreadTasks.length,
|
outThreadTasksCount: outThreadTasks.length,
|
||||||
outThreadFee,
|
outThreadFee,
|
||||||
});
|
});
|
||||||
|
|
||||||
return { tx: [...inThreadTxs, ...outThreadTxs], calls: inThreadCallsPrepared + outThreadCallsPrepared };
|
return { txs: [...inThreadTxs, ...outThreadTxs], calls: inThreadCallsPrepared + outThreadCallsPrepared };
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,3 +1,4 @@
|
|||||||
|
export * from './batchId';
|
||||||
export * from './callstack';
|
export * from './callstack';
|
||||||
export * from './constructTx';
|
export * from './constructTx';
|
||||||
export * from './typeGuards';
|
export * from './typeGuards';
|
||||||
|
|||||||
@ -41,5 +41,8 @@ export type ExecutorMethodArgs = [
|
|||||||
initialArgs?: unknown[],
|
initialArgs?: unknown[],
|
||||||
resolvedOps?: ResolvedOp[],
|
resolvedOps?: ResolvedOp[],
|
||||||
caller?: User,
|
caller?: User,
|
||||||
isChild?: boolean,
|
thisId?: string,
|
||||||
|
parentId?: string,
|
||||||
|
saveResult?: boolean,
|
||||||
|
takenFundsIds?: string[],
|
||||||
];
|
];
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
VITE_API_URL='https://api-cloud.coinweb.io/wallet'
|
VITE_API_URL='https://api-cloud.coinweb.io/wallet'
|
||||||
VITE_EXPLORER_URL='https://explorer.coinweb.io'
|
VITE_EXPLORER_URL='https://explorer.coinweb.io'
|
||||||
|
|
||||||
VITE_CONTRACT_ADDRESS="0x69c4c76e827dc84cb21219e61fa78b69d881dca601b8a33a5b52be29a1a55851"
|
VITE_CONTRACT_ADDRESS="0x8c89cb42634cfe892290845d907af8ec2d482cead42afaef3ccc3cea4446fce5"
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user