Merge branch 'use-cwait'
This commit is contained in:
commit
cb4a2fb33d
@ -9,5 +9,5 @@ export enum PUBLIC_METHODS {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const FEE = {
|
export const FEE = {
|
||||||
ADD_WORD: 10000n,
|
ADD_WORD: 100000n,
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import { constructClaim } from '@coinweb/contract-kit';
|
import { constructClaim } from '@coinweb/contract-kit';
|
||||||
import { readOp, storeOp } from 'cwait';
|
import { readOp, storeOp, cwait } from 'cwait';
|
||||||
|
|
||||||
import { TypedClaim } from '../../../lib/dist/shared/types';
|
import { TypedClaim } from '../../../lib/dist/shared/types';
|
||||||
import { AddWordArgs, createWordKey, WordClaimBody } from '../offchain/shared';
|
import { AddWordArgs, createWordKey, WordClaimBody } from '../offchain/shared';
|
||||||
@ -18,28 +18,37 @@ function hashCode(str: string): string {
|
|||||||
return `${(hash < 0 ? hash * -1 : hash).toString(16)}`;
|
return `${(hash < 0 ? hash * -1 : hash).toString(16)}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const addWord = async (...[word]: AddWordArgs) => {
|
export const addWord = cwait(async (...[word]: AddWordArgs) => {
|
||||||
|
console.log('addWord START');
|
||||||
|
|
||||||
const id = hashCode(word);
|
const id = hashCode(word);
|
||||||
|
|
||||||
|
console.log('await storeOp');
|
||||||
await storeOp(constructClaim(createWordKey(id), { word }, '0x0'));
|
await storeOp(constructClaim(createWordKey(id), { word }, '0x0'));
|
||||||
|
|
||||||
|
console.log('await extraLogic');
|
||||||
const wordClaim = await extraLogic(id);
|
const wordClaim = await extraLogic(id);
|
||||||
|
|
||||||
const newWord1 = (wordClaim?.body.word ?? '') + '!';
|
const newWord1 = (wordClaim?.body.word ?? '') + '_1';
|
||||||
const newId1 = hashCode(newWord1);
|
const newId1 = hashCode(newWord1);
|
||||||
|
|
||||||
const newWord2 = (wordClaim?.body.word ?? '') + '!!';
|
const newWord2 = (wordClaim?.body.word ?? '') + '_2';
|
||||||
const newId2 = hashCode(newWord2);
|
const newId2 = hashCode(newWord2);
|
||||||
|
|
||||||
const newWord3 = (wordClaim?.body.word ?? '') + '!!!';
|
const newWord3 = (wordClaim?.body.word ?? '') + '_3';
|
||||||
const newId3 = hashCode(newWord3);
|
const newId3 = hashCode(newWord3);
|
||||||
|
|
||||||
storeOp(constructClaim(createWordKey(newId1), { word: newWord1 }, '0x0'));
|
console.log('free storeOp');
|
||||||
|
storeOp(constructClaim(createWordKey(newId1), { word: wordClaim?.body.word + '_free' }, '0x0'));
|
||||||
|
|
||||||
|
console.log('await Promise.all');
|
||||||
await Promise.all([
|
await Promise.all([
|
||||||
storeOp(constructClaim(createWordKey(newId2), { word: newWord2 }, '0x0')),
|
storeOp(constructClaim(createWordKey(newId2), { word: wordClaim?.body.word + '_in_promise_all' }, '0x0')),
|
||||||
storeOp(constructClaim(createWordKey(newId3), { word: newWord3 }, '0x0')),
|
storeOp(constructClaim(createWordKey(newId3), { word: 'WIN' }, '0x0')),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
console.log('free readOp');
|
||||||
readOp<TypedClaim<WordClaimBody>>(createWordKey(newId3));
|
readOp<TypedClaim<WordClaimBody>>(createWordKey(newId3));
|
||||||
};
|
|
||||||
|
console.log('addWord END');
|
||||||
|
});
|
||||||
|
|||||||
@ -1,7 +1,6 @@
|
|||||||
import { SELF_REGISTER_HANDLER_NAME, ContractHandlers as CKContractHandlers } from '@coinweb/contract-kit';
|
import { SELF_REGISTER_HANDLER_NAME } from '@coinweb/contract-kit';
|
||||||
import { selfRegisterHandler } from '@coinweb/self-register';
|
import { selfRegisterHandler } from '@coinweb/self-register';
|
||||||
import { addMethodHandler, ContractHandlers, executeHandler, executor } from 'cwait';
|
import { addMethodHandler, ContractHandlers, executeHandler, executor } from 'cwait';
|
||||||
import { queue } from 'lib/onchain';
|
|
||||||
|
|
||||||
import { PUBLIC_METHODS } from '../offchain/shared';
|
import { PUBLIC_METHODS } from '../offchain/shared';
|
||||||
|
|
||||||
@ -14,8 +13,6 @@ const createModule = (): ContractHandlers => {
|
|||||||
|
|
||||||
addMethodHandler(module, SELF_REGISTER_HANDLER_NAME, selfRegisterHandler);
|
addMethodHandler(module, SELF_REGISTER_HANDLER_NAME, selfRegisterHandler);
|
||||||
|
|
||||||
queue.applyQueue(module as CKContractHandlers, [PUBLIC_METHODS.ADD_WORD]);
|
|
||||||
|
|
||||||
return module;
|
return module;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -1,9 +1,18 @@
|
|||||||
import { readOp, TypedClaim } from 'cwait';
|
import { constructClaim } from '@coinweb/contract-kit';
|
||||||
|
import { cwait, readOp, storeOp, TypedClaim } from 'cwait';
|
||||||
|
|
||||||
import { createWordKey, WordClaimBody } from '../offchain';
|
import { createWordKey, WordClaimBody } from '../offchain';
|
||||||
|
|
||||||
export const extraLogic = async (id: string) => {
|
import { extraLogic2 } from './extraLogic2';
|
||||||
|
|
||||||
|
export const extraLogic = cwait(async (id: string) => {
|
||||||
|
console.log('extraLogic START');
|
||||||
const result = await readOp<TypedClaim<WordClaimBody>>(createWordKey(id));
|
const result = await readOp<TypedClaim<WordClaimBody>>(createWordKey(id));
|
||||||
|
|
||||||
return result;
|
await storeOp(
|
||||||
};
|
constructClaim(createWordKey(id), { word: result?.body.word.split('').reverse().join('') + '_extraLogic' }, '0x0')
|
||||||
|
);
|
||||||
|
|
||||||
|
console.log('extraLogic return extraLogic2');
|
||||||
|
return extraLogic2(id);
|
||||||
|
});
|
||||||
|
|||||||
13
packages/contract.cm/src/onchain/extraLogic2.ts
Normal file
13
packages/contract.cm/src/onchain/extraLogic2.ts
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
import { cwait, readOp, TypedClaim } from 'cwait';
|
||||||
|
|
||||||
|
import { createWordKey, WordClaimBody } from '../offchain';
|
||||||
|
|
||||||
|
export const extraLogic2 = cwait(async (id: string) => {
|
||||||
|
console.log('extraLogic2 START');
|
||||||
|
|
||||||
|
console.log('await readOp');
|
||||||
|
const result = await readOp<TypedClaim<WordClaimBody>>(createWordKey(id));
|
||||||
|
|
||||||
|
console.log('extraLogic2 END');
|
||||||
|
return result;
|
||||||
|
});
|
||||||
@ -17,3 +17,7 @@ declare module '@coinweb/contract-kit/dist/esm/operations/block' {
|
|||||||
declare module '@coinweb/contract-kit/dist/esm/operations/call' {
|
declare module '@coinweb/contract-kit/dist/esm/operations/call' {
|
||||||
export * from '@coinweb/contract-kit/dist/types/operations/call';
|
export * from '@coinweb/contract-kit/dist/types/operations/call';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
declare module '@coinweb/contract-kit/dist/esm/operations/read' {
|
||||||
|
export * from '@coinweb/contract-kit/dist/types/operations/read';
|
||||||
|
}
|
||||||
|
|||||||
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));
|
||||||
2
packages/cwait/src/onchain/claims/index.ts
Normal file
2
packages/cwait/src/onchain/claims/index.ts
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
export * from './funds';
|
||||||
|
export * from './result';
|
||||||
37
packages/cwait/src/onchain/claims/result.ts
Normal file
37
packages/cwait/src/onchain/claims/result.ts
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
import {
|
||||||
|
BlockFilter,
|
||||||
|
constructClaim,
|
||||||
|
constructClaimKey,
|
||||||
|
constructStore,
|
||||||
|
constructTake,
|
||||||
|
CwebStore,
|
||||||
|
GStore,
|
||||||
|
constructRead,
|
||||||
|
} from '@coinweb/contract-kit';
|
||||||
|
|
||||||
|
import { ResolvedOp } from '../../types';
|
||||||
|
import { context } from '../context';
|
||||||
|
|
||||||
|
export const resultKey = '_result';
|
||||||
|
|
||||||
|
export const constructResultClaimKey = (id: string) => constructClaimKey([resultKey], [id]);
|
||||||
|
|
||||||
|
export const constructResultClaim = (id: string, result: ResolvedOp[]) =>
|
||||||
|
constructClaim(constructResultClaimKey(id), result, '0x0');
|
||||||
|
|
||||||
|
export const constructResultClaimStore = (id: string, result: ResolvedOp[]): GStore<CwebStore> =>
|
||||||
|
constructStore(constructResultClaim(id, result));
|
||||||
|
|
||||||
|
export const constructResultClaimRead = (id: string) => constructRead(context.issuer, constructResultClaimKey(id));
|
||||||
|
|
||||||
|
export const constructResultClaimTake = (id: string) => constructTake(constructResultClaimKey(id));
|
||||||
|
|
||||||
|
export const constructResultBlockFilter = (id: string): BlockFilter => {
|
||||||
|
const { first_part: first, second_part: second } = constructResultClaimKey(id);
|
||||||
|
|
||||||
|
return {
|
||||||
|
issuer: context.issuer,
|
||||||
|
first,
|
||||||
|
second,
|
||||||
|
};
|
||||||
|
};
|
||||||
@ -1,4 +1,11 @@
|
|||||||
import { constructContractIssuer, Context, extractUser, getAuthenticated, getContractId } from '@coinweb/contract-kit';
|
import { Context, extractUser, getMethodArguments } from '@coinweb/contract-kit';
|
||||||
|
import { getCallParameters, getContractIssuer } from 'lib/onchain';
|
||||||
|
|
||||||
|
import { ExecutorMethodArgs } from '../../types';
|
||||||
|
import { uuid } from '../utils';
|
||||||
|
|
||||||
|
import { extractFunds } from './extractFunds';
|
||||||
|
import { extractOps } from './extractOps';
|
||||||
|
|
||||||
let rawContext: Context | null = null;
|
let rawContext: Context | null = null;
|
||||||
|
|
||||||
@ -14,14 +21,75 @@ export const getRawContext = () => {
|
|||||||
return rawContext;
|
return rawContext;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const getMethodArgs = () => {
|
||||||
|
return getMethodArguments(getRawContext()) as [methodName: string, ...ExecutorMethodArgs];
|
||||||
|
};
|
||||||
|
|
||||||
|
let thisId: string | undefined;
|
||||||
|
|
||||||
export const context = {
|
export const context = {
|
||||||
get issuer() {
|
get isChild() {
|
||||||
return constructContractIssuer(getContractId(getRawContext().tx));
|
return !!getMethodArgs()[5];
|
||||||
},
|
},
|
||||||
get authenticated() {
|
get thisId() {
|
||||||
return getAuthenticated(getRawContext().tx);
|
thisId = thisId ?? getMethodArgs()[4] ?? uuid();
|
||||||
|
return thisId;
|
||||||
|
},
|
||||||
|
get parentId() {
|
||||||
|
return getMethodArgs()[5];
|
||||||
|
},
|
||||||
|
get ops() {
|
||||||
|
console.log('Parse ops in context');
|
||||||
|
|
||||||
|
const previousOps = getMethodArgs()[2] ?? [];
|
||||||
|
const { extractedOps } = extractOps();
|
||||||
|
|
||||||
|
const allResolvedOps = [...previousOps, ...extractedOps];
|
||||||
|
|
||||||
|
console.log('new ops >>>', JSON.stringify(extractedOps));
|
||||||
|
|
||||||
|
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() {
|
||||||
|
return getMethodArguments(getRawContext())[0] as string;
|
||||||
|
},
|
||||||
|
get initialArgs() {
|
||||||
|
return getMethodArgs()[1] ?? [];
|
||||||
},
|
},
|
||||||
get user() {
|
get user() {
|
||||||
return extractUser(getAuthenticated(getRawContext().tx));
|
const { authInfo } = getCallParameters(getRawContext());
|
||||||
|
const provided = getMethodArgs()[3];
|
||||||
|
|
||||||
|
const user = (authInfo && extractUser(authInfo)) ?? provided;
|
||||||
|
|
||||||
|
if (!user) {
|
||||||
|
throw new Error('User not found');
|
||||||
|
}
|
||||||
|
|
||||||
|
return user;
|
||||||
|
},
|
||||||
|
get issuer() {
|
||||||
|
return getContractIssuer(getRawContext());
|
||||||
|
},
|
||||||
|
get parentTxId() {
|
||||||
|
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,133 +1,56 @@
|
|||||||
import {
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||||
Context,
|
import { Context, NewTx, getMethodArguments, isSelfCall } from '@coinweb/contract-kit';
|
||||||
extractContractArgs,
|
|
||||||
NewTx,
|
|
||||||
getMethodArguments,
|
|
||||||
constructContinueTx,
|
|
||||||
constructContractRef,
|
|
||||||
constructDataUnverified,
|
|
||||||
isSelfCall,
|
|
||||||
} from '@coinweb/contract-kit';
|
|
||||||
import { getCallParameters, queue } from 'lib/onchain';
|
|
||||||
|
|
||||||
import { ResolvedOp, Task } from '../types';
|
|
||||||
|
|
||||||
import { context, getRawContext, setRawContext } from './context';
|
import { context, getRawContext, setRawContext } from './context';
|
||||||
import { getAwaitedOps } from './promisifiedOps/awaited';
|
|
||||||
import { pushResolvedOp } from './promisifiedOps/resolved';
|
import { pushResolvedOp } from './promisifiedOps/resolved';
|
||||||
|
import { constructTx } from './utils';
|
||||||
|
|
||||||
let abortExecution: ((result: boolean) => void) | null = null;
|
let abortExecution: ((result: boolean) => void) | null = null;
|
||||||
|
|
||||||
const handleState = () => {
|
export const executor = (method: (...args: any[]) => Promise<void>) => {
|
||||||
const ctx = getRawContext();
|
return async (ctx: Context): Promise<NewTx[]> => {
|
||||||
|
console.log('executor-start >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>');
|
||||||
|
setRawContext(ctx);
|
||||||
|
pushResolvedOp(context.ops);
|
||||||
|
|
||||||
const resolvedOps = extractContractArgs(ctx.tx);
|
if (getMethodArguments(getRawContext()).length > 2 && !isSelfCall(ctx)) {
|
||||||
const methodArgs = getMethodArguments(ctx) as [unknown, unknown[], ResolvedOp[]];
|
throw new Error('Wrong contract call, check the call arguments');
|
||||||
|
}
|
||||||
|
|
||||||
const initialArgs = methodArgs[1] ?? [];
|
const execution = new Promise<boolean>((resolve, reject) => {
|
||||||
const previousOps = methodArgs[2] ?? [];
|
abortExecution = resolve;
|
||||||
const allResolvedOps = [...previousOps, ...resolvedOps];
|
|
||||||
|
|
||||||
pushResolvedOp(allResolvedOps);
|
method(...context.initialArgs).then(
|
||||||
|
() => {
|
||||||
|
console.log('<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< executor-resolved');
|
||||||
|
resolve(true);
|
||||||
|
},
|
||||||
|
(error) => {
|
||||||
|
console.log(' <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<executor-rejected');
|
||||||
|
console.log(error);
|
||||||
|
reject(error);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
return {
|
//@ts-expect-error
|
||||||
args: initialArgs,
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-call
|
||||||
methodName: methodArgs[0] as string,
|
os.setTimeout(() => {
|
||||||
ops: allResolvedOps,
|
abortExecution?.(false);
|
||||||
isChildCall: previousOps.length > 0,
|
}, 0);
|
||||||
|
|
||||||
|
try {
|
||||||
|
const isFullyExecuted = await execution;
|
||||||
|
return constructTx(isFullyExecuted);
|
||||||
|
} catch (error) {
|
||||||
|
console.log('<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< executor-error');
|
||||||
|
console.log((error as Error).message);
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
export const executor =
|
export const stopExecution = () => {
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
console.log('stopExecution');
|
||||||
(method: (...args: any[]) => Promise<void>) =>
|
abortExecution?.(false);
|
||||||
async (ctx: Context): Promise<NewTx[]> => {
|
};
|
||||||
console.log('executor-start');
|
|
||||||
setRawContext(ctx);
|
|
||||||
|
|
||||||
const { args, methodName, ops, isChildCall } = handleState();
|
|
||||||
|
|
||||||
if (isChildCall && !isSelfCall(ctx)) {
|
|
||||||
throw new Error('Only contract itself can call it');
|
|
||||||
}
|
|
||||||
|
|
||||||
const execution = new Promise<boolean>((resolve, reject) => {
|
|
||||||
abortExecution = resolve;
|
|
||||||
|
|
||||||
method(...args).then(
|
|
||||||
() => {
|
|
||||||
console.log('executor-resolved');
|
|
||||||
resolve(true);
|
|
||||||
},
|
|
||||||
() => {
|
|
||||||
console.log('executor-rejected');
|
|
||||||
reject();
|
|
||||||
}
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
//@ts-expect-error
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-call
|
|
||||||
os.setTimeout(() => {
|
|
||||||
abortExecution?.(false);
|
|
||||||
}, 0);
|
|
||||||
|
|
||||||
const isFullyExecuted = await execution;
|
|
||||||
|
|
||||||
console.log('executor-executed');
|
|
||||||
|
|
||||||
const { authInfo, availableCweb } = getCallParameters(ctx);
|
|
||||||
|
|
||||||
const awaitedOps = getAwaitedOps();
|
|
||||||
|
|
||||||
if (!awaitedOps.length) {
|
|
||||||
return [constructContinueTx(ctx, [constructDataUnverified({ isFullyExecuted })]), ...queue.gateway.unlock(ctx)];
|
|
||||||
}
|
|
||||||
|
|
||||||
const callArgs: Task[] = [];
|
|
||||||
|
|
||||||
if (!isFullyExecuted) {
|
|
||||||
callArgs.push(awaitedOps.pop()!);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (callArgs[0]?.isBatch) {
|
|
||||||
while (awaitedOps.at(-1)?.isBatch) {
|
|
||||||
callArgs.push(awaitedOps.pop()!);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const callFee = 700n + BigInt(callArgs.length) * 100n;
|
|
||||||
const opTxFee = awaitedOps.length ? 100n + BigInt(awaitedOps.length) * 100n : 0n;
|
|
||||||
|
|
||||||
return [
|
|
||||||
constructContinueTx(
|
|
||||||
ctx,
|
|
||||||
awaitedOps.map(({ op }) => op),
|
|
||||||
[
|
|
||||||
{
|
|
||||||
callInfo: {
|
|
||||||
ref: constructContractRef(context.issuer, []),
|
|
||||||
methodInfo: {
|
|
||||||
methodName,
|
|
||||||
methodArgs: [
|
|
||||||
args,
|
|
||||||
[
|
|
||||||
...ops,
|
|
||||||
...Array(awaitedOps.length).fill({ SlotOp: 0 } satisfies ResolvedOp),
|
|
||||||
] satisfies ResolvedOp[],
|
|
||||||
isFullyExecuted,
|
|
||||||
callArgs,
|
|
||||||
awaitedOps,
|
|
||||||
],
|
|
||||||
},
|
|
||||||
contractInfo: {
|
|
||||||
providedCweb: availableCweb - callFee - opTxFee,
|
|
||||||
authenticated: authInfo,
|
|
||||||
},
|
|
||||||
contractArgs: callArgs.map(({ op }) => op),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
]
|
|
||||||
),
|
|
||||||
];
|
|
||||||
};
|
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
import { markOpBatch } from './promisifiedOps/awaited';
|
import { markTaskBatch } from './promisifiedOps/awaited';
|
||||||
|
import { getBatchId } from './utils';
|
||||||
|
|
||||||
export const opMarker = Symbol('opMarker');
|
export const opMarker = Symbol('opMarker');
|
||||||
|
|
||||||
@ -14,7 +15,7 @@ const wrapPromiseUtil =
|
|||||||
});
|
});
|
||||||
|
|
||||||
if (argsWithMarker > 0) {
|
if (argsWithMarker > 0) {
|
||||||
markOpBatch(argsWithMarker);
|
markTaskBatch(argsWithMarker, getBatchId());
|
||||||
}
|
}
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
|
||||||
|
|||||||
@ -1,20 +1,17 @@
|
|||||||
import { PreparedOperation } from '@coinweb/contract-kit';
|
import { PreparedOp, Task } from '../../types';
|
||||||
|
|
||||||
import { Task } from '../../types';
|
const awaitedTasks: Task[] = [];
|
||||||
import { getStack } from '../utils';
|
|
||||||
|
|
||||||
const awaitedOps: Task[] = [];
|
export const pushAwaitedTask = (op: PreparedOp) => {
|
||||||
|
awaitedTasks.push({ op, batchId: -1 });
|
||||||
export const pushAwaitedOp = (op: PreparedOperation) => {
|
|
||||||
const stack = getStack({ skip: 2 });
|
|
||||||
|
|
||||||
awaitedOps.push({ op, stack, isBatch: false });
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export const getAwaitedOps = () => awaitedOps;
|
export const getAwaitedTasks = () => awaitedTasks;
|
||||||
|
|
||||||
export const markOpBatch = (count: number) => {
|
export const markTaskBatch = (count: number, batchId: number) => {
|
||||||
for (let i = 1; i <= count; i++) {
|
for (let i = 1; i <= count; i++) {
|
||||||
awaitedOps.at(i * -1)!.isBatch = true;
|
awaitedTasks.at(i * -1)!.batchId = batchId;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const getAwaitedTasksCount = () => awaitedTasks.length;
|
||||||
|
|||||||
82
packages/cwait/src/onchain/promisifiedOps/cwait.ts
Normal file
82
packages/cwait/src/onchain/promisifiedOps/cwait.ts
Normal file
@ -0,0 +1,82 @@
|
|||||||
|
import { constructStore } from '@coinweb/contract-kit/dist/esm/operations/store';
|
||||||
|
|
||||||
|
import { constructResultClaim } from '../claims/result';
|
||||||
|
import { context } from '../context';
|
||||||
|
import { stopExecution } from '../executor';
|
||||||
|
import { opMarker } from '../global';
|
||||||
|
import { isResolvedChildOp, isResolvedExecOp, isResolvedSlotOp } from '../utils';
|
||||||
|
import { uuid } from '../utils';
|
||||||
|
|
||||||
|
import { getAwaitedTasks, pushAwaitedTask } from './awaited';
|
||||||
|
import { getUsedOps, saveUsedOps, shiftResolvedOp } from './resolved';
|
||||||
|
|
||||||
|
let isRootDetected = false;
|
||||||
|
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
|
export const cwait = <TAsyncCallback extends (...args: any[]) => Promise<unknown>>(asyncCallback: TAsyncCallback) => {
|
||||||
|
console.log('cwait: ', asyncCallback.name);
|
||||||
|
let isRoot = false;
|
||||||
|
|
||||||
|
return (async (...args: Parameters<TAsyncCallback>) => {
|
||||||
|
console.log('cwait callback');
|
||||||
|
if (!isRootDetected) {
|
||||||
|
isRootDetected = true;
|
||||||
|
isRoot = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('isRoot:', isRoot);
|
||||||
|
console.log('isChild:', context.isChild);
|
||||||
|
|
||||||
|
if (isRoot) {
|
||||||
|
return asyncCallback(...args);
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('child logic');
|
||||||
|
|
||||||
|
const { op, isOp } = shiftResolvedOp();
|
||||||
|
|
||||||
|
if (!isOp) {
|
||||||
|
pushAwaitedTask({
|
||||||
|
ExecOp: {
|
||||||
|
id: uuid(),
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const result = new Promise(() => null) as Promise<unknown> & { [opMarker]: boolean };
|
||||||
|
|
||||||
|
result[opMarker] = true;
|
||||||
|
|
||||||
|
return result as ReturnType<TAsyncCallback>;
|
||||||
|
} else {
|
||||||
|
if (isResolvedSlotOp(op)) {
|
||||||
|
console.log('cwait-slotOp');
|
||||||
|
return new Promise(() => null);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isResolvedExecOp(op)) {
|
||||||
|
console.log('cwait-execOp');
|
||||||
|
|
||||||
|
saveUsedOps();
|
||||||
|
|
||||||
|
const result = await asyncCallback(...args);
|
||||||
|
|
||||||
|
const awaitedOps = getAwaitedTasks();
|
||||||
|
|
||||||
|
if (!awaitedOps.length) {
|
||||||
|
pushAwaitedTask(constructStore(constructResultClaim(op.ExecOp.id, getUsedOps())));
|
||||||
|
|
||||||
|
stopExecution();
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isResolvedChildOp(op)) {
|
||||||
|
return asyncCallback(...args);
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('cwait-error');
|
||||||
|
throw new Error('Read operation not found');
|
||||||
|
}
|
||||||
|
}) as TAsyncCallback;
|
||||||
|
};
|
||||||
@ -1,3 +1,4 @@
|
|||||||
export * from './awaited';
|
export * from './awaited';
|
||||||
export * from './resolved';
|
export * from './cwait';
|
||||||
export * from './ops';
|
export * from './ops';
|
||||||
|
export * from './resolved';
|
||||||
|
|||||||
@ -2,7 +2,7 @@ import { BlockFilter, constructBlock, extractBlock } from '@coinweb/contract-kit
|
|||||||
|
|
||||||
import { opMarker } from '../../global';
|
import { opMarker } from '../../global';
|
||||||
import { isResolvedBlockOp, isResolvedSlotOp } from '../../utils';
|
import { isResolvedBlockOp, isResolvedSlotOp } from '../../utils';
|
||||||
import { pushAwaitedOp } from '../awaited';
|
import { pushAwaitedTask } from '../awaited';
|
||||||
import { shiftResolvedOp } from '../resolved';
|
import { shiftResolvedOp } from '../resolved';
|
||||||
|
|
||||||
export const blockOp = (filters: BlockFilter[]) => {
|
export const blockOp = (filters: BlockFilter[]) => {
|
||||||
@ -14,7 +14,7 @@ export const blockOp = (filters: BlockFilter[]) => {
|
|||||||
const { op, isOp } = shiftResolvedOp();
|
const { op, isOp } = shiftResolvedOp();
|
||||||
|
|
||||||
if (!isOp) {
|
if (!isOp) {
|
||||||
pushAwaitedOp(constructBlock(filters));
|
pushAwaitedTask(constructBlock(filters));
|
||||||
opMarkerValue = true;
|
opMarkerValue = true;
|
||||||
} else {
|
} else {
|
||||||
if (isResolvedSlotOp(op)) {
|
if (isResolvedSlotOp(op)) {
|
||||||
|
|||||||
@ -5,7 +5,7 @@ import { TypedClaim } from '../../../types';
|
|||||||
import { context } from '../../context';
|
import { context } from '../../context';
|
||||||
import { opMarker } from '../../global';
|
import { opMarker } from '../../global';
|
||||||
import { isResolvedReadOp, isResolvedSlotOp } from '../../utils';
|
import { isResolvedReadOp, isResolvedSlotOp } from '../../utils';
|
||||||
import { pushAwaitedOp } from '../awaited';
|
import { pushAwaitedTask } from '../awaited';
|
||||||
import { shiftResolvedOp } from '../resolved';
|
import { shiftResolvedOp } from '../resolved';
|
||||||
|
|
||||||
export const rangeReadOp = <TClaims extends Claim[] = TypedClaim[]>(
|
export const rangeReadOp = <TClaims extends Claim[] = TypedClaim[]>(
|
||||||
@ -21,7 +21,7 @@ export const rangeReadOp = <TClaims extends Claim[] = TypedClaim[]>(
|
|||||||
const { op, isOp } = shiftResolvedOp();
|
const { op, isOp } = shiftResolvedOp();
|
||||||
|
|
||||||
if (!isOp) {
|
if (!isOp) {
|
||||||
pushAwaitedOp(constructRangeRead(context.issuer, firstPart, range, maxCount));
|
pushAwaitedTask(constructRangeRead(context.issuer, firstPart, range, maxCount));
|
||||||
opMarkerValue = true;
|
opMarkerValue = true;
|
||||||
} else {
|
} else {
|
||||||
if (isResolvedSlotOp(op)) {
|
if (isResolvedSlotOp(op)) {
|
||||||
|
|||||||
@ -4,7 +4,7 @@ import { TypedClaim } from '../../../types';
|
|||||||
import { context } from '../../context';
|
import { context } from '../../context';
|
||||||
import { opMarker } from '../../global';
|
import { opMarker } from '../../global';
|
||||||
import { isResolvedReadOp, isResolvedSlotOp } from '../../utils';
|
import { isResolvedReadOp, isResolvedSlotOp } from '../../utils';
|
||||||
import { pushAwaitedOp } from '../awaited';
|
import { pushAwaitedTask } from '../awaited';
|
||||||
import { shiftResolvedOp } from '../resolved';
|
import { shiftResolvedOp } from '../resolved';
|
||||||
|
|
||||||
export const readOp = <TClaim extends Claim = TypedClaim>(key: ClaimKey) => {
|
export const readOp = <TClaim extends Claim = TypedClaim>(key: ClaimKey) => {
|
||||||
@ -16,7 +16,7 @@ export const readOp = <TClaim extends Claim = TypedClaim>(key: ClaimKey) => {
|
|||||||
const { op, isOp } = shiftResolvedOp();
|
const { op, isOp } = shiftResolvedOp();
|
||||||
|
|
||||||
if (!isOp) {
|
if (!isOp) {
|
||||||
pushAwaitedOp(constructRead(context.issuer, key));
|
pushAwaitedTask(constructRead(context.issuer, key));
|
||||||
opMarkerValue = true;
|
opMarkerValue = true;
|
||||||
} else {
|
} else {
|
||||||
if (isResolvedSlotOp(op)) {
|
if (isResolvedSlotOp(op)) {
|
||||||
|
|||||||
@ -3,7 +3,7 @@ import { extractStore } from '@coinweb/contract-kit/dist/esm/operations/store';
|
|||||||
|
|
||||||
import { opMarker } from '../../global';
|
import { opMarker } from '../../global';
|
||||||
import { isResolvedSlotOp, isResolvedStoreOp } from '../../utils';
|
import { isResolvedSlotOp, isResolvedStoreOp } from '../../utils';
|
||||||
import { pushAwaitedOp } from '../awaited';
|
import { pushAwaitedTask } from '../awaited';
|
||||||
import { shiftResolvedOp } from '../resolved';
|
import { shiftResolvedOp } from '../resolved';
|
||||||
|
|
||||||
export const storeOp = (claim: Claim) => {
|
export const storeOp = (claim: Claim) => {
|
||||||
@ -15,7 +15,7 @@ export const storeOp = (claim: Claim) => {
|
|||||||
const { op, isOp } = shiftResolvedOp();
|
const { op, isOp } = shiftResolvedOp();
|
||||||
|
|
||||||
if (!isOp) {
|
if (!isOp) {
|
||||||
pushAwaitedOp(constructStore(claim));
|
pushAwaitedTask(constructStore(claim));
|
||||||
opMarkerValue = true;
|
opMarkerValue = true;
|
||||||
} else {
|
} else {
|
||||||
if (isResolvedSlotOp(op)) {
|
if (isResolvedSlotOp(op)) {
|
||||||
|
|||||||
@ -3,7 +3,7 @@ import { Claim, ClaimKey, constructTake, extractTake } from '@coinweb/contract-k
|
|||||||
import { TypedClaim } from '../../../types';
|
import { TypedClaim } from '../../../types';
|
||||||
import { opMarker } from '../../global';
|
import { opMarker } from '../../global';
|
||||||
import { isResolvedSlotOp, isResolvedTakeOp } from '../../utils';
|
import { isResolvedSlotOp, isResolvedTakeOp } from '../../utils';
|
||||||
import { pushAwaitedOp } from '../awaited';
|
import { pushAwaitedTask } from '../awaited';
|
||||||
import { shiftResolvedOp } from '../resolved';
|
import { shiftResolvedOp } from '../resolved';
|
||||||
|
|
||||||
export const takeOp = <TClaim extends Claim = TypedClaim>(key: ClaimKey) => {
|
export const takeOp = <TClaim extends Claim = TypedClaim>(key: ClaimKey) => {
|
||||||
@ -15,7 +15,7 @@ export const takeOp = <TClaim extends Claim = TypedClaim>(key: ClaimKey) => {
|
|||||||
const { op, isOp } = shiftResolvedOp();
|
const { op, isOp } = shiftResolvedOp();
|
||||||
|
|
||||||
if (!isOp) {
|
if (!isOp) {
|
||||||
pushAwaitedOp(constructTake(key));
|
pushAwaitedTask(constructTake(key));
|
||||||
opMarkerValue = true;
|
opMarkerValue = true;
|
||||||
} else {
|
} else {
|
||||||
if (isResolvedSlotOp(op)) {
|
if (isResolvedSlotOp(op)) {
|
||||||
|
|||||||
@ -2,6 +2,9 @@ import { ResolvedOp } from '../../types';
|
|||||||
|
|
||||||
const resolvedOps: ResolvedOp[] = [];
|
const resolvedOps: ResolvedOp[] = [];
|
||||||
|
|
||||||
|
let usedOps: ResolvedOp[] = [];
|
||||||
|
let isSavingUsed = false;
|
||||||
|
|
||||||
export const pushResolvedOp = (op: ResolvedOp | ResolvedOp[]) => {
|
export const pushResolvedOp = (op: ResolvedOp | ResolvedOp[]) => {
|
||||||
if (Array.isArray(op)) {
|
if (Array.isArray(op)) {
|
||||||
resolvedOps.push(...op);
|
resolvedOps.push(...op);
|
||||||
@ -10,11 +13,11 @@ export const pushResolvedOp = (op: ResolvedOp | ResolvedOp[]) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export const shiftResolvedOp = () =>
|
export const shiftResolvedOp = () => {
|
||||||
({
|
const result = {
|
||||||
isOp: resolvedOps.length > 0,
|
isOp: resolvedOps.length > 0,
|
||||||
op: resolvedOps.shift(),
|
op: resolvedOps.shift(),
|
||||||
}) as
|
} as
|
||||||
| {
|
| {
|
||||||
isOp: true;
|
isOp: true;
|
||||||
op: ResolvedOp | null;
|
op: ResolvedOp | null;
|
||||||
@ -23,3 +26,17 @@ export const shiftResolvedOp = () =>
|
|||||||
isOp: false;
|
isOp: false;
|
||||||
op: undefined;
|
op: undefined;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (isSavingUsed && result.op) {
|
||||||
|
usedOps.push(result.op);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const getUsedOps = () => usedOps;
|
||||||
|
|
||||||
|
export const saveUsedOps = () => {
|
||||||
|
usedOps = [];
|
||||||
|
isSavingUsed = true;
|
||||||
|
};
|
||||||
|
|||||||
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++;
|
||||||
@ -0,0 +1,9 @@
|
|||||||
|
import { prepareTx } from './prepareTxs';
|
||||||
|
|
||||||
|
export const constructTx = (isFullyExecuted: boolean) => {
|
||||||
|
const { calls } = prepareTx(isFullyExecuted);
|
||||||
|
|
||||||
|
const { txs } = prepareTx(isFullyExecuted, calls);
|
||||||
|
|
||||||
|
return txs;
|
||||||
|
};
|
||||||
1
packages/cwait/src/onchain/utils/constructTx/index.ts
Normal file
1
packages/cwait/src/onchain/utils/constructTx/index.ts
Normal file
@ -0,0 +1 @@
|
|||||||
|
export * from './constructTx';
|
||||||
@ -0,0 +1,191 @@
|
|||||||
|
import {
|
||||||
|
constructBlock,
|
||||||
|
constructContinueTx,
|
||||||
|
constructContractRef,
|
||||||
|
FullCallInfo,
|
||||||
|
NewTx,
|
||||||
|
passCwebFrom,
|
||||||
|
PreparedOperation,
|
||||||
|
sendCwebInterface,
|
||||||
|
} from '@coinweb/contract-kit';
|
||||||
|
import { CwebBlock } from '@coinweb/contract-kit/dist/esm/operations/block';
|
||||||
|
import { GBlock } from '@coinweb/contract-kit/dist/types/operations/generics';
|
||||||
|
|
||||||
|
import { ExecutorMethodArgs, ResolvedOp, ResolvedSlotOp, Task } from '../../../types';
|
||||||
|
import { constructFundsClaimRangRead, constructFundsClaimStore } from '../../claims/funds';
|
||||||
|
import { constructResultBlockFilter, constructResultClaimTake, resultKey } from '../../claims/result';
|
||||||
|
import { context, getRawContext } from '../../context';
|
||||||
|
import { isPreparedBlockOp, isPreparedExecOp } from '../typeGuards';
|
||||||
|
|
||||||
|
export const prepareInThreadTxs = ({
|
||||||
|
cwebPerCall,
|
||||||
|
outThreadTasksCount,
|
||||||
|
outThreadFee,
|
||||||
|
tasks,
|
||||||
|
}: {
|
||||||
|
tasks: Task[];
|
||||||
|
cwebPerCall: bigint;
|
||||||
|
outThreadTasksCount: number;
|
||||||
|
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 callsPrepared = 0;
|
||||||
|
const resolvedSlotOps = new Array(outThreadTasksCount).fill({ SlotOp: 0 }) satisfies ResolvedSlotOp[];
|
||||||
|
|
||||||
|
const resolvedChildOps: ResolvedOp[] = [...context.ops, ...resolvedSlotOps];
|
||||||
|
|
||||||
|
//Arg for the main call
|
||||||
|
const callArgs: PreparedOperation[] = [];
|
||||||
|
|
||||||
|
//Info for separate child call
|
||||||
|
const childCalls: FullCallInfo[] = [];
|
||||||
|
|
||||||
|
//Block ops for separate child call
|
||||||
|
const childBlocks = tasks
|
||||||
|
.filter((task): task is { op: GBlock<CwebBlock>; batchId: number } => isPreparedBlockOp(task.op))
|
||||||
|
.map(({ op }) => op);
|
||||||
|
|
||||||
|
tasks.forEach((task) => {
|
||||||
|
if (isPreparedExecOp(task.op)) {
|
||||||
|
console.log('Child call info');
|
||||||
|
const id = task.op.ExecOp.id;
|
||||||
|
|
||||||
|
callArgs.push(constructBlock([constructResultBlockFilter(id)]), constructResultClaimTake(id));
|
||||||
|
txFee += 200n;
|
||||||
|
|
||||||
|
childCalls.push({
|
||||||
|
callInfo: {
|
||||||
|
ref: constructContractRef(context.issuer, []),
|
||||||
|
methodInfo: {
|
||||||
|
methodName: context.methodName,
|
||||||
|
methodArgs: [
|
||||||
|
context.initialArgs,
|
||||||
|
[...resolvedChildOps, { ExecOp: { id } }],
|
||||||
|
context.user,
|
||||||
|
id,
|
||||||
|
context.thisId,
|
||||||
|
true,
|
||||||
|
] satisfies ExecutorMethodArgs,
|
||||||
|
},
|
||||||
|
contractInfo: {
|
||||||
|
providedCweb: cwebPerCall - 700n,
|
||||||
|
authenticated: null,
|
||||||
|
},
|
||||||
|
contractArgs: [],
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
callsPrepared++;
|
||||||
|
} else {
|
||||||
|
callArgs.push(task.op);
|
||||||
|
txFee += 100n;
|
||||||
|
}
|
||||||
|
|
||||||
|
resolvedChildOps.push({ SlotOp: 0 });
|
||||||
|
});
|
||||||
|
|
||||||
|
const returnTxs: NewTx[] = [];
|
||||||
|
|
||||||
|
if (callArgs.length) {
|
||||||
|
const { storedCweb, takeOps } = context.funds;
|
||||||
|
|
||||||
|
const latestCallArg = callArgs.at(-1)!;
|
||||||
|
|
||||||
|
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) {
|
||||||
|
throw new Error('Unexpected count of result ops');
|
||||||
|
}
|
||||||
|
|
||||||
|
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 {
|
||||||
|
txFee += 800n + outThreadFee + BigInt(takeOps.length) * 100n;
|
||||||
|
callsPrepared++;
|
||||||
|
|
||||||
|
returnTxs.push(
|
||||||
|
constructContinueTx(
|
||||||
|
getRawContext(),
|
||||||
|
[passCwebFrom(context.issuer, cwebPerCall - outThreadFee), ...takeOps],
|
||||||
|
[
|
||||||
|
{
|
||||||
|
callInfo: {
|
||||||
|
ref: constructContractRef(context.issuer, []),
|
||||||
|
methodInfo: {
|
||||||
|
methodName: context.methodName,
|
||||||
|
methodArgs: [
|
||||||
|
context.initialArgs,
|
||||||
|
[...context.ops, ...resolvedSlotOps],
|
||||||
|
context.user,
|
||||||
|
context.thisId,
|
||||||
|
context.parentId,
|
||||||
|
context.needSaveResult,
|
||||||
|
takeOps.map((op) => (op.TakeOp.key.second_part as [string])[0]),
|
||||||
|
] satisfies ExecutorMethodArgs,
|
||||||
|
},
|
||||||
|
contractInfo: {
|
||||||
|
providedCweb: cwebPerCall - txFee + storedCweb,
|
||||||
|
authenticated: null,
|
||||||
|
},
|
||||||
|
contractArgs: [constructFundsClaimRangRead(context.thisId), ...callArgs],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
]
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
if (childCalls.length) {
|
||||||
|
returnTxs.push(constructContinueTx(getRawContext(), childBlocks, childCalls));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return { txs: returnTxs, calls: callsPrepared };
|
||||||
|
};
|
||||||
@ -0,0 +1,97 @@
|
|||||||
|
import {
|
||||||
|
constructContinueTx,
|
||||||
|
constructContractRef,
|
||||||
|
FullCallInfo,
|
||||||
|
NewTx,
|
||||||
|
PreparedOperation,
|
||||||
|
} from '@coinweb/contract-kit';
|
||||||
|
|
||||||
|
import { ExecutorMethodArgs, Task } from '../../../types';
|
||||||
|
import { context, getRawContext } from '../../context';
|
||||||
|
import { isPreparedExecOp } from '../typeGuards';
|
||||||
|
|
||||||
|
export const prepareOutThreadTxs = ({
|
||||||
|
tasks,
|
||||||
|
cwebPerCall,
|
||||||
|
}: {
|
||||||
|
tasks: Task[];
|
||||||
|
cwebPerCall: bigint;
|
||||||
|
}): {
|
||||||
|
txs: NewTx[];
|
||||||
|
fee: bigint;
|
||||||
|
calls: number;
|
||||||
|
} => {
|
||||||
|
const siblingCallResolvedOps = [...context.ops];
|
||||||
|
|
||||||
|
const siblingTxInfo: {
|
||||||
|
[batchId: number]: {
|
||||||
|
calls: FullCallInfo[];
|
||||||
|
ops: PreparedOperation[];
|
||||||
|
};
|
||||||
|
} = {};
|
||||||
|
|
||||||
|
let txFee = 0n;
|
||||||
|
let callsPrepared = 0;
|
||||||
|
|
||||||
|
tasks.forEach((task) => {
|
||||||
|
if (isPreparedExecOp(task.op)) {
|
||||||
|
console.log('Sibling call info');
|
||||||
|
|
||||||
|
const id = task.op.ExecOp.id;
|
||||||
|
|
||||||
|
const callInfo = {
|
||||||
|
callInfo: {
|
||||||
|
ref: constructContractRef(context.issuer, []),
|
||||||
|
methodInfo: {
|
||||||
|
methodName: context.methodName,
|
||||||
|
methodArgs: [
|
||||||
|
context.initialArgs,
|
||||||
|
[...siblingCallResolvedOps, { ExecOp: { id } }],
|
||||||
|
context.user,
|
||||||
|
id,
|
||||||
|
context.parentId ?? context.thisId,
|
||||||
|
false,
|
||||||
|
] satisfies ExecutorMethodArgs,
|
||||||
|
},
|
||||||
|
contractInfo: {
|
||||||
|
providedCweb: cwebPerCall - 700n,
|
||||||
|
authenticated: null,
|
||||||
|
},
|
||||||
|
contractArgs: [],
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
if (siblingTxInfo[task.batchId]) {
|
||||||
|
siblingTxInfo[task.batchId].calls.push(callInfo);
|
||||||
|
} else {
|
||||||
|
siblingTxInfo[task.batchId] = {
|
||||||
|
calls: [callInfo],
|
||||||
|
ops: [],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
callsPrepared++;
|
||||||
|
} else {
|
||||||
|
if (siblingTxInfo[task.batchId]) {
|
||||||
|
siblingTxInfo[task.batchId].ops.push(task.op);
|
||||||
|
} else {
|
||||||
|
siblingTxInfo[task.batchId] = {
|
||||||
|
calls: [],
|
||||||
|
ops: [task.op],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
txFee += 100n;
|
||||||
|
}
|
||||||
|
|
||||||
|
siblingCallResolvedOps.push({ SlotOp: 0 });
|
||||||
|
});
|
||||||
|
|
||||||
|
const siblingTxs = Object.values(siblingTxInfo).map(({ calls, ops }) =>
|
||||||
|
constructContinueTx(getRawContext(), ops, calls)
|
||||||
|
);
|
||||||
|
|
||||||
|
txFee += BigInt(siblingTxs.length) * 100n;
|
||||||
|
|
||||||
|
return { txs: siblingTxs, fee: txFee, calls: callsPrepared };
|
||||||
|
};
|
||||||
61
packages/cwait/src/onchain/utils/constructTx/prepareTxs.ts
Normal file
61
packages/cwait/src/onchain/utils/constructTx/prepareTxs.ts
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
import { constructContinueTx, NewTx, passCwebFrom, sendCwebInterface } from '@coinweb/contract-kit';
|
||||||
|
|
||||||
|
import { context, getRawContext } from '../../context';
|
||||||
|
import { getAwaitedTasks } from '../../promisifiedOps';
|
||||||
|
|
||||||
|
import { prepareInThreadTxs } from './prepareInThreadTxs';
|
||||||
|
import { prepareOutThreadTxs } from './prepareOutThreadTxs';
|
||||||
|
import { splitTasks } from './splitTasks';
|
||||||
|
|
||||||
|
export const prepareTx = (isFullyExecuted: boolean, callsCount?: number): { txs: NewTx[]; calls: number } => {
|
||||||
|
console.log('Calls Count: ', callsCount);
|
||||||
|
|
||||||
|
const awaitedTasks = getAwaitedTasks();
|
||||||
|
|
||||||
|
console.log('Awaited Tasks: ', JSON.stringify(awaitedTasks));
|
||||||
|
|
||||||
|
if (!awaitedTasks.length) {
|
||||||
|
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 { availableCweb } = context.funds;
|
||||||
|
|
||||||
|
const cwebPerCall = availableCweb / BigInt(callsCount || 1);
|
||||||
|
const {
|
||||||
|
txs: outThreadTxs,
|
||||||
|
fee: outThreadFee,
|
||||||
|
calls: outThreadCallsPrepared,
|
||||||
|
} = prepareOutThreadTxs({ tasks: outThreadTasks, cwebPerCall });
|
||||||
|
|
||||||
|
const { txs: inThreadTxs, calls: inThreadCallsPrepared } = prepareInThreadTxs({
|
||||||
|
tasks: inThreadTasks,
|
||||||
|
cwebPerCall,
|
||||||
|
outThreadTasksCount: outThreadTasks.length,
|
||||||
|
outThreadFee,
|
||||||
|
});
|
||||||
|
|
||||||
|
return { txs: [...inThreadTxs, ...outThreadTxs], calls: inThreadCallsPrepared + outThreadCallsPrepared };
|
||||||
|
};
|
||||||
48
packages/cwait/src/onchain/utils/constructTx/splitTasks.ts
Normal file
48
packages/cwait/src/onchain/utils/constructTx/splitTasks.ts
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
import { Task } from '../../../types';
|
||||||
|
import { isPreparedBlockOp } from '../typeGuards';
|
||||||
|
|
||||||
|
export const splitTasks = (awaitedTasks: Task[], isFullyExecuted: boolean) => {
|
||||||
|
const awaitedTasksBatched: (Task | Task[])[] = [];
|
||||||
|
const preparedTasks: (Task | Task[])[] = [];
|
||||||
|
|
||||||
|
awaitedTasks.forEach((task) => {
|
||||||
|
if (task.batchId === -1) {
|
||||||
|
awaitedTasksBatched.push(task);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const latestTask = awaitedTasksBatched.at(-1);
|
||||||
|
|
||||||
|
if (Array.isArray(latestTask) && latestTask.at(-1)?.batchId === task.batchId) {
|
||||||
|
latestTask.push(task);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
awaitedTasksBatched.push([task]);
|
||||||
|
});
|
||||||
|
|
||||||
|
awaitedTasksBatched.forEach((task, i) => {
|
||||||
|
if (
|
||||||
|
i === awaitedTasksBatched.length - 1 ||
|
||||||
|
!Array.isArray(task) ||
|
||||||
|
(task.length > 1 && task.some(({ op }) => isPreparedBlockOp(op)))
|
||||||
|
) {
|
||||||
|
preparedTasks.push(task);
|
||||||
|
} else {
|
||||||
|
preparedTasks.push(...task.map((task) => ({ ...task, batchId: -1 })));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
let inThreadTasks: Task[] = [];
|
||||||
|
let outThreadTasks: Task[] = [];
|
||||||
|
|
||||||
|
if (!isFullyExecuted) {
|
||||||
|
const preparedCallTasks = preparedTasks.at(-1)!;
|
||||||
|
inThreadTasks = [...(Array.isArray(preparedCallTasks) ? preparedCallTasks : [preparedCallTasks])];
|
||||||
|
outThreadTasks = preparedTasks.slice(0, -1).flat();
|
||||||
|
} else {
|
||||||
|
outThreadTasks = preparedTasks.flat();
|
||||||
|
}
|
||||||
|
|
||||||
|
return { inThreadTasks, outThreadTasks };
|
||||||
|
};
|
||||||
@ -1,2 +1,5 @@
|
|||||||
|
export * from './batchId';
|
||||||
export * from './callstack';
|
export * from './callstack';
|
||||||
|
export * from './constructTx';
|
||||||
export * from './typeGuards';
|
export * from './typeGuards';
|
||||||
|
export * from './uuid';
|
||||||
|
|||||||
@ -4,47 +4,93 @@ import {
|
|||||||
isResolvedRead,
|
isResolvedRead,
|
||||||
isResolvedStore,
|
isResolvedStore,
|
||||||
isResolvedTake,
|
isResolvedTake,
|
||||||
|
ResolvedOperation,
|
||||||
ResolvedRead,
|
ResolvedRead,
|
||||||
ResolvedTake,
|
ResolvedTake,
|
||||||
} from '@coinweb/contract-kit';
|
} from '@coinweb/contract-kit';
|
||||||
|
import { CwebBlock } from '@coinweb/contract-kit/dist/esm/operations/block';
|
||||||
import { CwebCallRefResolved, isResolvedCall } from '@coinweb/contract-kit/dist/esm/operations/call';
|
import { CwebCallRefResolved, isResolvedCall } from '@coinweb/contract-kit/dist/esm/operations/call';
|
||||||
import { ResolvedBlock } from '@coinweb/contract-kit/dist/types/operations/block';
|
import { ResolvedBlock } from '@coinweb/contract-kit/dist/types/operations/block';
|
||||||
import { GBlock, GCall, GRead, GStore, GTake } from '@coinweb/contract-kit/dist/types/operations/generics';
|
import { GBlock, GCall, GRead, GStore, GTake } from '@coinweb/contract-kit/dist/types/operations/generics';
|
||||||
|
|
||||||
import { ResolvedOp, SlotOp } from '../../types';
|
import { PreparedExecOp, PreparedOp, ResolvedChildOp, ResolvedExecOp, ResolvedOp, ResolvedSlotOp } from '../../types';
|
||||||
|
|
||||||
|
export const isResolvedSlotOp = (op?: ResolvedOp | null): op is ResolvedSlotOp => {
|
||||||
|
if (op && 'SlotOp' in op) {
|
||||||
|
console.log('isResolvedSlotOp >>> ', JSON.stringify(op));
|
||||||
|
}
|
||||||
|
|
||||||
export const isResolvedSlotOp = (op?: ResolvedOp | null): op is SlotOp => {
|
|
||||||
console.log('isResolvedSlotOp', JSON.stringify(op));
|
|
||||||
console.log('isResolvedSlotOp', !!(op && 'SlotOp' in op));
|
|
||||||
return !!(op && 'SlotOp' in op);
|
return !!(op && 'SlotOp' in op);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const isResolvedExecOp = (op?: ResolvedOp | null): op is ResolvedExecOp => {
|
||||||
|
if (op && 'ExecOp' in op) {
|
||||||
|
console.log('isResolvedExecOp >>> ', JSON.stringify(op));
|
||||||
|
}
|
||||||
|
|
||||||
|
return !!(op && 'ExecOp' in op);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const isResolvedChildOp = (op?: ResolvedOp | null): op is ResolvedChildOp => {
|
||||||
|
if (op && 'ChildOp' in op) {
|
||||||
|
console.log('isResolvedChildOp >>> ', JSON.stringify(op));
|
||||||
|
}
|
||||||
|
|
||||||
|
return !!(op && 'ChildOp' in op);
|
||||||
|
};
|
||||||
|
|
||||||
export const isResolvedBlockOp = (op?: ResolvedOp | null): op is GBlock<ResolvedBlock> => {
|
export const isResolvedBlockOp = (op?: ResolvedOp | null): op is GBlock<ResolvedBlock> => {
|
||||||
console.log('isResolvedBlockOp', JSON.stringify(op));
|
if (op && 'BlockOp' in op) {
|
||||||
console.log('isResolvedBlockOp', !!(op && !isResolvedSlotOp(op) && isResolvedBlock(op)));
|
console.log('isResolvedBlockOp >>> ', JSON.stringify(op));
|
||||||
return !!(op && !isResolvedSlotOp(op) && isResolvedBlock(op));
|
}
|
||||||
|
|
||||||
|
return isResolvedBlock(op as ResolvedOperation); //TODO: Fix contract-kit types
|
||||||
};
|
};
|
||||||
|
|
||||||
export const isResolvedStoreOp = (op?: ResolvedOp | null): op is GStore<CwebStore> => {
|
export const isResolvedStoreOp = (op?: ResolvedOp | null): op is GStore<CwebStore> => {
|
||||||
console.log('isResolvedStoreOp', JSON.stringify(op));
|
if (op && 'StoreOp' in op) {
|
||||||
console.log('isResolvedStoreOp', !!(op && !isResolvedSlotOp(op) && isResolvedStore(op)));
|
console.log('isResolvedStoreOp >>> ', JSON.stringify(op));
|
||||||
return !!(op && !isResolvedSlotOp(op) && isResolvedStore(op));
|
}
|
||||||
|
|
||||||
|
return isResolvedStore(op as ResolvedOperation); //TODO: Fix contract-kit types
|
||||||
};
|
};
|
||||||
|
|
||||||
export const isResolvedCallOp = (op?: ResolvedOp | null): op is GCall<CwebCallRefResolved> => {
|
export const isResolvedCallOp = (op?: ResolvedOp | null): op is GCall<CwebCallRefResolved> => {
|
||||||
console.log('isResolvedCallOp', JSON.stringify(op));
|
if (op && 'CallOp' in op) {
|
||||||
console.log('isResolvedCallOp', !!(op && !isResolvedSlotOp(op) && isResolvedCall(op)));
|
console.log('isResolvedCallOp >>> ', JSON.stringify(op));
|
||||||
return !!(op && !isResolvedSlotOp(op) && isResolvedCall(op));
|
}
|
||||||
|
|
||||||
|
return isResolvedCall(op as ResolvedOperation); //TODO: Fix contract-kit types
|
||||||
};
|
};
|
||||||
|
|
||||||
export const isResolvedTakeOp = (op?: ResolvedOp | null): op is GTake<ResolvedTake> => {
|
export const isResolvedTakeOp = (op?: ResolvedOp | null): op is GTake<ResolvedTake> => {
|
||||||
console.log('isResolvedTakeOp', JSON.stringify(op));
|
if (op && 'TakeOp' in op) {
|
||||||
console.log('isResolvedTakeOp', !!(op && !isResolvedSlotOp(op) && isResolvedTake(op)));
|
console.log('isResolvedTakeOp >>> ', JSON.stringify(op));
|
||||||
return !!(op && !isResolvedSlotOp(op) && isResolvedTake(op));
|
}
|
||||||
|
|
||||||
|
return isResolvedTake(op as ResolvedOperation); //TODO: Fix contract-kit types
|
||||||
};
|
};
|
||||||
|
|
||||||
export const isResolvedReadOp = (op?: ResolvedOp | null): op is GRead<ResolvedRead> => {
|
export const isResolvedReadOp = (op?: ResolvedOp | null): op is GRead<ResolvedRead> => {
|
||||||
console.log('isResolvedReadOp', JSON.stringify(op));
|
if (op && 'ReadOp' in op) {
|
||||||
console.log('isResolvedReadOp', !!(op && !isResolvedSlotOp(op) && isResolvedRead(op)));
|
console.log('isResolvedReadOp >>> ', JSON.stringify(op));
|
||||||
return !!(op && !isResolvedSlotOp(op) && isResolvedRead(op));
|
}
|
||||||
|
|
||||||
|
return isResolvedRead(op as ResolvedOperation); //TODO: Fix contract-kit types
|
||||||
|
};
|
||||||
|
|
||||||
|
export const isPreparedExecOp = (op?: PreparedOp | null): op is PreparedExecOp => {
|
||||||
|
if (op && 'ExecOp' in op) {
|
||||||
|
console.log('isPreparedExecOp >>> ', JSON.stringify(op));
|
||||||
|
}
|
||||||
|
|
||||||
|
return !!(op && 'ExecOp' in op);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const isPreparedBlockOp = (op?: PreparedOp | null): op is GBlock<CwebBlock> => {
|
||||||
|
if (op && 'BlockOp' in op) {
|
||||||
|
console.log('isPreparedBlockOp >>> ', JSON.stringify(op));
|
||||||
|
}
|
||||||
|
|
||||||
|
return !!(op && 'BlockOp' in op);
|
||||||
};
|
};
|
||||||
|
|||||||
12
packages/cwait/src/onchain/utils/uuid.ts
Normal file
12
packages/cwait/src/onchain/utils/uuid.ts
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
import { context } from '../context';
|
||||||
|
|
||||||
|
let next = 0n;
|
||||||
|
|
||||||
|
export const uuid = () => {
|
||||||
|
const parentTxId = context.parentTxId;
|
||||||
|
|
||||||
|
const id = `${parentTxId}${next.toString(16)}`;
|
||||||
|
next += 1n;
|
||||||
|
|
||||||
|
return id;
|
||||||
|
};
|
||||||
@ -1,4 +1,4 @@
|
|||||||
import { Claim, ClaimKey, OrdJson, PreparedOperation, ResolvedOperation } from '@coinweb/contract-kit';
|
import { Claim, ClaimKey, OrdJson, PreparedOperation, ResolvedOperation, User } from '@coinweb/contract-kit';
|
||||||
|
|
||||||
export type HexBigInt = `0x${string}`;
|
export type HexBigInt = `0x${string}`;
|
||||||
|
|
||||||
@ -8,14 +8,41 @@ export type TypedClaim<TBody extends OrdJson = OrdJson, TKey extends ClaimKey =
|
|||||||
key: TKey;
|
key: TKey;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type Task = {
|
export type ResolvedSlotOp = {
|
||||||
op: PreparedOperation;
|
|
||||||
stack: string;
|
|
||||||
isBatch: boolean;
|
|
||||||
};
|
|
||||||
|
|
||||||
export type SlotOp = {
|
|
||||||
SlotOp: 0;
|
SlotOp: 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type ResolvedOp = ResolvedOperation | SlotOp;
|
export type ResolvedExecOp = {
|
||||||
|
ExecOp: {
|
||||||
|
id: string;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export type ResolvedChildOp = {
|
||||||
|
ChildOp: 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type ResolvedOp = ResolvedOperation | ResolvedSlotOp | ResolvedExecOp | ResolvedChildOp;
|
||||||
|
|
||||||
|
export type PreparedExecOp = {
|
||||||
|
ExecOp: {
|
||||||
|
id: string;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export type PreparedOp = PreparedOperation | PreparedExecOp;
|
||||||
|
|
||||||
|
export type Task = {
|
||||||
|
op: PreparedOp;
|
||||||
|
batchId: number;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type ExecutorMethodArgs = [
|
||||||
|
initialArgs?: unknown[],
|
||||||
|
resolvedOps?: ResolvedOp[],
|
||||||
|
caller?: User,
|
||||||
|
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="0xd0b364db47a35710320a815fbcae80435ae83e0a1730e70529f1b0b2a6b7bfd5"
|
VITE_CONTRACT_ADDRESS="0x8c89cb42634cfe892290845d907af8ec2d482cead42afaef3ccc3cea4446fce5"
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user