Compare commits
No commits in common. "5dd0aef4723e037aebf7533f93d63406b04e2f2e" and "cb4a2fb33d7aa0fd1b252b560f6ad7b859a03bfb" have entirely different histories.
5dd0aef472
...
cb4a2fb33d
@ -1,9 +1,25 @@
|
|||||||
import { constructCwebMain } from 'cwait';
|
import { SELF_REGISTER_HANDLER_NAME } from '@coinweb/contract-kit';
|
||||||
|
import { selfRegisterHandler } from '@coinweb/self-register';
|
||||||
|
import { addMethodHandler, ContractHandlers, executeHandler, executor } from 'cwait';
|
||||||
|
|
||||||
import { PUBLIC_METHODS } from '../offchain/shared';
|
import { PUBLIC_METHODS } from '../offchain/shared';
|
||||||
|
|
||||||
import { addWord } from './addWord';
|
import { addWord } from './addWord';
|
||||||
|
|
||||||
export const cwebMain = constructCwebMain({
|
const createModule = (): ContractHandlers => {
|
||||||
[PUBLIC_METHODS.ADD_WORD]: addWord,
|
const module: ContractHandlers = { handlers: {} };
|
||||||
});
|
|
||||||
|
addMethodHandler(module, PUBLIC_METHODS.ADD_WORD, executor(addWord));
|
||||||
|
|
||||||
|
addMethodHandler(module, SELF_REGISTER_HANDLER_NAME, selfRegisterHandler);
|
||||||
|
|
||||||
|
return module;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const cwebMain = () => {
|
||||||
|
return (async () => {
|
||||||
|
const module = createModule();
|
||||||
|
|
||||||
|
await executeHandler(module);
|
||||||
|
})();
|
||||||
|
};
|
||||||
|
|||||||
@ -1,27 +0,0 @@
|
|||||||
import { ContractHandlers as ContractHandlersOrig, SELF_REGISTER_HANDLER_NAME } from '@coinweb/contract-kit';
|
|
||||||
import { selfRegisterHandler } from '@coinweb/self-register';
|
|
||||||
import { queue } from 'lib/onchain';
|
|
||||||
|
|
||||||
import { addMethodHandler, ContractHandlers, executeHandler } from '../contract-kit';
|
|
||||||
|
|
||||||
import { executor } from './executor';
|
|
||||||
import { mutexMethods } from './mutex';
|
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
||||||
export const constructCwebMain = (methods: Record<string, (...args: any[]) => Promise<void>>) => async () => {
|
|
||||||
const module: ContractHandlers = { handlers: {} };
|
|
||||||
|
|
||||||
Object.entries(methods).forEach(([name, handler]) => {
|
|
||||||
addMethodHandler(module, name, executor(handler));
|
|
||||||
});
|
|
||||||
|
|
||||||
Object.entries(mutexMethods).forEach(([name, handler]) => {
|
|
||||||
addMethodHandler(module, name, handler);
|
|
||||||
});
|
|
||||||
|
|
||||||
addMethodHandler(module, SELF_REGISTER_HANDLER_NAME, selfRegisterHandler);
|
|
||||||
|
|
||||||
queue.applyQueue(module as ContractHandlersOrig, []);
|
|
||||||
|
|
||||||
await executeHandler(module);
|
|
||||||
};
|
|
||||||
@ -43,7 +43,7 @@ export const executor = (method: (...args: any[]) => Promise<void>) => {
|
|||||||
const isFullyExecuted = await execution;
|
const isFullyExecuted = await execution;
|
||||||
return constructTx(isFullyExecuted);
|
return constructTx(isFullyExecuted);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log('<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< executor-error');
|
console.log('<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< executor-error');
|
||||||
console.log((error as Error).message);
|
console.log((error as Error).message);
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,26 +0,0 @@
|
|||||||
import { ContractIssuer, constructContractRef } from '@coinweb/contract-kit';
|
|
||||||
|
|
||||||
import { constructMutexLockClaimRangeRead } from '../claims';
|
|
||||||
import { getAccessMethodName } from '../methods';
|
|
||||||
import { MutexGetAccessArgs } from '../types';
|
|
||||||
|
|
||||||
export const constructGetAccessCall = (
|
|
||||||
issuer: ContractIssuer,
|
|
||||||
...[claimKey, processId, uniqueId]: MutexGetAccessArgs
|
|
||||||
) => {
|
|
||||||
return {
|
|
||||||
callInfo: {
|
|
||||||
ref: constructContractRef(issuer, []),
|
|
||||||
methodInfo: {
|
|
||||||
methodName: getAccessMethodName,
|
|
||||||
methodArgs: [claimKey, processId, uniqueId] satisfies MutexGetAccessArgs,
|
|
||||||
},
|
|
||||||
contractInfo: {
|
|
||||||
providedCweb: 800n,
|
|
||||||
authenticated: null,
|
|
||||||
},
|
|
||||||
contractArgs: [constructMutexLockClaimRangeRead(issuer)],
|
|
||||||
},
|
|
||||||
fee: 900n,
|
|
||||||
};
|
|
||||||
};
|
|
||||||
@ -1,24 +0,0 @@
|
|||||||
import { ContractIssuer, constructContractRef } from '@coinweb/contract-kit';
|
|
||||||
|
|
||||||
import { constructMutexBlockAccessClaimTake, constructMutexLockBlock } from '../claims';
|
|
||||||
import { lockMethodName } from '../methods';
|
|
||||||
import { lockFee } from '../settings';
|
|
||||||
|
|
||||||
export const constructLockCall = (issuer: ContractIssuer, lockId: string) => {
|
|
||||||
return {
|
|
||||||
callInfo: {
|
|
||||||
ref: constructContractRef(issuer, []),
|
|
||||||
methodInfo: {
|
|
||||||
methodName: lockMethodName,
|
|
||||||
methodArgs: [],
|
|
||||||
},
|
|
||||||
contractInfo: {
|
|
||||||
providedCweb: lockFee,
|
|
||||||
authenticated: null,
|
|
||||||
},
|
|
||||||
contractArgs: [],
|
|
||||||
},
|
|
||||||
ops: [constructMutexLockBlock(lockId, issuer), constructMutexBlockAccessClaimTake(lockId)],
|
|
||||||
fee: lockFee + 200n,
|
|
||||||
};
|
|
||||||
};
|
|
||||||
@ -1,23 +0,0 @@
|
|||||||
import { constructContractRef, ContractIssuer } from '@coinweb/contract-kit';
|
|
||||||
|
|
||||||
import { constructMutexLockClaimRangeRead } from '../claims';
|
|
||||||
import { tryOpMethodName } from '../methods';
|
|
||||||
import { MutexTryOpArgs } from '../types';
|
|
||||||
|
|
||||||
export const constructTryOpCall = (issuer: ContractIssuer, ...[op, processId]: MutexTryOpArgs) => {
|
|
||||||
return {
|
|
||||||
callInfo: {
|
|
||||||
ref: constructContractRef(issuer, []),
|
|
||||||
methodInfo: {
|
|
||||||
methodName: tryOpMethodName,
|
|
||||||
methodArgs: [op, processId] satisfies MutexTryOpArgs,
|
|
||||||
},
|
|
||||||
contractInfo: {
|
|
||||||
providedCweb: 800n,
|
|
||||||
authenticated: null,
|
|
||||||
},
|
|
||||||
contractArgs: [constructMutexLockClaimRangeRead(issuer)],
|
|
||||||
},
|
|
||||||
fee: 900n,
|
|
||||||
};
|
|
||||||
};
|
|
||||||
@ -1,24 +0,0 @@
|
|||||||
import { constructContractRef, ContractIssuer } from '@coinweb/contract-kit';
|
|
||||||
|
|
||||||
import { constructMutexBlockUnlockClaimTake, constructMutexUnlockBlock } from '../claims';
|
|
||||||
import { unlockMethodName } from '../methods';
|
|
||||||
import { MutexUnlockArgs } from '../types';
|
|
||||||
|
|
||||||
export const constructUnlockCall = (issuer: ContractIssuer, ...[lockId, timestamp, notify]: MutexUnlockArgs) => {
|
|
||||||
return {
|
|
||||||
callInfo: {
|
|
||||||
ref: constructContractRef(issuer, []),
|
|
||||||
methodInfo: {
|
|
||||||
methodName: unlockMethodName,
|
|
||||||
methodArgs: [lockId, timestamp] satisfies MutexUnlockArgs,
|
|
||||||
},
|
|
||||||
contractInfo: {
|
|
||||||
providedCweb: 1000n,
|
|
||||||
authenticated: null,
|
|
||||||
},
|
|
||||||
contractArgs: [],
|
|
||||||
},
|
|
||||||
ops: notify ? [constructMutexUnlockBlock(lockId, issuer), constructMutexBlockUnlockClaimTake(lockId)] : [],
|
|
||||||
fee: 1200n,
|
|
||||||
};
|
|
||||||
};
|
|
||||||
@ -1,4 +0,0 @@
|
|||||||
export * from './constructGetAccessCall';
|
|
||||||
export * from './constructLockCall';
|
|
||||||
export * from './constructTryOpCall';
|
|
||||||
export * from './constructUnlockCall';
|
|
||||||
@ -1,4 +0,0 @@
|
|||||||
export * from './mutexBlockAccess';
|
|
||||||
export * from './mutexBlockLock';
|
|
||||||
export * from './mutexBlockUnlock';
|
|
||||||
export * from './mutexLock';
|
|
||||||
@ -1,41 +0,0 @@
|
|||||||
import {
|
|
||||||
BlockFilter,
|
|
||||||
constructBlock,
|
|
||||||
constructClaim,
|
|
||||||
constructClaimKey,
|
|
||||||
constructStore,
|
|
||||||
constructTake,
|
|
||||||
ContractIssuer,
|
|
||||||
CwebStore,
|
|
||||||
GStore,
|
|
||||||
} from '@coinweb/contract-kit';
|
|
||||||
|
|
||||||
import { MutexAccessResult, MutexAccessStatus } from '../types';
|
|
||||||
|
|
||||||
export const mutexBlockAccessKey = 'mutex_block_access';
|
|
||||||
|
|
||||||
export const constructMutexBlockAccessClaimKey = (uniqueId: string) =>
|
|
||||||
constructClaimKey([mutexBlockAccessKey], [uniqueId]);
|
|
||||||
|
|
||||||
export const constructMutexBlockAccessClaim = (uniqueId: string, status: MutexAccessStatus) =>
|
|
||||||
constructClaim(constructMutexBlockAccessClaimKey(uniqueId), { status } satisfies MutexAccessResult, '0x0');
|
|
||||||
|
|
||||||
export const constructMutexBlockAccessClaimStore = (uniqueId: string, status: MutexAccessStatus): GStore<CwebStore> =>
|
|
||||||
constructStore(constructMutexBlockAccessClaim(uniqueId, status));
|
|
||||||
|
|
||||||
export const constructMutexBlockAccessClaimTake = (uniqueId: string) =>
|
|
||||||
constructTake(constructMutexBlockAccessClaimKey(uniqueId));
|
|
||||||
|
|
||||||
export const constructMutexBlockAccessBlockFilter = (lockId: string, issuer: ContractIssuer): BlockFilter => {
|
|
||||||
const { first_part: first, second_part: second } = constructMutexBlockAccessClaimKey(lockId);
|
|
||||||
|
|
||||||
return {
|
|
||||||
issuer,
|
|
||||||
first,
|
|
||||||
second,
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
export const constructMutexAccessBlock = (lockId: string, issuer: ContractIssuer) => {
|
|
||||||
return constructBlock([constructMutexBlockAccessBlockFilter(lockId, issuer)]);
|
|
||||||
};
|
|
||||||
@ -1,36 +0,0 @@
|
|||||||
import {
|
|
||||||
BlockFilter,
|
|
||||||
constructBlock,
|
|
||||||
constructClaim,
|
|
||||||
constructClaimKey,
|
|
||||||
constructStore,
|
|
||||||
constructTake,
|
|
||||||
ContractIssuer,
|
|
||||||
} from '@coinweb/contract-kit';
|
|
||||||
|
|
||||||
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 constructMutexBlockLockClaimStore = ({ lockId }: { lockId: string }) =>
|
|
||||||
constructStore(constructMutexBlockLockClaim({ lockId }));
|
|
||||||
|
|
||||||
export const constructMutexBlockLockClaimTake = (lockId: string) =>
|
|
||||||
constructTake(constructMutexBlockLockClaimKey(lockId));
|
|
||||||
|
|
||||||
export const constructMutexLockBlockFilter = (lockId: string, issuer: ContractIssuer): BlockFilter => {
|
|
||||||
const { first_part: first, second_part: second } = constructMutexBlockLockClaimKey(lockId);
|
|
||||||
|
|
||||||
return {
|
|
||||||
issuer,
|
|
||||||
first,
|
|
||||||
second,
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
export const constructMutexLockBlock = (lockId: string, issuer: ContractIssuer) => {
|
|
||||||
return constructBlock([constructMutexLockBlockFilter(lockId, issuer)]);
|
|
||||||
};
|
|
||||||
@ -1,39 +0,0 @@
|
|||||||
import {
|
|
||||||
BlockFilter,
|
|
||||||
constructBlock,
|
|
||||||
constructClaim,
|
|
||||||
constructClaimKey,
|
|
||||||
constructStore,
|
|
||||||
constructTake,
|
|
||||||
ContractIssuer,
|
|
||||||
CwebStore,
|
|
||||||
GStore,
|
|
||||||
} from '@coinweb/contract-kit';
|
|
||||||
|
|
||||||
export const mutexBlockUnlockKey = 'mutex_block_unlock';
|
|
||||||
|
|
||||||
export const constructMutexBlockUnlockClaimKey = (uniqueId: string) =>
|
|
||||||
constructClaimKey([mutexBlockUnlockKey], [uniqueId]);
|
|
||||||
|
|
||||||
export const constructMutexBlockUnlockClaim = (uniqueId: string) =>
|
|
||||||
constructClaim(constructMutexBlockUnlockClaimKey(uniqueId), {}, '0x0');
|
|
||||||
|
|
||||||
export const constructMutexBlockUnlockClaimStore = (uniqueId: string): GStore<CwebStore> =>
|
|
||||||
constructStore(constructMutexBlockUnlockClaim(uniqueId));
|
|
||||||
|
|
||||||
export const constructMutexBlockUnlockClaimTake = (uniqueId: string) =>
|
|
||||||
constructTake(constructMutexBlockUnlockClaimKey(uniqueId));
|
|
||||||
|
|
||||||
export const constructMutexUnlockBlockFilter = (lockId: string, issuer: ContractIssuer): BlockFilter => {
|
|
||||||
const { first_part: first, second_part: second } = constructMutexBlockUnlockClaimKey(lockId);
|
|
||||||
|
|
||||||
return {
|
|
||||||
issuer,
|
|
||||||
first,
|
|
||||||
second,
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
export const constructMutexUnlockBlock = (lockId: string, issuer: ContractIssuer) => {
|
|
||||||
return constructBlock([constructMutexUnlockBlockFilter(lockId, issuer)]);
|
|
||||||
};
|
|
||||||
@ -1,63 +0,0 @@
|
|||||||
import {
|
|
||||||
constructClaim,
|
|
||||||
constructClaimKey,
|
|
||||||
constructRangeRead,
|
|
||||||
constructStore,
|
|
||||||
ContractIssuer,
|
|
||||||
GRead,
|
|
||||||
} from '@coinweb/contract-kit';
|
|
||||||
import { CwebRead } from '@coinweb/contract-kit/dist/esm/operations/read';
|
|
||||||
import { toHex } from 'lib/shared';
|
|
||||||
|
|
||||||
import { rangeReadLimit } from '../settings';
|
|
||||||
import { LockedKey, MutexLockState } from '../types';
|
|
||||||
|
|
||||||
export const mutexLockKey = 'mutex_lock';
|
|
||||||
|
|
||||||
export const constructMutexLockFirstPart = () => [mutexLockKey];
|
|
||||||
|
|
||||||
export const constructMutexLockClaimKey = (lockId: string, timestamp: number) =>
|
|
||||||
constructClaimKey(constructMutexLockFirstPart(), [timestamp, lockId]);
|
|
||||||
|
|
||||||
export const constructMutexLockClaim = ({
|
|
||||||
fee,
|
|
||||||
keys,
|
|
||||||
locked,
|
|
||||||
lockId,
|
|
||||||
timestamp,
|
|
||||||
processId,
|
|
||||||
}: {
|
|
||||||
lockId: string;
|
|
||||||
timestamp: number;
|
|
||||||
locked: boolean;
|
|
||||||
keys: LockedKey[];
|
|
||||||
fee: bigint;
|
|
||||||
processId: string;
|
|
||||||
}) =>
|
|
||||||
constructClaim(
|
|
||||||
constructMutexLockClaimKey(lockId, timestamp),
|
|
||||||
{ locked, keys, processId } satisfies MutexLockState,
|
|
||||||
toHex(fee)
|
|
||||||
);
|
|
||||||
|
|
||||||
export const constructMutexLockClaimStore = ({
|
|
||||||
fee,
|
|
||||||
keys,
|
|
||||||
locked,
|
|
||||||
lockId,
|
|
||||||
timestamp,
|
|
||||||
processId,
|
|
||||||
}: {
|
|
||||||
fee: bigint;
|
|
||||||
keys: LockedKey[];
|
|
||||||
locked: boolean;
|
|
||||||
lockId: string;
|
|
||||||
timestamp: number;
|
|
||||||
processId: string;
|
|
||||||
}) => constructStore(constructMutexLockClaim({ fee, keys, locked, lockId, timestamp, processId }));
|
|
||||||
|
|
||||||
export const constructMutexLockClaimRangeRead = (issuer: ContractIssuer): GRead<CwebRead> =>
|
|
||||||
constructRangeRead(issuer, constructMutexLockFirstPart(), {}, rangeReadLimit);
|
|
||||||
|
|
||||||
// export const constructMutexLockClaimTake = (lockId: string, timestamp: number) =>
|
|
||||||
// constructTake(constructMutexLockClaimKey(lockId, timestamp));
|
|
||||||
@ -1,20 +0,0 @@
|
|||||||
import {
|
|
||||||
execLockMethodName,
|
|
||||||
getAccessMethodName,
|
|
||||||
lockMethodName,
|
|
||||||
mutexExecLock,
|
|
||||||
mutexGetAccess,
|
|
||||||
mutexLock,
|
|
||||||
mutexUnlock,
|
|
||||||
unlockMethodName,
|
|
||||||
} from './methods';
|
|
||||||
|
|
||||||
export * from './claims';
|
|
||||||
export * from './types';
|
|
||||||
|
|
||||||
export const mutexMethods = {
|
|
||||||
[execLockMethodName]: mutexExecLock,
|
|
||||||
[getAccessMethodName]: mutexGetAccess,
|
|
||||||
[lockMethodName]: mutexLock,
|
|
||||||
[unlockMethodName]: mutexUnlock,
|
|
||||||
};
|
|
||||||
@ -1,89 +0,0 @@
|
|||||||
import {
|
|
||||||
constructClaim,
|
|
||||||
constructContinueTx,
|
|
||||||
constructContractRef,
|
|
||||||
constructStore,
|
|
||||||
constructTake,
|
|
||||||
Context,
|
|
||||||
extractContractArgs,
|
|
||||||
extractRead,
|
|
||||||
passCwebFrom,
|
|
||||||
} from '@coinweb/contract-kit';
|
|
||||||
import { getCallParameters, getContractIssuer } from 'lib/onchain';
|
|
||||||
import { toHex, TypedClaim } from 'lib/shared';
|
|
||||||
|
|
||||||
import { lockFee } from '../settings';
|
|
||||||
import { MutexLockState } from '../types';
|
|
||||||
import { isMatchLockKeys } from '../utils';
|
|
||||||
|
|
||||||
import { lockMethodName, notifyLockMethodName } from './names';
|
|
||||||
|
|
||||||
export const mutexExecLock = (context: Context) => {
|
|
||||||
const { availableCweb } = getCallParameters(context);
|
|
||||||
const issuer = getContractIssuer(context);
|
|
||||||
|
|
||||||
const lockQueue = extractRead(extractContractArgs(context.tx)[0])?.map(
|
|
||||||
({ content }) => content as TypedClaim<MutexLockState>
|
|
||||||
);
|
|
||||||
|
|
||||||
if (!lockQueue) {
|
|
||||||
throw new Error('No lock queue found');
|
|
||||||
}
|
|
||||||
|
|
||||||
const alreadyLockedKeys = lockQueue.filter(({ body }) => body.locked).map(({ key }) => key);
|
|
||||||
|
|
||||||
const lockCandidate = lockQueue.find(
|
|
||||||
({ body, key }) => !body.locked && !alreadyLockedKeys.some((lockedKey) => isMatchLockKeys(lockedKey, key))
|
|
||||||
);
|
|
||||||
|
|
||||||
if (!lockCandidate) {
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
|
|
||||||
return [
|
|
||||||
constructContinueTx(
|
|
||||||
context,
|
|
||||||
[
|
|
||||||
passCwebFrom(issuer, availableCweb),
|
|
||||||
constructTake(lockCandidate.key),
|
|
||||||
constructStore(
|
|
||||||
constructClaim(
|
|
||||||
lockCandidate.key,
|
|
||||||
{ ...lockCandidate.body, locked: true },
|
|
||||||
toHex(BigInt(lockCandidate.fees_stored) - lockFee)
|
|
||||||
)
|
|
||||||
),
|
|
||||||
],
|
|
||||||
[
|
|
||||||
{
|
|
||||||
callInfo: {
|
|
||||||
ref: constructContractRef(issuer, []),
|
|
||||||
methodInfo: {
|
|
||||||
methodName: lockMethodName,
|
|
||||||
methodArgs: [],
|
|
||||||
},
|
|
||||||
contractInfo: {
|
|
||||||
providedCweb: lockFee,
|
|
||||||
authenticated: null,
|
|
||||||
},
|
|
||||||
contractArgs: [],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
callInfo: {
|
|
||||||
ref: constructContractRef(issuer, []),
|
|
||||||
methodInfo: {
|
|
||||||
methodName: notifyLockMethodName,
|
|
||||||
methodArgs: [(lockCandidate.key.second_part as [number, string])[1]],
|
|
||||||
},
|
|
||||||
contractInfo: {
|
|
||||||
providedCweb: 200n,
|
|
||||||
authenticated: null,
|
|
||||||
},
|
|
||||||
contractArgs: [],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
]
|
|
||||||
),
|
|
||||||
];
|
|
||||||
};
|
|
||||||
@ -1,32 +0,0 @@
|
|||||||
import { constructContinueTx, Context, extractContractArgs, extractRead } from '@coinweb/contract-kit';
|
|
||||||
import { getContractArguments } from 'lib/onchain';
|
|
||||||
import { TypedClaim } from 'lib/shared';
|
|
||||||
|
|
||||||
import { constructMutexBlockAccessClaimStore } from '../claims';
|
|
||||||
import { MutexAccessStatus, MutexGetAccessArgs, MutexLockState } from '../types';
|
|
||||||
import { isMatchLockKeys } from '../utils';
|
|
||||||
|
|
||||||
export const mutexGetAccess = (context: Context) => {
|
|
||||||
const [claimKey, processId, uniqueId] = getContractArguments<MutexGetAccessArgs>(context);
|
|
||||||
|
|
||||||
const lockQueue = extractRead(extractContractArgs(context.tx)[0])?.map(
|
|
||||||
({ content }) => content as TypedClaim<MutexLockState>
|
|
||||||
);
|
|
||||||
|
|
||||||
if (!lockQueue) {
|
|
||||||
throw new Error('No lock queue found');
|
|
||||||
}
|
|
||||||
|
|
||||||
const isLockedByOtherProcess = lockQueue.some(
|
|
||||||
({ body }) => body.locked && body.processId !== processId && body.keys.some((key) => isMatchLockKeys(key, claimKey))
|
|
||||||
);
|
|
||||||
|
|
||||||
return [
|
|
||||||
constructContinueTx(context, [
|
|
||||||
constructMutexBlockAccessClaimStore(
|
|
||||||
uniqueId,
|
|
||||||
isLockedByOtherProcess ? MutexAccessStatus.DENIED : MutexAccessStatus.GRANTED
|
|
||||||
),
|
|
||||||
]),
|
|
||||||
];
|
|
||||||
};
|
|
||||||
@ -1,7 +0,0 @@
|
|||||||
export * from './execLock';
|
|
||||||
export * from './getAccess';
|
|
||||||
export * from './lock';
|
|
||||||
export * from './names';
|
|
||||||
export * from './notifyLock';
|
|
||||||
export * from './tryOp';
|
|
||||||
export * from './unlock';
|
|
||||||
@ -1,34 +0,0 @@
|
|||||||
import { constructContinueTx, constructContractRef, Context } from '@coinweb/contract-kit';
|
|
||||||
import { getCallParameters, getContractIssuer } from 'lib/onchain';
|
|
||||||
|
|
||||||
import { constructMutexLockClaimRangeRead } from '../claims';
|
|
||||||
|
|
||||||
import { execLockMethodName } from './names';
|
|
||||||
|
|
||||||
export const mutexLock = (context: Context) => {
|
|
||||||
const { availableCweb } = getCallParameters(context);
|
|
||||||
const issuer = getContractIssuer(context);
|
|
||||||
|
|
||||||
return [
|
|
||||||
constructContinueTx(
|
|
||||||
context,
|
|
||||||
[],
|
|
||||||
[
|
|
||||||
{
|
|
||||||
callInfo: {
|
|
||||||
ref: constructContractRef(issuer, []),
|
|
||||||
methodInfo: {
|
|
||||||
methodName: execLockMethodName,
|
|
||||||
methodArgs: [],
|
|
||||||
},
|
|
||||||
contractInfo: {
|
|
||||||
providedCweb: availableCweb - 700n,
|
|
||||||
authenticated: null,
|
|
||||||
},
|
|
||||||
contractArgs: [constructMutexLockClaimRangeRead(issuer)],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
]
|
|
||||||
),
|
|
||||||
];
|
|
||||||
};
|
|
||||||
@ -1,6 +0,0 @@
|
|||||||
export const lockMethodName = '_mutex_lock';
|
|
||||||
export const execLockMethodName = '_mutex_execLock';
|
|
||||||
export const getAccessMethodName = '_mutex_get_access';
|
|
||||||
export const unlockMethodName = '_mutex_unlock';
|
|
||||||
export const tryOpMethodName = '_mutex_try_op';
|
|
||||||
export const notifyLockMethodName = '_mutex_notify_lock';
|
|
||||||
@ -1,11 +0,0 @@
|
|||||||
import { constructContinueTx, Context } from '@coinweb/contract-kit';
|
|
||||||
import { getContractArguments } from 'lib/onchain';
|
|
||||||
|
|
||||||
import { constructMutexBlockLockClaimStore } from '../claims/mutexBlockLock';
|
|
||||||
import { MutexNotifyLockArgs } from '../types';
|
|
||||||
|
|
||||||
export const notifyLock = (context: Context) => {
|
|
||||||
const [lockId] = getContractArguments<MutexNotifyLockArgs>(context);
|
|
||||||
|
|
||||||
return [constructContinueTx(context, [constructMutexBlockLockClaimStore({ lockId })])];
|
|
||||||
};
|
|
||||||
@ -1,30 +0,0 @@
|
|||||||
import { constructContinueTx, Context, extractContractArgs, extractRead } from '@coinweb/contract-kit';
|
|
||||||
import { getContractArguments } from 'lib/onchain';
|
|
||||||
import { TypedClaim } from 'lib/shared';
|
|
||||||
|
|
||||||
import { MutexLockState, MutexTryOpArgs } from '../types';
|
|
||||||
import { isMatchLockKeys } from '../utils';
|
|
||||||
|
|
||||||
export const tryOp = (context: Context) => {
|
|
||||||
const [op, processId] = getContractArguments<MutexTryOpArgs>(context);
|
|
||||||
|
|
||||||
const claimKey = 'StoreOp' in op ? op.StoreOp.key : op.TakeOp.key;
|
|
||||||
|
|
||||||
const lockQueue = extractRead(extractContractArgs(context.tx)[0])?.map(
|
|
||||||
({ content }) => content as TypedClaim<MutexLockState>
|
|
||||||
);
|
|
||||||
|
|
||||||
if (!lockQueue) {
|
|
||||||
throw new Error('No lock queue found');
|
|
||||||
}
|
|
||||||
|
|
||||||
const isLockedByOtherProcess = lockQueue.some(
|
|
||||||
({ body }) => body.locked && body.processId !== processId && body.keys.some((key) => isMatchLockKeys(key, claimKey))
|
|
||||||
);
|
|
||||||
|
|
||||||
if (isLockedByOtherProcess) {
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
|
|
||||||
return [constructContinueTx(context, [op])];
|
|
||||||
};
|
|
||||||
@ -1,38 +0,0 @@
|
|||||||
import { constructContinueTx, constructContractRef, constructTake, Context, passCwebFrom } from '@coinweb/contract-kit';
|
|
||||||
import { getCallParameters, getContractArguments, getContractIssuer } from 'lib/onchain';
|
|
||||||
|
|
||||||
import { constructMutexLockClaimKey } from '../claims';
|
|
||||||
import { lockFee } from '../settings';
|
|
||||||
import { MutexUnlockArgs } from '../types';
|
|
||||||
|
|
||||||
import { lockMethodName } from './names';
|
|
||||||
|
|
||||||
export const mutexUnlock = (context: Context) => {
|
|
||||||
const { availableCweb } = getCallParameters(context);
|
|
||||||
const issuer = getContractIssuer(context);
|
|
||||||
|
|
||||||
const [lockId, timestamp] = getContractArguments<MutexUnlockArgs>(context);
|
|
||||||
|
|
||||||
return [
|
|
||||||
constructContinueTx(
|
|
||||||
context,
|
|
||||||
[passCwebFrom(issuer, availableCweb), constructTake(constructMutexLockClaimKey(lockId, timestamp))],
|
|
||||||
[
|
|
||||||
{
|
|
||||||
callInfo: {
|
|
||||||
ref: constructContractRef(issuer, []),
|
|
||||||
methodInfo: {
|
|
||||||
methodName: lockMethodName,
|
|
||||||
methodArgs: [],
|
|
||||||
},
|
|
||||||
contractInfo: {
|
|
||||||
providedCweb: lockFee,
|
|
||||||
authenticated: null,
|
|
||||||
},
|
|
||||||
contractArgs: [],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
]
|
|
||||||
),
|
|
||||||
];
|
|
||||||
};
|
|
||||||
@ -1,4 +0,0 @@
|
|||||||
export const lockFee = 5000n;
|
|
||||||
export const unlockFee = 1000n + lockFee;
|
|
||||||
|
|
||||||
export const rangeReadLimit = 10000;
|
|
||||||
@ -1,26 +0,0 @@
|
|||||||
import { Claim, ClaimKey, GStore, GTake } from '@coinweb/contract-kit';
|
|
||||||
|
|
||||||
export type LockedKey = Omit<ClaimKey, 'second_part'> & Partial<Pick<ClaimKey, 'second_part'>>;
|
|
||||||
|
|
||||||
export type MutexLockState = {
|
|
||||||
locked: boolean;
|
|
||||||
keys: LockedKey[];
|
|
||||||
processId: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
export enum MutexAccessStatus {
|
|
||||||
GRANTED = 'granted',
|
|
||||||
DENIED = 'denied',
|
|
||||||
}
|
|
||||||
|
|
||||||
export type MutexAccessResult = {
|
|
||||||
status: MutexAccessStatus;
|
|
||||||
};
|
|
||||||
|
|
||||||
export type MutexGetAccessArgs = [claimKey: ClaimKey, processId: string, uniqueId: string];
|
|
||||||
|
|
||||||
export type MutexUnlockArgs = [lockId: string, timestamp: number, notify?: boolean];
|
|
||||||
|
|
||||||
export type MutexTryOpArgs = [op: GTake<Claim> | GStore<Claim>, processId: string];
|
|
||||||
|
|
||||||
export type MutexNotifyLockArgs = [lockId: string];
|
|
||||||
@ -1 +0,0 @@
|
|||||||
export * from './isMatchLockKeys';
|
|
||||||
@ -1,9 +0,0 @@
|
|||||||
import { LockedKey } from '../types';
|
|
||||||
|
|
||||||
export const isMatchLockKeys = (lockKey1: LockedKey, lockKey2: LockedKey) => {
|
|
||||||
if (!lockKey1.second_part || !lockKey2.second_part) {
|
|
||||||
return lockKey1.first_part === lockKey2.first_part;
|
|
||||||
}
|
|
||||||
|
|
||||||
return lockKey1.first_part === lockKey2.first_part && lockKey1.second_part === lockKey2.second_part;
|
|
||||||
};
|
|
||||||
@ -27,7 +27,7 @@ export const blockOp = (filters: BlockFilter[]) => {
|
|||||||
throw new Error('Block operation not found');
|
throw new Error('Block operation not found');
|
||||||
}
|
}
|
||||||
|
|
||||||
const result = extractBlock(op);
|
const result = op && extractBlock(op);
|
||||||
|
|
||||||
resolve(result);
|
resolve(result);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,42 +0,0 @@
|
|||||||
import { ResolvedLockOp } from '../../../types';
|
|
||||||
import { opMarker } from '../../global';
|
|
||||||
import { LockedKey } from '../../mutex';
|
|
||||||
import { isResolvedLockOp, isResolvedSlotOp, uuid } from '../../utils';
|
|
||||||
import { pushAwaitedTask } from '../awaited';
|
|
||||||
import { shiftResolvedOp } from '../resolved';
|
|
||||||
|
|
||||||
export const lockOp = (keys: LockedKey[] | LockedKey) => {
|
|
||||||
console.log('lockOp');
|
|
||||||
let opMarkerValue = false;
|
|
||||||
|
|
||||||
const result = new Promise<ResolvedLockOp['LockOp']>((resolve, reject) => {
|
|
||||||
try {
|
|
||||||
const { op, isOp } = shiftResolvedOp();
|
|
||||||
|
|
||||||
if (!isOp) {
|
|
||||||
pushAwaitedTask({ LockOp: { lockId: uuid(), keys: Array.isArray(keys) ? keys : [keys] } });
|
|
||||||
opMarkerValue = true;
|
|
||||||
} else {
|
|
||||||
if (isResolvedSlotOp(op)) {
|
|
||||||
console.log('storeOp-slotOp');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!isResolvedLockOp(op)) {
|
|
||||||
console.log('lockOp-error');
|
|
||||||
throw new Error('Lock operation not found');
|
|
||||||
}
|
|
||||||
|
|
||||||
const result = op.LockOp;
|
|
||||||
|
|
||||||
resolve(result);
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
reject(error);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
(result as Promise<ResolvedLockOp['LockOp']> & { [opMarker]: boolean })[opMarker] = opMarkerValue;
|
|
||||||
|
|
||||||
return result;
|
|
||||||
};
|
|
||||||
@ -34,7 +34,7 @@ export const rangeReadOp = <TClaims extends Claim[] = TypedClaim[]>(
|
|||||||
throw new Error('Read operation not found');
|
throw new Error('Read operation not found');
|
||||||
}
|
}
|
||||||
|
|
||||||
const claim = (extractRead(op)?.map((result) => result.content) ?? null) as TClaims | null;
|
const claim = op && ((extractRead(op)?.map((result) => result.content) ?? null) as TClaims | null);
|
||||||
resolve(claim);
|
resolve(claim);
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|||||||
@ -29,7 +29,7 @@ export const readOp = <TClaim extends Claim = TypedClaim>(key: ClaimKey) => {
|
|||||||
throw new Error('Read operation not found');
|
throw new Error('Read operation not found');
|
||||||
}
|
}
|
||||||
|
|
||||||
const claim = (extractRead(op)?.[0]?.content ?? null) as TClaim | null;
|
const claim = op && ((extractRead(op)?.[0]?.content ?? null) as TClaim | null);
|
||||||
resolve(claim);
|
resolve(claim);
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|||||||
@ -28,7 +28,7 @@ export const storeOp = (claim: Claim) => {
|
|||||||
throw new Error('Store operation not found');
|
throw new Error('Store operation not found');
|
||||||
}
|
}
|
||||||
|
|
||||||
const result = extractStore(op);
|
const result = op && extractStore(op);
|
||||||
|
|
||||||
resolve(result);
|
resolve(result);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -28,7 +28,7 @@ export const takeOp = <TClaim extends Claim = TypedClaim>(key: ClaimKey) => {
|
|||||||
throw new Error('Take operation not found');
|
throw new Error('Take operation not found');
|
||||||
}
|
}
|
||||||
|
|
||||||
const claim = extractTake(op);
|
const claim = op && extractTake(op);
|
||||||
resolve(claim as TClaim | null);
|
resolve(claim as TClaim | null);
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|||||||
@ -1,38 +0,0 @@
|
|||||||
import { opMarker } from '../../global';
|
|
||||||
import { isResolvedSlotOp, isResolvedUnlockOp } from '../../utils';
|
|
||||||
import { pushAwaitedTask } from '../awaited';
|
|
||||||
import { shiftResolvedOp } from '../resolved';
|
|
||||||
|
|
||||||
export const unlock = (lockId: string) => {
|
|
||||||
console.log('lockOp');
|
|
||||||
let opMarkerValue = false;
|
|
||||||
|
|
||||||
const result = new Promise<void>((resolve, reject) => {
|
|
||||||
try {
|
|
||||||
const { op, isOp } = shiftResolvedOp();
|
|
||||||
|
|
||||||
if (!isOp) {
|
|
||||||
pushAwaitedTask({ UnlockOp: { lockId } });
|
|
||||||
opMarkerValue = true;
|
|
||||||
} else {
|
|
||||||
if (isResolvedSlotOp(op)) {
|
|
||||||
console.log('unlockOp-slotOp');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!isResolvedUnlockOp(op)) {
|
|
||||||
console.log('unlockOp-error');
|
|
||||||
throw new Error('Unlock operation not found');
|
|
||||||
}
|
|
||||||
|
|
||||||
resolve();
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
reject(error);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
(result as Promise<void> & { [opMarker]: boolean })[opMarker] = opMarkerValue;
|
|
||||||
|
|
||||||
return result;
|
|
||||||
};
|
|
||||||
2
packages/cwait/src/onchain/promisifiedTxs/index.ts
Normal file
2
packages/cwait/src/onchain/promisifiedTxs/index.ts
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
export * from './jumpTx';
|
||||||
|
export * from './tx';
|
||||||
1
packages/cwait/src/onchain/promisifiedTxs/jumpTx.ts
Normal file
1
packages/cwait/src/onchain/promisifiedTxs/jumpTx.ts
Normal file
@ -0,0 +1 @@
|
|||||||
|
export const jumpTx = () => null;
|
||||||
1
packages/cwait/src/onchain/promisifiedTxs/tx.ts
Normal file
1
packages/cwait/src/onchain/promisifiedTxs/tx.ts
Normal file
@ -0,0 +1 @@
|
|||||||
|
export const tx = () => null;
|
||||||
@ -13,16 +13,7 @@ import { CwebCallRefResolved, isResolvedCall } from '@coinweb/contract-kit/dist/
|
|||||||
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 {
|
import { PreparedExecOp, PreparedOp, ResolvedChildOp, ResolvedExecOp, ResolvedOp, ResolvedSlotOp } from '../../types';
|
||||||
PreparedExecOp,
|
|
||||||
PreparedOp,
|
|
||||||
ResolvedChildOp,
|
|
||||||
ResolvedExecOp,
|
|
||||||
ResolvedLockOp,
|
|
||||||
ResolvedOp,
|
|
||||||
ResolvedSlotOp,
|
|
||||||
ResolvedUnlockOp,
|
|
||||||
} from '../../types';
|
|
||||||
|
|
||||||
export const isResolvedSlotOp = (op?: ResolvedOp | null): op is ResolvedSlotOp => {
|
export const isResolvedSlotOp = (op?: ResolvedOp | null): op is ResolvedSlotOp => {
|
||||||
if (op && 'SlotOp' in op) {
|
if (op && 'SlotOp' in op) {
|
||||||
@ -48,22 +39,6 @@ export const isResolvedChildOp = (op?: ResolvedOp | null): op is ResolvedChildOp
|
|||||||
return !!(op && 'ChildOp' in op);
|
return !!(op && 'ChildOp' in op);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const isResolvedLockOp = (op?: ResolvedOp | null): op is ResolvedLockOp => {
|
|
||||||
if (op && 'LockOp' in op) {
|
|
||||||
console.log('isResolvedLockOp >>> ', JSON.stringify(op));
|
|
||||||
}
|
|
||||||
|
|
||||||
return !!(op && 'LockOp' in op);
|
|
||||||
};
|
|
||||||
|
|
||||||
export const isResolvedUnlockOp = (op?: ResolvedOp | null): op is ResolvedUnlockOp => {
|
|
||||||
if (op && 'UnlockOp' in op) {
|
|
||||||
console.log('isResolvedUnlockOp >>> ', JSON.stringify(op));
|
|
||||||
}
|
|
||||||
|
|
||||||
return !!(op && 'UnlockOp' in op);
|
|
||||||
};
|
|
||||||
|
|
||||||
export const isResolvedBlockOp = (op?: ResolvedOp | null): op is GBlock<ResolvedBlock> => {
|
export const isResolvedBlockOp = (op?: ResolvedOp | null): op is GBlock<ResolvedBlock> => {
|
||||||
if (op && 'BlockOp' in op) {
|
if (op && 'BlockOp' in op) {
|
||||||
console.log('isResolvedBlockOp >>> ', JSON.stringify(op));
|
console.log('isResolvedBlockOp >>> ', JSON.stringify(op));
|
||||||
|
|||||||
@ -1,7 +1,5 @@
|
|||||||
import { Claim, ClaimKey, OrdJson, PreparedOperation, ResolvedOperation, User } from '@coinweb/contract-kit';
|
import { Claim, ClaimKey, OrdJson, PreparedOperation, ResolvedOperation, User } from '@coinweb/contract-kit';
|
||||||
|
|
||||||
import { LockedKey } from './onchain/mutex';
|
|
||||||
|
|
||||||
export type HexBigInt = `0x${string}`;
|
export type HexBigInt = `0x${string}`;
|
||||||
|
|
||||||
export type TypedClaim<TBody extends OrdJson = OrdJson, TKey extends ClaimKey = ClaimKey> = Claim & {
|
export type TypedClaim<TBody extends OrdJson = OrdJson, TKey extends ClaimKey = ClaimKey> = Claim & {
|
||||||
@ -24,23 +22,7 @@ export type ResolvedChildOp = {
|
|||||||
ChildOp: 0;
|
ChildOp: 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type ResolvedLockOp = {
|
export type ResolvedOp = ResolvedOperation | ResolvedSlotOp | ResolvedExecOp | ResolvedChildOp;
|
||||||
LockOp: {
|
|
||||||
lockId: string;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
export type ResolvedUnlockOp = {
|
|
||||||
UnlockOp: 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
export type ResolvedOp =
|
|
||||||
| ResolvedOperation
|
|
||||||
| ResolvedSlotOp
|
|
||||||
| ResolvedExecOp
|
|
||||||
| ResolvedChildOp
|
|
||||||
| ResolvedLockOp
|
|
||||||
| ResolvedUnlockOp;
|
|
||||||
|
|
||||||
export type PreparedExecOp = {
|
export type PreparedExecOp = {
|
||||||
ExecOp: {
|
ExecOp: {
|
||||||
@ -48,20 +30,7 @@ export type PreparedExecOp = {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
export type PreparedLockOp = {
|
export type PreparedOp = PreparedOperation | PreparedExecOp;
|
||||||
LockOp: {
|
|
||||||
lockId: string;
|
|
||||||
keys: LockedKey[];
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
export type PreparedUnlockOp = {
|
|
||||||
UnlockOp: {
|
|
||||||
lockId: string;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
export type PreparedOp = PreparedOperation | PreparedExecOp | PreparedLockOp | PreparedUnlockOp;
|
|
||||||
|
|
||||||
export type Task = {
|
export type Task = {
|
||||||
op: PreparedOp;
|
op: PreparedOp;
|
||||||
|
|||||||
@ -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="0xbf9ca1687e3441bed1afd495405778a9c06c2f5173829d47d9b87dfb150063d8"
|
VITE_CONTRACT_ADDRESS="0x8c89cb42634cfe892290845d907af8ec2d482cead42afaef3ccc3cea4446fce5"
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user