diff --git a/.cweb-config/dapp-ecosystem-test.yaml b/.cweb-config/dapp-ecosystem-test.yaml index dd5f4a7..94176f9 100644 --- a/.cweb-config/dapp-ecosystem-test.yaml +++ b/.cweb-config/dapp-ecosystem-test.yaml @@ -19,8 +19,6 @@ use: - jump-forwarder.cm v0.1.5 - jump_forwarder_devnet v0.1.5 - - interpreters: {} contract_templates: @@ -33,4 +31,3 @@ contract_instances: template: contract.cm v0.0.1 parameters: content: [] - diff --git a/package.json b/package.json index 0a9303c..16149d2 100644 --- a/package.json +++ b/package.json @@ -10,7 +10,7 @@ "build:production": "yarn build:cm && yarn workspace dapp-ui build:production", "build:lib": "yarn workspaces foreach -Ap --include 'packages/lib' --include 'packages/cwait' run build", "build:cm": "yarn build:lib && yarn workspaces foreach -Ap --include 'packages/*.cm' run build", - "build:non-cm": "yarn workspaces foreach -Ap --include 'packages/*' --exclude 'packages/*.cm' --exclude 'packages/lib' --exclude 'packages/cwait' run build", + "build:non-cm": "yarn workspaces foreach -Ap --include 'packages/*' --exclude 'packages/*.cm' --exclude 'packages/*.ignore' --exclude 'packages/lib' --exclude 'packages/cwait' run build", "create-index": "cweb-tool create-index -c ./.cweb-config/config.yaml --profile $REGISTRATION_PROFILE", "publish-index": "cweb-tool publish-index -c ./.cweb-config/config.yaml --profile $REGISTRATION_PROFILE", "deploy-contracts": "yarn build:cm && yarn publish-actions", @@ -39,7 +39,7 @@ "g:lint": "cd $INIT_CWD && eslint", "g:vitest": "cd $INIT_CWD && vitest", "g:lint-staged": "cd $INIT_CWD && lint-staged", - "publish:lib": "yarn workspaces foreach -Ap --include 'packages/cwap-cm-*' run publish:lib" + "publish:lib": "yarn workspaces foreach -Ap --include 'packages/lib' run publish:lib" }, "resolutions": { "@coinweb/cweb-tool": "2.0.22", diff --git a/packages/contract.cm/.gitignore b/packages/btc-like-provider.cm.ignore/.gitignore similarity index 100% rename from packages/contract.cm/.gitignore rename to packages/btc-like-provider.cm.ignore/.gitignore diff --git a/packages/contract.cm/deploy/calls.yaml.template b/packages/btc-like-provider.cm.ignore/deploy/calls.yaml.template similarity index 100% rename from packages/contract.cm/deploy/calls.yaml.template rename to packages/btc-like-provider.cm.ignore/deploy/calls.yaml.template diff --git a/packages/btc-like-provider.cm.ignore/package.json b/packages/btc-like-provider.cm.ignore/package.json new file mode 100644 index 0000000..aa410ef --- /dev/null +++ b/packages/btc-like-provider.cm.ignore/package.json @@ -0,0 +1,37 @@ +{ + "name": "btc-like-provider.cm", + "version": "0.0.1-dev", + "type": "module", + "scripts": { + "build": "yarn build:files && yarn pack:all", + "build:files": "yarn clean && yarn g:tsc -p tsconfig.build.json && NODE_ENV=production ./scripts/build.sh", + "start": "node src/offchain/index.js", + "test": "yarn g:vitest run --pool=forks", + "test:prepare": "mkdir -p tests_data && cp ../../.cweb_tool/simulation/unknown.json tests_data/state.json && cp ../../.dapp-ecosystem-lock-test.yaml tests_data/index.yaml", + "test:watch": "yarn g:vitest", + "test:coverage": "yarn g:vitest run --coverage", + "pack:relink": "cd $INIT_CWD && node scripts/package-relink.js", + "pack:all": "yarn pack:cweb && yarn pack:relink && yarn pack:yarn && yarn pack:relink", + "pack:cweb": "yarn g:cweb-tool pack . dist/out ../../.cweb-config/cweb-pack.yaml -c ../../.cweb-config/config.yaml --profile $REGISTRATION_PROFILE", + "pack:yarn": "cd dist/out && touch yarn.lock && yarn pack -o my-contract-module.tgz", + "clean": "rm -rf cweb_dist dist .calls.yaml", + "typecheck": "yarn g:tsc --noEmit", + "dev": "yarn g:tsc -p tsconfig.dev.json --watch", + "lint": "yarn g:lint ." + }, + "dependencies": { + "@coinweb/contract-kit": "0.2.6", + "@coinweb/self-register": "0.1.3", + "@noble/hashes": "1.4.0", + "bech32": "2.0.0", + "bs58": "6.0.0", + "lib": "workspaces:*" + }, + "devDependencies": { + "esbuild": "^0.20.2" + }, + "main": "cweb_dist/offchain/index.js", + "engines": { + "cweb_interpreter": "a344c6003922f9e44385f6e8234a7d2567d9a676b14330ad3b42cbd1948a92bf" + } +} diff --git a/packages/contract.cm/scripts/build.sh b/packages/btc-like-provider.cm.ignore/scripts/build.sh similarity index 100% rename from packages/contract.cm/scripts/build.sh rename to packages/btc-like-provider.cm.ignore/scripts/build.sh diff --git a/packages/contract.cm/scripts/package-relink.js b/packages/btc-like-provider.cm.ignore/scripts/package-relink.js similarity index 100% rename from packages/contract.cm/scripts/package-relink.js rename to packages/btc-like-provider.cm.ignore/scripts/package-relink.js diff --git a/packages/contract.cm/src/offchain/api.ts b/packages/btc-like-provider.cm.ignore/src/offchain/api.ts similarity index 100% rename from packages/contract.cm/src/offchain/api.ts rename to packages/btc-like-provider.cm.ignore/src/offchain/api.ts diff --git a/packages/contract.cm/src/offchain/index.ts b/packages/btc-like-provider.cm.ignore/src/offchain/index.ts similarity index 66% rename from packages/contract.cm/src/offchain/index.ts rename to packages/btc-like-provider.cm.ignore/src/offchain/index.ts index 8a9677c..76de9d0 100644 --- a/packages/contract.cm/src/offchain/index.ts +++ b/packages/btc-like-provider.cm.ignore/src/offchain/index.ts @@ -1,3 +1,3 @@ export * from './api'; export * from './uiCommands'; -export * from './shared'; +export * from '../shared'; diff --git a/packages/contract.cm/src/offchain/uiCommands.ts b/packages/btc-like-provider.cm.ignore/src/offchain/uiCommands.ts similarity index 86% rename from packages/contract.cm/src/offchain/uiCommands.ts rename to packages/btc-like-provider.cm.ignore/src/offchain/uiCommands.ts index 68cc41c..819f85d 100644 --- a/packages/contract.cm/src/offchain/uiCommands.ts +++ b/packages/btc-like-provider.cm.ignore/src/offchain/uiCommands.ts @@ -1,6 +1,6 @@ import { constructCall, constructUiCommand } from 'lib/offchain'; -import { AddWordArgs, FEE, PUBLIC_METHODS } from './shared'; +import { AddWordArgs, FEE, PUBLIC_METHODS } from '../shared'; export const constructAddWordUiCommand = ({ word, contractId }: { word: string; contractId: string }) => { return constructUiCommand([ diff --git a/packages/contract.cm/src/onchain/__tests__/handlers.test.ts b/packages/btc-like-provider.cm.ignore/src/onchain/__tests__/handlers.test.ts similarity index 100% rename from packages/contract.cm/src/onchain/__tests__/handlers.test.ts rename to packages/btc-like-provider.cm.ignore/src/onchain/__tests__/handlers.test.ts diff --git a/packages/contract.cm/src/onchain/__tests__/helpers.ts b/packages/btc-like-provider.cm.ignore/src/onchain/__tests__/helpers.ts similarity index 100% rename from packages/contract.cm/src/onchain/__tests__/helpers.ts rename to packages/btc-like-provider.cm.ignore/src/onchain/__tests__/helpers.ts diff --git a/packages/contract.cm/src/onchain/addWord.ts b/packages/btc-like-provider.cm.ignore/src/onchain/addWord.ts similarity index 100% rename from packages/contract.cm/src/onchain/addWord.ts rename to packages/btc-like-provider.cm.ignore/src/onchain/addWord.ts diff --git a/packages/contract.cm/src/onchain/contract.ts b/packages/btc-like-provider.cm.ignore/src/onchain/contract.ts similarity index 76% rename from packages/contract.cm/src/onchain/contract.ts rename to packages/btc-like-provider.cm.ignore/src/onchain/contract.ts index 800500b..64a944d 100644 --- a/packages/contract.cm/src/onchain/contract.ts +++ b/packages/btc-like-provider.cm.ignore/src/onchain/contract.ts @@ -1,6 +1,6 @@ import { constructCwebMain } from 'cwait'; -import { PUBLIC_METHODS } from '../offchain/shared'; +import { PUBLIC_METHODS } from '../shared'; import { addWord } from './addWord'; diff --git a/packages/contract.cm/src/onchain/extraLogic.ts b/packages/btc-like-provider.cm.ignore/src/onchain/extraLogic.ts similarity index 100% rename from packages/contract.cm/src/onchain/extraLogic.ts rename to packages/btc-like-provider.cm.ignore/src/onchain/extraLogic.ts diff --git a/packages/contract.cm/src/onchain/extraLogic2.ts b/packages/btc-like-provider.cm.ignore/src/onchain/extraLogic2.ts similarity index 100% rename from packages/contract.cm/src/onchain/extraLogic2.ts rename to packages/btc-like-provider.cm.ignore/src/onchain/extraLogic2.ts diff --git a/packages/contract.cm/src/onchain/index.ts b/packages/btc-like-provider.cm.ignore/src/onchain/index.ts similarity index 100% rename from packages/contract.cm/src/onchain/index.ts rename to packages/btc-like-provider.cm.ignore/src/onchain/index.ts diff --git a/packages/btc-like-provider.cm.ignore/src/shared/constants/constants.ts b/packages/btc-like-provider.cm.ignore/src/shared/constants/constants.ts new file mode 100644 index 0000000..9c5d393 --- /dev/null +++ b/packages/btc-like-provider.cm.ignore/src/shared/constants/constants.ts @@ -0,0 +1,96 @@ +export enum Key { + ACTIVE_INDEX = 'ACTIVE_INDEX', + MAKER_INDEX = 'MAKER_INDEX', + DATE_INDEX = 'DATE_INDEX', + RATE_INDEX = 'RATE_INDEX', + + MAKER = 'MAKER', + + ORDER = 'ORDER', //ORDER_STATE + ORDER_FUNDS + LATEST_ORDER_ID = 'LATEST_ORDER_ID', //INCREMENT_INDEX + ORDER_DIRECTION_INDEX = 'ORDER_DIRECTION_INDEX', + + PACT = 'PACT', //ORDER_STATE + ORDER_COLLATERAL + LATEST_PACT_ID = 'LATEST_PACT_ID', //INCREMENT_INDEX + PACT_PENALTY_INDEX = 'PACT_PENALTY_INDEX', + + SWAP_INFO = 'SWAP_INFO', //L1_TX_INFO + PAYMENT_NONCE = 'PAYMENT_NONCE', //BTC_NONCE + UNIQUE_VALUE = 'UNIQUE_VALUE', + FEE_POOL_ADDRESS = 'FEE_POOL_ADDRESS', +} + +export enum PUBLIC_METHODS { + CREATE_ORDERS = 'CREATE_ORDERS', + CANCEL_ORDERS = 'CANCEL_ORDERS', + DEPOSIT_COLLATERAL = 'DEPOSIT_COLLATERAL', + WITHDRAW_COLLATERAL = 'WITHDRAW_COLLATERAL', +} + +export const FEE: Record<`${PUBLIC_METHODS}` | 'CHANGE_FEE_POOL_ADDRESS', bigint> = { + CREATE_ORDERS: 10000000n, + CANCEL_ORDERS: 10000000n, + DEPOSIT_COLLATERAL: 10000000n, + WITHDRAW_COLLATERAL: 10000000n, + CHANGE_FEE_POOL_ADDRESS: 10000000n, +}; + +export enum ORDER_STATUS { + ACTIVE = 'ACTIVE', + DEACTIVATED = 'DEACTIVATED', + DISABLED = 'DISABLED', +} + +export enum PACT_STATUS { + ACTIVE = 'ACTIVE', + DISABLED = 'DISABLED', +} + +export enum AddressEncoding { + Hex = 'Hex', + Base58 = 'Base58', + Bech32 = 'Bech32', + Bech32m = 'Bech32m', +} + +export enum ProviderType { + Evm = 'Evm', + Btc = 'Btc', +} + +export const BTC_MAIN_NET = { + bech32: 'bc', + pubKeyHash: 0x00, + scriptHash: 0x05, + wif: 0x80, +}; + +export const BTC_TEST_NET: BtcNetworkParams = { + bech32: 'tb', + pubKeyHash: 0x6f, + scriptHash: 0xc4, + wif: 0xef, +}; + +export const BtcShardNetwork = { + btc: BTC_MAIN_NET, + tbtc: BTC_TEST_NET, +} satisfies Record<'btc' | 'tbtc', BtcNetworkParams>; + +export enum BtcNetworkCode { + btc = 'btc', + tbtc = 'tbtc', +} + +export const BtcCodeNetwork = { + [BtcNetworkCode.btc]: BTC_MAIN_NET, + [BtcNetworkCode.tbtc]: BTC_TEST_NET, +}; + +export const OrderBatchFields = [ + 'l1Amount', + 'l1Address', + 'minL1Amount', + 'baseAmount', + 'chainData', +] as const satisfies (keyof CreateOrderBaseParams)[]; diff --git a/packages/btc-like-provider.cm.ignore/src/shared/index.ts b/packages/btc-like-provider.cm.ignore/src/shared/index.ts new file mode 100644 index 0000000..6659bde --- /dev/null +++ b/packages/btc-like-provider.cm.ignore/src/shared/index.ts @@ -0,0 +1,3 @@ +export * from './keys'; +export * from './constants/constants'; +export * from './types'; diff --git a/packages/btc-like-provider.cm.ignore/src/shared/market-maker/api/index.ts b/packages/btc-like-provider.cm.ignore/src/shared/market-maker/api/index.ts new file mode 100644 index 0000000..e69de29 diff --git a/packages/btc-like-provider.cm.ignore/src/shared/market-maker/index.ts b/packages/btc-like-provider.cm.ignore/src/shared/market-maker/index.ts new file mode 100644 index 0000000..e69de29 diff --git a/packages/btc-like-provider.cm.ignore/src/shared/market-maker/keys.ts b/packages/btc-like-provider.cm.ignore/src/shared/market-maker/keys.ts new file mode 100644 index 0000000..e69de29 diff --git a/packages/btc-like-provider.cm.ignore/src/shared/market-maker/types.ts b/packages/btc-like-provider.cm.ignore/src/shared/market-maker/types.ts new file mode 100644 index 0000000..e69de29 diff --git a/packages/btc-like-provider.cm.ignore/src/shared/market-maker/ui-commands/index.ts b/packages/btc-like-provider.cm.ignore/src/shared/market-maker/ui-commands/index.ts new file mode 100644 index 0000000..e69de29 diff --git a/packages/btc-like-provider.cm.ignore/src/shared/order/api/index.ts b/packages/btc-like-provider.cm.ignore/src/shared/order/api/index.ts new file mode 100644 index 0000000..e69de29 diff --git a/packages/btc-like-provider.cm.ignore/src/shared/order/index.ts b/packages/btc-like-provider.cm.ignore/src/shared/order/index.ts new file mode 100644 index 0000000..e69de29 diff --git a/packages/btc-like-provider.cm.ignore/src/shared/order/keys.ts b/packages/btc-like-provider.cm.ignore/src/shared/order/keys.ts new file mode 100644 index 0000000..e69de29 diff --git a/packages/btc-like-provider.cm.ignore/src/shared/order/types.ts b/packages/btc-like-provider.cm.ignore/src/shared/order/types.ts new file mode 100644 index 0000000..e69de29 diff --git a/packages/btc-like-provider.cm.ignore/src/shared/order/ui-commands/index.ts b/packages/btc-like-provider.cm.ignore/src/shared/order/ui-commands/index.ts new file mode 100644 index 0000000..e69de29 diff --git a/packages/btc-like-provider.cm.ignore/src/shared/pact/api/index.ts b/packages/btc-like-provider.cm.ignore/src/shared/pact/api/index.ts new file mode 100644 index 0000000..e69de29 diff --git a/packages/btc-like-provider.cm.ignore/src/shared/pact/index.ts b/packages/btc-like-provider.cm.ignore/src/shared/pact/index.ts new file mode 100644 index 0000000..e69de29 diff --git a/packages/btc-like-provider.cm.ignore/src/shared/pact/keys.ts b/packages/btc-like-provider.cm.ignore/src/shared/pact/keys.ts new file mode 100644 index 0000000..e69de29 diff --git a/packages/btc-like-provider.cm.ignore/src/shared/pact/types.ts b/packages/btc-like-provider.cm.ignore/src/shared/pact/types.ts new file mode 100644 index 0000000..e69de29 diff --git a/packages/btc-like-provider.cm.ignore/src/shared/pact/ui-commands/index.ts b/packages/btc-like-provider.cm.ignore/src/shared/pact/ui-commands/index.ts new file mode 100644 index 0000000..e69de29 diff --git a/packages/btc-like-provider.cm.ignore/src/shared/types.ts b/packages/btc-like-provider.cm.ignore/src/shared/types.ts new file mode 100644 index 0000000..32c5f6f --- /dev/null +++ b/packages/btc-like-provider.cm.ignore/src/shared/types.ts @@ -0,0 +1,121 @@ +import type { HexString, User } from '@coinweb/contract-kit'; +import { HexBigInt } from 'lib/shared'; + +import { ORDER_STATUS, OrderBatchFields, AddressEncoding } from './constants/constants'; + +export type ProviderData = unknown; + +export type BtcProviderData = { + l1TxId: string; + vout: number; + psbt: string; +}; + +export type DirectionParameter = { + provider: string; + providerData: ProviderData; + value: HexBigInt; +}; + +export type Direction = { + from: DirectionParameter; + to: DirectionParameter; +}; + +export type OrderStateClaimBody = { + recipient: string; + cwebAmount: HexBigInt; + minCwebSwapAmount: HexBigInt; + directions: Direction[]; + createdAt: number; + expirationDate: number; + status: ORDER_STATUS; + parentTxId: string; + history: HistoryAccess; + maker: User; +}; + +export type SwapInfoData = { + l1TxId: string; + recipientAddress: string; + backPayAddress: string; + amount: HexBigInt; + l2TxId: string; +}; + +export type SwapToBtcL1Payload = { + minL1Amount: HexBigInt; + promisedL1Amount: HexBigInt; + l1Recipient: HexString; + fallbackRecipient: HexString; +}; + +export type SwapToEvmL1Payload = { + minL1Amount: HexBigInt; + promisedL1Amount: HexBigInt; + l1Recipient: HexString; +}; + +export type SwapToEvmPreset = { + toL1ChainType: L1Types.Evm; + c2ContractId: HexString; + c2ContractMethod: HexString; + fallbackC1ContractId: HexString; + fallbackC1ContractMethod: HexString; +}; + +export type SwapToBtcPreset = { + toL1ChainType: L1Types.Btc; + c2ContractId: HexString; + c2ContractMethod: HexString; + encoding: AddressEncoding; +}; + +export type SwapPreset = SwapToEvmPreset | SwapToBtcPreset; + +export type CreateOrderBaseParams = { + cwebAmount?: bigint; + minCwebSwapAmount?: bigint; + directions: Direction[]; +}; + +export type CreateOrderEvmBaseParams = CreateOrderBaseParams; +export type CreateOrderBtcBaseParams = Omit & { + chainData: BtcChainData; +}; + +export type OrdersBatch = [ + number, + Partial, + Partial[]?, +][]; +export type EvmOrdersBatch = OrdersBatch; +export type BtcOrdersBatch = OrdersBatch; + +export type SerializableOrderParams = BigIntToHex; + +type BatchFields = typeof OrderBatchFields; + +export type SerializedOrderTemplate = { + [I in keyof BatchFields & `${number}`]: BatchFields[I] extends keyof CreateOrderBaseParams + ? BigIntToHex> | null + : never; +}; + +export type SerializedOrderTune = { + [I in keyof BatchFields & `${number}`]?: BatchFields[I] extends keyof CreateOrderBaseParams + ? BigIntToHex + : never; +}; + +export type SerializedOrdersBatch = [OrdersBatch[number][0], SerializedOrderTemplate, SerializedOrderTune[]?][]; + +export type CreateOrderCallArgs = [orders: SerializedOrdersBatch]; + +export type CancelOrderArguments = [ids: string[]]; +export type ChangeContractOwnerArguments = [newOwner: User]; + +export type BtcNetworkParams = { + bech32: string; + scriptHash: number; +}; diff --git a/packages/btc-like-provider.cm.ignore/src/shared/types/index.ts b/packages/btc-like-provider.cm.ignore/src/shared/types/index.ts new file mode 100644 index 0000000..e69de29 diff --git a/packages/btc-like-provider.cm.ignore/src/shared/types/utils.ts b/packages/btc-like-provider.cm.ignore/src/shared/types/utils.ts new file mode 100644 index 0000000..e69de29 diff --git a/packages/contract.cm/tsconfig.build.json b/packages/btc-like-provider.cm.ignore/tsconfig.build.json similarity index 100% rename from packages/contract.cm/tsconfig.build.json rename to packages/btc-like-provider.cm.ignore/tsconfig.build.json diff --git a/packages/contract.cm/tsconfig.dev.json b/packages/btc-like-provider.cm.ignore/tsconfig.dev.json similarity index 100% rename from packages/contract.cm/tsconfig.dev.json rename to packages/btc-like-provider.cm.ignore/tsconfig.dev.json diff --git a/packages/contract.cm/tsconfig.json b/packages/btc-like-provider.cm.ignore/tsconfig.json similarity index 100% rename from packages/contract.cm/tsconfig.json rename to packages/btc-like-provider.cm.ignore/tsconfig.json diff --git a/packages/contract.cm/vitest.config.ts b/packages/btc-like-provider.cm.ignore/vitest.config.ts similarity index 100% rename from packages/contract.cm/vitest.config.ts rename to packages/btc-like-provider.cm.ignore/vitest.config.ts diff --git a/packages/contract.cm/src/offchain/shared/constants.ts b/packages/contract.cm/src/offchain/shared/constants.ts deleted file mode 100644 index c28e3bb..0000000 --- a/packages/contract.cm/src/offchain/shared/constants.ts +++ /dev/null @@ -1,13 +0,0 @@ -export enum Key { - WORD = 'WORD', - SET = 'SET', - BY_LETTER = 'BY_LETTER', -} - -export enum PUBLIC_METHODS { - ADD_WORD = 'ADD_WORD', -} - -export const FEE = { - ADD_WORD: 10000000n, -}; diff --git a/packages/contract.cm/src/offchain/shared/keys.ts b/packages/contract.cm/src/offchain/shared/keys.ts deleted file mode 100644 index 6e24ab3..0000000 --- a/packages/contract.cm/src/offchain/shared/keys.ts +++ /dev/null @@ -1,29 +0,0 @@ -import type { ClaimKey } from '@coinweb/contract-kit'; - -import { Key } from './constants'; - -/* FirstPart */ -export const createWordFirstPart = () => [Key.WORD]; - -export const createByLetterFirstPart = (letter: string) => [Key.BY_LETTER, letter]; - -export const createSetFirstPart = () => [Key.SET]; - -/* Key */ -export const createWordKey = (id: string) => - ({ - first_part: createWordFirstPart(), - second_part: [id], - }) satisfies ClaimKey; - -export const createByLetterKey = (letter: string, id: string) => - ({ - first_part: createByLetterFirstPart(letter), - second_part: [id], - }) satisfies ClaimKey; - -export const createSetKey = (letter: string) => - ({ - first_part: createSetFirstPart(), - second_part: [letter], - }) satisfies ClaimKey; diff --git a/packages/contract.cm/src/offchain/shared/types.ts b/packages/contract.cm/src/offchain/shared/types.ts deleted file mode 100644 index 4c2937e..0000000 --- a/packages/contract.cm/src/offchain/shared/types.ts +++ /dev/null @@ -1,9 +0,0 @@ -export type SetClaimBody = { - set: string; -}; - -export type WordClaimBody = { - word: string; -}; - -export type AddWordArgs = [string]; diff --git a/packages/evm-provider.cm.ignore/.gitignore b/packages/evm-provider.cm.ignore/.gitignore new file mode 100644 index 0000000..3eb4131 --- /dev/null +++ b/packages/evm-provider.cm.ignore/.gitignore @@ -0,0 +1 @@ +deploy/calls.yaml \ No newline at end of file diff --git a/packages/evm-provider.cm.ignore/deploy/calls.yaml.template b/packages/evm-provider.cm.ignore/deploy/calls.yaml.template new file mode 100644 index 0000000..5ca3928 --- /dev/null +++ b/packages/evm-provider.cm.ignore/deploy/calls.yaml.template @@ -0,0 +1,12 @@ +# this is the contract id +__CWEB_CONTRACT_SELF_REFERENCE__: + # out contract does not take any arguments, so we pass an empty object + args: + - "CREATE_ORDER" + - "0x000000000000000000000000000000000000000000000001236efcbcbb340000" + - "0x0000000000000000000000000000000000000000000000000de0b6b3a7640000" + - "0x9A4250b8c30Ca3cC5Dc33Ddbe30f71509a2E60a5" + - "0x00000000000000000000000000000000000000000000000002ea11e32ad50000" + - "0x00000000000000000000000000000000000000000000000000000000000186a0" + cweb_provided: "0x00000000000000000000000000000000000000000000000126590e9fe60a86a0" + auth: true \ No newline at end of file diff --git a/packages/evm-provider.cm.ignore/package.json b/packages/evm-provider.cm.ignore/package.json new file mode 100644 index 0000000..20323cc --- /dev/null +++ b/packages/evm-provider.cm.ignore/package.json @@ -0,0 +1,37 @@ +{ + "name": "evm-provider.cm", + "version": "0.0.1-dev", + "type": "module", + "scripts": { + "build": "yarn build:files && yarn pack:all", + "build:files": "yarn clean && yarn g:tsc -p tsconfig.build.json && NODE_ENV=production ./scripts/build.sh", + "start": "node src/offchain/index.js", + "test": "yarn g:vitest run --pool=forks", + "test:prepare": "mkdir -p tests_data && cp ../../.cweb_tool/simulation/unknown.json tests_data/state.json && cp ../../.dapp-ecosystem-lock-test.yaml tests_data/index.yaml", + "test:watch": "yarn g:vitest", + "test:coverage": "yarn g:vitest run --coverage", + "pack:relink": "cd $INIT_CWD && node scripts/package-relink.js", + "pack:all": "yarn pack:cweb && yarn pack:relink && yarn pack:yarn && yarn pack:relink", + "pack:cweb": "yarn g:cweb-tool pack . dist/out ../../.cweb-config/cweb-pack.yaml -c ../../.cweb-config/config.yaml --profile $REGISTRATION_PROFILE", + "pack:yarn": "cd dist/out && touch yarn.lock && yarn pack -o my-contract-module.tgz", + "clean": "rm -rf cweb_dist dist .calls.yaml", + "typecheck": "yarn g:tsc --noEmit", + "dev": "yarn g:tsc -p tsconfig.dev.json --watch", + "lint": "yarn g:lint ." + }, + "dependencies": { + "@coinweb/contract-kit": "0.2.6", + "@coinweb/self-register": "0.1.3", + "@noble/hashes": "1.4.0", + "bech32": "2.0.0", + "bs58": "6.0.0", + "lib": "workspaces:*" + }, + "devDependencies": { + "esbuild": "^0.20.2" + }, + "main": "cweb_dist/offchain/index.js", + "engines": { + "cweb_interpreter": "a344c6003922f9e44385f6e8234a7d2567d9a676b14330ad3b42cbd1948a92bf" + } +} diff --git a/packages/evm-provider.cm.ignore/scripts/build.sh b/packages/evm-provider.cm.ignore/scripts/build.sh new file mode 100755 index 0000000..85713c5 --- /dev/null +++ b/packages/evm-provider.cm.ignore/scripts/build.sh @@ -0,0 +1,41 @@ +#!/usr/bin/env bash +set -euo pipefail + +DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" +ROOT=$DIR/.. + +rm -rf $ROOT/{cweb_dist/{on,off}chain,dist/tmp/{step{1,2,3},final}} +mkdir -p $ROOT/{cweb_dist/{on,off}chain,dist/tmp/{step{1,2,3},final}} + +( + cd $ROOT + cp -rf dist/offchain/. cweb_dist/offchain/ + + ## Bundle and transpile `index.js` so it can be understood by the quickjs interpreter: + echo 'import {cwebMain as f} from "../../../dist/onchain/index"; f();' \ + > dist/tmp/step1/onchain.js + + yarn esbuild \ + --bundle \ + --log-level=error \ + --format=esm \ + dist/tmp/step1/onchain.js \ + --outfile=dist/tmp/step2/onchain.js + + echo 'import * as std from "std";' | + cat - dist/tmp/step2/onchain.js \ + > dist/tmp/step3/onchain.js + + yarn esbuild \ + --bundle \ + --log-level=error \ + --format=esm \ + --external:std \ + --tree-shaking=true \ + dist/tmp/step3/onchain.js \ + --outfile=dist/tmp/final/onchain.js + + cp dist/tmp/final/onchain.js cweb_dist/onchain/index.js +) + +rm -rf $ROOT/dist/{tmp,offchain,onchain} diff --git a/packages/evm-provider.cm.ignore/scripts/package-relink.js b/packages/evm-provider.cm.ignore/scripts/package-relink.js new file mode 100644 index 0000000..3719980 --- /dev/null +++ b/packages/evm-provider.cm.ignore/scripts/package-relink.js @@ -0,0 +1,33 @@ +import { readFileSync, writeFileSync } from 'fs'; +import { resolve } from 'path'; +import { fileURLToPath } from 'url'; + +const workspaceLink = 'workspaces:*'; +const __dirname = fileURLToPath(new URL('.', import.meta.url)); + +// Update target package.json +const targetPath = resolve(__dirname, '../dist/out/package.json'); +const targetPackage = JSON.parse(readFileSync(targetPath, 'utf8')); + +// Process all cm- dependencies +Object.keys(targetPackage.dependencies).forEach((dependency) => { + if (dependency.startsWith('cwap-cm-')) { + // Read source version from the corresponding package + const sourcePath = resolve(__dirname, `../../${dependency}/package.json`); + try { + const sourcePackage = JSON.parse(readFileSync(sourcePath, 'utf8')); + const sourceVersion = sourcePackage.version; + + if (targetPackage.dependencies[dependency] === workspaceLink) { + targetPackage.dependencies[dependency] = sourceVersion; + } else { + targetPackage.dependencies[dependency] = workspaceLink; + } + } catch (err) { + console.warn(`Warning: Could not read package.json for ${dependency} at ${sourcePath}: ${err.message}`); + } + } +}); + +// Write back the updated package.json +writeFileSync(targetPath, JSON.stringify(targetPackage, null, 2)); diff --git a/packages/evm-provider.cm.ignore/src/offchain/api.ts b/packages/evm-provider.cm.ignore/src/offchain/api.ts new file mode 100644 index 0000000..3511ade --- /dev/null +++ b/packages/evm-provider.cm.ignore/src/offchain/api.ts @@ -0,0 +1,41 @@ +import { ClaimKey } from '@coinweb/contract-kit'; +import { Client } from 'lib/offchain'; + +import { SetClaimBody, WordClaimBody } from './shared'; +import { createWordFirstPart, createSetKey, createWordKey, createByLetterFirstPart } from './shared/keys'; + +export const getWord = async (client: Client, id: string) => { + const key = createWordKey(id); + + const claimResponse = (await client.fetchClaims(key.first_part, key.second_part))[0]; + + const data = claimResponse.content.body as WordClaimBody; + + return data.word; +}; + +export const getWords = async (client: Client): Promise => { + const claimsResponse = await client.fetchClaims(createWordFirstPart(), null); + + return claimsResponse.map(({ content }) => (content.body as WordClaimBody).word); +}; + +export const getWordsByLetter = async (client: Client, letter: string): Promise => { + const indexResponse = await client.fetchClaims(createByLetterFirstPart(letter), null); + + const ids = indexResponse.map(({ content }) => ((content.key as ClaimKey).second_part as [string])[0]); + + const words = await Promise.all(ids.map((id) => getWord(client, id))); + + return words; +}; + +export const getSet = async (client: Client, letter: string): Promise => { + const key = createSetKey(letter); + + const claimResponse = (await client.fetchClaims(key.first_part, key.second_part))[0]; + + const data = claimResponse.content.body as SetClaimBody; + + return data.set; +}; diff --git a/packages/evm-provider.cm.ignore/src/offchain/index.ts b/packages/evm-provider.cm.ignore/src/offchain/index.ts new file mode 100644 index 0000000..76de9d0 --- /dev/null +++ b/packages/evm-provider.cm.ignore/src/offchain/index.ts @@ -0,0 +1,3 @@ +export * from './api'; +export * from './uiCommands'; +export * from '../shared'; diff --git a/packages/evm-provider.cm.ignore/src/offchain/uiCommands.ts b/packages/evm-provider.cm.ignore/src/offchain/uiCommands.ts new file mode 100644 index 0000000..819f85d --- /dev/null +++ b/packages/evm-provider.cm.ignore/src/offchain/uiCommands.ts @@ -0,0 +1,15 @@ +import { constructCall, constructUiCommand } from 'lib/offchain'; + +import { AddWordArgs, FEE, PUBLIC_METHODS } from '../shared'; + +export const constructAddWordUiCommand = ({ word, contractId }: { word: string; contractId: string }) => { + return constructUiCommand([ + constructCall({ + contractId, + methodName: PUBLIC_METHODS.ADD_WORD, + methodArgs: [[word] satisfies AddWordArgs], + cost: FEE.ADD_WORD, + withQueue: false, + }), + ]); +}; diff --git a/packages/evm-provider.cm.ignore/src/onchain/__tests__/handlers.test.ts b/packages/evm-provider.cm.ignore/src/onchain/__tests__/handlers.test.ts new file mode 100644 index 0000000..b8cd823 --- /dev/null +++ b/packages/evm-provider.cm.ignore/src/onchain/__tests__/handlers.test.ts @@ -0,0 +1,94 @@ +import path from 'node:path'; + +import { constructContractIssuer, constructContractRef, type PreparedCallInfo } from '@coinweb/contract-kit'; +import { UnitTest, type ExecInfo, type RoundInfo, type UnitTestContext, type DbWriteOp } from '@coinweb/testing-sdk'; +import { describe, it, expect, beforeAll } from 'vitest'; + +import { AddWordArgs, FEE, PUBLIC_METHODS } from '../../offchain/shared'; + +import { CONTRACT_INSTANCE_ID, TEST_PRIVATE_KEY, TEST_PUBLIC_KEY, waitRoundsCount } from './helpers'; + +const addWordRound = (creatorAccount: Buffer): RoundInfo => { + const self = constructContractIssuer(CONTRACT_INSTANCE_ID); + + const kvDeleteCallInfo: PreparedCallInfo = { + ref: constructContractRef(self, []), + methodInfo: { methodName: PUBLIC_METHODS.ADD_WORD, methodArgs: ['TEST_HELLO'] satisfies AddWordArgs }, + contractArgs: [], + contractInfo: { providedCweb: FEE.ADD_WORD, authenticated: null }, // null = authenticated account in tests + }; + + const withFunds = { type: { privateKey: creatorAccount } }; + + return { + txsInfo: { + // @ts-ignore + txs: [{ callInfo: kvDeleteCallInfo, withFunds }], + l1_events: [], + }, + claims: [], + blocks_on: [], + }; +}; + +const runTest = async (context: UnitTestContext, input: ExecInfo, checkFn: (results: DbWriteOp[]) => void) => { + const test = new UnitTest(context); + await test.load(path.join(import.meta.dirname, '../../../tests_data/state.json')); + await test.run(input, { checkFn }); +}; + +describe('PUBLIC_METHODS.ADD_WORD Tests', () => { + let creatorAccount: { publicKey: Buffer; privateKey: Buffer }; + + beforeAll(() => { + creatorAccount = { + privateKey: Buffer.from(TEST_PRIVATE_KEY, 'hex'), + publicKey: Buffer.from(TEST_PUBLIC_KEY, 'hex'), + }; + }); + + it('Should successfully execute', async () => { + const input: ExecInfo = { + rounds: [...waitRoundsCount(50), addWordRound(creatorAccount.privateKey), ...waitRoundsCount(2)], + }; + + const checkFn = (results: DbWriteOp[]) => { + expect(results).toBeDefined(); + + // @ts-ignore + // const errors = findAllValuesRecursivelyByKey<{ ContractError: ContractError }>(results, 'Invalid'); + // expect(errors.length).toBe(0); + + // @ts-ignore + // const storeOps = findAllValuesRecursivelyByKey(results, 'StoreOp'); + // expect(storeOps.length).toBeGreaterThan(0); + + // const existingPayload = storeOps.find((s) => isEqual(s.key.first_part, createFirstPartDefault())); + + // expect(existingPayload).toBeDefined(); + // expect(existingPayload?.key).toStrictEqual(createDefaultKey(Number.MAX_SAFE_INTEGER)); + // expect(existingPayload?.key.first_part).toStrictEqual(createFirstPartDefault()); + + // const { id, data, owner, tx } = existingPayload?.body as StoreKvPayload; + // expect(id).toBeDefined(); + // expect(data).toBeDefined(); + // expect(owner).toBeDefined(); + // expect(tx).toBeDefined(); + // expect(tx?.timestamp).toBeDefined(); + // expect(tx?.coinwebTxId).toBeDefined(); + // expect(Number(id)).toStrictEqual(Number.MAX_SAFE_INTEGER); + // expect(owner).toStrictEqual({ + // auth: 'EcdsaContract', + // payload: TEST_PUBLIC_KEY, + // }); + }; + + const context: UnitTestContext = { + name: 'add_word', + testPath: path.join(import.meta.dirname, './tests_data/add_word'), + verbose: true, + }; + + await runTest(context, input, checkFn); + }); +}); diff --git a/packages/evm-provider.cm.ignore/src/onchain/__tests__/helpers.ts b/packages/evm-provider.cm.ignore/src/onchain/__tests__/helpers.ts new file mode 100644 index 0000000..47473e4 --- /dev/null +++ b/packages/evm-provider.cm.ignore/src/onchain/__tests__/helpers.ts @@ -0,0 +1,35 @@ +import path from 'node:path'; + +import { getInstanceFromIndex, type RoundInfo } from '@coinweb/testing-sdk'; + +const onchainPackage = (await import('../../../dist/out/package.json')) as { + name: string; +}; + +export const CONTRACT_INSTANCE = await getInstanceFromIndex({ + path: path.resolve(import.meta.dirname, '../../../tests_data/index.yaml'), + instance_alias: 'cwait-contract 0.0.1-test', +}); + +export const CONTRACT_INSTANCE_ID = '0x'.concat(CONTRACT_INSTANCE.instance_id.replace(/0x/, '')); + +export const CONTRACT_TEMPLATE_ID = `0x${onchainPackage.name.substring(5)}`; + +export const TEST_PRIVATE_KEY = '31c70848e4e3aaffcf91f134853ec966e913aa9a813115bcb81512e7625f46a9'; +export const TEST_PUBLIC_KEY = '03951f89fe78e13f295d96eb7afa1e0da726df7d58f9c84f7144e5febc30efeec4'; + +export const waitRoundsCount = (roundsCount: number): RoundInfo[] => { + const emptyRound: RoundInfo = { + txsInfo: { + txs: [], + l1_events: [], + }, + claims: [], + blocks_on: [], + }; + const rounds: RoundInfo[] = []; + for (let i = 0; i < roundsCount; i++) { + rounds.push(emptyRound); + } + return rounds; +}; diff --git a/packages/evm-provider.cm.ignore/src/onchain/addWord.ts b/packages/evm-provider.cm.ignore/src/onchain/addWord.ts new file mode 100644 index 0000000..aa27151 --- /dev/null +++ b/packages/evm-provider.cm.ignore/src/onchain/addWord.ts @@ -0,0 +1,54 @@ +import { constructClaim } from '@coinweb/contract-kit'; +import { readOp, storeOp, cwait } from 'cwait'; + +import { TypedClaim } from '../../../lib/dist/shared/types'; +import { AddWordArgs, createWordKey, WordClaimBody } from '../offchain/shared'; + +import { extraLogic } from './extraLogic'; + +function hashCode(str: string): string { + let hash = 0; + for (let i = 0, len = str.length; i < len; i++) { + const chr = str.charCodeAt(i); + // eslint-disable-next-line no-bitwise + hash = (hash << 5) - hash + chr; + // eslint-disable-next-line no-bitwise + hash |= 0; + } + return `${(hash < 0 ? hash * -1 : hash).toString(16)}`; +} + +export const addWord = cwait(async (...[word]: AddWordArgs) => { + console.log('addWord START'); + + const id = hashCode(word); + + console.log('await storeOp'); + await storeOp(constructClaim(createWordKey(id), { word }, '0x0')); + + console.log('await extraLogic'); + const [wordClaim] = await Promise.all([extraLogic(id, 1), extraLogic(id, 2)]); + + const newWord1 = (wordClaim?.body.word ?? '') + '_1'; + const newId1 = hashCode(newWord1); + + const newWord2 = (wordClaim?.body.word ?? '') + '_2'; + const newId2 = hashCode(newWord2); + + const newWord3 = (wordClaim?.body.word ?? '') + '_3'; + const newId3 = hashCode(newWord3); + + console.log('free storeOp'); + storeOp(constructClaim(createWordKey(newId1), { word: wordClaim?.body.word + '_free' }, '0x0')); + + console.log('await Promise.all'); + await Promise.all([ + storeOp(constructClaim(createWordKey(newId2), { word: wordClaim?.body.word + '_in_promise_all' }, '0x0')), + storeOp(constructClaim(createWordKey(newId3), { word: 'WIN' }, '0x0')), + ]); + + console.log('free readOp'); + readOp>(createWordKey(newId3)); + + console.log('addWord END'); +}); diff --git a/packages/evm-provider.cm.ignore/src/onchain/contract.ts b/packages/evm-provider.cm.ignore/src/onchain/contract.ts new file mode 100644 index 0000000..64a944d --- /dev/null +++ b/packages/evm-provider.cm.ignore/src/onchain/contract.ts @@ -0,0 +1,9 @@ +import { constructCwebMain } from 'cwait'; + +import { PUBLIC_METHODS } from '../shared'; + +import { addWord } from './addWord'; + +export const cwebMain = constructCwebMain({ + [PUBLIC_METHODS.ADD_WORD]: addWord, +}); diff --git a/packages/evm-provider.cm.ignore/src/onchain/extraLogic.ts b/packages/evm-provider.cm.ignore/src/onchain/extraLogic.ts new file mode 100644 index 0000000..4eea7a2 --- /dev/null +++ b/packages/evm-provider.cm.ignore/src/onchain/extraLogic.ts @@ -0,0 +1,31 @@ +import { constructClaim } from '@coinweb/contract-kit'; +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 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), + { word: result?.body.word.split('').reverse().join('') + '_extraLogic + ' + i }, + '0x0' + ) + ); + + console.log('extraLogic unlock + ', i); + await unlock(); + + console.log('extraLogic return extraLogic2 + ', i); + return extraLogic2(id, i); +}); diff --git a/packages/evm-provider.cm.ignore/src/onchain/extraLogic2.ts b/packages/evm-provider.cm.ignore/src/onchain/extraLogic2.ts new file mode 100644 index 0000000..70bbfd7 --- /dev/null +++ b/packages/evm-provider.cm.ignore/src/onchain/extraLogic2.ts @@ -0,0 +1,13 @@ +import { cwait, readOp, TypedClaim } from 'cwait'; + +import { createWordKey, WordClaimBody } from '../offchain'; + +export const extraLogic2 = cwait(async (id: string, i: number) => { + console.log('extraLogic2 START + ', i); + + console.log('await extraLogic2 readOp + ', i); + const result = await readOp>(createWordKey(id)); + + console.log('extraLogic2 END + ', i); + return result; +}); diff --git a/packages/evm-provider.cm.ignore/src/onchain/index.ts b/packages/evm-provider.cm.ignore/src/onchain/index.ts new file mode 100644 index 0000000..394968d --- /dev/null +++ b/packages/evm-provider.cm.ignore/src/onchain/index.ts @@ -0,0 +1 @@ +export * from './contract'; diff --git a/packages/evm-provider.cm.ignore/src/shared/constants/constants.ts b/packages/evm-provider.cm.ignore/src/shared/constants/constants.ts new file mode 100644 index 0000000..9c5d393 --- /dev/null +++ b/packages/evm-provider.cm.ignore/src/shared/constants/constants.ts @@ -0,0 +1,96 @@ +export enum Key { + ACTIVE_INDEX = 'ACTIVE_INDEX', + MAKER_INDEX = 'MAKER_INDEX', + DATE_INDEX = 'DATE_INDEX', + RATE_INDEX = 'RATE_INDEX', + + MAKER = 'MAKER', + + ORDER = 'ORDER', //ORDER_STATE + ORDER_FUNDS + LATEST_ORDER_ID = 'LATEST_ORDER_ID', //INCREMENT_INDEX + ORDER_DIRECTION_INDEX = 'ORDER_DIRECTION_INDEX', + + PACT = 'PACT', //ORDER_STATE + ORDER_COLLATERAL + LATEST_PACT_ID = 'LATEST_PACT_ID', //INCREMENT_INDEX + PACT_PENALTY_INDEX = 'PACT_PENALTY_INDEX', + + SWAP_INFO = 'SWAP_INFO', //L1_TX_INFO + PAYMENT_NONCE = 'PAYMENT_NONCE', //BTC_NONCE + UNIQUE_VALUE = 'UNIQUE_VALUE', + FEE_POOL_ADDRESS = 'FEE_POOL_ADDRESS', +} + +export enum PUBLIC_METHODS { + CREATE_ORDERS = 'CREATE_ORDERS', + CANCEL_ORDERS = 'CANCEL_ORDERS', + DEPOSIT_COLLATERAL = 'DEPOSIT_COLLATERAL', + WITHDRAW_COLLATERAL = 'WITHDRAW_COLLATERAL', +} + +export const FEE: Record<`${PUBLIC_METHODS}` | 'CHANGE_FEE_POOL_ADDRESS', bigint> = { + CREATE_ORDERS: 10000000n, + CANCEL_ORDERS: 10000000n, + DEPOSIT_COLLATERAL: 10000000n, + WITHDRAW_COLLATERAL: 10000000n, + CHANGE_FEE_POOL_ADDRESS: 10000000n, +}; + +export enum ORDER_STATUS { + ACTIVE = 'ACTIVE', + DEACTIVATED = 'DEACTIVATED', + DISABLED = 'DISABLED', +} + +export enum PACT_STATUS { + ACTIVE = 'ACTIVE', + DISABLED = 'DISABLED', +} + +export enum AddressEncoding { + Hex = 'Hex', + Base58 = 'Base58', + Bech32 = 'Bech32', + Bech32m = 'Bech32m', +} + +export enum ProviderType { + Evm = 'Evm', + Btc = 'Btc', +} + +export const BTC_MAIN_NET = { + bech32: 'bc', + pubKeyHash: 0x00, + scriptHash: 0x05, + wif: 0x80, +}; + +export const BTC_TEST_NET: BtcNetworkParams = { + bech32: 'tb', + pubKeyHash: 0x6f, + scriptHash: 0xc4, + wif: 0xef, +}; + +export const BtcShardNetwork = { + btc: BTC_MAIN_NET, + tbtc: BTC_TEST_NET, +} satisfies Record<'btc' | 'tbtc', BtcNetworkParams>; + +export enum BtcNetworkCode { + btc = 'btc', + tbtc = 'tbtc', +} + +export const BtcCodeNetwork = { + [BtcNetworkCode.btc]: BTC_MAIN_NET, + [BtcNetworkCode.tbtc]: BTC_TEST_NET, +}; + +export const OrderBatchFields = [ + 'l1Amount', + 'l1Address', + 'minL1Amount', + 'baseAmount', + 'chainData', +] as const satisfies (keyof CreateOrderBaseParams)[]; diff --git a/packages/evm-provider.cm.ignore/src/shared/index.ts b/packages/evm-provider.cm.ignore/src/shared/index.ts new file mode 100644 index 0000000..6659bde --- /dev/null +++ b/packages/evm-provider.cm.ignore/src/shared/index.ts @@ -0,0 +1,3 @@ +export * from './keys'; +export * from './constants/constants'; +export * from './types'; diff --git a/packages/evm-provider.cm.ignore/src/shared/market-maker/api/index.ts b/packages/evm-provider.cm.ignore/src/shared/market-maker/api/index.ts new file mode 100644 index 0000000..e69de29 diff --git a/packages/evm-provider.cm.ignore/src/shared/market-maker/index.ts b/packages/evm-provider.cm.ignore/src/shared/market-maker/index.ts new file mode 100644 index 0000000..e69de29 diff --git a/packages/evm-provider.cm.ignore/src/shared/market-maker/keys.ts b/packages/evm-provider.cm.ignore/src/shared/market-maker/keys.ts new file mode 100644 index 0000000..e69de29 diff --git a/packages/evm-provider.cm.ignore/src/shared/market-maker/types.ts b/packages/evm-provider.cm.ignore/src/shared/market-maker/types.ts new file mode 100644 index 0000000..e69de29 diff --git a/packages/evm-provider.cm.ignore/src/shared/market-maker/ui-commands/index.ts b/packages/evm-provider.cm.ignore/src/shared/market-maker/ui-commands/index.ts new file mode 100644 index 0000000..e69de29 diff --git a/packages/evm-provider.cm.ignore/src/shared/order/api/index.ts b/packages/evm-provider.cm.ignore/src/shared/order/api/index.ts new file mode 100644 index 0000000..e69de29 diff --git a/packages/evm-provider.cm.ignore/src/shared/order/index.ts b/packages/evm-provider.cm.ignore/src/shared/order/index.ts new file mode 100644 index 0000000..e69de29 diff --git a/packages/evm-provider.cm.ignore/src/shared/order/keys.ts b/packages/evm-provider.cm.ignore/src/shared/order/keys.ts new file mode 100644 index 0000000..e69de29 diff --git a/packages/evm-provider.cm.ignore/src/shared/order/types.ts b/packages/evm-provider.cm.ignore/src/shared/order/types.ts new file mode 100644 index 0000000..e69de29 diff --git a/packages/evm-provider.cm.ignore/src/shared/order/ui-commands/index.ts b/packages/evm-provider.cm.ignore/src/shared/order/ui-commands/index.ts new file mode 100644 index 0000000..e69de29 diff --git a/packages/evm-provider.cm.ignore/src/shared/pact/api/index.ts b/packages/evm-provider.cm.ignore/src/shared/pact/api/index.ts new file mode 100644 index 0000000..e69de29 diff --git a/packages/evm-provider.cm.ignore/src/shared/pact/index.ts b/packages/evm-provider.cm.ignore/src/shared/pact/index.ts new file mode 100644 index 0000000..e69de29 diff --git a/packages/evm-provider.cm.ignore/src/shared/pact/keys.ts b/packages/evm-provider.cm.ignore/src/shared/pact/keys.ts new file mode 100644 index 0000000..e69de29 diff --git a/packages/evm-provider.cm.ignore/src/shared/pact/types.ts b/packages/evm-provider.cm.ignore/src/shared/pact/types.ts new file mode 100644 index 0000000..e69de29 diff --git a/packages/evm-provider.cm.ignore/src/shared/pact/ui-commands/index.ts b/packages/evm-provider.cm.ignore/src/shared/pact/ui-commands/index.ts new file mode 100644 index 0000000..e69de29 diff --git a/packages/evm-provider.cm.ignore/src/shared/types.ts b/packages/evm-provider.cm.ignore/src/shared/types.ts new file mode 100644 index 0000000..32c5f6f --- /dev/null +++ b/packages/evm-provider.cm.ignore/src/shared/types.ts @@ -0,0 +1,121 @@ +import type { HexString, User } from '@coinweb/contract-kit'; +import { HexBigInt } from 'lib/shared'; + +import { ORDER_STATUS, OrderBatchFields, AddressEncoding } from './constants/constants'; + +export type ProviderData = unknown; + +export type BtcProviderData = { + l1TxId: string; + vout: number; + psbt: string; +}; + +export type DirectionParameter = { + provider: string; + providerData: ProviderData; + value: HexBigInt; +}; + +export type Direction = { + from: DirectionParameter; + to: DirectionParameter; +}; + +export type OrderStateClaimBody = { + recipient: string; + cwebAmount: HexBigInt; + minCwebSwapAmount: HexBigInt; + directions: Direction[]; + createdAt: number; + expirationDate: number; + status: ORDER_STATUS; + parentTxId: string; + history: HistoryAccess; + maker: User; +}; + +export type SwapInfoData = { + l1TxId: string; + recipientAddress: string; + backPayAddress: string; + amount: HexBigInt; + l2TxId: string; +}; + +export type SwapToBtcL1Payload = { + minL1Amount: HexBigInt; + promisedL1Amount: HexBigInt; + l1Recipient: HexString; + fallbackRecipient: HexString; +}; + +export type SwapToEvmL1Payload = { + minL1Amount: HexBigInt; + promisedL1Amount: HexBigInt; + l1Recipient: HexString; +}; + +export type SwapToEvmPreset = { + toL1ChainType: L1Types.Evm; + c2ContractId: HexString; + c2ContractMethod: HexString; + fallbackC1ContractId: HexString; + fallbackC1ContractMethod: HexString; +}; + +export type SwapToBtcPreset = { + toL1ChainType: L1Types.Btc; + c2ContractId: HexString; + c2ContractMethod: HexString; + encoding: AddressEncoding; +}; + +export type SwapPreset = SwapToEvmPreset | SwapToBtcPreset; + +export type CreateOrderBaseParams = { + cwebAmount?: bigint; + minCwebSwapAmount?: bigint; + directions: Direction[]; +}; + +export type CreateOrderEvmBaseParams = CreateOrderBaseParams; +export type CreateOrderBtcBaseParams = Omit & { + chainData: BtcChainData; +}; + +export type OrdersBatch = [ + number, + Partial, + Partial[]?, +][]; +export type EvmOrdersBatch = OrdersBatch; +export type BtcOrdersBatch = OrdersBatch; + +export type SerializableOrderParams = BigIntToHex; + +type BatchFields = typeof OrderBatchFields; + +export type SerializedOrderTemplate = { + [I in keyof BatchFields & `${number}`]: BatchFields[I] extends keyof CreateOrderBaseParams + ? BigIntToHex> | null + : never; +}; + +export type SerializedOrderTune = { + [I in keyof BatchFields & `${number}`]?: BatchFields[I] extends keyof CreateOrderBaseParams + ? BigIntToHex + : never; +}; + +export type SerializedOrdersBatch = [OrdersBatch[number][0], SerializedOrderTemplate, SerializedOrderTune[]?][]; + +export type CreateOrderCallArgs = [orders: SerializedOrdersBatch]; + +export type CancelOrderArguments = [ids: string[]]; +export type ChangeContractOwnerArguments = [newOwner: User]; + +export type BtcNetworkParams = { + bech32: string; + scriptHash: number; +}; diff --git a/packages/evm-provider.cm.ignore/src/shared/types/index.ts b/packages/evm-provider.cm.ignore/src/shared/types/index.ts new file mode 100644 index 0000000..e69de29 diff --git a/packages/evm-provider.cm.ignore/src/shared/types/utils.ts b/packages/evm-provider.cm.ignore/src/shared/types/utils.ts new file mode 100644 index 0000000..e69de29 diff --git a/packages/evm-provider.cm.ignore/tsconfig.build.json b/packages/evm-provider.cm.ignore/tsconfig.build.json new file mode 100644 index 0000000..6d00f4e --- /dev/null +++ b/packages/evm-provider.cm.ignore/tsconfig.build.json @@ -0,0 +1,10 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "declaration": true, + "rootDir": "./src", + "outDir": "./dist" + }, + "include": ["./src/**/*.ts"], + "exclude": ["**/__tests__", "**/__mocks__", "*.tests.ts"] +} diff --git a/packages/evm-provider.cm.ignore/tsconfig.dev.json b/packages/evm-provider.cm.ignore/tsconfig.dev.json new file mode 100644 index 0000000..c8b7792 --- /dev/null +++ b/packages/evm-provider.cm.ignore/tsconfig.dev.json @@ -0,0 +1,9 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "declaration": true, + "rootDir": "./src", + "outDir": "./cweb_dist/" + }, + "exclude": ["**/__tests__", "**/__mocks__", "vitest.config.ts", "tsconfig.dev.json", "*.tests.ts"] +} diff --git a/packages/evm-provider.cm.ignore/tsconfig.json b/packages/evm-provider.cm.ignore/tsconfig.json new file mode 100644 index 0000000..8d823a1 --- /dev/null +++ b/packages/evm-provider.cm.ignore/tsconfig.json @@ -0,0 +1,13 @@ +{ + "compilerOptions": { + "strict": true, + "target": "ESNEXT", + "module": "ESNEXT", + "moduleResolution": "Bundler", + "rootDir": ".", + "resolveJsonModule": true, + "esModuleInterop": true, + "types": ["vitest/globals"] + }, + "include": ["src/**/*.ts", "vitest.*.ts", "__tests__", "../cwap-cm-lib/src/onchain/features/logger.ts"] +} diff --git a/packages/evm-provider.cm.ignore/vitest.config.ts b/packages/evm-provider.cm.ignore/vitest.config.ts new file mode 100644 index 0000000..a7b2399 --- /dev/null +++ b/packages/evm-provider.cm.ignore/vitest.config.ts @@ -0,0 +1,14 @@ +import { defineConfig } from 'vitest/config'; + +export default defineConfig({ + test: { + globals: true, + environment: 'node', + reporters: 'default', + silent: false, + testTimeout: 240000, + teardownTimeout: 240000, + hookTimeout: 240000, + pool: 'forks', + }, +}); diff --git a/packages/lib/src/shared/utils/claimKeys.ts b/packages/lib/src/shared/utils/claimKeys.ts new file mode 100644 index 0000000..80a6247 --- /dev/null +++ b/packages/lib/src/shared/utils/claimKeys.ts @@ -0,0 +1,106 @@ +import { constructClaimKey } from '@coinweb/contract-kit'; + +// eslint-disable-next-line @typescript-eslint/no-explicit-any +type ClaimKeyFirstPartConstructor = (...args: any[]) => unknown[]; +// eslint-disable-next-line @typescript-eslint/no-explicit-any +type ClaimKeySecondPartConstructor = (...args: any[]) => unknown[] | null; + +type ClaimKeyConstructors = { + firstPart?: ClaimKeyFirstPartConstructor; + secondPart: ClaimKeySecondPartConstructor; +}; + +type ClaimKey = { + first_part: TFirstPart; + second_part: TSecondPart; +}; + +export type ClaimKeyDefinitions = { + [Key: string]: ClaimKeyConstructors | ClaimKeyDefinitions; +}; + +type KeyConstructor< + TCreateSecondPart extends (...args: unknown[]) => unknown[] | null, + TCreateFirstPart extends ((...args: unknown[]) => unknown[]) | undefined = undefined, +> = { + firstPart: TCreateFirstPart extends ClaimKeyFirstPartConstructor + ? (...args: Parameters) => [string, ...ReturnType] + : () => [string]; + secondPart: TCreateSecondPart; +} & (TCreateFirstPart extends ClaimKeySecondPartConstructor + ? ( + ...args: [...Parameters, ...Parameters] + ) => ClaimKey<[string, ...ReturnType], ReturnType> + : (...args: Parameters) => ClaimKey<[string], ReturnType>); + +type ConstructKeys = { + [Key in keyof T]: T[Key] extends ClaimKeyDefinitions + ? ConstructKeys + : T[Key] extends ClaimKeyConstructors + ? KeyConstructor + : never; +}; + +const domainPropSymbol = Symbol('domain'); + +export const constructClaimKeys = (domain: string, keys: T): ConstructKeys => + new Proxy(keys as ClaimKeyDefinitions & { [domainPropSymbol]?: string }, { + get: (target, prop) => { + if (typeof prop !== 'string') { + throw new Error('Property is not a string'); + } + + const value = target[prop]; + const currentDomain = target[domainPropSymbol] ? `${target[domainPropSymbol]}_${prop}` : domain; + + if ('secondPart' in value) { + const secondPart = value.secondPart; + + const firstPartDefinedConstructor = value.firstPart; + + if (typeof firstPartDefinedConstructor === 'function') { + const firstPart = (...args: Parameters) => [ + currentDomain, + ...firstPartDefinedConstructor(...args), + ]; + + return { + firstPart, + secondPart, + }; + } + + return { + firstPart: () => [currentDomain], + secondPart, + }; + } + + (value as ClaimKeyDefinitions & { [domainPropSymbol]: string })[domainPropSymbol] = currentDomain; + + return value; + }, + apply(target, prop, argArray) { + const value = target[prop]; + const currentDomain = target[domainPropSymbol] ? `${target[domainPropSymbol]}_${prop}` : domain; + + const secondPartConstructor = value.secondPart; + + if (typeof secondPartConstructor !== 'function') { + throw new Error('Property is not callable'); + } + + const secondPartArgs = argArray.slice(argArray.length - secondPartConstructor.length); + const secondPart = secondPartConstructor(...secondPartArgs); + + const firstPartDefinedConstructor = value.firstPart; + + const firstPart: unknown[] = [currentDomain]; + + if (typeof firstPartDefinedConstructor === 'function') { + firstPart.push(...firstPartDefinedConstructor(...argArray)); + } + + return constructClaimKey(firstPart, secondPart); + }, + }) as ConstructKeys; diff --git a/packages/lib/src/shared/utils/index.ts b/packages/lib/src/shared/utils/index.ts index ccbfd5c..bde8827 100644 --- a/packages/lib/src/shared/utils/index.ts +++ b/packages/lib/src/shared/utils/index.ts @@ -5,3 +5,4 @@ export * from './stableStringifyObject'; export * from './toHex'; export * from './toHex32'; export * from './isEqualUser'; +export * from './claimKeys'; diff --git a/packages/market.cm/.gitignore b/packages/market.cm/.gitignore new file mode 100644 index 0000000..3eb4131 --- /dev/null +++ b/packages/market.cm/.gitignore @@ -0,0 +1 @@ +deploy/calls.yaml \ No newline at end of file diff --git a/packages/market.cm/deploy/calls.yaml.template b/packages/market.cm/deploy/calls.yaml.template new file mode 100644 index 0000000..5ca3928 --- /dev/null +++ b/packages/market.cm/deploy/calls.yaml.template @@ -0,0 +1,12 @@ +# this is the contract id +__CWEB_CONTRACT_SELF_REFERENCE__: + # out contract does not take any arguments, so we pass an empty object + args: + - "CREATE_ORDER" + - "0x000000000000000000000000000000000000000000000001236efcbcbb340000" + - "0x0000000000000000000000000000000000000000000000000de0b6b3a7640000" + - "0x9A4250b8c30Ca3cC5Dc33Ddbe30f71509a2E60a5" + - "0x00000000000000000000000000000000000000000000000002ea11e32ad50000" + - "0x00000000000000000000000000000000000000000000000000000000000186a0" + cweb_provided: "0x00000000000000000000000000000000000000000000000126590e9fe60a86a0" + auth: true \ No newline at end of file diff --git a/packages/contract.cm/package.json b/packages/market.cm/package.json similarity index 93% rename from packages/contract.cm/package.json rename to packages/market.cm/package.json index 8e05d62..fa73bce 100644 --- a/packages/contract.cm/package.json +++ b/packages/market.cm/package.json @@ -1,6 +1,6 @@ { - "name": "contract.cm", - "version": "0.0.1", + "name": "market.cm", + "version": "0.0.1-dev", "type": "module", "scripts": { "build": "yarn build:files && yarn pack:all", @@ -24,7 +24,8 @@ "@coinweb/self-register": "0.1.3", "@noble/hashes": "1.4.0", "bech32": "2.0.0", - "bs58": "6.0.0" + "bs58": "6.0.0", + "lib": "workspaces:*" }, "devDependencies": { "esbuild": "^0.20.2" diff --git a/packages/market.cm/scripts/build.sh b/packages/market.cm/scripts/build.sh new file mode 100755 index 0000000..85713c5 --- /dev/null +++ b/packages/market.cm/scripts/build.sh @@ -0,0 +1,41 @@ +#!/usr/bin/env bash +set -euo pipefail + +DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" +ROOT=$DIR/.. + +rm -rf $ROOT/{cweb_dist/{on,off}chain,dist/tmp/{step{1,2,3},final}} +mkdir -p $ROOT/{cweb_dist/{on,off}chain,dist/tmp/{step{1,2,3},final}} + +( + cd $ROOT + cp -rf dist/offchain/. cweb_dist/offchain/ + + ## Bundle and transpile `index.js` so it can be understood by the quickjs interpreter: + echo 'import {cwebMain as f} from "../../../dist/onchain/index"; f();' \ + > dist/tmp/step1/onchain.js + + yarn esbuild \ + --bundle \ + --log-level=error \ + --format=esm \ + dist/tmp/step1/onchain.js \ + --outfile=dist/tmp/step2/onchain.js + + echo 'import * as std from "std";' | + cat - dist/tmp/step2/onchain.js \ + > dist/tmp/step3/onchain.js + + yarn esbuild \ + --bundle \ + --log-level=error \ + --format=esm \ + --external:std \ + --tree-shaking=true \ + dist/tmp/step3/onchain.js \ + --outfile=dist/tmp/final/onchain.js + + cp dist/tmp/final/onchain.js cweb_dist/onchain/index.js +) + +rm -rf $ROOT/dist/{tmp,offchain,onchain} diff --git a/packages/market.cm/scripts/package-relink.js b/packages/market.cm/scripts/package-relink.js new file mode 100644 index 0000000..3719980 --- /dev/null +++ b/packages/market.cm/scripts/package-relink.js @@ -0,0 +1,33 @@ +import { readFileSync, writeFileSync } from 'fs'; +import { resolve } from 'path'; +import { fileURLToPath } from 'url'; + +const workspaceLink = 'workspaces:*'; +const __dirname = fileURLToPath(new URL('.', import.meta.url)); + +// Update target package.json +const targetPath = resolve(__dirname, '../dist/out/package.json'); +const targetPackage = JSON.parse(readFileSync(targetPath, 'utf8')); + +// Process all cm- dependencies +Object.keys(targetPackage.dependencies).forEach((dependency) => { + if (dependency.startsWith('cwap-cm-')) { + // Read source version from the corresponding package + const sourcePath = resolve(__dirname, `../../${dependency}/package.json`); + try { + const sourcePackage = JSON.parse(readFileSync(sourcePath, 'utf8')); + const sourceVersion = sourcePackage.version; + + if (targetPackage.dependencies[dependency] === workspaceLink) { + targetPackage.dependencies[dependency] = sourceVersion; + } else { + targetPackage.dependencies[dependency] = workspaceLink; + } + } catch (err) { + console.warn(`Warning: Could not read package.json for ${dependency} at ${sourcePath}: ${err.message}`); + } + } +}); + +// Write back the updated package.json +writeFileSync(targetPath, JSON.stringify(targetPackage, null, 2)); diff --git a/packages/market.cm/src/offchain/index.ts b/packages/market.cm/src/offchain/index.ts new file mode 100644 index 0000000..76de9d0 --- /dev/null +++ b/packages/market.cm/src/offchain/index.ts @@ -0,0 +1,3 @@ +export * from './api'; +export * from './uiCommands'; +export * from '../shared'; diff --git a/packages/market.cm/src/offchain/order/api/getOrder.ts b/packages/market.cm/src/offchain/order/api/getOrder.ts new file mode 100644 index 0000000..e69de29 diff --git a/packages/market.cm/src/offchain/order/api/getOrders.ts b/packages/market.cm/src/offchain/order/api/getOrders.ts new file mode 100644 index 0000000..e69de29 diff --git a/packages/market.cm/src/offchain/order/api/getOrdersByDate.ts b/packages/market.cm/src/offchain/order/api/getOrdersByDate.ts new file mode 100644 index 0000000..e69de29 diff --git a/packages/market.cm/src/offchain/order/api/index.ts b/packages/market.cm/src/offchain/order/api/index.ts new file mode 100644 index 0000000..e69de29 diff --git a/packages/market.cm/src/offchain/order/index.ts b/packages/market.cm/src/offchain/order/index.ts new file mode 100644 index 0000000..e69de29 diff --git a/packages/market.cm/src/offchain/order/ui-commands/cancelOrder.ts b/packages/market.cm/src/offchain/order/ui-commands/cancelOrder.ts new file mode 100644 index 0000000..e69de29 diff --git a/packages/market.cm/src/offchain/order/ui-commands/createOrder.ts b/packages/market.cm/src/offchain/order/ui-commands/createOrder.ts new file mode 100644 index 0000000..70aaac3 --- /dev/null +++ b/packages/market.cm/src/offchain/order/ui-commands/createOrder.ts @@ -0,0 +1,128 @@ +import { constructCall, constructUiCommand } from 'lib/offchain'; + +import { FEE, serializeOrdersBatch, PUBLIC_METHODS, ordersBatchToList, calculateOrdersListParams } from './shared'; +import { + CancelOrdersData, + CreateOrdersBtcData, + CreateOrdersEvmData, + CreateOrdersData, + CancelOrderData, + CreateOrderBtcData, + CreateOrderEvmData, +} from './types'; + +const constructCreateOrdersCall = ({ contractId, accessId, orders, contractOwnerFee }: CreateOrdersData) => { + const { l1Amount, minL1Amount, definedBaseAmount, fee } = calculateOrdersListParams(ordersBatchToList(orders)); + + if (l1Amount < minL1Amount) { + throw new Error('creteNewOrderUiCommand: l1Amount is less than minimum value'); + } + + return constructCall( + contractId, + PUBLIC_METHODS.CREATE_ORDER, + withMetadata([serializeOrdersBatch(orders)], accessId), + definedBaseAmount + fee + contractOwnerFee + (accessId ? HISTORY_ACCESS_FEE : 0n) + ); +}; + +export const constructCreateBtcOrdersCall = (data: CreateOrdersBtcData) => { + return constructCreateOrdersCall(data); +}; + +export const constructCreateEvmOrdersCall = (data: CreateOrdersEvmData) => { + return constructCreateOrdersCall(data); +}; + +export const constructCancelOrdersCall = ({ contractId, orderIds, accessId }: CancelOrdersData) => { + return constructCall( + contractId, + PUBLIC_METHODS.CANCEL_ORDER, + withMetadata([orderIds], accessId), + FEE.CANCEL_ORDER * BigInt(orderIds.length) + (accessId ? HISTORY_ACCESS_FEE : 0n) + ); +}; + +export const createOrderBtcUiCommand = ({ + contractId, + baseAmount, + l1Amount, + minL1Amount, + l1Address, + chainData, + accessId, + contractOwnerFee, +}: CreateOrderBtcData) => { + if (!baseAmount) { + throw new Error('createOrderBtcUiCommand: baseAmount is not defined'); + } + + return constructUiCommand([ + constructCreateOrdersCall({ + contractId, + orders: [ + [ + 1, + { + baseAmount, + l1Amount, + minL1Amount, + l1Address, + chainData, + }, + ], + ], + accessId, + contractOwnerFee, + }), + ]); +}; + +export const createOrderEvmUiCommand = ({ + contractId, + baseAmount, + l1Amount, + minL1Amount, + l1Address, + accessId, + contractOwnerFee, +}: CreateOrderEvmData) => { + if (!baseAmount) { + throw new Error('createOrderEvmUiCommand: baseAmount is not defined'); + } + + return constructUiCommand([ + constructCreateOrdersCall({ + contractId, + orders: [ + [ + 1, + { + baseAmount, + l1Amount, + minL1Amount, + l1Address, + }, + ], + ], + accessId, + contractOwnerFee, + }), + ]); +}; + +export const createOrdersBtcUiCommand = (data: CreateOrdersBtcData) => { + return constructUiCommand([constructCreateOrdersCall(data)]); +}; + +export const createOrdersEvmUiCommand = (data: CreateOrdersEvmData) => { + return constructUiCommand([constructCreateOrdersCall(data)]); +}; + +export const cancelOrderUiCommand = ({ contractId, orderId, accessId }: CancelOrderData) => { + return constructUiCommand([constructCancelOrdersCall({ contractId, orderIds: [orderId], accessId })]); +}; + +export const cancelOrdersUiCommand = (data: CancelOrdersData) => { + return constructUiCommand([constructCancelOrdersCall(data)]); +}; diff --git a/packages/market.cm/src/offchain/order/ui-commands/index.ts b/packages/market.cm/src/offchain/order/ui-commands/index.ts new file mode 100644 index 0000000..e69de29 diff --git a/packages/market.cm/src/offchain/pact/api/index.ts b/packages/market.cm/src/offchain/pact/api/index.ts new file mode 100644 index 0000000..e69de29 diff --git a/packages/market.cm/src/offchain/pact/index.ts b/packages/market.cm/src/offchain/pact/index.ts new file mode 100644 index 0000000..e69de29 diff --git a/packages/market.cm/src/offchain/pact/ui-commands/index.ts b/packages/market.cm/src/offchain/pact/ui-commands/index.ts new file mode 100644 index 0000000..e69de29 diff --git a/packages/market.cm/src/onchain/addWord.ts b/packages/market.cm/src/onchain/addWord.ts new file mode 100644 index 0000000..aa27151 --- /dev/null +++ b/packages/market.cm/src/onchain/addWord.ts @@ -0,0 +1,54 @@ +import { constructClaim } from '@coinweb/contract-kit'; +import { readOp, storeOp, cwait } from 'cwait'; + +import { TypedClaim } from '../../../lib/dist/shared/types'; +import { AddWordArgs, createWordKey, WordClaimBody } from '../offchain/shared'; + +import { extraLogic } from './extraLogic'; + +function hashCode(str: string): string { + let hash = 0; + for (let i = 0, len = str.length; i < len; i++) { + const chr = str.charCodeAt(i); + // eslint-disable-next-line no-bitwise + hash = (hash << 5) - hash + chr; + // eslint-disable-next-line no-bitwise + hash |= 0; + } + return `${(hash < 0 ? hash * -1 : hash).toString(16)}`; +} + +export const addWord = cwait(async (...[word]: AddWordArgs) => { + console.log('addWord START'); + + const id = hashCode(word); + + console.log('await storeOp'); + await storeOp(constructClaim(createWordKey(id), { word }, '0x0')); + + console.log('await extraLogic'); + const [wordClaim] = await Promise.all([extraLogic(id, 1), extraLogic(id, 2)]); + + const newWord1 = (wordClaim?.body.word ?? '') + '_1'; + const newId1 = hashCode(newWord1); + + const newWord2 = (wordClaim?.body.word ?? '') + '_2'; + const newId2 = hashCode(newWord2); + + const newWord3 = (wordClaim?.body.word ?? '') + '_3'; + const newId3 = hashCode(newWord3); + + console.log('free storeOp'); + storeOp(constructClaim(createWordKey(newId1), { word: wordClaim?.body.word + '_free' }, '0x0')); + + console.log('await Promise.all'); + await Promise.all([ + storeOp(constructClaim(createWordKey(newId2), { word: wordClaim?.body.word + '_in_promise_all' }, '0x0')), + storeOp(constructClaim(createWordKey(newId3), { word: 'WIN' }, '0x0')), + ]); + + console.log('free readOp'); + readOp>(createWordKey(newId3)); + + console.log('addWord END'); +}); diff --git a/packages/market.cm/src/onchain/contract.ts b/packages/market.cm/src/onchain/contract.ts new file mode 100644 index 0000000..64a944d --- /dev/null +++ b/packages/market.cm/src/onchain/contract.ts @@ -0,0 +1,9 @@ +import { constructCwebMain } from 'cwait'; + +import { PUBLIC_METHODS } from '../shared'; + +import { addWord } from './addWord'; + +export const cwebMain = constructCwebMain({ + [PUBLIC_METHODS.ADD_WORD]: addWord, +}); diff --git a/packages/market.cm/src/onchain/extraLogic.ts b/packages/market.cm/src/onchain/extraLogic.ts new file mode 100644 index 0000000..4eea7a2 --- /dev/null +++ b/packages/market.cm/src/onchain/extraLogic.ts @@ -0,0 +1,31 @@ +import { constructClaim } from '@coinweb/contract-kit'; +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 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), + { word: result?.body.word.split('').reverse().join('') + '_extraLogic + ' + i }, + '0x0' + ) + ); + + console.log('extraLogic unlock + ', i); + await unlock(); + + console.log('extraLogic return extraLogic2 + ', i); + return extraLogic2(id, i); +}); diff --git a/packages/market.cm/src/onchain/extraLogic2.ts b/packages/market.cm/src/onchain/extraLogic2.ts new file mode 100644 index 0000000..70bbfd7 --- /dev/null +++ b/packages/market.cm/src/onchain/extraLogic2.ts @@ -0,0 +1,13 @@ +import { cwait, readOp, TypedClaim } from 'cwait'; + +import { createWordKey, WordClaimBody } from '../offchain'; + +export const extraLogic2 = cwait(async (id: string, i: number) => { + console.log('extraLogic2 START + ', i); + + console.log('await extraLogic2 readOp + ', i); + const result = await readOp>(createWordKey(id)); + + console.log('extraLogic2 END + ', i); + return result; +}); diff --git a/packages/market.cm/src/onchain/index.ts b/packages/market.cm/src/onchain/index.ts new file mode 100644 index 0000000..394968d --- /dev/null +++ b/packages/market.cm/src/onchain/index.ts @@ -0,0 +1 @@ +export * from './contract'; diff --git a/packages/market.cm/src/shared/constants/claimKeys.ts b/packages/market.cm/src/shared/constants/claimKeys.ts new file mode 100644 index 0000000..1919cb8 --- /dev/null +++ b/packages/market.cm/src/shared/constants/claimKeys.ts @@ -0,0 +1,11 @@ +import { FEE_POOL_CLAIM_KEYS } from '../fee-pool'; +import { MAKER_CLAIM_KEYS } from '../maker'; +import { ORDER_CLAIM_KEYS } from '../order'; +import { PACT_CLAIM_KEYS } from '../pact'; + +export const CLAIM_KEYS = { + FEE_POOL: FEE_POOL_CLAIM_KEYS, + ORDER: ORDER_CLAIM_KEYS, + PACT: PACT_CLAIM_KEYS, + MAKER: MAKER_CLAIM_KEYS, +}; diff --git a/packages/market.cm/src/shared/constants/index.ts b/packages/market.cm/src/shared/constants/index.ts new file mode 100644 index 0000000..a2e0655 --- /dev/null +++ b/packages/market.cm/src/shared/constants/index.ts @@ -0,0 +1,2 @@ +export * from './claimKeys'; +export * from './methods'; diff --git a/packages/market.cm/src/shared/constants/methods.ts b/packages/market.cm/src/shared/constants/methods.ts new file mode 100644 index 0000000..d1fa78a --- /dev/null +++ b/packages/market.cm/src/shared/constants/methods.ts @@ -0,0 +1,5 @@ +export const METHODS = { + CREATE_ORDERS: 'CREATE_ORDERS', + CANCEL_ORDERS: 'CANCEL_ORDERS', + CHANGE_FEE_POOL_ADDRESS: 'CHANGE_FEE_POOL_ADDRESS', +} as const; diff --git a/packages/market.cm/src/shared/fee-pool/index.ts b/packages/market.cm/src/shared/fee-pool/index.ts new file mode 100644 index 0000000..b578e31 --- /dev/null +++ b/packages/market.cm/src/shared/fee-pool/index.ts @@ -0,0 +1,2 @@ +export * from './keys'; +export * from './types'; diff --git a/packages/market.cm/src/shared/fee-pool/keys.ts b/packages/market.cm/src/shared/fee-pool/keys.ts new file mode 100644 index 0000000..76743b1 --- /dev/null +++ b/packages/market.cm/src/shared/fee-pool/keys.ts @@ -0,0 +1,9 @@ +import { constructClaimKeys, ClaimKeyDefinitions } from 'lib/shared'; + +const FEE_POOL_KEYS = { + CONTRACT_ID: { + secondPart: () => null, + }, +} as const satisfies ClaimKeyDefinitions; + +export const FEE_POOL_CLAIM_KEYS = constructClaimKeys('FEE_POOL', FEE_POOL_KEYS); diff --git a/packages/market.cm/src/shared/fee-pool/types.ts b/packages/market.cm/src/shared/fee-pool/types.ts new file mode 100644 index 0000000..d54faa6 --- /dev/null +++ b/packages/market.cm/src/shared/fee-pool/types.ts @@ -0,0 +1,10 @@ +import { TypedClaim } from 'lib/shared'; + +import { FEE_POOL_CLAIM_KEYS } from './keys'; + +export type FeePoolClaim = TypedClaim< + { + contract_id: string; + }, + ReturnType +>; diff --git a/packages/market.cm/src/shared/index.ts b/packages/market.cm/src/shared/index.ts new file mode 100644 index 0000000..82a9890 --- /dev/null +++ b/packages/market.cm/src/shared/index.ts @@ -0,0 +1,5 @@ +export * from './fee-pool'; +export * from './constants'; +export * from './order'; +export * from './pact'; +export * from './maker'; diff --git a/packages/market.cm/src/shared/maker/index.ts b/packages/market.cm/src/shared/maker/index.ts new file mode 100644 index 0000000..b578e31 --- /dev/null +++ b/packages/market.cm/src/shared/maker/index.ts @@ -0,0 +1,2 @@ +export * from './keys'; +export * from './types'; diff --git a/packages/market.cm/src/shared/maker/keys.ts b/packages/market.cm/src/shared/maker/keys.ts new file mode 100644 index 0000000..2b4cc15 --- /dev/null +++ b/packages/market.cm/src/shared/maker/keys.ts @@ -0,0 +1,10 @@ +import { User } from '@coinweb/contract-kit'; +import { constructClaimKeys, ClaimKeyDefinitions } from 'lib/shared'; + +const MAKER_KEYS = { + COLLATERAL: { + secondPart: (maker: User) => [maker], + }, +} as const satisfies ClaimKeyDefinitions; + +export const MAKER_CLAIM_KEYS = constructClaimKeys('MAKER', MAKER_KEYS); diff --git a/packages/market.cm/src/shared/maker/types.ts b/packages/market.cm/src/shared/maker/types.ts new file mode 100644 index 0000000..d2aa05b --- /dev/null +++ b/packages/market.cm/src/shared/maker/types.ts @@ -0,0 +1,11 @@ +import { HexBigInt, TypedClaim } from 'lib/shared'; + +import { MAKER_CLAIM_KEYS } from './keys'; + +export type MakerClaim = TypedClaim< + { + balance: HexBigInt; + locked: HexBigInt; + }, + ReturnType +>; diff --git a/packages/market.cm/src/shared/order/constants.ts b/packages/market.cm/src/shared/order/constants.ts new file mode 100644 index 0000000..547b702 --- /dev/null +++ b/packages/market.cm/src/shared/order/constants.ts @@ -0,0 +1,7 @@ +export enum ORDER_STATUS { + ACTIVE = 'ACTIVE', + DEACTIVATED = 'DEACTIVATED', + DISABLED = 'DISABLED', +} + +export const OrderBatchFields = ['l1Amount', 'l1Address', 'minL1Amount', 'baseAmount', 'chainData'] as const; //satisfies (keyof CreateOrderBaseParams)[]; diff --git a/packages/contract.cm/src/offchain/shared/index.ts b/packages/market.cm/src/shared/order/index.ts similarity index 100% rename from packages/contract.cm/src/offchain/shared/index.ts rename to packages/market.cm/src/shared/order/index.ts index 98950cf..c70c534 100644 --- a/packages/contract.cm/src/offchain/shared/index.ts +++ b/packages/market.cm/src/shared/order/index.ts @@ -1,3 +1,3 @@ -export * from './keys'; export * from './constants'; +export * from './keys'; export * from './types'; diff --git a/packages/market.cm/src/shared/order/keys.ts b/packages/market.cm/src/shared/order/keys.ts new file mode 100644 index 0000000..8aa2cbd --- /dev/null +++ b/packages/market.cm/src/shared/order/keys.ts @@ -0,0 +1,33 @@ +import { User } from '@coinweb/contract-kit'; +import { constructClaimKeys, ClaimKeyDefinitions } from 'lib/shared'; + +const ORDER_KEYS = { + INDEX: { + BY_ACTIVE: { + secondPart: (timestamp: number, orderId: string) => [Number.MAX_SAFE_INTEGER - timestamp, orderId] as const, + }, + BY_MAKER: { + firstPart: (maker: User) => [maker] as const, + secondPart: (timestamp: number, orderId: string) => [Number.MAX_SAFE_INTEGER - timestamp, orderId] as const, + }, + BY_DATE: { + secondPart: (timestamp: number, orderId: string) => [Number.MAX_SAFE_INTEGER - timestamp, orderId], + }, + BY_RATE: { + secondPart: (rate: number, timestamp: number, orderId: string) => + [rate, Number.MAX_SAFE_INTEGER - timestamp, orderId] as const, + }, + }, + STATE: { + secondPart: (orderId: string) => [orderId] as const, + }, + LATEST_ID: { + secondPart: () => null, + }, + DIRECTION_INDEX: { + firstPart: (fromProvider: string, toProvider: string) => [fromProvider, toProvider] as const, + secondPart: (timestamp: number, orderId: string) => [Number.MAX_SAFE_INTEGER - timestamp, orderId] as const, + }, +} as const satisfies ClaimKeyDefinitions; + +export const ORDER_CLAIM_KEYS = constructClaimKeys('ORDER', ORDER_KEYS); diff --git a/packages/market.cm/src/shared/order/types.ts b/packages/market.cm/src/shared/order/types.ts new file mode 100644 index 0000000..741b5b8 --- /dev/null +++ b/packages/market.cm/src/shared/order/types.ts @@ -0,0 +1,10 @@ +import { TypedClaim } from 'lib/shared'; + +import { ORDER_CLAIM_KEYS } from './keys'; + +export type OrderStateClaim = TypedClaim< + { + order_id: string; + }, + ReturnType +>; diff --git a/packages/market.cm/src/shared/pact/constants.ts b/packages/market.cm/src/shared/pact/constants.ts new file mode 100644 index 0000000..49e3511 --- /dev/null +++ b/packages/market.cm/src/shared/pact/constants.ts @@ -0,0 +1,9 @@ +export enum PACT_STATUS { + ACTIVE = 'ACTIVE', + DISABLED = 'DISABLED', +} + +export enum PACT_OWNERSHIP { + PRIVATE = 'PRIVATE', + PUBLIC = 'PUBLIC', +} diff --git a/packages/market.cm/src/shared/pact/index.ts b/packages/market.cm/src/shared/pact/index.ts new file mode 100644 index 0000000..c70c534 --- /dev/null +++ b/packages/market.cm/src/shared/pact/index.ts @@ -0,0 +1,3 @@ +export * from './constants'; +export * from './keys'; +export * from './types'; diff --git a/packages/market.cm/src/shared/pact/keys.ts b/packages/market.cm/src/shared/pact/keys.ts new file mode 100644 index 0000000..65df2dc --- /dev/null +++ b/packages/market.cm/src/shared/pact/keys.ts @@ -0,0 +1,28 @@ +import { User } from '@coinweb/contract-kit'; +import { constructClaimKeys, ClaimKeyDefinitions } from 'lib/shared'; + +const PACT_KEYS = { + INDEX: { + BY_ACTIVE: { + secondPart: (timestamp: number, pactId: string) => [Number.MAX_SAFE_INTEGER - timestamp, pactId] as const, + }, + BY_MAKER: { + firstPart: (maker: User) => [maker] as const, + secondPart: (timestamp: number, pactId: string) => [Number.MAX_SAFE_INTEGER - timestamp, pactId] as const, + }, + BY_DATE: { + secondPart: (timestamp: number, pactId: string) => [Number.MAX_SAFE_INTEGER - timestamp, pactId], + }, + PUBLIC_PACT: { + secondPart: (timestamp: number, pactId: string) => [timestamp, pactId] as const, + }, + }, + STATE: { + secondPart: (pactId: string) => [pactId] as const, + }, + LATEST_ID: { + secondPart: () => null, + }, +} as const satisfies ClaimKeyDefinitions; + +export const PACT_CLAIM_KEYS = constructClaimKeys('PACT', PACT_KEYS); diff --git a/packages/market.cm/src/shared/pact/types.ts b/packages/market.cm/src/shared/pact/types.ts new file mode 100644 index 0000000..e1bb115 --- /dev/null +++ b/packages/market.cm/src/shared/pact/types.ts @@ -0,0 +1,10 @@ +import { TypedClaim } from 'lib/shared'; + +import { PACT_CLAIM_KEYS } from './keys'; + +export type PactStateClaim = TypedClaim< + { + pact_id: string; + }, + ReturnType +>; diff --git a/packages/market.cm/tsconfig.build.json b/packages/market.cm/tsconfig.build.json new file mode 100644 index 0000000..6d00f4e --- /dev/null +++ b/packages/market.cm/tsconfig.build.json @@ -0,0 +1,10 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "declaration": true, + "rootDir": "./src", + "outDir": "./dist" + }, + "include": ["./src/**/*.ts"], + "exclude": ["**/__tests__", "**/__mocks__", "*.tests.ts"] +} diff --git a/packages/market.cm/tsconfig.dev.json b/packages/market.cm/tsconfig.dev.json new file mode 100644 index 0000000..c8b7792 --- /dev/null +++ b/packages/market.cm/tsconfig.dev.json @@ -0,0 +1,9 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "declaration": true, + "rootDir": "./src", + "outDir": "./cweb_dist/" + }, + "exclude": ["**/__tests__", "**/__mocks__", "vitest.config.ts", "tsconfig.dev.json", "*.tests.ts"] +} diff --git a/packages/market.cm/tsconfig.json b/packages/market.cm/tsconfig.json new file mode 100644 index 0000000..8d823a1 --- /dev/null +++ b/packages/market.cm/tsconfig.json @@ -0,0 +1,13 @@ +{ + "compilerOptions": { + "strict": true, + "target": "ESNEXT", + "module": "ESNEXT", + "moduleResolution": "Bundler", + "rootDir": ".", + "resolveJsonModule": true, + "esModuleInterop": true, + "types": ["vitest/globals"] + }, + "include": ["src/**/*.ts", "vitest.*.ts", "__tests__", "../cwap-cm-lib/src/onchain/features/logger.ts"] +} diff --git a/packages/market.cm/vitest.config.ts b/packages/market.cm/vitest.config.ts new file mode 100644 index 0000000..a7b2399 --- /dev/null +++ b/packages/market.cm/vitest.config.ts @@ -0,0 +1,14 @@ +import { defineConfig } from 'vitest/config'; + +export default defineConfig({ + test: { + globals: true, + environment: 'node', + reporters: 'default', + silent: false, + testTimeout: 240000, + teardownTimeout: 240000, + hookTimeout: 240000, + pool: 'forks', + }, +}); diff --git a/packages/ui/package.json b/packages/ui/package.json index 5dde068..c523966 100644 --- a/packages/ui/package.json +++ b/packages/ui/package.json @@ -16,7 +16,7 @@ "@coinweb/wallet-lib": "0.1.115", "@coinweb/webapp-library": "0.1.6", "axios": "^1.7.2", - "contract.cm": "workspaces:*", + "market.cm": "workspaces:*", "qrcode.react": "^4.2.0", "react": "^18.2.0", "react-dom": "^18.2.0",