diff --git a/packages/contract.cm/src/onchain/extraLogic.ts b/packages/contract.cm/src/onchain/extraLogic.ts index 3a09acf..4eea7a2 100644 --- a/packages/contract.cm/src/onchain/extraLogic.ts +++ b/packages/contract.cm/src/onchain/extraLogic.ts @@ -1,14 +1,20 @@ import { constructClaim } from '@coinweb/contract-kit'; -import { cwait, readOp, storeOp, TypedClaim } from 'cwait'; +import { cwait, lock, readOp, storeOp, TypedClaim } from 'cwait'; import { createWordKey, WordClaimBody } from '../offchain'; import { extraLogic2 } from './extraLogic2'; export const extraLogic = cwait(async (id: string, i: number) => { - console.log('extraLogic START + ', i); + console.log('extraLogic START ++ ', i); + + console.log('extraLogic lock + ', i); + const unlock = await lock(createWordKey(id)); + + console.log('extraLogic readOp + ', i); const result = await readOp>(createWordKey(id)); + console.log('extraLogic storeOp + ', i); await storeOp( constructClaim( createWordKey(id), @@ -17,6 +23,9 @@ export const extraLogic = cwait(async (id: string, i: number) => { ) ); + console.log('extraLogic unlock + ', i); + await unlock(); + console.log('extraLogic return extraLogic2 + ', i); return extraLogic2(id, i); }); diff --git a/packages/cwait/src/onchain/context/context.ts b/packages/cwait/src/onchain/context/context.ts index 778ff46..41513b2 100644 --- a/packages/cwait/src/onchain/context/context.ts +++ b/packages/cwait/src/onchain/context/context.ts @@ -12,7 +12,6 @@ import { getCallParameters, getContractIssuer } from 'lib/onchain'; import { ExecutorMethodArgs, ResolvedOp } from '../../types'; import { pushAwaitedTask } from '../promisifiedFeatures'; -import { uuid } from '../utils'; import { extractOps } from './extractOps'; @@ -65,7 +64,9 @@ export const handleContext = (ctx: Context) => { ] = getMethodArgs(); initialContext.isChild = !!parentId; - initialContext.thisId = thisId ?? uuid(); + initialContext.thisId = + thisId ?? + (BigInt(`0x${parentId ?? '0'}`) * 3n + BigInt(`0x${getRawContext().call.txid}`)).toString(16).slice(0, 32); initialContext.parentId = parentId; initialContext.methodName = methodName; initialContext.initialArgs = initialArgs ?? []; diff --git a/packages/cwait/src/onchain/context/extractOps.ts b/packages/cwait/src/onchain/context/extractOps.ts index f070a51..1d3d302 100644 --- a/packages/cwait/src/onchain/context/extractOps.ts +++ b/packages/cwait/src/onchain/context/extractOps.ts @@ -3,7 +3,13 @@ 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 { + mutexBlockLockKey, + mutexBlockUnlockKey, + mutexExecOpsKey, + MutexExecOpsResult, + MutexNotifyLockState, +} from '../mutex'; import { isResolvedBlockOp, isResolvedReadOp, isResolvedTakeOp } from '../utils'; const extractFunds = (fundsOp: GRead, takenFundsIds: string[]) => { @@ -92,7 +98,9 @@ export const extractOps = ({ throw new Error('Wrong mutex lock result'); } - extractedOps.push({ SlotOp: { ok: true } }); + extractedOps.push({ + LockOp: nextAfterBlock.TakeOp.result.body as MutexNotifyLockState, + }); i += 2; continue; diff --git a/packages/cwait/src/onchain/mutex/calls/constructLockCall.ts b/packages/cwait/src/onchain/mutex/calls/constructLockCall.ts index aee89c0..7cdeca5 100644 --- a/packages/cwait/src/onchain/mutex/calls/constructLockCall.ts +++ b/packages/cwait/src/onchain/mutex/calls/constructLockCall.ts @@ -1,10 +1,23 @@ import { ContractIssuer, constructContractRef } from '@coinweb/contract-kit'; -import { constructMutexBlockLockClaimTake, constructMutexLockBlock } from '../claims'; +import { constructMutexBlockLockClaimTake, constructMutexLockBlock, constructMutexLockClaimStore } from '../claims'; import { lockMethodName } from '../methods'; import { lockFee } from '../settings'; +import { LockedKey } from '../types'; -export const constructLockCall = (issuer: ContractIssuer, lockId: string) => { +export const constructLockCall = ({ + issuer, + keys, + lockId, + timestamp, + processId, +}: { + issuer: ContractIssuer; + lockId: string; + timestamp: number; + keys: LockedKey[]; + processId: string; +}) => { return { callInfo: { ref: constructContractRef(issuer, []), @@ -18,7 +31,10 @@ export const constructLockCall = (issuer: ContractIssuer, lockId: string) => { }, contractArgs: [], }, - ops: [constructMutexLockBlock(lockId, issuer), constructMutexBlockLockClaimTake(lockId)] as const, - fee: lockFee + 200n, + inThreadOps: [constructMutexLockBlock(lockId, issuer), constructMutexBlockLockClaimTake(lockId)] as const, + outThreadOps: [ + constructMutexLockClaimStore({ fee: lockFee, keys, lockId, timestamp, processId, locked: false }), + ] as const, + fee: lockFee * 2n + 200n, }; }; diff --git a/packages/cwait/src/onchain/mutex/claims/mutexBlockLock.ts b/packages/cwait/src/onchain/mutex/claims/mutexBlockLock.ts index 0f6484e..92de7cc 100644 --- a/packages/cwait/src/onchain/mutex/claims/mutexBlockLock.ts +++ b/packages/cwait/src/onchain/mutex/claims/mutexBlockLock.ts @@ -8,15 +8,17 @@ import { ContractIssuer, } from '@coinweb/contract-kit'; +import { MutexNotifyLockState } from '../types'; + export const mutexBlockLockKey = '_mutex_block_lock'; export const constructMutexBlockLockClaimKey = (lockId: string) => constructClaimKey([mutexBlockLockKey], [lockId]); -export const constructMutexBlockLockClaim = ({ lockId }: { lockId: string }) => - constructClaim(constructMutexBlockLockClaimKey(lockId), {}, '0x0'); +export const constructMutexBlockLockClaim = ({ lockId, timestamp }: MutexNotifyLockState) => + constructClaim(constructMutexBlockLockClaimKey(lockId), { lockId, timestamp } satisfies MutexNotifyLockState, '0x0'); -export const constructMutexBlockLockClaimStore = ({ lockId }: { lockId: string }) => - constructStore(constructMutexBlockLockClaim({ lockId })); +export const constructMutexBlockLockClaimStore = ({ lockId, timestamp }: MutexNotifyLockState) => + constructStore(constructMutexBlockLockClaim({ lockId, timestamp })); export const constructMutexBlockLockClaimTake = (lockId: string) => constructTake(constructMutexBlockLockClaimKey(lockId)); diff --git a/packages/cwait/src/onchain/mutex/claims/mutexLock.ts b/packages/cwait/src/onchain/mutex/claims/mutexLock.ts index 5441d8e..2e135c5 100644 --- a/packages/cwait/src/onchain/mutex/claims/mutexLock.ts +++ b/packages/cwait/src/onchain/mutex/claims/mutexLock.ts @@ -43,17 +43,17 @@ export const constructMutexLockClaim = ({ export const constructMutexLockClaimStore = ({ fee, keys, - locked, lockId, timestamp, processId, + locked, }: { fee: bigint; keys: LockedKey[]; - locked: boolean; lockId: string; timestamp: number; processId: string; + locked: boolean; }) => constructStore(constructMutexLockClaim({ fee, keys, locked, lockId, timestamp, processId })); export const constructMutexLockClaimRangeRead = (issuer: ContractIssuer): GRead => diff --git a/packages/cwait/src/onchain/mutex/index.ts b/packages/cwait/src/onchain/mutex/index.ts index 793cef3..16dd33a 100644 --- a/packages/cwait/src/onchain/mutex/index.ts +++ b/packages/cwait/src/onchain/mutex/index.ts @@ -6,6 +6,8 @@ import { mutexExecLock, mutexLock, mutexUnlock, + notifyLock, + notifyLockMethodName, preReadExecTakeOpsMethodName, saveExecOpResult, saveExecOpResultMethodName, @@ -27,4 +29,5 @@ export const mutexMethods = { [preReadExecTakeOpsMethodName]: preReadExecTakeOps, [saveExecOpResultMethodName]: saveExecOpResult, [waitMethodName]: wait, + [notifyLockMethodName]: notifyLock, }; diff --git a/packages/cwait/src/onchain/mutex/methods/execLock.ts b/packages/cwait/src/onchain/mutex/methods/execLock.ts index 4d8d5ff..c5a8934 100644 --- a/packages/cwait/src/onchain/mutex/methods/execLock.ts +++ b/packages/cwait/src/onchain/mutex/methods/execLock.ts @@ -16,7 +16,7 @@ import { lockFee } from '../settings'; import { MutexLockState, MutexWaitNotifyArgs } from '../types'; import { isMatchLockKeys } from '../utils'; -import { lockMethodName, notifyLockMethodName } from './names'; +import { waitMethodName } from './names'; export const mutexExecLock = (context: Context) => { const { availableCweb } = getCallParameters(context); @@ -59,25 +59,17 @@ export const mutexExecLock = (context: Context) => { callInfo: { ref: constructContractRef(issuer, []), methodInfo: { - methodName: lockMethodName, - methodArgs: [], + methodName: waitMethodName, + methodArgs: [ + 0, + { + timestamp: (lockCandidate.key.second_part as [number, string])[0], + lockId: (lockCandidate.key.second_part as [number, string])[1], + }, + ] satisfies MutexWaitNotifyArgs, }, contractInfo: { - providedCweb: lockFee, - authenticated: null, - }, - contractArgs: [], - }, - }, - { - callInfo: { - ref: constructContractRef(issuer, []), - methodInfo: { - methodName: notifyLockMethodName, - methodArgs: [0, (lockCandidate.key.second_part as [number, string])[1]] satisfies MutexWaitNotifyArgs, - }, - contractInfo: { - providedCweb: 200n, + providedCweb: availableCweb + BigInt(lockCandidate.fees_stored) - 1000n, authenticated: null, }, contractArgs: [], diff --git a/packages/cwait/src/onchain/mutex/methods/notifyLock.ts b/packages/cwait/src/onchain/mutex/methods/notifyLock.ts index 41d6c2f..a49ed88 100644 --- a/packages/cwait/src/onchain/mutex/methods/notifyLock.ts +++ b/packages/cwait/src/onchain/mutex/methods/notifyLock.ts @@ -5,7 +5,7 @@ import { constructMutexBlockLockClaimStore } from '../claims/mutexBlockLock'; import { MutexNotifyLockArgs } from '../types'; export const notifyLock = (context: Context) => { - const [lockId] = getMethodArguments(context); + const [lockInfo] = getMethodArguments(context); - return [constructContinueTx(context, [constructMutexBlockLockClaimStore({ lockId })])]; + return [constructContinueTx(context, [constructMutexBlockLockClaimStore(lockInfo)])]; }; diff --git a/packages/cwait/src/onchain/mutex/methods/wait.ts b/packages/cwait/src/onchain/mutex/methods/wait.ts index 5104d4b..7ed1eff 100644 --- a/packages/cwait/src/onchain/mutex/methods/wait.ts +++ b/packages/cwait/src/onchain/mutex/methods/wait.ts @@ -1,14 +1,15 @@ import { constructContinueTx, constructContractRef, Context } from '@coinweb/contract-kit'; -import { getContractIssuer, getMethodArguments } from 'lib/onchain'; +import { getCallParameters, getContractIssuer, getMethodArguments } from 'lib/onchain'; import { waitSteps } from '../settings'; import { MutexNotifyLockArgs, MutexWaitNotifyArgs } from '../types'; -import { notifyLockMethodName } from './names'; +import { notifyLockMethodName, waitMethodName } from './names'; export const wait = (context: Context) => { const issuer = getContractIssuer(context); - const [step, lockId] = getMethodArguments(context); + const [step, lockInfo] = getMethodArguments(context); + const { availableCweb } = getCallParameters(context); //Including the notifyLock method as step if (step + 1 < waitSteps) { @@ -21,11 +22,11 @@ export const wait = (context: Context) => { callInfo: { ref: constructContractRef(issuer, []), methodInfo: { - methodName: notifyLockMethodName, - methodArgs: [step + 1, lockId] satisfies MutexWaitNotifyArgs, + methodName: waitMethodName, + methodArgs: [step + 1, lockInfo] satisfies MutexWaitNotifyArgs, }, contractInfo: { - providedCweb: 200n, + providedCweb: availableCweb - 800n, authenticated: null, }, contractArgs: [], @@ -46,10 +47,10 @@ export const wait = (context: Context) => { ref: constructContractRef(issuer, []), methodInfo: { methodName: notifyLockMethodName, - methodArgs: [lockId] satisfies MutexNotifyLockArgs, + methodArgs: [lockInfo] satisfies MutexNotifyLockArgs, }, contractInfo: { - providedCweb: 200n, + providedCweb: availableCweb - 800n, authenticated: null, }, contractArgs: [], diff --git a/packages/cwait/src/onchain/mutex/types.ts b/packages/cwait/src/onchain/mutex/types.ts index 245e8af..9766fbf 100644 --- a/packages/cwait/src/onchain/mutex/types.ts +++ b/packages/cwait/src/onchain/mutex/types.ts @@ -9,6 +9,11 @@ export type MutexLockState = { processId: string; }; +export type MutexNotifyLockState = { + timestamp: number; + lockId: string; +}; + export type MutexExecOpsResult = ( | { ok: true; @@ -24,9 +29,9 @@ export type MutexUnlockArgs = [lockId: string, timestamp: number, notify?: boole export type MutexExecOpArgs = [ops: (GTake | GStore)[], processId: string, execId?: string]; -export type MutexWaitNotifyArgs = [step: number, lockId: string]; +export type MutexWaitNotifyArgs = [step: number, lockInfo: MutexNotifyLockState]; -export type MutexNotifyLockArgs = [lockId: string]; +export type MutexNotifyLockArgs = [lockInfo: MutexNotifyLockState]; export type MutexPreReadTakeOpsArgs = [execId: string, unavailableIndexes: number[], ops: PreparedOperation[]]; diff --git a/packages/cwait/src/onchain/utils/constructTx/prepareInThreadTxs.ts b/packages/cwait/src/onchain/utils/constructTx/prepareInThreadTxs.ts index f889651..496580f 100644 --- a/packages/cwait/src/onchain/utils/constructTx/prepareInThreadTxs.ts +++ b/packages/cwait/src/onchain/utils/constructTx/prepareInThreadTxs.ts @@ -79,6 +79,8 @@ export const prepareInThreadTxs = ({ //Info for separate child call const childCalls: FullCallInfo[] = []; + const outThreadOps: PreparedOperation[] = []; + ops.forEach((op, i) => { switch (true) { case isPreparedExecOp(op): { @@ -136,12 +138,25 @@ export const prepareInThreadTxs = ({ break; } case isPreparedLockOp(op): { - const { callInfo, fee, ops } = constructLockCall(context.issuer, op.LockOp.lockId); + const { + callInfo, + fee, + inThreadOps, + outThreadOps: outThreadOpsFromLockCall, + } = constructLockCall({ + issuer: context.issuer, + lockId: op.LockOp.lockId, + timestamp: op.LockOp.timestamp, + keys: op.LockOp.keys, + processId: context.thisId, + }); childCalls.push({ callInfo }); - callArgs.push(...ops); + callArgs.push(...inThreadOps); txFee += fee; + outThreadOps.push(...outThreadOpsFromLockCall); + break; } case isPreparedUnlockOp(op): { @@ -252,8 +267,8 @@ export const prepareInThreadTxs = ({ ) ); - if (childCalls.length) { - returnTxs.push(constructContinueTx(getRawContext(), [], childCalls)); + if (childCalls.length || outThreadOps.length) { + returnTxs.push(constructContinueTx(getRawContext(), outThreadOps, childCalls)); } } } diff --git a/packages/cwait/src/onchain/utils/constructTx/prepareOutThreadTxs.ts b/packages/cwait/src/onchain/utils/constructTx/prepareOutThreadTxs.ts index c2d98e8..ff9c2bb 100644 --- a/packages/cwait/src/onchain/utils/constructTx/prepareOutThreadTxs.ts +++ b/packages/cwait/src/onchain/utils/constructTx/prepareOutThreadTxs.ts @@ -79,11 +79,19 @@ export const prepareOutThreadTxs = ({ break; } case isPreparedLockOp(op): { - const { callInfo, fee } = constructLockCall(context.issuer, op.LockOp.lockId); + const { callInfo, fee, outThreadOps } = constructLockCall({ + issuer: context.issuer, + lockId: op.LockOp.lockId, + timestamp: op.LockOp.timestamp, + keys: op.LockOp.keys, + processId: context.thisId, + }); preparedCalls.push({ callInfo }); txFee += fee; + preparedOps.push(...outThreadOps); + break; } case isPreparedUnlockOp(op): { diff --git a/packages/cwait/src/onchain/utils/uuid.ts b/packages/cwait/src/onchain/utils/uuid.ts index 9921fef..f7d8772 100644 --- a/packages/cwait/src/onchain/utils/uuid.ts +++ b/packages/cwait/src/onchain/utils/uuid.ts @@ -3,9 +3,8 @@ import { context } from '../context'; let next = 0n; export const uuid = () => { - const parentTxId = context.parentTxId; + const id = (BigInt(`0x${context.thisId}`) * 3n + BigInt(`0x${context.parentTxId}`) + next).toString(16).slice(-32); - const id = `${parentTxId}${next.toString(16)}`; next += 1n; return id; diff --git a/packages/ui/.env b/packages/ui/.env index d30b9fc..fc545dd 100644 --- a/packages/ui/.env +++ b/packages/ui/.env @@ -1,4 +1,4 @@ VITE_API_URL='https://api-cloud.coinweb.io/wallet' VITE_EXPLORER_URL='https://explorer.coinweb.io' -VITE_CONTRACT_ADDRESS="0x5b7c1e53461f5497d467cb9d5c772be5e8c1a61b60e7f2f4ce71c7249d8e768a" +VITE_CONTRACT_ADDRESS="0xedca91a29553fa2466e89eef02ac06dc49ab68be5e81fa91d05765cab79ec02a"