feat: add base mutex methods
This commit is contained in:
parent
cb4a2fb33d
commit
0d5850ec25
@ -5,12 +5,18 @@ import { addMethodHandler, ContractHandlers, executeHandler, executor } from 'cw
|
|||||||
import { PUBLIC_METHODS } from '../offchain/shared';
|
import { PUBLIC_METHODS } from '../offchain/shared';
|
||||||
|
|
||||||
import { addWord } from './addWord';
|
import { addWord } from './addWord';
|
||||||
|
import { mutexLock } from './mutex/lock';
|
||||||
|
import { mutexUnlock, mutexUnlockExec } from './mutex/unlock';
|
||||||
|
|
||||||
const createModule = (): ContractHandlers => {
|
const createModule = (): ContractHandlers => {
|
||||||
const module: ContractHandlers = { handlers: {} };
|
const module: ContractHandlers = { handlers: {} };
|
||||||
|
|
||||||
addMethodHandler(module, PUBLIC_METHODS.ADD_WORD, executor(addWord));
|
addMethodHandler(module, PUBLIC_METHODS.ADD_WORD, executor(addWord));
|
||||||
|
|
||||||
|
addMethodHandler(module, '_lock', mutexLock);
|
||||||
|
addMethodHandler(module, '_unlock', mutexUnlock);
|
||||||
|
addMethodHandler(module, '_unlock_exec', mutexUnlockExec);
|
||||||
|
|
||||||
addMethodHandler(module, SELF_REGISTER_HANDLER_NAME, selfRegisterHandler);
|
addMethodHandler(module, SELF_REGISTER_HANDLER_NAME, selfRegisterHandler);
|
||||||
|
|
||||||
return module;
|
return module;
|
||||||
|
|||||||
1
packages/contract.cm/src/onchain/mutex/access.ts
Normal file
1
packages/contract.cm/src/onchain/mutex/access.ts
Normal file
@ -0,0 +1 @@
|
|||||||
|
export const mutexAccess = () => {};
|
||||||
43
packages/contract.cm/src/onchain/mutex/lock.ts
Normal file
43
packages/contract.cm/src/onchain/mutex/lock.ts
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
import {
|
||||||
|
constructClaim,
|
||||||
|
constructClaimKey,
|
||||||
|
constructContinueTx,
|
||||||
|
constructContractIssuer,
|
||||||
|
constructContractRef,
|
||||||
|
constructStore,
|
||||||
|
Context,
|
||||||
|
extractContractInfo,
|
||||||
|
getContractId,
|
||||||
|
} from '@coinweb/contract-kit';
|
||||||
|
|
||||||
|
export const mutexLock = (context: Context) => {
|
||||||
|
const { providedCweb } = extractContractInfo(context.tx);
|
||||||
|
const issuer = constructContractIssuer(getContractId(context.tx));
|
||||||
|
|
||||||
|
return [
|
||||||
|
constructContinueTx(
|
||||||
|
context,
|
||||||
|
[
|
||||||
|
constructStore(
|
||||||
|
constructClaim(constructClaimKey('mutex', context.call.txid.slice(0, 8)), { word: 'CLASH' }, '0x0')
|
||||||
|
),
|
||||||
|
],
|
||||||
|
[
|
||||||
|
{
|
||||||
|
callInfo: {
|
||||||
|
ref: constructContractRef(issuer, []),
|
||||||
|
methodInfo: {
|
||||||
|
methodName: '_unlock',
|
||||||
|
methodArgs: [],
|
||||||
|
},
|
||||||
|
contractInfo: {
|
||||||
|
providedCweb: providedCweb ? providedCweb - 1000n : 1000n,
|
||||||
|
authenticated: null,
|
||||||
|
},
|
||||||
|
contractArgs: [],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
]
|
||||||
|
),
|
||||||
|
];
|
||||||
|
};
|
||||||
59
packages/contract.cm/src/onchain/mutex/unlock.ts
Normal file
59
packages/contract.cm/src/onchain/mutex/unlock.ts
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
import {
|
||||||
|
constructContinueTx,
|
||||||
|
constructContractIssuer,
|
||||||
|
constructContractRef,
|
||||||
|
constructRangeRead,
|
||||||
|
constructTake,
|
||||||
|
Context,
|
||||||
|
extractContractArgs,
|
||||||
|
extractContractInfo,
|
||||||
|
extractRead,
|
||||||
|
getContractId,
|
||||||
|
} from '@coinweb/contract-kit';
|
||||||
|
|
||||||
|
export const mutexUnlock = (context: Context) => {
|
||||||
|
const { providedCweb } = extractContractInfo(context.tx);
|
||||||
|
const issuer = constructContractIssuer(getContractId(context.tx));
|
||||||
|
return [
|
||||||
|
constructContinueTx(
|
||||||
|
context,
|
||||||
|
[],
|
||||||
|
[
|
||||||
|
{
|
||||||
|
callInfo: {
|
||||||
|
ref: constructContractRef(issuer, []),
|
||||||
|
methodInfo: {
|
||||||
|
methodName: '_unlock_exec',
|
||||||
|
methodArgs: [],
|
||||||
|
},
|
||||||
|
contractInfo: {
|
||||||
|
providedCweb: (providedCweb ? providedCweb - 1000n : 1000n) / 2n,
|
||||||
|
authenticated: null,
|
||||||
|
},
|
||||||
|
contractArgs: [constructRangeRead(issuer, 'mutex', {}, 10000)],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
callInfo: {
|
||||||
|
ref: constructContractRef(issuer, []),
|
||||||
|
methodInfo: {
|
||||||
|
methodName: '_unlock',
|
||||||
|
methodArgs: [],
|
||||||
|
},
|
||||||
|
contractInfo: {
|
||||||
|
providedCweb: (providedCweb ? providedCweb - 1000n : 1000n) / 2n,
|
||||||
|
authenticated: null,
|
||||||
|
},
|
||||||
|
contractArgs: [],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
]
|
||||||
|
),
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
|
export const mutexUnlockExec = (context: Context) => {
|
||||||
|
const claim = extractContractArgs(context.tx)[0]!;
|
||||||
|
const take = extractRead(claim)![0];
|
||||||
|
return [constructContinueTx(context, [constructTake(take.content.key)])];
|
||||||
|
};
|
||||||
26
packages/cwait/src/onchain/mutex/claims/access.ts
Normal file
26
packages/cwait/src/onchain/mutex/claims/access.ts
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
import {
|
||||||
|
constructClaim,
|
||||||
|
constructClaimKey,
|
||||||
|
constructStore,
|
||||||
|
constructTake,
|
||||||
|
CwebStore,
|
||||||
|
GStore,
|
||||||
|
} from '@coinweb/contract-kit';
|
||||||
|
|
||||||
|
import { MutexAccessResult, MutexAccessStatus } from '../types';
|
||||||
|
|
||||||
|
export const mutexAccessKey = 'mutex_access';
|
||||||
|
|
||||||
|
export const constructMutexAccessFirstPart = () => [mutexAccessKey];
|
||||||
|
|
||||||
|
export const constructMutexAccessClaimKey = (uniqueId: string) =>
|
||||||
|
constructClaimKey(constructMutexAccessFirstPart(), [uniqueId]);
|
||||||
|
|
||||||
|
export const constructMutexAccessClaim = (uniqueId: string, status: MutexAccessStatus) =>
|
||||||
|
constructClaim(constructMutexAccessClaimKey(uniqueId), { status } satisfies MutexAccessResult, '0x0');
|
||||||
|
|
||||||
|
export const constructMutexAccessClaimStore = (uniqueId: string, status: MutexAccessStatus): GStore<CwebStore> =>
|
||||||
|
constructStore(constructMutexAccessClaim(uniqueId, status));
|
||||||
|
|
||||||
|
export const constructMutexAccessClaimTake = (uniqueId: string) =>
|
||||||
|
constructTake(constructMutexAccessClaimKey(uniqueId));
|
||||||
2
packages/cwait/src/onchain/mutex/claims/index.ts
Normal file
2
packages/cwait/src/onchain/mutex/claims/index.ts
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
export * from './access';
|
||||||
|
export * from './lock';
|
||||||
70
packages/cwait/src/onchain/mutex/claims/lock.ts
Normal file
70
packages/cwait/src/onchain/mutex/claims/lock.ts
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
import {
|
||||||
|
constructClaim,
|
||||||
|
constructClaimKey,
|
||||||
|
constructContractIssuer,
|
||||||
|
constructRangeRead,
|
||||||
|
constructStore,
|
||||||
|
Context,
|
||||||
|
getContractId,
|
||||||
|
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 = (context: Context): GRead<CwebRead> =>
|
||||||
|
constructRangeRead(
|
||||||
|
constructContractIssuer(getContractId(context.tx)),
|
||||||
|
constructMutexLockFirstPart(),
|
||||||
|
{},
|
||||||
|
rangeReadLimit
|
||||||
|
);
|
||||||
|
|
||||||
|
// export const constructMutexLockClaimTake = (lockId: string, timestamp: number) =>
|
||||||
|
// constructTake(constructMutexLockClaimKey(lockId, timestamp));
|
||||||
20
packages/cwait/src/onchain/mutex/index.ts
Normal file
20
packages/cwait/src/onchain/mutex/index.ts
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
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,
|
||||||
|
};
|
||||||
75
packages/cwait/src/onchain/mutex/methods/execLock.ts
Normal file
75
packages/cwait/src/onchain/mutex/methods/execLock.ts
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
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 } 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: [],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
]
|
||||||
|
),
|
||||||
|
];
|
||||||
|
};
|
||||||
32
packages/cwait/src/onchain/mutex/methods/getAccess.ts
Normal file
32
packages/cwait/src/onchain/mutex/methods/getAccess.ts
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
import { constructContinueTx, Context, extractContractArgs, extractRead } from '@coinweb/contract-kit';
|
||||||
|
import { getContractArguments } from 'lib/onchain';
|
||||||
|
import { TypedClaim } from 'lib/shared';
|
||||||
|
|
||||||
|
import { constructMutexAccessClaimStore } 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, [
|
||||||
|
constructMutexAccessClaimStore(
|
||||||
|
uniqueId,
|
||||||
|
isLockedByOtherProcess ? MutexAccessStatus.DENIED : MutexAccessStatus.GRANTED
|
||||||
|
),
|
||||||
|
]),
|
||||||
|
];
|
||||||
|
};
|
||||||
5
packages/cwait/src/onchain/mutex/methods/index.ts
Normal file
5
packages/cwait/src/onchain/mutex/methods/index.ts
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
export * from './execLock';
|
||||||
|
export * from './getAccess';
|
||||||
|
export * from './lock';
|
||||||
|
export * from './names';
|
||||||
|
export * from './unlock';
|
||||||
34
packages/cwait/src/onchain/mutex/methods/lock.ts
Normal file
34
packages/cwait/src/onchain/mutex/methods/lock.ts
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
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(context)],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
]
|
||||||
|
),
|
||||||
|
];
|
||||||
|
};
|
||||||
4
packages/cwait/src/onchain/mutex/methods/names.ts
Normal file
4
packages/cwait/src/onchain/mutex/methods/names.ts
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
export const lockMethodName = '_mutex_lock';
|
||||||
|
export const execLockMethodName = '_mutex_execLock';
|
||||||
|
export const getAccessMethodName = '_mutex_get_access';
|
||||||
|
export const unlockMethodName = '_mutex_unlock';
|
||||||
38
packages/cwait/src/onchain/mutex/methods/unlock.ts
Normal file
38
packages/cwait/src/onchain/mutex/methods/unlock.ts
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
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: [],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
]
|
||||||
|
),
|
||||||
|
];
|
||||||
|
};
|
||||||
4
packages/cwait/src/onchain/mutex/settings.ts
Normal file
4
packages/cwait/src/onchain/mutex/settings.ts
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
export const lockFee = 5000n;
|
||||||
|
export const unlockFee = 1000n + lockFee;
|
||||||
|
|
||||||
|
export const rangeReadLimit = 10000;
|
||||||
22
packages/cwait/src/onchain/mutex/types.ts
Normal file
22
packages/cwait/src/onchain/mutex/types.ts
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
import { ClaimKey } 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];
|
||||||
1
packages/cwait/src/onchain/mutex/utils/index.ts
Normal file
1
packages/cwait/src/onchain/mutex/utils/index.ts
Normal file
@ -0,0 +1 @@
|
|||||||
|
export * from './isMatchLockKeys';
|
||||||
@ -0,0 +1,9 @@
|
|||||||
|
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;
|
||||||
|
};
|
||||||
@ -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="0x8c89cb42634cfe892290845d907af8ec2d482cead42afaef3ccc3cea4446fce5"
|
VITE_CONTRACT_ADDRESS="0xbf9ca1687e3441bed1afd495405778a9c06c2f5173829d47d9b87dfb150063d8"
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user