From 7c735bf9b16ede73333345a8de3da3c09b6d7f36 Mon Sep 17 00:00:00 2001 From: vladilen11 Date: Sun, 10 Sep 2023 21:01:38 +0800 Subject: [PATCH 01/16] upgrade sui.js to 0.41.0 --- packages/client/package.json | 4 +- packages/client/scripts/init.ts | 3 +- packages/client/src/index.ts | 1 - .../src/libs/suiAccountManager/index.ts | 2 +- .../src/libs/suiAccountManager/keypair.ts | 2 +- .../src/libs/suiAccountManager/types.ts | 10 - .../src/libs/suiContractFactory/index.ts | 1 - .../defaultConfig.ts} | 6 +- .../client/src/libs/suiInteractor/index.ts | 2 + .../src/libs/suiInteractor/suiInteractor.ts | 269 ++++++++++++++++++ .../client/src/libs/suiInteractor/util.ts | 2 + packages/client/src/libs/suiModel/index.ts | 2 + .../src/libs/suiModel/suiOwnedObject.ts | 62 ++++ .../src/libs/suiModel/suiSharedObject.ts | 33 +++ .../client/src/libs/suiRpcProvider/faucet.ts | 57 ---- .../client/src/libs/suiRpcProvider/index.ts | 150 ---------- .../client/src/libs/suiRpcProvider/types.ts | 17 -- .../client/src/libs/suiTxBuilder/index.ts | 2 +- .../client/src/libs/suiTxBuilder/types.ts | 32 --- packages/client/src/libs/suiTxBuilder/util.ts | 2 +- packages/client/src/metadata/index.ts | 14 +- packages/client/src/obelisk.ts | 164 +++-------- packages/client/src/types/index.ts | 102 ++++++- packages/client/yarn.lock | 44 +-- 24 files changed, 524 insertions(+), 459 deletions(-) delete mode 100644 packages/client/src/libs/suiAccountManager/types.ts rename packages/client/src/libs/{suiRpcProvider/defaultChainConfigs.ts => suiInteractor/defaultConfig.ts} (76%) create mode 100644 packages/client/src/libs/suiInteractor/index.ts create mode 100644 packages/client/src/libs/suiInteractor/suiInteractor.ts create mode 100644 packages/client/src/libs/suiInteractor/util.ts create mode 100644 packages/client/src/libs/suiModel/index.ts create mode 100644 packages/client/src/libs/suiModel/suiOwnedObject.ts create mode 100644 packages/client/src/libs/suiModel/suiSharedObject.ts delete mode 100644 packages/client/src/libs/suiRpcProvider/faucet.ts delete mode 100644 packages/client/src/libs/suiRpcProvider/index.ts delete mode 100644 packages/client/src/libs/suiRpcProvider/types.ts delete mode 100644 packages/client/src/libs/suiTxBuilder/types.ts diff --git a/packages/client/package.json b/packages/client/package.json index 54904843..47a59774 100644 --- a/packages/client/package.json +++ b/packages/client/package.json @@ -58,7 +58,7 @@ }, "dependencies": { "@mysten/bcs": "^0.7.3", - "@mysten/sui.js": "^0.37.1", + "@mysten/sui.js": "^0.41.0", "@obelisk/common": "link:../common", "@scure/bip39": "^1.2.1", "assert": "^2.0.0", @@ -71,7 +71,7 @@ "ts-retry-promise": "^0.7.0" }, "peerDependencies": { - "@mysten/sui.js": "^0.37.1" + "@mysten/sui.js": "^0.41.0" }, "devDependencies": { "@commitlint/cli": "^17.6.6", diff --git a/packages/client/scripts/init.ts b/packages/client/scripts/init.ts index ab35d9f7..2d34eb51 100644 --- a/packages/client/scripts/init.ts +++ b/packages/client/scripts/init.ts @@ -59,7 +59,8 @@ async function init() { console.log(JSON.stringify(data1)) let content = data1.data!.content as data; console.log(content.fields.value.fields.value); - + // await obelisk.getBalance() + await obelisk.requestFaucet("0x1804b821bba181110599b8757008eabe6f89f62774d7fafb5ee666ac742a41f8", "devnet"); // let ownerdObjects = await obelisk.getOwnedEntities("0x1804b821bba181110599b8757008eabe6f89f62774d7fafb5ee666ac742a41f8") // console.log(ownerdObjects) diff --git a/packages/client/src/index.ts b/packages/client/src/index.ts index 2a999bc4..c2585a79 100644 --- a/packages/client/src/index.ts +++ b/packages/client/src/index.ts @@ -6,7 +6,6 @@ export { export { Obelisk } from './obelisk'; export { SuiAccountManager } from './libs/suiAccountManager'; export { SuiTxBlock } from './libs/suiTxBuilder'; -export { SuiRpcProvider } from './libs/suiRpcProvider'; export { SuiContractFactory } from './libs/suiContractFactory'; export { getMetadata } from './metadata'; export type * from './types'; diff --git a/packages/client/src/libs/suiAccountManager/index.ts b/packages/client/src/libs/suiAccountManager/index.ts index e3f4f778..fe45482a 100644 --- a/packages/client/src/libs/suiAccountManager/index.ts +++ b/packages/client/src/libs/suiAccountManager/index.ts @@ -2,7 +2,7 @@ import { Ed25519Keypair } from '@mysten/sui.js'; import { getKeyPair } from './keypair'; import { hexOrBase64ToUint8Array, normalizePrivateKey } from './util'; import { generateMnemonic } from './crypto'; -import type { AccountMangerParams, DerivePathParams } from './types'; +import type { AccountMangerParams, DerivePathParams } from 'src/types'; export class SuiAccountManager { private mnemonics: string; diff --git a/packages/client/src/libs/suiAccountManager/keypair.ts b/packages/client/src/libs/suiAccountManager/keypair.ts index 340cf065..e7b1d626 100644 --- a/packages/client/src/libs/suiAccountManager/keypair.ts +++ b/packages/client/src/libs/suiAccountManager/keypair.ts @@ -1,5 +1,5 @@ import { Ed25519Keypair } from '@mysten/sui.js'; -import type { DerivePathParams } from './types'; +import type { DerivePathParams } from 'src/types'; /** * @description Get ed25519 derive path for SUI diff --git a/packages/client/src/libs/suiAccountManager/types.ts b/packages/client/src/libs/suiAccountManager/types.ts deleted file mode 100644 index 24c90ad3..00000000 --- a/packages/client/src/libs/suiAccountManager/types.ts +++ /dev/null @@ -1,10 +0,0 @@ -export type AccountMangerParams = { - mnemonics?: string; - secretKey?: string; -}; - -export type DerivePathParams = { - accountIndex?: number; - isExternal?: boolean; - addressIndex?: number; -}; diff --git a/packages/client/src/libs/suiContractFactory/index.ts b/packages/client/src/libs/suiContractFactory/index.ts index a65d915b..258ca03e 100644 --- a/packages/client/src/libs/suiContractFactory/index.ts +++ b/packages/client/src/libs/suiContractFactory/index.ts @@ -88,7 +88,6 @@ export class SuiContractFactory { } ); } - async worldCall() {} // async call(arguments: ({ // kind: "Input"; diff --git a/packages/client/src/libs/suiRpcProvider/defaultChainConfigs.ts b/packages/client/src/libs/suiInteractor/defaultConfig.ts similarity index 76% rename from packages/client/src/libs/suiRpcProvider/defaultChainConfigs.ts rename to packages/client/src/libs/suiInteractor/defaultConfig.ts index 82e5d583..0b7feb18 100644 --- a/packages/client/src/libs/suiRpcProvider/defaultChainConfigs.ts +++ b/packages/client/src/libs/suiInteractor/defaultConfig.ts @@ -5,14 +5,16 @@ import { mainnetConnection, } from '@mysten/sui.js'; import type { Connection } from '@mysten/sui.js'; -import type { NetworkType } from './types'; +import type { NetworkType } from 'src/types'; +export const defaultGasBudget = 10 ** 8; // 0.1 SUI, should be enough for most of the transactions +export const defaultGasPrice = 1000; // 1000 MIST /** * @description Get the default fullnode url and faucet url for the given network type * @param networkType, 'testnet' | 'mainnet' | 'devnet' | 'localnet', default is 'devnet' * @returns { fullNode: string, websocket: string, faucet?: string } */ -export const getDefaultNetworkParams = ( +export const getDefaultConnection = ( networkType: NetworkType = 'devnet' ): Connection => { switch (networkType) { diff --git a/packages/client/src/libs/suiInteractor/index.ts b/packages/client/src/libs/suiInteractor/index.ts new file mode 100644 index 00000000..6b1f98ad --- /dev/null +++ b/packages/client/src/libs/suiInteractor/index.ts @@ -0,0 +1,2 @@ +export { SuiInteractor } from './suiInteractor'; +export { getDefaultConnection } from './defaultConfig'; diff --git a/packages/client/src/libs/suiInteractor/suiInteractor.ts b/packages/client/src/libs/suiInteractor/suiInteractor.ts new file mode 100644 index 00000000..999951fe --- /dev/null +++ b/packages/client/src/libs/suiInteractor/suiInteractor.ts @@ -0,0 +1,269 @@ +import { + SuiTransactionBlockResponse, + SuiTransactionBlockResponseOptions, + JsonRpcProvider, + Connection, + getObjectDisplay, + getObjectFields, + getObjectId, + getObjectType, + getObjectVersion, + getSharedObjectInitialVersion, + DynamicFieldName, + SuiAddress +} from '@mysten/sui.js'; +import { requestSuiFromFaucetV0, getFaucetHost } from '@mysten/sui.js/faucet'; +import { SuiClient, getFullnodeUrl, GetBalanceParams } from '@mysten/sui.js/client'; +import { FaucetNetworkType, NetworkType, ObjectData } from 'src/types'; +import { SuiOwnedObject, SuiSharedObject } from '../suiModel'; +import { delay } from './util'; + +/** + * `SuiTransactionSender` is used to send transaction with a given gas coin. + * It always uses the gas coin to pay for the gas, + * and update the gas coin after the transaction. + */ +export class SuiInteractor { + public readonly providers: JsonRpcProvider[]; + public currentProvider: JsonRpcProvider; + public network?: NetworkType; + + constructor(fullNodeUrls: string[], network?: NetworkType) { + if (fullNodeUrls.length === 0) + throw new Error('fullNodeUrls must not be empty'); + this.providers = fullNodeUrls.map( + (url) => new JsonRpcProvider(new Connection({ fullnode: url })) + ); + this.currentProvider = this.providers[0]; + this.network = network; + } + + switchToNextProvider() { + const currentProviderIdx = this.providers.indexOf(this.currentProvider); + this.currentProvider = + this.providers[(currentProviderIdx + 1) % this.providers.length]; + } + + async sendTx( + transactionBlock: Uint8Array | string, + signature: string | string[] + ): Promise { + const txResOptions: SuiTransactionBlockResponseOptions = { + showEvents: true, + showEffects: true, + showObjectChanges: true, + showBalanceChanges: true, + }; + + // const currentProviderIdx = this.providers.indexOf(this.currentProvider); + // const providers = [ + // ...this.providers.slice(currentProviderIdx, this.providers.length), + // ...this.providers.slice(0, currentProviderIdx), + // ] + + for (const provider of this.providers) { + try { + const res = await provider.executeTransactionBlock({ + transactionBlock, + signature, + options: txResOptions, + }); + return res; + } catch (err) { + console.warn( + `Failed to send transaction with fullnode ${provider.connection.fullnode}: ${err}` + ); + await delay(2000); + } + } + throw new Error('Failed to send transaction with all fullnodes'); + } + async getObjects(ids: string[]) { + const options = { + showContent: true, + showDisplay: true, + showType: true, + showOwner: true, + }; + + // const currentProviderIdx = this.providers.indexOf(this.currentProvider); + // const providers = [ + // ...this.providers.slice(currentProviderIdx, this.providers.length), + // ...this.providers.slice(0, currentProviderIdx), + // ] + + for (const provider of this.providers) { + try { + const objects = await provider.multiGetObjects({ ids, options }); + const parsedObjects = objects.map((object) => { + const objectId = getObjectId(object); + const objectType = getObjectType(object); + const objectVersion = getObjectVersion(object); + const objectDigest = object.data ? object.data.digest : undefined; + const initialSharedVersion = getSharedObjectInitialVersion(object); + const objectFields = getObjectFields(object); + const objectDisplay = getObjectDisplay(object); + return { + objectId, + objectType, + objectVersion, + objectDigest, + objectFields, + objectDisplay, + initialSharedVersion, + }; + }); + return parsedObjects as ObjectData[]; + } catch (err) { + await delay(2000); + console.warn( + `Failed to get objects with fullnode ${provider.connection.fullnode}: ${err}` + ); + } + } + throw new Error('Failed to get objects with all fullnodes'); + } + + async getObject(id: string) { + const objects = await this.getObjects([id]); + return objects[0]; + } + + + async getDynamicFieldObject(parentId: string, name: string | DynamicFieldName) { + for (const provider of this.providers) { + try { + return provider.getDynamicFieldObject({ parentId, name }) + } catch (err) { + await delay(2000); + console.warn( + `Failed to get objects with fullnode ${provider.connection.fullnode}: ${err}` + ); + } + } + throw new Error('Failed to get objects with all fullnodes'); + } + + async getDynamicFields(parentId: string, cursor?: string, limit?: number) { + for (const provider of this.providers) { + try { + return provider.getDynamicFields({ parentId, cursor, limit }) + } catch (err) { + await delay(2000); + console.warn( + `Failed to get objects with fullnode ${provider.connection.fullnode}: ${err}` + ); + } + } + throw new Error('Failed to get objects with all fullnodes'); + } + + async getOwnedObjects(owner: SuiAddress, cursor?: string, limit?: number) { + for (const provider of this.providers) { + try { + return await provider.getOwnedObjects({ owner, cursor, limit }); + } catch (err) { + await delay(2000); + console.warn( + `Failed to get objects with fullnode ${provider.connection.fullnode}: ${err}` + ); + } + } + throw new Error('Failed to get objects with all fullnodes'); + } + + + async getNormalizedMoveModulesByPackage(packageId: string) { + for (const provider of this.providers) { + try { + return provider.getNormalizedMoveModulesByPackage({package: packageId}); + + } catch (err) { + await delay(2000); + console.warn( + `Failed to get objects with fullnode ${provider.connection.fullnode}: ${err}` + ); + } + } + throw new Error('Failed to get objects with all fullnodes'); + } + + /** + * @description Update objects in a batch + * @param suiObjects + */ + async updateObjects(suiObjects: (SuiOwnedObject | SuiSharedObject)[]) { + const objectIds = suiObjects.map((obj) => obj.objectId); + const objects = await this.getObjects(objectIds); + for (const object of objects) { + const suiObject = suiObjects.find( + (obj) => obj.objectId === object.objectId + ); + if (suiObject instanceof SuiSharedObject) { + suiObject.initialSharedVersion = object.initialSharedVersion; + } else if (suiObject instanceof SuiOwnedObject) { + suiObject.version = object.objectVersion; + suiObject.digest = object.objectDigest; + } + } + } + + /** + * @description Select coins that add up to the given amount. + * @param addr the address of the owner + * @param amount the amount that is needed for the coin + * @param coinType the coin type, default is '0x2::SUI::SUI' + */ + async selectCoins( + addr: string, + amount: number, + coinType: string = '0x2::SUI::SUI' + ) { + const selectedCoins: { + objectId: string; + digest: string; + version: string; + }[] = []; + let totalAmount = 0; + let hasNext = true, + nextCursor: string | null = null; + while (hasNext && totalAmount < amount) { + const coins = await this.currentProvider.getCoins({ + owner: addr, + coinType: coinType, + cursor: nextCursor, + }); + // Sort the coins by balance in descending order + coins.data.sort((a, b) => parseInt(b.balance) - parseInt(a.balance)); + for (const coinData of coins.data) { + selectedCoins.push({ + objectId: coinData.coinObjectId, + digest: coinData.digest, + version: coinData.version, + }); + totalAmount = totalAmount + parseInt(coinData.balance); + if (totalAmount >= amount) { + break; + } + } + + nextCursor = coins.nextCursor; + hasNext = coins.hasNextPage; + } + + if (!selectedCoins.length) { + throw new Error('No valid coins found for the transaction.'); + } + return selectedCoins; + } + + async requestFaucet(address: SuiAddress, network: FaucetNetworkType) { + await requestSuiFromFaucetV0({ + host: getFaucetHost(network), + recipient: address, + }); + // let params = { + // owner: address + // } as GetBalanceParams; + } +} diff --git a/packages/client/src/libs/suiInteractor/util.ts b/packages/client/src/libs/suiInteractor/util.ts new file mode 100644 index 00000000..59216636 --- /dev/null +++ b/packages/client/src/libs/suiInteractor/util.ts @@ -0,0 +1,2 @@ +export const delay = (ms: number) => + new Promise((resolve) => setTimeout(resolve, ms)); diff --git a/packages/client/src/libs/suiModel/index.ts b/packages/client/src/libs/suiModel/index.ts new file mode 100644 index 00000000..02a5b72c --- /dev/null +++ b/packages/client/src/libs/suiModel/index.ts @@ -0,0 +1,2 @@ +export { SuiOwnedObject } from './suiOwnedObject'; +export { SuiSharedObject } from './suiSharedObject'; diff --git a/packages/client/src/libs/suiModel/suiOwnedObject.ts b/packages/client/src/libs/suiModel/suiOwnedObject.ts new file mode 100644 index 00000000..547c6c4c --- /dev/null +++ b/packages/client/src/libs/suiModel/suiOwnedObject.ts @@ -0,0 +1,62 @@ +import { Infer } from 'superstruct'; +import { + getObjectChanges, + SuiTransactionBlockResponse, + ObjectCallArg, + ObjectId, +} from '@mysten/sui.js'; + +export class SuiOwnedObject { + public readonly objectId: string; + public version?: number | string; + public digest?: string; + + constructor(param: { objectId: string; version?: string; digest?: string }) { + this.objectId = param.objectId; + this.version = param.version; + this.digest = param.digest; + } + + /** + * Check if the object is fully initialized. + * So that when it's used as an input, it won't be necessary to fetch from fullnode again. + * Which can save time when sending transactions. + */ + isFullObject(): boolean { + return !!this.version && !!this.digest; + } + + asCallArg(): Infer | Infer { + if (!this.version || !this.digest) { + return this.objectId; + } + return { + Object: { + ImmOrOwned: { + objectId: this.objectId, + version: this.version, + digest: this.digest, + }, + }, + }; + } + + /** + * Update object version & digest based on the transaction response. + * @param txResponse + */ + updateFromTxResponse(txResponse: SuiTransactionBlockResponse) { + const changes = getObjectChanges(txResponse); + if (!changes) { + throw new Error('Bad transaction response!'); + } + for (const change of changes) { + if (change.type === 'mutated' && change.objectId === this.objectId) { + this.digest = change.digest; + this.version = change.version; + return; + } + } + throw new Error('Could not find object in transaction response!'); + } +} diff --git a/packages/client/src/libs/suiModel/suiSharedObject.ts b/packages/client/src/libs/suiModel/suiSharedObject.ts new file mode 100644 index 00000000..698f60f5 --- /dev/null +++ b/packages/client/src/libs/suiModel/suiSharedObject.ts @@ -0,0 +1,33 @@ +import { Infer } from 'superstruct'; +import { ObjectCallArg, ObjectId } from '@mysten/sui.js'; + +export class SuiSharedObject { + public readonly objectId: string; + public initialSharedVersion?: number | string; + + constructor(param: { + objectId: string; + initialSharedVersion?: number; + mutable?: boolean; + }) { + this.objectId = param.objectId; + this.initialSharedVersion = param.initialSharedVersion; + } + + asCallArg( + mutable: boolean = false + ): Infer | Infer { + if (!this.initialSharedVersion) { + return this.objectId; + } + return { + Object: { + Shared: { + objectId: this.objectId, + initialSharedVersion: this.initialSharedVersion, + mutable, + }, + }, + }; + } +} diff --git a/packages/client/src/libs/suiRpcProvider/faucet.ts b/packages/client/src/libs/suiRpcProvider/faucet.ts deleted file mode 100644 index e27ade40..00000000 --- a/packages/client/src/libs/suiRpcProvider/faucet.ts +++ /dev/null @@ -1,57 +0,0 @@ -import { - JsonRpcProvider, - FaucetRateLimitError, - assert, - FaucetResponse, -} from '@mysten/sui.js'; -import { retry } from 'ts-retry-promise'; - -/** - * Request some SUI from faucet - * @param address - * @param provider - * @returns {Promise}, return true if the request is successful - */ -export const requestFaucet = async ( - address: string, - provider: JsonRpcProvider -) => { - console.log('\nRequesting SUI from faucet for address: ', address); - const headers = { - authority: 'faucet.testnet.sui.io', - method: 'POST', - path: '/gas', - scheme: 'https', - accept: '*/*', - 'accept-encoding': 'gzip, deflate, br', - 'accept-language': 'zh-CN,zh;q=0.9,en;q=0.8,ja;q=0.7', - 'content-length': '105', - 'content-type': 'application/json', - origin: 'chrome-extension://opcgpfmipidbgpenhmajoajpbobppdil', - cookie: - '_ga=GA1.1.2092533979.1664032306; sui_io_cookie={"level":["necessary","analytics"],"revision":0,"data":null,"rfc_cookie":false}; _ga_YKP53WJMB0=GS1.1.1680531285.31.0.1680531334.11.0.0; _ga_0GW4F97GFL=GS1.1.1680826187.125.0.1680826187.60.0.0; __cf_bm=6rPjXUwuzUPy4yDlZuXgDj0v7xLPpUd5z0CFGCoN_YI-1680867579-0-AZMhU7/mKUUbUlOa27LmfW6eIFkBkXsPKqYgWjpjWpj2XzDckgUsRu/pxSRGfvXCspn3w7Df+uO1MR/b+XikJU0=; _cfuvid=zjwCXMmu19KBIVo_L9Qbq4TqFXJpophG3.EvFTxqdf4-1680867579342-0-604800000', - 'sec-ch-ua': - '"Google Chrome";v="111", "Not(A:Brand";v="8", "Chromium";v="111"', - 'sec-ch-ua-mobile': '?0', - 'sec-ch-ua-platform': 'macOS', - 'sec-fetch-dest': 'empty', - 'sec-fetch-mode': 'cors', - 'sec-fetch-site': 'none', - 'user-agent': - 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/111.0.0.0 Safari/537.36', - }; - // We need to add the following headers to the request, otherwise the request will be rejected by the faucet server - const resp = await retry( - () => provider.requestSuiFromFaucet(address, headers), - { - backoff: 'EXPONENTIAL', - // overall timeout in 60 seconds - timeout: 1000 * 60, - // skip retry if we hit the rate-limit error - retryIf: (error: any) => !(error instanceof FaucetRateLimitError), - logger: (msg) => console.warn(`Retry requesting faucet: ${msg}`), - } - ); - assert(resp, FaucetResponse, 'Request faucet failed\n'); - console.log('Request faucet success\n'); -}; diff --git a/packages/client/src/libs/suiRpcProvider/index.ts b/packages/client/src/libs/suiRpcProvider/index.ts deleted file mode 100644 index 1dad70a4..00000000 --- a/packages/client/src/libs/suiRpcProvider/index.ts +++ /dev/null @@ -1,150 +0,0 @@ -import { - Connection, - JsonRpcProvider, - getObjectType, - getObjectId, - getObjectFields, - getObjectDisplay, - getObjectVersion, - DynamicFieldName, - SuiAddress -} from '@mysten/sui.js'; -import { requestFaucet } from './faucet'; -import { getDefaultNetworkParams } from './defaultChainConfigs'; -import type { ObjectData, SuiRpcProviderParams } from './types'; - -export class SuiRpcProvider { - public fullnodeUrl: string; - public faucetUrl?: string; - public provider: JsonRpcProvider; - /** - * - * @param networkType, 'testnet' | 'mainnet' | 'devnet' | 'localnet', default is 'devnet' - * @param fullnodeUrl, the fullnode url, default is the preconfig fullnode url for the given network type - * @param faucetUrl, the faucet url, default is the preconfig faucet url for the given network type - */ - constructor({ - fullnodeUrl, - faucetUrl, - networkType, - }: SuiRpcProviderParams = {}) { - // Get the default fullnode url and faucet url for the given network type, default is 'testnet' - const defaultNetworkParams = getDefaultNetworkParams( - networkType || 'devnet' - ); - // Set fullnodeUrl and faucetUrl, if they are not provided, use the default value. - this.fullnodeUrl = fullnodeUrl || defaultNetworkParams.fullnode; - this.faucetUrl = faucetUrl || defaultNetworkParams.faucet; - - // Init the provider - const connection = new Connection({ - fullnode: this.fullnodeUrl, - faucet: this.faucetUrl, - }); - this.provider = new JsonRpcProvider(connection); - } - - /** - * Request some SUI from faucet - * @Returns {Promise}, true if the request is successful, false otherwise. - */ - async requestFaucet(addr: string) { - return requestFaucet(addr, this.provider); - } - - async getBalance(addr: string, coinType?: string) { - return this.provider.getBalance({ owner: addr, coinType }); - } - - - async getDynamicFieldObject(parentId: string, name: string | DynamicFieldName) { - return this.provider.getDynamicFieldObject({ parentId, name }) - } - - async getDynamicFields(parentId: string, cursor?: string, limit?: number) { - return this.provider.getDynamicFields({ parentId, cursor, limit }) - } - - async getOwnedObjects(owner: SuiAddress, cursor?: string, limit?: number) { - return await this.provider.getOwnedObjects({ owner, cursor, limit }); - } - - async getObject(id: string) { - const options = { showContent: true, showDisplay: true, showType: true }; - const object = await this.provider.getObject({ id, options }); - const objectId = getObjectId(object); - const objectType = getObjectType(object); - const objectVersion = getObjectVersion(object); - const objectFields = getObjectFields(object); - const objectDisplay = getObjectDisplay(object); - return { - objectId, - objectType, - objectVersion, - objectFields, - objectDisplay, - } as ObjectData; - } - - async getObjects(ids: string[]) { - const options = { showContent: true, showDisplay: true, showType: true }; - const objects = await this.provider.multiGetObjects({ ids, options }); - const parsedObjects = objects.map((object) => { - const objectId = getObjectId(object); - const objectType = getObjectType(object); - const objectVersion = getObjectVersion(object); - const objectFields = getObjectFields(object); - const objectDisplay = getObjectDisplay(object); - return { - objectId, - objectType, - objectVersion, - objectFields, - objectDisplay, - }; - }); - return parsedObjects as ObjectData[]; - } - - async getNormalizedMoveModulesByPackage(packageId: string) { - return this.provider.getNormalizedMoveModulesByPackage({package: packageId}); - } - - /** - * @description Select coins that add up to the given amount. - * @param addr the address of the owner - * @param amount the amount that is needed for the coin - * @param coinType the coin type, default is '0x2::SUI::SUI' - */ - async selectCoins( - addr: string, - amount: number, - coinType: string = '0x2::SUI::SUI' - ) { - const coins = await this.provider.getCoins({ owner: addr, coinType }); - const selectedCoins: { - objectId: string; - digest: string; - version: string; - }[] = []; - let totalAmount = 0; - // Sort the coins by balance in descending order - coins.data.sort((a, b) => parseInt(b.balance) - parseInt(a.balance)); - for (const coinData of coins.data) { - selectedCoins.push({ - objectId: coinData.coinObjectId, - digest: coinData.digest, - version: coinData.version, - }); - totalAmount = totalAmount + parseInt(coinData.balance); - if (totalAmount >= amount) { - break; - } - } - - if (!selectedCoins.length) { - throw new Error('No valid coins found for the transaction.'); - } - return selectedCoins; - } -} diff --git a/packages/client/src/libs/suiRpcProvider/types.ts b/packages/client/src/libs/suiRpcProvider/types.ts deleted file mode 100644 index 6193fdef..00000000 --- a/packages/client/src/libs/suiRpcProvider/types.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { DisplayFieldsResponse, ObjectContentFields } from '@mysten/sui.js'; - -export type NetworkType = 'testnet' | 'mainnet' | 'devnet' | 'localnet'; - -export type ObjectData = { - objectId: string; - objectType: string; - objectVersion: number; - objectDisplay: DisplayFieldsResponse; - objectFields: ObjectContentFields; -}; - -export type SuiRpcProviderParams = { - fullnodeUrl?: string; - faucetUrl?: string; - networkType?: NetworkType; -}; diff --git a/packages/client/src/libs/suiTxBuilder/index.ts b/packages/client/src/libs/suiTxBuilder/index.ts index bf5c0f78..ce417ccf 100644 --- a/packages/client/src/libs/suiTxBuilder/index.ts +++ b/packages/client/src/libs/suiTxBuilder/index.ts @@ -10,7 +10,7 @@ import { ObjectCallArg, } from '@mysten/sui.js'; import { convertArgs } from './util'; -import type { SuiTxArg, SuiObjectArg, SuiVecTxArg } from './types'; +import type { SuiTxArg, SuiObjectArg, SuiVecTxArg } from 'src/types'; export class SuiTxBlock { public txBlock: TransactionBlock; diff --git a/packages/client/src/libs/suiTxBuilder/types.ts b/packages/client/src/libs/suiTxBuilder/types.ts deleted file mode 100644 index 3a82823e..00000000 --- a/packages/client/src/libs/suiTxBuilder/types.ts +++ /dev/null @@ -1,32 +0,0 @@ -import { - SharedObjectRef, - SuiObjectRef, - TransactionArgument, -} from '@mysten/sui.js'; - -export type SuiTxArg = TransactionArgument | string | number | bigint | boolean; - -export type SuiObjectArg = - | SharedObjectRef - | SuiObjectRef - | string - | TransactionArgument; - -export type SuiVecTxArg = - | { value: SuiTxArg[]; vecType: SuiInputTypes } - | SuiTxArg[]; - -/** - * These are the basics types that can be used in the SUI - */ -export type SuiBasicTypes = - | 'address' - | 'bool' - | 'u8' - | 'u16' - | 'u32' - | 'u64' - | 'u128' - | 'u256'; - -export type SuiInputTypes = 'object' | SuiBasicTypes; diff --git a/packages/client/src/libs/suiTxBuilder/util.ts b/packages/client/src/libs/suiTxBuilder/util.ts index b88ed85b..eb2d82ff 100644 --- a/packages/client/src/libs/suiTxBuilder/util.ts +++ b/packages/client/src/libs/suiTxBuilder/util.ts @@ -3,7 +3,7 @@ import { TransactionArgument, TransactionBlock, } from '@mysten/sui.js'; -import { SuiTxArg, SuiInputTypes } from './types'; +import { SuiTxArg, SuiInputTypes } from 'src/types'; export const getDefaultSuiInputType = (value: any): SuiInputTypes => { if (typeof value === 'string' && value.startsWith('0x')) { diff --git a/packages/client/src/metadata/index.ts b/packages/client/src/metadata/index.ts index dddc433e..d9191fa8 100644 --- a/packages/client/src/metadata/index.ts +++ b/packages/client/src/metadata/index.ts @@ -1,14 +1,14 @@ import { SuiMoveNormalizedModules } from '@mysten/sui.js'; -import { SuiRpcProvider } from '../libs/suiRpcProvider'; -import { NetworkType } from '../libs/suiRpcProvider/types'; +import { SuiInteractor, getDefaultConnection } from '../libs/suiInteractor'; -export async function getMetadata(networkType: NetworkType, packageId: string) { - const rpcProvider = new SuiRpcProvider({ - networkType, - }); +import { NetworkType } from 'src/types'; +export async function getMetadata(networkType: NetworkType, packageId: string) { + // Init the rpc provider + const fullnodeUrls = [getDefaultConnection(networkType).fullnode]; + const suiInteractor = new SuiInteractor(fullnodeUrls); if (packageId !== undefined) { - const jsonData = await rpcProvider.getNormalizedMoveModulesByPackage(packageId); + const jsonData = await suiInteractor.getNormalizedMoveModulesByPackage(packageId); return jsonData as SuiMoveNormalizedModules; } else { diff --git a/packages/client/src/obelisk.ts b/packages/client/src/obelisk.ts index f6b2307a..97bd716b 100644 --- a/packages/client/src/obelisk.ts +++ b/packages/client/src/obelisk.ts @@ -1,14 +1,18 @@ -import { ObjectData } from './libs/suiRpcProvider/types'; import { RawSigner, TransactionBlock, DevInspectResults, SuiTransactionBlockResponse, - SuiMoveNormalizedModules, DynamicFieldPage, DynamicFieldName, SuiAddress, + SuiMoveNormalizedModules, + DynamicFieldName, + SuiAddress } from '@mysten/sui.js'; import { SuiAccountManager } from './libs/suiAccountManager'; -import { SuiRpcProvider } from './libs/suiRpcProvider'; import { SuiTxBlock } from './libs/suiTxBuilder'; +import { SuiInteractor, getDefaultConnection } from './libs/suiInteractor'; +import { SuiSharedObject, SuiOwnedObject } from './libs/suiModel'; + +import { ObeliskObjectData } from 'src/types'; import { SuiContractFactory } from './libs/suiContractFactory'; import { SuiMoveMoudleValueType, SuiMoveMoudleFuncType } from './libs/suiContractFactory/types'; import { @@ -18,7 +22,7 @@ import { ComponentContentType, SuiTxArgument, ContractQuery, ContractTx, MapMoudleFuncQuery, - MapMoudleFuncTx + MapMoudleFuncTx, FaucetNetworkType } from './types'; import {capitalizeFirstLetter} from "./utils" import keccak256 from "keccak256"; @@ -59,18 +63,15 @@ function createTx( */ export class Obelisk { public accountManager: SuiAccountManager; - public rpcProvider: SuiRpcProvider; + public suiInteractor: SuiInteractor; public contractFactory: SuiContractFactory; public packageId: string | undefined; - // public needLoad: boolean | undefined; public metadata: SuiMoveNormalizedModules; - public epsId: string; - public componentsId: string; readonly #query: MapMoudleFuncQuery = {}; readonly #tx: MapMoudleFuncTx = {}; /** - * Support the following ways to init the SuiToolkit: + * Support the following ways to init the ObeliskClient: * 1. mnemonics * 2. secretKey (base64 or hex) * If none of them is provided, will generate a random mnemonics with 24 words. @@ -79,29 +80,22 @@ export class Obelisk { * @param secretKey, base64 or hex string, when mnemonics is provided, secretKey will be ignored * @param networkType, 'testnet' | 'mainnet' | 'devnet' | 'localnet', default is 'devnet' * @param fullnodeUrl, the fullnode url, default is the preconfig fullnode url for the given network type - * @param faucetUrl, the faucet url, default is the preconfig faucet url for the given network type * @param packageId */ constructor({ mnemonics, secretKey, networkType, - fullnodeUrl, - faucetUrl, + fullnodeUrls, packageId, metadata }: ObeliskParams = {}) { // Init the account manager this.accountManager = new SuiAccountManager({ mnemonics, secretKey }); // Init the rpc provider - this.rpcProvider = new SuiRpcProvider({ - fullnodeUrl, - faucetUrl, - networkType, - }); + fullnodeUrls = fullnodeUrls || [getDefaultConnection(networkType).fullnode]; + this.suiInteractor = new SuiInteractor(fullnodeUrls, networkType); - this.epsId = "0xf2196f638c3174e18c0e31aa630a02fd516c2c5deec1ded72c0fea864c9f091a" - this.componentsId = "0x3bc407eb543149e42846ade59ac2a3c901584af4339dc1ecd0affd090529545f" this.packageId = packageId; this.metadata = metadata as SuiMoveNormalizedModules; Object.values(metadata as SuiMoveNormalizedModules).forEach(value => { @@ -134,16 +128,6 @@ export class Obelisk { }) } - // async initialize() { - // const metadata = await this.loadData(); - // this.metadata = metadata as SuiMoveNormalizedModules; - // this.contractFactory = new SuiContractFactory({ - // packageId: this.packageId, - // metadata: this.metadata - // }) - // return metadata - // } - public get query (): MapMoudleFuncQuery { return this.#query; } @@ -184,7 +168,7 @@ export class Obelisk { */ getSigner(derivePathParams?: DerivePathParams) { const keyPair = this.accountManager.getKeyPair(derivePathParams); - return new RawSigner(keyPair, this.rpcProvider.provider); + return new RawSigner(keyPair, this.suiInteractor.currentProvider); } /** @@ -207,7 +191,7 @@ export class Obelisk { } provider() { - return this.rpcProvider.provider; + return this.suiInteractor.currentProvider; } getPackageId() { @@ -221,24 +205,25 @@ export class Obelisk { * Request some SUI from faucet * @Returns {Promise}, true if the request is successful, false otherwise. */ - async requestFaucet(derivePathParams?: DerivePathParams) { - const addr = this.accountManager.getAddress(derivePathParams); - return this.rpcProvider.requestFaucet(addr); + async requestFaucet(address: SuiAddress, network: FaucetNetworkType) { + // const addr = this.accountManager.getAddress(derivePathParams); + return this.suiInteractor.requestFaucet(address, network); } async getBalance(coinType?: string, derivePathParams?: DerivePathParams) { const owner = this.accountManager.getAddress(derivePathParams); - return this.rpcProvider.getBalance(owner, coinType); + return this.suiInteractor.currentProvider.getBalance({ owner, coinType }); } async getObject(objectId: string) { - return this.rpcProvider.getObject(objectId); + return this.suiInteractor.getObject(objectId); } async getObjects(objectIds: string[]) { - return this.rpcProvider.getObjects(objectIds); + return this.suiInteractor.getObjects(objectIds); } + async signTxn( tx: Uint8Array | TransactionBlock | SuiTxBlock, derivePathParams?: DerivePathParams @@ -252,16 +237,11 @@ export class Obelisk { tx: Uint8Array | TransactionBlock | SuiTxBlock, derivePathParams?: DerivePathParams ): Promise { - tx = tx instanceof SuiTxBlock ? tx.txBlock : tx; - const signer = this.getSigner(derivePathParams); - return signer.signAndExecuteTransactionBlock({ - transactionBlock: tx, - options: { - showEffects: true, - showEvents: true, - showObjectChanges: true, - }, - }); + const { transactionBlockBytes, signature } = await this.signTxn( + tx, + derivePathParams + ); + return this.suiInteractor.sendTx(transactionBlockBytes, signature); } /** @@ -312,7 +292,7 @@ export class Obelisk { const tx = new SuiTxBlock(); const owner = this.accountManager.getAddress(derivePathParams); const totalAmount = amounts.reduce((a, b) => a + b, 0); - const coins = await this.rpcProvider.selectCoins( + const coins = await this.suiInteractor.selectCoins( owner, totalAmount, coinType @@ -379,7 +359,7 @@ export class Obelisk { owner?: string ) { owner = owner || this.accountManager.currentAddress; - const coins = await this.rpcProvider.selectCoins(owner, amount, coinType); + const coins = await this.suiInteractor.selectCoins(owner, amount, coinType); return coins.map((c) => c.objectId); } @@ -410,37 +390,21 @@ export class Obelisk { tx: Uint8Array | TransactionBlock | SuiTxBlock, derivePathParams?: DerivePathParams ): Promise { - tx = tx instanceof SuiTxBlock ? tx.txBlock : tx; - return this.rpcProvider.provider.devInspectTransactionBlock({ + return this.suiInteractor.currentProvider.devInspectTransactionBlock({ transactionBlock: tx, sender: this.getAddress(derivePathParams), }); } async getWorld(worldObjectId: string) { - return this.rpcProvider.getObject(worldObjectId) - } - - async getAllEntities(worldId: string, cursor?: string, limit?: number) { - const parentId = (await this.rpcProvider.getObject(worldId)).objectFields.entities.fields.id.id; - return await this.rpcProvider.getDynamicFields(parentId, cursor, limit) as DynamicFieldPage; - } - - async getEntity(worldId: string, entityId: string) { - const parentId = (await this.rpcProvider.getObject(worldId)).objectFields.entities.fields.id.id; - - const name = { - type: "0x2::object::ID", - value: entityId - } as DynamicFieldName - return await this.rpcProvider.getDynamicFieldObject(parentId, name); + return this.suiInteractor.getObject(worldObjectId) } async getComponents(worldId: string) { - const parentId = (await this.rpcProvider.getObject(worldId)).objectFields.components.fields.id.id; + const parentId = (await this.suiInteractor.getObject(worldId)).objectFields.components.fields.id.id; - return await this.rpcProvider.getDynamicFields(parentId); + return await this.suiInteractor.getDynamicFields(parentId); } @@ -451,20 +415,19 @@ export class Obelisk { async getComponent(worldId: string, componentId: Buffer) { const componentIdValue: number[] = Array.from(componentId); - const parentId = (await this.rpcProvider.getObject(worldId)).objectFields.components.fields.id.id; + const parentId = (await this.suiInteractor.getObject(worldId)).objectFields.components.fields.id.id; const name = { - // type: "0x2::object::ID", type: "vector", value: componentIdValue // value: [250,208,186,160,39,171,62,206,98,224,138,41,11,217,63,100,248,104,207,64,78,126,43,109,129,68,64,127,236,113,152,132] } as DynamicFieldName - return await this.rpcProvider.getDynamicFieldObject(parentId, name); + return await this.suiInteractor.getDynamicFieldObject(parentId, name); } async getOwnedEntities(owner: SuiAddress, cursor?: string, limit?: number) { - const ownedObjects = await this.rpcProvider.getOwnedObjects(owner, cursor, limit) - let ownedEntities: ObjectData[] = []; + const ownedObjects = await this.suiInteractor.getOwnedObjects(owner, cursor, limit) + let ownedEntities: ObeliskObjectData[] = []; for (const object of ownedObjects.data) { let objectDetail = await this.getObject(object.data!.objectId); @@ -476,57 +439,4 @@ export class Obelisk { return ownedEntities; } - - async getTable(worldId: string, entityId: string) { - const parentId = (await this.rpcProvider.getObject(worldId)).objectFields.storages.fields.id.id; - - const name = { - type: "0x2::object::ID", - value: entityId - } as DynamicFieldName - return await this.rpcProvider.getDynamicFieldObject(parentId, name); - } - - async getEntityComponents(worldId: string, entityId: string, cursor?: string, limit?: number) { - const parentContent = (await this.getEntity(worldId, entityId)).data!.content as ComponentContentType; - const parentId = parentContent.fields.value.fields.components.fields.id.id; - return await this.rpcProvider.getDynamicFields(parentId, cursor, limit) as DynamicFieldPage; - } - - async getEntityComponent(entityId: string, componentId: string) { - const parentId = (await this.rpcProvider.getObject(entityId)).objectFields.id.id; - - const name = { - type: "0x2::object::ID", - value: componentId - } as DynamicFieldName - return await this.rpcProvider.getDynamicFieldObject(parentId, name); - } - - - // async loadData() { - // const jsonFileName = `metadata/${this.packageId}.json`; - - // try { - // const data = await fs.promises.readFile(jsonFileName, 'utf-8'); - // const jsonData = JSON.parse(data); - - // return jsonData as SuiMoveNormalizedModules; - // } catch (error) { - // if (this.packageId !== undefined) { - // const jsonData = await this.rpcProvider.getNormalizedMoveModulesByPackage(this.packageId); - - // fs.writeFile(jsonFileName, JSON.stringify(jsonData, null, 2), (err) => { - // if (err) { - // console.error('写入文件时出错:', err); - // } else { - // console.log('JSON 数据已保存到文件:', jsonFileName); - // } - // }); - // return jsonData as SuiMoveNormalizedModules; - // } else { - // console.error('please set your package id.'); - // } - // } - // } } diff --git a/packages/client/src/types/index.ts b/packages/client/src/types/index.ts index 00dcb57c..704728ca 100644 --- a/packages/client/src/types/index.ts +++ b/packages/client/src/types/index.ts @@ -1,22 +1,34 @@ -import { SuiMoveNormalizedModules, DevInspectResults, SuiTransactionBlockResponse, SuiMoveNormalizedType, TransactionBlock } from "@mysten/sui.js"; +import { Infer } from 'superstruct'; +import { + DisplayFieldsResponse, + ObjectCallArg, + ObjectContentFields, + SharedObjectRef, + SuiObjectRef, + TransactionArgument, + TransactionBlock, + SuiTransactionBlockResponse, + DevInspectResults, + SuiMoveNormalizedModules +} from '@mysten/sui.js'; -import type { NetworkType as SuiNetworkType } from '../libs/suiRpcProvider/types'; -export type { DerivePathParams } from '../libs/suiAccountManager/types'; import { SuiMoveMoudleValueType, SuiMoveMoudleFuncType } from '../libs/suiContractFactory/types'; -export type { - SuiTxArg, - SuiVecTxArg, - SuiObjectArg, -} from '../libs/suiTxBuilder/types'; -export type NetworkType = SuiNetworkType; +export type ObeliskObjectData = { + objectId: string; + objectType: string; + objectVersion: number; + objectDisplay: DisplayFieldsResponse; + objectFields: ObjectContentFields; +}; + export type ObeliskParams = { mnemonics?: string; secretKey?: string; - fullnodeUrl?: string; + fullnodeUrls?: string[]; faucetUrl?: string; networkType?: NetworkType; packageId?: string, @@ -89,3 +101,73 @@ export type MapMoudleFuncQuery = Record; export type MapMoudleFuncTest = Record>; export type MapMoudleFuncQueryTest = Record>; + + + +export type AccountMangerParams = { + mnemonics?: string; + secretKey?: string; +}; + +export type DerivePathParams = { + accountIndex?: number; + isExternal?: boolean; + addressIndex?: number; +}; + +export type NetworkType = 'testnet' | 'mainnet' | 'devnet' | 'localnet'; +export type FaucetNetworkType = 'testnet' | 'devnet' | 'localnet' + +export type SuiKitParams = { + mnemonics?: string; + secretKey?: string; + fullnodeUrls?: string[]; + faucetUrl?: string; + networkType?: NetworkType; +}; + +export type ObjectData = { + objectId: string; + objectType: string; + objectVersion: number; + objectDigest: string; + initialSharedVersion?: number; + objectDisplay: DisplayFieldsResponse; + objectFields: ObjectContentFields; +}; + + + +export type SuiTxArg = + | Infer + | Infer + | string + | number + | bigint + | boolean; + +export type SuiObjectArg = + | SharedObjectRef + | Infer + | string + | Infer + | Infer; + +export type SuiVecTxArg = + | { value: SuiTxArg[]; vecType: SuiInputTypes } + | SuiTxArg[]; + +/** + * These are the basics types that can be used in the SUI + */ +export type SuiBasicTypes = + | 'address' + | 'bool' + | 'u8' + | 'u16' + | 'u32' + | 'u64' + | 'u128' + | 'u256'; + +export type SuiInputTypes = 'object' | SuiBasicTypes; diff --git a/packages/client/yarn.lock b/packages/client/yarn.lock index 9afa90d9..4ccdc6c6 100644 --- a/packages/client/yarn.lock +++ b/packages/client/yarn.lock @@ -549,22 +549,6 @@ dependencies: bs58 "^5.0.0" -"@mysten/sui.js@^0.37.1": - version "0.37.1" - resolved "https://registry.npmmirror.com/@mysten/sui.js/-/sui.js-0.37.1.tgz#b6a0c7312d979bec6903683d7db07fc33ff7d9ea" - integrity sha512-nEOqnjUqb/VJcVk23LgZOX1FmBib/mBCwAWaJhtsCHLwv2jIAfCPY/fpB9lJ62QHrM8UFclpWxsLkqcUkKyPgA== - dependencies: - "@mysten/bcs" "0.7.3" - "@noble/curves" "^1.0.0" - "@noble/hashes" "^1.3.0" - "@open-rpc/client-js" "^1.8.1" - "@scure/bip32" "^1.3.0" - "@scure/bip39" "^1.2.0" - "@suchipi/femver" "^1.0.0" - events "^3.3.0" - superstruct "^1.0.3" - tweetnacl "^1.0.3" - "@mysten/sui.js@^0.41.0": version "0.41.1" resolved "https://registry.npmmirror.com/@mysten/sui.js/-/sui.js-0.41.1.tgz#880b454829c5100b78f506f567f0575cbb621892" @@ -581,13 +565,6 @@ superstruct "^1.0.3" tweetnacl "^1.0.3" -"@noble/curves@^1.0.0", "@noble/curves@~1.1.0": - version "1.1.0" - resolved "https://registry.npmmirror.com/@noble/curves/-/curves-1.1.0.tgz#f13fc667c89184bc04cccb9b11e8e7bae27d8c3d" - integrity sha512-091oBExgENk/kGj3AZmtBDMpxQPDtxQABR2B9lb1JbVTs6ytdzZNwvhxQ4MWasRNEzlbEH8jCWFCwhF/Obj5AA== - dependencies: - "@noble/hashes" "1.3.1" - "@noble/curves@^1.1.0", "@noble/curves@~1.2.0": version "1.2.0" resolved "https://registry.npmmirror.com/@noble/curves/-/curves-1.2.0.tgz#92d7e12e4e49b23105a2555c6984d41733d65c35" @@ -595,16 +572,16 @@ dependencies: "@noble/hashes" "1.3.2" -"@noble/hashes@1.3.1", "@noble/hashes@^1.3.0", "@noble/hashes@~1.3.0", "@noble/hashes@~1.3.1": - version "1.3.1" - resolved "https://registry.npmmirror.com/@noble/hashes/-/hashes-1.3.1.tgz#8831ef002114670c603c458ab8b11328406953a9" - integrity sha512-EbqwksQwz9xDRGfDST86whPBgM65E0OH/pCgqW0GBVzO22bNE+NuIbeTb714+IfSjU3aRk47EUvXIb5bTsenKA== - "@noble/hashes@1.3.2", "@noble/hashes@^1.3.1", "@noble/hashes@~1.3.2": version "1.3.2" resolved "https://registry.npmmirror.com/@noble/hashes/-/hashes-1.3.2.tgz#6f26dbc8fbc7205873ce3cee2f690eba0d421b39" integrity sha512-MVC8EAQp7MvEcm30KWENFjgR+Mkmf+D189XJTkFIlwohU5hcBbn1ZkKq7KVTi2Hme3PMGF390DaL52beVrIihQ== +"@noble/hashes@~1.3.0": + version "1.3.1" + resolved "https://registry.npmmirror.com/@noble/hashes/-/hashes-1.3.1.tgz#8831ef002114670c603c458ab8b11328406953a9" + integrity sha512-EbqwksQwz9xDRGfDST86whPBgM65E0OH/pCgqW0GBVzO22bNE+NuIbeTb714+IfSjU3aRk47EUvXIb5bTsenKA== + "@nodelib/fs.scandir@2.1.5": version "2.1.5" resolved "https://registry.npmmirror.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz#7619c2eb21b25483f6d167548b4cfd5a7488c3d5" @@ -650,15 +627,6 @@ resolved "https://registry.npmmirror.com/@scure/base/-/base-1.1.3.tgz#8584115565228290a6c6c4961973e0903bb3df2f" integrity sha512-/+SgoRjLq7Xlf0CWuLHq2LUZeL/w65kfzAPG5NH9pcmBhs+nunQTn4gvdwgMTIXnt9b2C/1SeL2XiysZEyIC9Q== -"@scure/bip32@^1.3.0": - version "1.3.1" - resolved "https://registry.npmmirror.com/@scure/bip32/-/bip32-1.3.1.tgz#7248aea723667f98160f593d621c47e208ccbb10" - integrity sha512-osvveYtyzdEVbt3OfwwXFr4P2iVBL5u1Q3q4ONBfDY/UpOuXmOlbgwc1xECEboY8wIays8Yt6onaWMUdUbfl0A== - dependencies: - "@noble/curves" "~1.1.0" - "@noble/hashes" "~1.3.1" - "@scure/base" "~1.1.0" - "@scure/bip32@^1.3.1": version "1.3.2" resolved "https://registry.npmmirror.com/@scure/bip32/-/bip32-1.3.2.tgz#90e78c027d5e30f0b22c1f8d50ff12f3fb7559f8" @@ -668,7 +636,7 @@ "@noble/hashes" "~1.3.2" "@scure/base" "~1.1.2" -"@scure/bip39@^1.2.0", "@scure/bip39@^1.2.1": +"@scure/bip39@^1.2.1": version "1.2.1" resolved "https://registry.npmmirror.com/@scure/bip39/-/bip39-1.2.1.tgz#5cee8978656b272a917b7871c981e0541ad6ac2a" integrity sha512-Z3/Fsz1yr904dduJD0NpiyRHhRYHdcnyh73FZWiV+/qhWi83wNJ3NWolYqCEN+ZWsUz2TWwajJggcRE9r1zUYg== From 6e2970e63c62e9b4182f9c6b497da5b20d2f15b2 Mon Sep 17 00:00:00 2001 From: henryliu <17600047539@163.com> Date: Sun, 10 Sep 2023 22:55:35 +0800 Subject: [PATCH 02/16] update --- packages/cli/package.json | 2 +- packages/client/package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/cli/package.json b/packages/cli/package.json index 0f099937..293aed89 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -1,6 +1,6 @@ { "name": "@0xobelisk/cli", - "version": "0.0.5", + "version": "0.0.7", "description": "Tookit for interacting with move eps framework", "keywords": [ "sui", diff --git a/packages/client/package.json b/packages/client/package.json index 47a59774..033c51be 100644 --- a/packages/client/package.json +++ b/packages/client/package.json @@ -1,6 +1,6 @@ { "name": "@0xobelisk/client", - "version": "0.0.7", + "version": "0.1.0", "description": "Tookit for interacting with move eps framework", "keywords": [ "sui", From 25949ecd2aab07c2fcd8db4002fff5f2c23f17bd Mon Sep 17 00:00:00 2001 From: vladilen11 Date: Sun, 10 Sep 2023 23:09:17 +0800 Subject: [PATCH 03/16] update --- packages/client/src/index.ts | 2 ++ packages/client/src/libs/suiAccountManager/keypair.ts | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/client/src/index.ts b/packages/client/src/index.ts index c2585a79..35018648 100644 --- a/packages/client/src/index.ts +++ b/packages/client/src/index.ts @@ -3,6 +3,8 @@ export { SUI_CLOCK_OBJECT_ID, SUI_SYSTEM_STATE_OBJECT_ID, } from '@mysten/sui.js'; +export { Ed25519Keypair } from '@mysten/sui.js/keypairs/ed25519'; +export { fromB64, toB64 } from '@mysten/sui.js'; export { Obelisk } from './obelisk'; export { SuiAccountManager } from './libs/suiAccountManager'; export { SuiTxBlock } from './libs/suiTxBuilder'; diff --git a/packages/client/src/libs/suiAccountManager/keypair.ts b/packages/client/src/libs/suiAccountManager/keypair.ts index e7b1d626..a28aa3c0 100644 --- a/packages/client/src/libs/suiAccountManager/keypair.ts +++ b/packages/client/src/libs/suiAccountManager/keypair.ts @@ -1,4 +1,4 @@ -import { Ed25519Keypair } from '@mysten/sui.js'; +import { Ed25519Keypair, fromB64 } from '@mysten/sui.js'; import type { DerivePathParams } from 'src/types'; /** From 3ee9d5788952c746bcd24813f5ffb73e3f60caac Mon Sep 17 00:00:00 2001 From: henryliu <17600047539@163.com> Date: Sun, 10 Sep 2023 23:11:03 +0800 Subject: [PATCH 04/16] update --- packages/client/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/client/package.json b/packages/client/package.json index 033c51be..00cddde3 100644 --- a/packages/client/package.json +++ b/packages/client/package.json @@ -1,6 +1,6 @@ { "name": "@0xobelisk/client", - "version": "0.1.0", + "version": "0.1.1", "description": "Tookit for interacting with move eps framework", "keywords": [ "sui", From 192e12733594aaeef6d078576a910236561cd973 Mon Sep 17 00:00:00 2001 From: vladilen11 Date: Sun, 10 Sep 2023 23:20:38 +0800 Subject: [PATCH 05/16] update --- packages/client/src/index.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/client/src/index.ts b/packages/client/src/index.ts index 35018648..fefb2df5 100644 --- a/packages/client/src/index.ts +++ b/packages/client/src/index.ts @@ -5,6 +5,7 @@ export { } from '@mysten/sui.js'; export { Ed25519Keypair } from '@mysten/sui.js/keypairs/ed25519'; export { fromB64, toB64 } from '@mysten/sui.js'; +export * from '@mysten/sui.js/bcs'; export { Obelisk } from './obelisk'; export { SuiAccountManager } from './libs/suiAccountManager'; export { SuiTxBlock } from './libs/suiTxBuilder'; From 11d47e0193714788c0ad41c23d7d7f641f4cf7a9 Mon Sep 17 00:00:00 2001 From: henryliu <17600047539@163.com> Date: Mon, 11 Sep 2023 00:07:51 +0800 Subject: [PATCH 06/16] update --- packages/client/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/client/package.json b/packages/client/package.json index 00cddde3..c1a96f44 100644 --- a/packages/client/package.json +++ b/packages/client/package.json @@ -1,6 +1,6 @@ { "name": "@0xobelisk/client", - "version": "0.1.1", + "version": "0.1.2", "description": "Tookit for interacting with move eps framework", "keywords": [ "sui", From 41010371e245a8d617b1af3940389a8f673a92fc Mon Sep 17 00:00:00 2001 From: henryliu <17600047539@163.com> Date: Mon, 11 Sep 2023 00:14:29 +0800 Subject: [PATCH 07/16] add cocos-lib-builder --- .gitignore | 1 + tools/cocos-lib-builder/index.ts | 39 ++++++++++++++++++++++++++++ tools/cocos-lib-builder/main.js | 3 +++ tools/cocos-lib-builder/package.json | 22 ++++++++++++++++ 4 files changed, 65 insertions(+) create mode 100644 tools/cocos-lib-builder/index.ts create mode 100644 tools/cocos-lib-builder/main.js create mode 100644 tools/cocos-lib-builder/package.json diff --git a/.gitignore b/.gitignore index 5e59139a..4c3e18d0 100644 --- a/.gitignore +++ b/.gitignore @@ -26,6 +26,7 @@ npm-debug.log* yarn-debug.log* yarn-error.log* +pnpm-lock.yaml # local env files .env.local diff --git a/tools/cocos-lib-builder/index.ts b/tools/cocos-lib-builder/index.ts new file mode 100644 index 00000000..79f87500 --- /dev/null +++ b/tools/cocos-lib-builder/index.ts @@ -0,0 +1,39 @@ +// import { +// Ed25519Keypair, +// JsonRpcProvider, +// RawSigner, +// TransactionBlock, +// localnetConnection +// } from '@mysten/sui.js'; +// +// +// const keypair = Ed25519Keypair.generate() +// const provider = new JsonRpcProvider(); +// const signer = new RawSigner(keypair, provider); +// const tx = new TransactionBlock(); +// const user_sui_address = keypair.getPublicKey().toSuiAddress() +// await provider.requestSuiFromFaucet(user_sui_address) +// + +// const { Ed25519Keypair,fromB64 } = require("@0xobelisk/client"); +import {NetworkType, Obelisk} from "@0xobelisk/client"; + + +const main = async () => { + + const NETWORK: NetworkType = 'testnet'; + const obelisk = new Obelisk({ + secretKey: 'c71a1529d774a80d521e02953ce656f1b1cef126451daacaebec763f8dd0b535', + networkType: NETWORK, + }); + // const obeject_id = '0x97706e7066536b8c542c175e77eec801989cca8c3c4c68b80db056c5ca30330f' + // const result = await obelisk.getObjects([obeject_id]) + // console.log(result[0].objectFields.number) + const world_id = '0xea07f58052bcdef935a3eee097d41a97bc4a0f0b1b60ff6b18f2caa858609bf8' + const system_name = 'counter_change' + const counter = '0x97706e7066536b8c542c175e77eec801989cca8c3c4c68b80db056c5ca30330f' + const result= await obelisk.call(world_id,system_name,counter) + console.log(result) +} + +main() diff --git a/tools/cocos-lib-builder/main.js b/tools/cocos-lib-builder/main.js new file mode 100644 index 00000000..d20cf1d8 --- /dev/null +++ b/tools/cocos-lib-builder/main.js @@ -0,0 +1,3 @@ +var obelisk = require('@0xobelisk/client'); + +window.obelisk = obelisk; diff --git a/tools/cocos-lib-builder/package.json b/tools/cocos-lib-builder/package.json new file mode 100644 index 00000000..37f8477d --- /dev/null +++ b/tools/cocos-lib-builder/package.json @@ -0,0 +1,22 @@ +{ + "name": "suinpm", + "version": "1.0.0", + "description": "", + "main": "index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1", + "build": "browserify main.js -p esmify > ./obelisk.js" + }, + "keywords": [], + "author": "", + "license": "ISC", + "dependencies": { + "@0xobelisk/client": "^0.1.2", + "@mysten/sui.js": "^0.41.0", + "browser-resolve": "^2.0.0", + "browser-sync": "^2.29.3" + }, + "devDependencies": { + "esmify": "^2.1.1" + } +} From 1ce5f99f80406ca0c6aed683e105dd904590a2b4 Mon Sep 17 00:00:00 2001 From: vladilen11 Date: Mon, 11 Sep 2023 01:11:37 +0800 Subject: [PATCH 08/16] update obelisk client --- packages/client/scripts/cli.ts | 35 ---------------------- packages/client/scripts/init.ts | 5 ++-- packages/client/src/obelisk.ts | 53 +++++++++++++++++---------------- 3 files changed, 29 insertions(+), 64 deletions(-) delete mode 100644 packages/client/scripts/cli.ts diff --git a/packages/client/scripts/cli.ts b/packages/client/scripts/cli.ts deleted file mode 100644 index c4c54aae..00000000 --- a/packages/client/scripts/cli.ts +++ /dev/null @@ -1,35 +0,0 @@ -import { worldgen } from "../../common/src/codegen"; -import { ObeliskConfig } from "../../common/src/codegen/types"; - -async function init() { - let config = { - project_name: "withinfinity", - systems: [ - "fee_system", - "home_system", - "pet_system", - "state_system", - ], - components: { - // Key - Struct value - level: { - hunger: "u64", - cleanliness: "u64", - mood: "u64", - level: "u64", - }, - // Key - Struct value - state: { - state: "vector" , - last_update_time: "u64" , - }, - // Key - Single value - suifren: { - data: "bool" - }, - }, - } as ObeliskConfig; - worldgen(config); -} - -init(); diff --git a/packages/client/scripts/init.ts b/packages/client/scripts/init.ts index 2d34eb51..564397aa 100644 --- a/packages/client/scripts/init.ts +++ b/packages/client/scripts/init.ts @@ -48,8 +48,8 @@ async function init() { const obelisk = new Obelisk({ networkType: network as NetworkType, - packageId: packageId, - metadata: metadata, + // packageId: packageId, + // metadata: metadata, // secretKey: privkey }); @@ -59,7 +59,6 @@ async function init() { console.log(JSON.stringify(data1)) let content = data1.data!.content as data; console.log(content.fields.value.fields.value); - // await obelisk.getBalance() await obelisk.requestFaucet("0x1804b821bba181110599b8757008eabe6f89f62774d7fafb5ee666ac742a41f8", "devnet"); // let ownerdObjects = await obelisk.getOwnedEntities("0x1804b821bba181110599b8757008eabe6f89f62774d7fafb5ee666ac742a41f8") // console.log(ownerdObjects) diff --git a/packages/client/src/obelisk.ts b/packages/client/src/obelisk.ts index 97bd716b..b68a465b 100644 --- a/packages/client/src/obelisk.ts +++ b/packages/client/src/obelisk.ts @@ -66,7 +66,7 @@ export class Obelisk { public suiInteractor: SuiInteractor; public contractFactory: SuiContractFactory; public packageId: string | undefined; - public metadata: SuiMoveNormalizedModules; + public metadata: SuiMoveNormalizedModules | undefined; readonly #query: MapMoudleFuncQuery = {}; readonly #tx: MapMoudleFuncTx = {}; @@ -97,31 +97,32 @@ export class Obelisk { this.suiInteractor = new SuiInteractor(fullnodeUrls, networkType); this.packageId = packageId; - this.metadata = metadata as SuiMoveNormalizedModules; - Object.values(metadata as SuiMoveNormalizedModules).forEach(value => { - let data = value as SuiMoveMoudleValueType; - let moduleName = data.name; - Object.entries(data.exposedFunctions).forEach(([funcName, value]) => { - let meta = value as SuiMoveMoudleFuncType; - meta.moudleName = moduleName; - meta.funcName = funcName; - - if (isUndefined(this.#query[moduleName])) { - this.#query[moduleName] = {}; - } - if (isUndefined(this.#query[moduleName][funcName])) { - this.#query[moduleName][funcName] = createQuery(meta, (tx, p, isRaw) => this.#read(meta, tx, p, isRaw)) - } - - if (isUndefined(this.#tx[moduleName])) { - this.#tx[moduleName] = {}; - } - if (isUndefined(this.#tx[moduleName][funcName])) { - this.#tx[moduleName][funcName] = createTx(meta, (tx, p, isRaw) => this.#exec(meta, tx, p, isRaw)) - } - }); - }) - + if (metadata !== undefined) { + this.metadata = metadata as SuiMoveNormalizedModules; + Object.values(metadata as SuiMoveNormalizedModules).forEach(value => { + let data = value as SuiMoveMoudleValueType; + let moduleName = data.name; + Object.entries(data.exposedFunctions).forEach(([funcName, value]) => { + let meta = value as SuiMoveMoudleFuncType; + meta.moudleName = moduleName; + meta.funcName = funcName; + + if (isUndefined(this.#query[moduleName])) { + this.#query[moduleName] = {}; + } + if (isUndefined(this.#query[moduleName][funcName])) { + this.#query[moduleName][funcName] = createQuery(meta, (tx, p, isRaw) => this.#read(meta, tx, p, isRaw)) + } + + if (isUndefined(this.#tx[moduleName])) { + this.#tx[moduleName] = {}; + } + if (isUndefined(this.#tx[moduleName][funcName])) { + this.#tx[moduleName][funcName] = createTx(meta, (tx, p, isRaw) => this.#exec(meta, tx, p, isRaw)) + } + }); + }) + } this.contractFactory = new SuiContractFactory({ packageId, metadata From e1c30d64732f84026867c236f159595e1208cd38 Mon Sep 17 00:00:00 2001 From: henryliu <17600047539@163.com> Date: Mon, 11 Sep 2023 01:49:51 +0800 Subject: [PATCH 09/16] update --- tools/cocos-lib-builder/index.ts | 39 -------------------------------- 1 file changed, 39 deletions(-) delete mode 100644 tools/cocos-lib-builder/index.ts diff --git a/tools/cocos-lib-builder/index.ts b/tools/cocos-lib-builder/index.ts deleted file mode 100644 index 79f87500..00000000 --- a/tools/cocos-lib-builder/index.ts +++ /dev/null @@ -1,39 +0,0 @@ -// import { -// Ed25519Keypair, -// JsonRpcProvider, -// RawSigner, -// TransactionBlock, -// localnetConnection -// } from '@mysten/sui.js'; -// -// -// const keypair = Ed25519Keypair.generate() -// const provider = new JsonRpcProvider(); -// const signer = new RawSigner(keypair, provider); -// const tx = new TransactionBlock(); -// const user_sui_address = keypair.getPublicKey().toSuiAddress() -// await provider.requestSuiFromFaucet(user_sui_address) -// - -// const { Ed25519Keypair,fromB64 } = require("@0xobelisk/client"); -import {NetworkType, Obelisk} from "@0xobelisk/client"; - - -const main = async () => { - - const NETWORK: NetworkType = 'testnet'; - const obelisk = new Obelisk({ - secretKey: 'c71a1529d774a80d521e02953ce656f1b1cef126451daacaebec763f8dd0b535', - networkType: NETWORK, - }); - // const obeject_id = '0x97706e7066536b8c542c175e77eec801989cca8c3c4c68b80db056c5ca30330f' - // const result = await obelisk.getObjects([obeject_id]) - // console.log(result[0].objectFields.number) - const world_id = '0xea07f58052bcdef935a3eee097d41a97bc4a0f0b1b60ff6b18f2caa858609bf8' - const system_name = 'counter_change' - const counter = '0x97706e7066536b8c542c175e77eec801989cca8c3c4c68b80db056c5ca30330f' - const result= await obelisk.call(world_id,system_name,counter) - console.log(result) -} - -main() From 6987d5958e5092225e5d8d8cfd07bcce82cbfec2 Mon Sep 17 00:00:00 2001 From: vladilen11 Date: Mon, 11 Sep 2023 22:22:04 +0800 Subject: [PATCH 10/16] update obelisk project_name to projectName --- packages/cli/obelisk.config.ts | 2 +- packages/cli/scripts/compgen-test.js | 2 +- packages/cli/scripts/compgen-test.ts | 4 ++-- packages/cli/src/commands/publish.ts | 2 +- packages/common/src/codegen/types/index.ts | 2 +- .../utils/renderMove/generateComponent.ts | 16 ++++++++-------- .../utils/renderMove/generateEntityKey.ts | 4 ++-- .../src/codegen/utils/renderMove/generateEps.ts | 4 ++-- .../src/codegen/utils/renderMove/generateInit.ts | 10 +++++----- .../codegen/utils/renderMove/generateSystem.ts | 4 ++-- .../src/codegen/utils/renderMove/generateToml.ts | 6 +++--- .../src/codegen/utils/renderMove/worldgen.ts | 4 ++-- 12 files changed, 30 insertions(+), 30 deletions(-) diff --git a/packages/cli/obelisk.config.ts b/packages/cli/obelisk.config.ts index 817df748..81d25f45 100644 --- a/packages/cli/obelisk.config.ts +++ b/packages/cli/obelisk.config.ts @@ -1,7 +1,7 @@ import { ObeliskConfig } from "@0xobelisk/common/src/codegen/types"; export const obeliskConfig = { - project_name: "withinfinity", + projectName: "withinfinity", systems: [ "fee_system", "home_system", diff --git a/packages/cli/scripts/compgen-test.js b/packages/cli/scripts/compgen-test.js index 795f0fa2..64f94c5c 100644 --- a/packages/cli/scripts/compgen-test.js +++ b/packages/cli/scripts/compgen-test.js @@ -42,7 +42,7 @@ function init() { var config, output, a; return __generator(this, function (_a) { config = { - project_name: "withinfinity", + projectName: "withinfinity", systems: [ "fee_system", "home_system", diff --git a/packages/cli/scripts/compgen-test.ts b/packages/cli/scripts/compgen-test.ts index 9fe3d400..87654b90 100644 --- a/packages/cli/scripts/compgen-test.ts +++ b/packages/cli/scripts/compgen-test.ts @@ -6,7 +6,7 @@ type ComponentValueType = string type ConfigDataType = Record type ObeliskConfig = { - project_name: string, + projectName: string, systems: string[], components: Record // world 的顶级存储,适合定义world的规则,比如一个admin, 一个fee,并且可以帮你初始化数据 @@ -43,7 +43,7 @@ type ObeliskConfig = { async function init() { let config = { - project_name: "withinfinity", + projectName: "withinfinity", systems: [ "fee_system", "home_system", diff --git a/packages/cli/src/commands/publish.ts b/packages/cli/src/commands/publish.ts index 867df5cd..5f775307 100644 --- a/packages/cli/src/commands/publish.ts +++ b/packages/cli/src/commands/publish.ts @@ -27,7 +27,7 @@ const commandModule: CommandModule = { try { const obeliskConfig = await loadConfig(configPath) as ObeliskConfig; - await publishHandler(obeliskConfig.project_name, network, savePath); + await publishHandler(obeliskConfig.projectName, network, savePath); } catch (error: any) { logError(error); process.exit(1); diff --git a/packages/common/src/codegen/types/index.ts b/packages/common/src/codegen/types/index.ts index 89b4179b..45c0b6ad 100644 --- a/packages/common/src/codegen/types/index.ts +++ b/packages/common/src/codegen/types/index.ts @@ -11,7 +11,7 @@ export type singletonComponentMapType = string | Record export type ObeliskConfig = { - project_name: string, + projectName: string, systems: string[], components: Record singletonComponents: Record diff --git a/packages/common/src/codegen/utils/renderMove/generateComponent.ts b/packages/common/src/codegen/utils/renderMove/generateComponent.ts index 5041c819..aff24f67 100644 --- a/packages/common/src/codegen/utils/renderMove/generateComponent.ts +++ b/packages/common/src/codegen/utils/renderMove/generateComponent.ts @@ -11,13 +11,13 @@ import { export function generateComponent(config: ObeliskConfig, srcPrefix: string) { Object.entries(config.components).forEach(([componentName, value]) => { - let code = `module ${config.project_name}::${componentName}_component { + let code = `module ${config.projectName}::${componentName}_component { use sui::tx_context::TxContext; use sui::table::{Self, Table}; - use ${config.project_name}::world::{Self , World}; + use ${config.projectName}::world::{Self , World}; // Systems - ${getFriendSystem(config.project_name,config.systems)} + ${getFriendSystem(config.projectName,config.systems)} \tconst COMPONENT_NAME: vector = b"${capitalizeFirstLetter(componentName)} Component"; @@ -31,17 +31,17 @@ export function generateComponent(config: ObeliskConfig, srcPrefix: string) { ${renderContainFunc(componentName)} } ` - formatAndWriteMove(code, `${srcPrefix}/contracts/${config.project_name}/sources/codegen/components/${componentName}.move`, "formatAndWriteMove"); + formatAndWriteMove(code, `${srcPrefix}/contracts/${config.projectName}/sources/codegen/components/${componentName}.move`, "formatAndWriteMove"); }) } export function generateSingletonComponent(config: ObeliskConfig, srcPrefix: string) { Object.entries(config.singletonComponents).forEach(([componentName, value]) => { - let code = `module ${config.project_name}::${componentName}_component { - use ${config.project_name}::world::{Self , World}; + let code = `module ${config.projectName}::${componentName}_component { + use ${config.projectName}::world::{Self , World}; // Systems -${getFriendSystem(config.project_name,config.systems)} +${getFriendSystem(config.projectName,config.systems)} \tconst COMPONENT_NAME: vector = b"${capitalizeFirstLetter(componentName)} Component"; @@ -52,6 +52,6 @@ ${getFriendSystem(config.project_name,config.systems)} ${renderSingletonQueryFunc(componentName, value)} } ` - formatAndWriteMove(code, `${srcPrefix}/contracts/${config.project_name}/sources/codegen/components/${componentName}.move`, "formatAndWriteMove"); + formatAndWriteMove(code, `${srcPrefix}/contracts/${config.projectName}/sources/codegen/components/${componentName}.move`, "formatAndWriteMove"); }) } \ No newline at end of file diff --git a/packages/common/src/codegen/utils/renderMove/generateEntityKey.ts b/packages/common/src/codegen/utils/renderMove/generateEntityKey.ts index b915bf25..aa64e52c 100644 --- a/packages/common/src/codegen/utils/renderMove/generateEntityKey.ts +++ b/packages/common/src/codegen/utils/renderMove/generateEntityKey.ts @@ -2,7 +2,7 @@ import { ObeliskConfig } from '../../types'; import { formatAndWriteMove } from '../formatAndWrite'; export function generateEntityKey(config: ObeliskConfig, srcPrefix: string) { - let code = `module ${config.project_name}::entity_key { + let code = `module ${config.projectName}::entity_key { use sui::object; public fun object_to_entity_key(object: &T): vector { @@ -10,5 +10,5 @@ export function generateEntityKey(config: ObeliskConfig, srcPrefix: string) { } } ` - formatAndWriteMove(code, `${srcPrefix}/contracts/${config.project_name}/sources/entity_key.move`, "formatAndWriteMove"); + formatAndWriteMove(code, `${srcPrefix}/contracts/${config.projectName}/sources/entity_key.move`, "formatAndWriteMove"); } \ No newline at end of file diff --git a/packages/common/src/codegen/utils/renderMove/generateEps.ts b/packages/common/src/codegen/utils/renderMove/generateEps.ts index d94bfa45..1ba44efa 100644 --- a/packages/common/src/codegen/utils/renderMove/generateEps.ts +++ b/packages/common/src/codegen/utils/renderMove/generateEps.ts @@ -2,7 +2,7 @@ import { ObeliskConfig } from '../../types'; import { formatAndWriteMove } from '../formatAndWrite'; export function generateEps(config: ObeliskConfig, srcPrefix: string) { - let code = `module ${config.project_name}::world { + let code = `module ${config.projectName}::world { use sui::tx_context::TxContext; use sui::hash::keccak256; use sui::bag::{ Self, Bag }; @@ -43,5 +43,5 @@ export function generateEps(config: ObeliskConfig, srcPrefix: string) { } } ` - formatAndWriteMove(code, `${srcPrefix}/contracts/${config.project_name}/sources/codegen/eps/world.move`, "formatAndWriteMove"); + formatAndWriteMove(code, `${srcPrefix}/contracts/${config.projectName}/sources/codegen/eps/world.move`, "formatAndWriteMove"); } \ No newline at end of file diff --git a/packages/common/src/codegen/utils/renderMove/generateInit.ts b/packages/common/src/codegen/utils/renderMove/generateInit.ts index 7ee8b7e8..7db455a8 100644 --- a/packages/common/src/codegen/utils/renderMove/generateInit.ts +++ b/packages/common/src/codegen/utils/renderMove/generateInit.ts @@ -3,12 +3,12 @@ import { formatAndWriteMove } from '../formatAndWrite'; import { getRegisterComponent, getRegisterSingletonComponent, getUseComponent } from './common'; export function generateInit(config: ObeliskConfig, srcPrefix: string) { - let code = `module ${config.project_name}::init { + let code = `module ${config.projectName}::init { use sui::transfer; use sui::tx_context::TxContext; - use ${config.project_name}::world; -${getUseComponent(config.project_name, config.components).join("\n")} -${getUseComponent(config.project_name, config.singletonComponents).join("\n")} + use ${config.projectName}::world; +${getUseComponent(config.projectName, config.components).join("\n")} +${getUseComponent(config.projectName, config.singletonComponents).join("\n")} fun init(ctx: &mut TxContext) { let world = world::create_world(ctx); @@ -26,5 +26,5 @@ ${getRegisterSingletonComponent(config.singletonComponents).join("\n")} } } ` - formatAndWriteMove(code, `${srcPrefix}/contracts/${config.project_name}/sources/codegen/init.move`, "formatAndWriteMove"); + formatAndWriteMove(code, `${srcPrefix}/contracts/${config.projectName}/sources/codegen/init.move`, "formatAndWriteMove"); } \ No newline at end of file diff --git a/packages/common/src/codegen/utils/renderMove/generateSystem.ts b/packages/common/src/codegen/utils/renderMove/generateSystem.ts index ecfd03b1..28cc507a 100644 --- a/packages/common/src/codegen/utils/renderMove/generateSystem.ts +++ b/packages/common/src/codegen/utils/renderMove/generateSystem.ts @@ -3,10 +3,10 @@ import { formatAndWriteMove } from '../formatAndWrite'; export function generateSystem(config: ObeliskConfig, srcPrefix: string) { config.systems.map((systemName) => { - let code = `module ${config.project_name}::${systemName} { + let code = `module ${config.projectName}::${systemName} { } ` - formatAndWriteMove(code, `${srcPrefix}/contracts/${config.project_name}/sources/system/${systemName}.move`, "formatAndWriteMove"); + formatAndWriteMove(code, `${srcPrefix}/contracts/${config.projectName}/sources/system/${systemName}.move`, "formatAndWriteMove"); }) } \ No newline at end of file diff --git a/packages/common/src/codegen/utils/renderMove/generateToml.ts b/packages/common/src/codegen/utils/renderMove/generateToml.ts index 32f18c23..e2239968 100644 --- a/packages/common/src/codegen/utils/renderMove/generateToml.ts +++ b/packages/common/src/codegen/utils/renderMove/generateToml.ts @@ -3,7 +3,7 @@ import { formatAndWriteMove } from '../formatAndWrite'; export function generateToml(config: ObeliskConfig, srcPrefix: string) { let code = `[package] -name = "${config.project_name}" +name = "${config.projectName}" version = "0.0.1" [dependencies] @@ -11,7 +11,7 @@ Sui = { git = "https://github.com/MystenLabs/sui.git", subdir = "crates/sui-fram [addresses] sui = "0x2" -${config.project_name} = "0x0" +${config.projectName} = "0x0" ` - formatAndWriteMove(code, `${srcPrefix}/contracts/${config.project_name}/Move.toml`, "formatAndWriteMove"); + formatAndWriteMove(code, `${srcPrefix}/contracts/${config.projectName}/Move.toml`, "formatAndWriteMove"); } \ No newline at end of file diff --git a/packages/common/src/codegen/utils/renderMove/worldgen.ts b/packages/common/src/codegen/utils/renderMove/worldgen.ts index 11d489bc..a2c89df2 100644 --- a/packages/common/src/codegen/utils/renderMove/worldgen.ts +++ b/packages/common/src/codegen/utils/renderMove/worldgen.ts @@ -16,8 +16,8 @@ export function worldgen(config: ObeliskConfig, srcPrefix?: string) { path = srcPrefix; } - if (existsSync(`${path}/contracts/${config.project_name}`)) { - deleteFolderRecursive(`${path}/contracts/${config.project_name}/sources/codegen`) + if (existsSync(`${path}/contracts/${config.projectName}`)) { + deleteFolderRecursive(`${path}/contracts/${config.projectName}/sources/codegen`) } else { generateSystem(config, path); generateToml(config, path); From a0e70ed6ad35d284264e570ef065391b812c6c03 Mon Sep 17 00:00:00 2001 From: henryliu <17600047539@163.com> Date: Mon, 11 Sep 2023 22:47:38 +0800 Subject: [PATCH 11/16] update --- packages/cli/package.json | 2 +- packages/client/package.json | 2 +- packages/common/package.json | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/cli/package.json b/packages/cli/package.json index 293aed89..c112d4ba 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -1,6 +1,6 @@ { "name": "@0xobelisk/cli", - "version": "0.0.7", + "version": "0.1.3", "description": "Tookit for interacting with move eps framework", "keywords": [ "sui", diff --git a/packages/client/package.json b/packages/client/package.json index c1a96f44..cbe6b0ef 100644 --- a/packages/client/package.json +++ b/packages/client/package.json @@ -1,6 +1,6 @@ { "name": "@0xobelisk/client", - "version": "0.1.2", + "version": "0.1.3", "description": "Tookit for interacting with move eps framework", "keywords": [ "sui", diff --git a/packages/common/package.json b/packages/common/package.json index 9fb1034d..cd1133f8 100644 --- a/packages/common/package.json +++ b/packages/common/package.json @@ -1,6 +1,6 @@ { "name": "@0xobelisk/common", - "version": "0.0.2", + "version": "0.1.3", "description": "Common low level logic shared between packages", "keywords": [ "sui", From 2058be30861eab947156125b1b30d1afc58c6da4 Mon Sep 17 00:00:00 2001 From: henryliu <17600047539@163.com> Date: Mon, 11 Sep 2023 22:48:15 +0800 Subject: [PATCH 12/16] update --- packages/cli/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/cli/package.json b/packages/cli/package.json index c112d4ba..6ef66285 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -39,7 +39,7 @@ "lint": "eslint . --ext .ts" }, "dependencies": { - "@0xobelisk/common": "0.0.2", + "@0xobelisk/common": "0.1.3", "@mysten/sui.js": "^0.41.0", "chalk": "^5.0.1", "child_process": "^1.0.2", From 4a63342922241fb7d6372aac81bc31915f7c17cc Mon Sep 17 00:00:00 2001 From: vladilen11 Date: Tue, 12 Sep 2023 16:48:16 +0800 Subject: [PATCH 13/16] Some nits. --- packages/client/scripts/init.ts | 4 ++-- packages/client/src/index.ts | 6 +----- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/packages/client/scripts/init.ts b/packages/client/scripts/init.ts index 564397aa..c86603a0 100644 --- a/packages/client/scripts/init.ts +++ b/packages/client/scripts/init.ts @@ -48,8 +48,8 @@ async function init() { const obelisk = new Obelisk({ networkType: network as NetworkType, - // packageId: packageId, - // metadata: metadata, + packageId: packageId, + metadata: metadata, // secretKey: privkey }); diff --git a/packages/client/src/index.ts b/packages/client/src/index.ts index fefb2df5..b77a15e5 100644 --- a/packages/client/src/index.ts +++ b/packages/client/src/index.ts @@ -1,8 +1,4 @@ -export { - TransactionBlock, - SUI_CLOCK_OBJECT_ID, - SUI_SYSTEM_STATE_OBJECT_ID, -} from '@mysten/sui.js'; +export * from '@mysten/sui.js'; export { Ed25519Keypair } from '@mysten/sui.js/keypairs/ed25519'; export { fromB64, toB64 } from '@mysten/sui.js'; export * from '@mysten/sui.js/bcs'; From 609f012159eb45590f8bf87678e38a91b3e49f53 Mon Sep 17 00:00:00 2001 From: henryliu <17600047539@163.com> Date: Wed, 13 Sep 2023 00:06:41 +0800 Subject: [PATCH 14/16] update README.md --- README.md | 30 ++++++++++++++++++------------ assets/obelisk-full-logo.png | Bin 0 -> 19136 bytes assets/obelisk-full.jpeg | Bin 0 -> 34581 bytes 3 files changed, 18 insertions(+), 12 deletions(-) create mode 100644 assets/obelisk-full-logo.png create mode 100644 assets/obelisk-full.jpeg diff --git a/README.md b/README.md index 1c8aac09..f453767e 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,20 @@ ## Obelisk-Engine +
+ +
+ ![Github Actions][gha-badge] @@ -16,30 +31,21 @@ Obelisk-Engine is still in its early stages of development, yet the dedicated co - Typed SDKs ## 🚀 Quick Start - +See the [start guide](https://obelisk.build/pack/docs/quick-start) in the document website. ## 🗒️ Documentation - +You can find more detailed documentation in [here](https://obelisk.build/pack/docs). ## ❓ Support - +If you encounter issues or have questions, [you can submit an issue on GitHub](https://github.com/0xobelisk/obelisk-engine/issues). You can also join our Discord for discussion and help. ## 🏗️ Contributing We'd love your support in improving Obelisk! This monorepo includes all of Obelisk source code, and pull requests are always welcome. To discuss new features or changes [join our Telegram](https://t.me/+0_98p03Fbv1hNzY1). - - -## ✏️ Environment - - - -## ⛩️ Built with Obelisk - - ## Contributors ✨ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/docs/en/emoji-key)): diff --git a/assets/obelisk-full-logo.png b/assets/obelisk-full-logo.png new file mode 100644 index 0000000000000000000000000000000000000000..5c8ee1b2bff4402455e1490a232f98b14a44afff GIT binary patch literal 19136 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 E0m&N*O#lD@ literal 0 HcmV?d00001 diff --git a/assets/obelisk-full.jpeg b/assets/obelisk-full.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..7c7ea118fcb10cf596991fdb07bcd0621eafe4fd GIT binary patch literal 34581 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 N*-6{%%-Xke{|}FGS7-nL literal 0 HcmV?d00001 From 9142d35441dd183b0e5ae6273657303a9ed22cc4 Mon Sep 17 00:00:00 2001 From: vladilen11 Date: Mon, 18 Sep 2023 17:17:09 +0800 Subject: [PATCH 15/16] update pnpm workspace --- packages/cli/package.json | 4 ++-- packages/cli/yarn.lock | 8 ++++---- packages/client/package.json | 4 ++-- pnpm-workspace.yaml | 2 ++ 4 files changed, 10 insertions(+), 8 deletions(-) create mode 100644 pnpm-workspace.yaml diff --git a/packages/cli/package.json b/packages/cli/package.json index 6ef66285..c7b109ef 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -39,7 +39,7 @@ "lint": "eslint . --ext .ts" }, "dependencies": { - "@0xobelisk/common": "0.1.3", + "@0xobelisk/common": "workspace:*", "@mysten/sui.js": "^0.41.0", "chalk": "^5.0.1", "child_process": "^1.0.2", @@ -74,4 +74,4 @@ "tsx": "^3.12.6", "vitest": "0.31.4" } -} +} \ No newline at end of file diff --git a/packages/cli/yarn.lock b/packages/cli/yarn.lock index 4e0b80eb..a5b74f83 100644 --- a/packages/cli/yarn.lock +++ b/packages/cli/yarn.lock @@ -2,10 +2,10 @@ # yarn lockfile v1 -"@0xobelisk/common@0.0.2": - version "0.0.1" - resolved "https://registry.npmmirror.com/@0xobelisk/common/-/common-0.0.1.tgz#444f8ba1dfc167d7b67b29f2ae49c34bedcf53a6" - integrity sha512-H+A5ou/92L33IKESCzGiaHivL1yBcw3NtGdDYqpVS2dPzxa9KwZq4ZCWH7zbeoSDuCZLlg1W2hQ/VUB/izDraA== +"@0xobelisk/common@workspace:*": + version "0.1.3" + resolved "https://registry.npmjs.org/@0xobelisk/common/-/common-0.1.3.tgz#ce6a4e6d24debc7b6b5b83d7573261d78c33cdd0" + integrity sha512-YT2laH3JSpX8TCzXLlN4lhMocEij6LgSSCoxrk1KC+rPNl0nXxtfpnhh8N6qk8qgVegGXl8zuXZkIjiil3q5cQ== dependencies: "@mysten/sui.js" "^0.41.0" chalk "^5.0.1" diff --git a/packages/client/package.json b/packages/client/package.json index cbe6b0ef..84c8ed51 100644 --- a/packages/client/package.json +++ b/packages/client/package.json @@ -59,7 +59,7 @@ "dependencies": { "@mysten/bcs": "^0.7.3", "@mysten/sui.js": "^0.41.0", - "@obelisk/common": "link:../common", + "@obelisk/common": "workspace:*", "@scure/bip39": "^1.2.1", "assert": "^2.0.0", "colorts": "^0.1.63", @@ -150,4 +150,4 @@ ] } } -} +} \ No newline at end of file diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml new file mode 100644 index 00000000..9bec5ba5 --- /dev/null +++ b/pnpm-workspace.yaml @@ -0,0 +1,2 @@ +packages: + - packages/* From f1652f320ff1b46f8692e58add267289efea8a77 Mon Sep 17 00:00:00 2001 From: vladilen11 Date: Mon, 18 Sep 2023 17:40:15 +0800 Subject: [PATCH 16/16] update client --- packages/client/LICENSE | 202 ---------------------------------------- 1 file changed, 202 deletions(-) delete mode 100644 packages/client/LICENSE diff --git a/packages/client/LICENSE b/packages/client/LICENSE deleted file mode 100644 index d58b6fef..00000000 --- a/packages/client/LICENSE +++ /dev/null @@ -1,202 +0,0 @@ - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright 2023 Scallop Labs - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License.