diff --git a/.Lib9c.Benchmarks/Program.cs b/.Lib9c.Benchmarks/Program.cs index 6b4126dd01..5fbd4ff964 100644 --- a/.Lib9c.Benchmarks/Program.cs +++ b/.Lib9c.Benchmarks/Program.cs @@ -121,7 +121,7 @@ static void Main(string[] args) block.Transactions.Count() ); - chain.DetermineBlockStateRootHash(block, out IReadOnlyList blockEvals); + chain.DetermineNextBlockStateRootHash(block, out IReadOnlyList blockEvals); txs += block.Transactions.LongCount(); actions += block.Transactions.Sum(tx => tx.Actions is { } customActions ? customActions.LongCount() : 0); diff --git a/.Lib9c.Tests/Action/RewardGoldTest.cs b/.Lib9c.Tests/Action/RewardGoldTest.cs index f62a615f3a..dab60ece07 100644 --- a/.Lib9c.Tests/Action/RewardGoldTest.cs +++ b/.Lib9c.Tests/Action/RewardGoldTest.cs @@ -491,88 +491,6 @@ void AssertMinerReward(int blockIndex, string expected) AssertMinerReward(50457601, "0"); } - [Theory] - [InlineData(true)] - [InlineData(false)] - public async Task Genesis_StateRootHash(bool mainnet) - { - BlockPolicySource blockPolicySource = new BlockPolicySource(); - NCStagePolicy stagePolicy = new NCStagePolicy(default, 2); - IBlockPolicy policy = blockPolicySource.GetPolicy(); - Block genesis; - if (mainnet) - { - const string genesisBlockPath = "https://release.nine-chronicles.com/genesis-block-9c-main"; - var uri = new Uri(genesisBlockPath); - using var client = new HttpClient(); - var rawBlock = await client.GetByteArrayAsync(uri); - var blockDict = (Bencodex.Types.Dictionary)new Codec().Decode(rawBlock); - genesis = BlockMarshaler.UnmarshalBlock(blockDict); - } - else - { - var adminPrivateKey = new PrivateKey(); - var adminAddress = adminPrivateKey.Address; - var activatedAccounts = ImmutableHashSet
.Empty; - var nonce = new byte[] { 0x00, 0x01, 0x02, 0x03 }; - var privateKey = new PrivateKey(); - (ActivationKey activationKey, PendingActivationState pendingActivation) = - ActivationKey.Create(privateKey, nonce); - var pendingActivationStates = new List - { - pendingActivation, - }; - var initializeStates = new InitializeStates( - rankingState: new RankingState0(), - shopState: new ShopState(), - gameConfigState: new GameConfigState(), - redeemCodeState: new RedeemCodeState(Bencodex.Types.Dictionary.Empty - .Add("address", RedeemCodeState.Address.Serialize()) - .Add("map", Bencodex.Types.Dictionary.Empty) - ), - adminAddressState: new AdminState(adminAddress, 1500000), - activatedAccountsState: new ActivatedAccountsState(activatedAccounts), -#pragma warning disable CS0618 - // Use of obsolete method Currency.Legacy(): https://github.com/planetarium/lib9c/discussions/1319 - goldCurrencyState: new GoldCurrencyState(Currency.Legacy("NCG", 2, null)), -#pragma warning restore CS0618 - goldDistributions: new GoldDistribution[0], - tableSheets: TableSheetsImporter.ImportSheets(), - pendingActivationStates: pendingActivationStates.ToArray() - ); - var tempActionEvaluator = new ActionEvaluator( - policyBlockActionGetter: _ => policy.BlockAction, - stateStore: new TrieStateStore(new MemoryKeyValueStore()), - actionTypeLoader: new NCActionLoader()); - genesis = BlockChain.ProposeGenesisBlock( - tempActionEvaluator, - transactions: ImmutableList.Empty - .Add(Transaction.Create( - 0, - new PrivateKey(), - null, - new ActionBase[] { initializeStates }.ToPlainValues())) - ); - } - - var store = new DefaultStore(null); - var stateStore = new TrieStateStore(new DefaultKeyValueStore(null)); - var blockChain = BlockChain.Create( - policy: policy, - store: store, - stagePolicy: stagePolicy, - stateStore: stateStore, - genesisBlock: genesis, - actionEvaluator: new ActionEvaluator( - policyBlockActionGetter: _ => policy.BlockAction, - stateStore: stateStore, - actionTypeLoader: new NCActionLoader() - ), - renderers: new IRenderer[] { new ActionRenderer(), new BlockRenderer() } - ); - Assert.Equal(genesis.StateRootHash, blockChain.Genesis.StateRootHash); - } - [Theory] [InlineData(5, 4)] [InlineData(101, 100)] diff --git a/.Lib9c.Tests/Policy/BlockPolicyTest.cs b/.Lib9c.Tests/Policy/BlockPolicyTest.cs index f420bec26e..90c2a93b2c 100644 --- a/.Lib9c.Tests/Policy/BlockPolicyTest.cs +++ b/.Lib9c.Tests/Policy/BlockPolicyTest.cs @@ -5,12 +5,14 @@ namespace Lib9c.Tests using System.Collections.Immutable; using System.Linq; using System.Numerics; + using System.Security.Cryptography; using Bencodex.Types; using Lib9c.Renderers; using Libplanet.Action; using Libplanet.Action.State; using Libplanet.Blockchain; using Libplanet.Blockchain.Policies; + using Libplanet.Common; using Libplanet.Crypto; using Libplanet.Store; using Libplanet.Store.Trie; @@ -395,7 +397,7 @@ public void EarnMiningGoldWhenSuccessMining() Block block = blockChain.ProposeBlock(adminPrivateKey); blockChain.Append(block, GenerateBlockCommit(block, adminPrivateKey)); FungibleAssetValue actualBalance = blockChain - .GetWorldState() + .GetNextWorldState() .GetBalance(adminAddress, _currency); FungibleAssetValue expectedBalance = new FungibleAssetValue(_currency, 10, 0); Assert.True(expectedBalance.Equals(actualBalance)); @@ -424,17 +426,18 @@ public void ValidateNextBlockWithManyTransactions() using var store = new DefaultStore(null); var stateStore = new TrieStateStore(new MemoryKeyValueStore()); + var actionEvaluator = new ActionEvaluator( + policyBlockActionGetter: _ => policy.BlockAction, + stateStore: stateStore, + actionTypeLoader: new NCActionLoader() + ); var blockChain = BlockChain.Create( policy, stagePolicy, store, stateStore, genesis, - new ActionEvaluator( - policyBlockActionGetter: _ => policy.BlockAction, - stateStore: stateStore, - actionTypeLoader: new NCActionLoader() - ) + actionEvaluator ); int nonce = 0; @@ -465,7 +468,7 @@ List GenerateTransactions(int count) txHash: BlockContent.DeriveTxHash(txs), lastCommit: null), transactions: txs).Propose(); - Block block1 = EvaluateAndSign(blockChain, preEvalBlock1, adminPrivateKey); + Block block1 = EvaluateAndSign(store, actionEvaluator, preEvalBlock1, adminPrivateKey); blockChain.Append(block1, GenerateBlockCommit(block1, adminPrivateKey)); Assert.Equal(2, blockChain.Count); Assert.True(blockChain.ContainsBlock(block1.Hash)); @@ -479,7 +482,7 @@ List GenerateTransactions(int count) txHash: BlockContent.DeriveTxHash(txs), lastCommit: GenerateBlockCommit(blockChain.Tip, adminPrivateKey)), transactions: txs).Propose(); - Block block2 = EvaluateAndSign(blockChain, preEvalBlock2, adminPrivateKey); + Block block2 = EvaluateAndSign(store, actionEvaluator, preEvalBlock2, adminPrivateKey); blockChain.Append(block2, GenerateBlockCommit(block2, adminPrivateKey)); Assert.Equal(3, blockChain.Count); Assert.True(blockChain.ContainsBlock(block2.Hash)); @@ -493,7 +496,7 @@ List GenerateTransactions(int count) txHash: BlockContent.DeriveTxHash(txs), lastCommit: GenerateBlockCommit(blockChain.Tip, adminPrivateKey)), transactions: txs).Propose(); - Block block3 = EvaluateAndSign(blockChain, preEvalBlock3, adminPrivateKey); + Block block3 = EvaluateAndSign(store, actionEvaluator, preEvalBlock3, adminPrivateKey); Assert.Throws( () => blockChain.Append(block3, GenerateBlockCommit(block3, adminPrivateKey))); Assert.Equal(3, blockChain.Count); @@ -525,17 +528,18 @@ public void ValidateNextBlockWithManyTransactionsPerSigner() using var store = new DefaultStore(null); var stateStore = new TrieStateStore(new MemoryKeyValueStore()); + var actionEvaluator = new ActionEvaluator( + policyBlockActionGetter: _ => policy.BlockAction, + stateStore: stateStore, + actionTypeLoader: new NCActionLoader() + ); var blockChain = BlockChain.Create( policy, stagePolicy, store, stateStore, genesis, - new ActionEvaluator( - policyBlockActionGetter: _ => policy.BlockAction, - stateStore: stateStore, - actionTypeLoader: new NCActionLoader() - ) + actionEvaluator ); int nonce = 0; @@ -566,7 +570,7 @@ List GenerateTransactions(int count) txHash: BlockContent.DeriveTxHash(txs), lastCommit: null), transactions: txs).Propose(); - Block block1 = EvaluateAndSign(blockChain, preEvalBlock1, adminPrivateKey); + Block block1 = EvaluateAndSign(store, actionEvaluator, preEvalBlock1, adminPrivateKey); // Should be fine since policy hasn't kicked in yet. blockChain.Append(block1, GenerateBlockCommit(block1, adminPrivateKey)); @@ -583,7 +587,7 @@ List GenerateTransactions(int count) txHash: BlockContent.DeriveTxHash(txs), lastCommit: GenerateBlockCommit(blockChain.Tip, adminPrivateKey)), transactions: txs).Propose(); - Block block2 = EvaluateAndSign(blockChain, preEvalBlock2, adminPrivateKey); + Block block2 = EvaluateAndSign(store, actionEvaluator, preEvalBlock2, adminPrivateKey); // Subpolicy kicks in. Assert.Throws( @@ -604,7 +608,7 @@ List GenerateTransactions(int count) txHash: BlockContent.DeriveTxHash(txs), lastCommit: GenerateBlockCommit(blockChain.Tip, adminPrivateKey)), transactions: txs).Propose(); - Block block3 = EvaluateAndSign(blockChain, preEvalBlock3, adminPrivateKey); + Block block3 = EvaluateAndSign(store, actionEvaluator, preEvalBlock3, adminPrivateKey); blockChain.Append(block3, GenerateBlockCommit(block3, adminPrivateKey)); Assert.Equal(3, blockChain.Count); Assert.True(blockChain.ContainsBlock(block3.Hash)); @@ -663,13 +667,29 @@ private Block MakeGenesisBlock( } private Block EvaluateAndSign( - BlockChain blockChain, + IStore store, + ActionEvaluator actionEvaluator, PreEvaluationBlock preEvaluationBlock, PrivateKey privateKey ) { - var stateRootHash = blockChain.DetermineBlockStateRootHash(preEvaluationBlock, out _); - return preEvaluationBlock.Sign(privateKey, stateRootHash); + if (preEvaluationBlock.Index < 1) + { + throw new ArgumentException( + $"Given {nameof(preEvaluationBlock)} must have block index " + + $"higher than 0"); + } + + if (preEvaluationBlock.ProtocolVersion < BlockMetadata.SlothProtocolVersion) + { + throw new ArgumentException( + $"{nameof(preEvaluationBlock)} of which protocol version less than" + + $"{BlockMetadata.SlothProtocolVersion} is not acceptable"); + } + + var stateRootHash = store.GetNextStateRootHash((BlockHash)preEvaluationBlock.PreviousHash); + + return preEvaluationBlock.Sign(privateKey, (HashDigest)stateRootHash); } } } diff --git a/.Lib9c.Tools/SubCommand/State.cs b/.Lib9c.Tools/SubCommand/State.cs index d418ebe4f4..06675d3a25 100644 --- a/.Lib9c.Tools/SubCommand/State.cs +++ b/.Lib9c.Tools/SubCommand/State.cs @@ -118,14 +118,16 @@ IStateStore stateStore _ => policy.BlockAction, stateStore, actionLoader); - HashDigest stateRootHash = block.Index < 1 - ? BlockChain.DetermineGenesisStateRootHash( - actionEvaluator, - preEvalBlock, - out _) - : chain.DetermineBlockStateRootHash( - preEvalBlock, - out _); + + HashDigest? refSrh = block.ProtocolVersion < BlockMetadata.SlothProtocolVersion + ? store.GetStateRootHash(block.PreviousHash) + : store.GetStateRootHash(block.Hash); + + IReadOnlyList evals = actionEvaluator.Evaluate(block, refSrh); + HashDigest stateRootHash = evals.Count > 0 + ? evals[evals.Count - 1].OutputState + : refSrh is { } prevSrh ? prevSrh : MerkleTrie.EmptyRootHash; + DateTimeOffset now = DateTimeOffset.Now; if (invalidStateRootHashBlock is null && !stateRootHash.Equals(block.StateRootHash)) { diff --git a/.Libplanet b/.Libplanet index d10613e3a1..ebb5e8493f 160000 --- a/.Libplanet +++ b/.Libplanet @@ -1 +1 @@ -Subproject commit d10613e3a1b49bc92c956e18bab16606d2f35f2f +Subproject commit ebb5e8493f2beeae562d2438403395991d43c51d diff --git a/@planetarium/lib9c/docs/.gitignore b/@planetarium/lib9c/docs/.gitignore new file mode 100644 index 0000000000..4f2fc4ac0e --- /dev/null +++ b/@planetarium/lib9c/docs/.gitignore @@ -0,0 +1 @@ +.vitepress/cache diff --git a/@planetarium/lib9c/docs/.vitepress/config.ts b/@planetarium/lib9c/docs/.vitepress/config.ts new file mode 100644 index 0000000000..4e95c78cfb --- /dev/null +++ b/@planetarium/lib9c/docs/.vitepress/config.ts @@ -0,0 +1,74 @@ +import { defineConfig } from 'vitepress' + +// https://vitepress.dev/reference/site-config +export default defineConfig({ + title: "@planetarium/lib9c", + description: "Documentation for @planetarium/lib9c package", + themeConfig: { + // https://vitepress.dev/reference/default-theme-config + nav: [ + { text: 'Docs', link: '/docs/index.md' }, + { text: 'API Reference', link: 'https://jsr.io/@planetarium/lib9c' }, + ], + + socialLinks: [ + { icon: 'github', link: 'https://github.com/planetarium/lib9c/tree/development/%40planetarium/lib9c' } + ], + + i18nRouting: true, + sidebar: [ + { + link: '/docs/index.md', + text: "Introduction" + }, + { + link: '/docs/installation.md', + text: "Installation" + }, + { + link: '/docs/actions.md', + text: "Actions" + }, + { + link: '/docs/utility.md', + text: "Utility" + } + ], + outline: 'deep' + }, + locales: { + root: { + label: 'English', + lang: 'en', + }, + ko: { + label: 'Korean', + lang: 'ko', + themeConfig: { + i18nRouting: true, + nav: [ + { text: '문서', link: '/ko/docs/index.md' }, + { text: 'API Reference', link: 'https://jsr.io/@planetarium/lib9c' }, + ], + sidebar: [ + { + link: '/ko/docs/index.md', + text: "소개" + }, + { + link: '/ko/docs/installation.md', + text: "설치" + }, + { + link: '/ko/docs/actions.md', + text: "액션" + }, + { + link: '/ko/docs/utility.md', + text: "유틸리티" + } + ] + } + }, + } +}) diff --git a/@planetarium/lib9c/docs/docs/actions.md b/@planetarium/lib9c/docs/docs/actions.md new file mode 100644 index 0000000000..593b2c6e9e --- /dev/null +++ b/@planetarium/lib9c/docs/docs/actions.md @@ -0,0 +1,91 @@ +# Actions + +## TransferAsset - Transfer + +This action is used when you want to transfer a `FungibleAssetValue` that you own to another address. + +```typescript +import { TransferAsset, NCG, fav } from “@planetarium/lib9c”; +import { Address } from “@planetarium/account”; + +const action = new TransferAsset({ + sender: Address.fromHex('0x491d9842ed8f1b5d291272cf9e7b66a7b7c90cda', true), + recipient: Address.fromHex('0xfee0bfb15fb3fe521560cbdb308ece4457d13cfa', true), + amount: fav(NCG, 2), +}); +``` + +If you want to send money to the Ethereum WNCG bridge and convert it to Ethereum WNCG, create an action as follows. This is only valid on the Odin mainnet network. + +```typescript +import { TransferAsset, NCG, fav } from “@planetarium/lib9c”; +import { Address } from “@planetarium/account”; + +const MY_ADDRESS = Address.fromHex('', true); // [!code warning] Replace with your address. +const ETHEREUM_BRIDGE_ADDRESS = Address.fromHex('0x9093dd96c4bb6b44a9e0a522e2de49641f146223', true); +const AMOUNT = '100.0'; // [!code warning] Replace with the amount you want to bridge. + +const action = new TransferAsset({ + sender: MY_ADDRESS, + recipient: ETHEREUM_BRIDGE_ADDRESS, + amount: fav(NCG, AMOUNT), +}); +``` + +## TransferAssets - Multiple transfers + +This action is used when you want to transfer a number of `FungibleAssetValue`s you own to different addresses. The example below sends 2 NCG to each address. + +```typescript +import { TransferAsses, NCG, fav } from “@planetarium/lib9c”; +import { Address } from “@planetarium/account”; + +const sender = Address.fromHex('0x2cBaDf26574756119cF705289C33710F27443767'); +const agentAddresses = [ + Address.fromHex(“0xfee0bfb15fb3fe521560cbdb308ece4457d13cfa”, true), + Address.fromHex(“0x491d9842ed8f1b5d291272cf9e7b66a7b7c90cda”, true), +]; +const recipients = agentAddresses.map((address) => [address, fav(NCG, 2)]); +const action = new TransferAssets({ + sender, + recipients, +}); +``` + +## DailyReward - Recharges Action Points + +```typescript +import { DailyReward } from “@planetarium/lib9c”; +import { Address } from “@planetarium/account”; + +const action = new DailyReward({ + avatarAddress: Address.fromHex('0xDE3873DB166647Cc3538ef64EAA8A0cCFD51B9fE'), +}); +``` + +## Stake - Staking + +This action is used when you want to proceed with monster collection (staking). Deposits an amount of NCG equal to `amount`. See [NCIP-17] for implementation definitions. + +```typescript +import { Stake } from “@planetarium/lib9c”; + +const action = new Stake({ + amount: 100n, +}); +``` + +## ClaimStakeReward - Claiming a Stake Reward + +This action is used when you want to claim a Monster Collection (Stake) reward. The `Stake` action will claim the reward corresponding to the NCG you have etched. Requires an `avatarAddress` to receive the reward. See [NCIP-17] for implementation definitions. + +```typescript +import { ClaimStakeReward } from “@planetarium/lib9c”; +import { Address } from “@planetarium/account”; + +const action = new ClaimStakeReward({ + avatarAddress: Address.fromHex('0xDE3873DB166647Cc3538ef64EAA8A0cCFD51B9fE'), +}); +``` + +[NCIP-17]: https://github.com/planetarium/NCIPs/blob/main/NCIP/ncip-17.md diff --git a/@planetarium/lib9c/docs/docs/index.md b/@planetarium/lib9c/docs/docs/index.md new file mode 100644 index 0000000000..dc4cab3541 --- /dev/null +++ b/@planetarium/lib9c/docs/docs/index.md @@ -0,0 +1,27 @@ +--- +outline: deep +--- + +# Introduction + +The `@planetarium/lib9c` library was created to help create the transactions needed to interact with the Nine Chronicles network. It is written in JavaScript/TypeScript for ease of use on the web. It will be very useful if you are creating a service or automated bot on top of the Nine Chronicles network. + +There may be some actions that are missing, but we hope the community will add and contribute as needed. There is documentation available, and if you're stuck, please ask for help in the docs. + +## Related Libraries + +The Nine Chronicles network is built utilizing a .NET-based blockchain library called Libplanet created by Planetarium. Therefore, we recommend using the `@planetarium/tx` and `@planetarium/account` libraries created by the Libplanet team to create and sign transactions. Please refer to their documentation to learn how to use these libraries. + +## Caveats when using JavaScript + +This library is written in TypeScript. It relies on type checking to ensure that values are passed in with sufficient validation. JavaScript does not have this type checking and this library does not have any logic to dynamically check, so please be aware that if you are using JavaScript, it may be difficult to notice problems caused by these invalid values. + +## Discord + +[![Planetarium Dev][planetarium-dev-badge]][planetarium-dev-invite-link] + +This library was created by the DX team of the Planetarium organization. It resides on the Planetarium Dev discord server and if you have any questions, please leave them on the server in channels like 'NINE CHRONICLES > #general', 'NINE CHRONICLES > #lib9c', etc. + + +[planetarium-dev-badge]: https://img.shields.io/discord/928926944937013338?color=6278DA&label=Planetarium-dev&logo=discord&logoColor=white +[planetarium-dev-invite-link]: https://discord.com/invite/RYJDyFRYY7 diff --git a/@planetarium/lib9c/docs/docs/installation.md b/@planetarium/lib9c/docs/docs/installation.md new file mode 100644 index 0000000000..6957c1be35 --- /dev/null +++ b/@planetarium/lib9c/docs/docs/installation.md @@ -0,0 +1,31 @@ +# Installation + +The `@planetarium/lib9c` library is distributed in a package registry called *[jsr]* and can be installed via the jsr package in npm. API documentation is also automatically generated by jsr and can be found at [package page][jsr-docs]. + + +[jsr]: https://jsr.io/ +[jsr-docs]: https://jsr.io/@planetarium/lib9c@0.2.0-dev.202406030026370315+cb90675a71818491e09469b27a6ad4f19f8e3ce2/doc + +## Node + +For Node.js, depending on the package manager you are using, you can use the following. + +```bash +# pnpm +npx jsr add --pnpm @planetarium/lib9c + +# Yarn +npx jsr add --yarn @planetarium/lib9c + +# npm +npx jsr add @planetarium/lib9c +``` + +## Deno + +For Deno, you can install it with the Deno CLI. + +```bash +# deno add @planetarium/lib9c@ +deno add @planetarium/lib9c@0.2.0-dev.202406030026370315+cb90675a71818491e09469b27a6ad4f19f8e3ce2 +``` diff --git a/@planetarium/lib9c/docs/docs/utility.md b/@planetarium/lib9c/docs/docs/utility.md new file mode 100644 index 0000000000..9bbc5b8af4 --- /dev/null +++ b/@planetarium/lib9c/docs/docs/utility.md @@ -0,0 +1,70 @@ +# Utility + +## Currency + +### NCG + +Nine Chronicles has a currency called *Nine Chronicles Gold*, abbreviated as “NCG”. It is used for staking, called Monster Collections. It can also be used to purchase or enhance items, or to purchase Arena tickets. + +```typescript +import { NCG } from “@planetarium/lib9c”; +``` + +However, Nine Chronicles operates two networks, Odin and Heimdall, under a system called Multiplanetary. Both are valid mainnets, but the WNCG bridge is unique to Odin. On Heimdall, you should use `MINTERLESS_NCG` instead of `NCG`. + +```typescript +import { MINTELESS_NCG } from “@planetarium/lib9c”; +``` + +### CRYSTAL + +'CRYSTAL' is the currency used to unlock and craft item recipes and participate in the Arena. It can be obtained through staking rewards. + +```typescript +import { CRYSTAL } from “@planetarium/lib9c”; +``` + +### MEAD + +'MEAD' is a currency used as a transaction fee on the Nine Chronicles network. + +```typescript +import { MEAD } from “@planetarium/lib9c”; +``` + +### GARAGE + +'GARAGE' is used to move non-transferable goods. See [NCIP-16](https://github.com/planetarium/NCIPs/blob/main/NCIP/ncip-16.md). + +```typescript +import { GARAGE } from “@planetarium/lib9c”; +``` + +## Utility functions + +### `fav` + +To create a `FungibleAssetValue` from the original `@planetarium/tx`, we need to write the code below. The code below creates a `FungibleAssetValue` that means `10 CRYSTAL`. + +```typescript +const fav: FungibleAssetValue = { + currency: CRYSTAL, + rawValue: BigInt(new Decimal(10).mul(Decimal.pow(10, CRYSTAL.decimalPlaces)).toString()) +} +``` + +The reason we do this with `decimal.js` is because `FungibleAssetValue` (hereafter `FAV`) doesn't otherwise support decimals when displaying quantities. Not supporting decimals doesn't really mean it doesn't support decimals, it just defines the decimal places by the value in `Currency.decimalPlaces` while keeping the actual value as an integer. + +For example, when creating a `2 NCG`, the `FAV.rawValue` is `200n`. Because `NCG.decimalPlaces` is 2, the `00` part is used as the decimal place and the `2` part is used as the natural number part, which is expressed as `2.00 NCG` in common decimal notation. + +The `fav` function is a utility function that allows you to abbreviate code like this. The above code would look like this as a `fav` function + +```typescript +fav(NCG, 2); +``` + +However, it is not recommended to use the `number` type to handle prime numbers because there is an error in floating point numbers. In addition to prime numbers, there are also limits on the size of numbers, so you should use `bigint`, `string`, or `decimal.js`. If you do use `decimal.js`, make it a `string` type with `.toString()` and pass it to us. + +```typescript +import { fav } from “@planetarium/lib9c”; +``` diff --git a/@planetarium/lib9c/docs/index.md b/@planetarium/lib9c/docs/index.md new file mode 100644 index 0000000000..63ea61f9b5 --- /dev/null +++ b/@planetarium/lib9c/docs/index.md @@ -0,0 +1,19 @@ +--- +# https://vitepress.dev/reference/default-theme-home-page +layout: home + +hero: + name: "@planetarium/lib9c" + text: "A library for
Nine Chronicles
3rd-party Apps." + tagline: Build Nine Chronicles actions easily + actions: + - theme: brand + text: Docs + link: /docs + +features: + - title: TypeScript + details: Support several actions of Nine Chronicles protocol with types. + - title: Utility + details: Provide some utilities to create transactions easily. +--- diff --git a/@planetarium/lib9c/docs/ko/docs/actions.md b/@planetarium/lib9c/docs/ko/docs/actions.md new file mode 100644 index 0000000000..b9f56cb2b3 --- /dev/null +++ b/@planetarium/lib9c/docs/ko/docs/actions.md @@ -0,0 +1,91 @@ +# 액션 + +## TransferAsset - 송금 + +본인이 소유한 `FungibleAssetValue` 를 다른 주소로 넘기고 싶을 때 사용하는 액션입니다. + +```typescript +import { TransferAsset, NCG, fav } from "@planetarium/lib9c"; +import { Address } from "@planetarium/account"; + +const action = new TransferAsset({ + sender: Address.fromHex('0x491d9842ed8f1b5d291272cf9e7b66a7b7c90cda', true), + recipient: Address.fromHex('0xfee0bfb15fb3fe521560cbdb308ece4457d13cfa', true), + amount: fav(NCG, 2), +}); +``` + +이더리움 WNCG 브릿지에 송금하여 이더리움 WNCG로 환전하고 싶다면 다음과 같이 액션을 만드세요. Odin 메인넷 네트워크에서만 유효합니다. + +```typescript +import { TransferAsset, NCG, fav } from "@planetarium/lib9c"; +import { Address } from "@planetarium/account"; + +const MY_ADDRESS = Address.fromHex('', true); // [!code warning] Replace with your address. +const ETHEREUM_BRIDGE_ADDRESS = Address.fromHex('0x9093dd96c4bb6b44a9e0a522e2de49641f146223', true); +const AMOUNT = '100.0'; // [!code warning] Replace with the amount you want to bridge. + +const action = new TransferAsset({ + sender: MY_ADDRESS, + recipient: ETHEREUM_BRIDGE_ADDRESS, + amount: fav(NCG, AMOUNT), +}); +``` + +## TransferAssets - 다중 송금 + +본인이 소유한 `FungibleAssetValue`들을 다른 여러 주소로 넘기고 싶을 때 사용하는 액션입니다. 아래 예제는 각 주소들에 2 NCG 씩 송금합니다. + +```typescript +import { TransferAsses, NCG, fav } from "@planetarium/lib9c"; +import { Address } from "@planetarium/account"; + +const sender = Address.fromHex('0x2cBaDf26574756119cF705289C33710F27443767'); +const agentAddresses = [ + Address.fromHex("0xfee0bfb15fb3fe521560cbdb308ece4457d13cfa", true), + Address.fromHex("0x491d9842ed8f1b5d291272cf9e7b66a7b7c90cda", true), +]; +const recipients = agentAddresses.map((address) => [address, fav(NCG, 2)]); +const action = new TransferAssets({ + sender, + recipients, +}); +``` + +## DailyReward - Action Point 충전 + +```typescript +import { DailyReward } from "@planetarium/lib9c"; +import { Address } from "@planetarium/account"; + +const action = new DailyReward({ + avatarAddress: Address.fromHex('0xDE3873DB166647Cc3538ef64EAA8A0cCFD51B9fE'), +}); +``` + +## Stake - 스테이킹 + +몬스터 컬렉션(스테이킹)을 진행하고 싶을 때 사용하는 액션입니다. `amount` 만큼 NCG를 예치합니다. 구현 정의는 [NCIP-17]을 참조해주세요. + +```typescript +import { Stake } from "@planetarium/lib9c"; + +const action = new Stake({ + amount: 100n, +}); +``` + +## ClaimStakeReward - 스테이킹 보상 수령 + +몬스터 컬렉션(스테이킹) 보상을 수령하고 싶을 때 사용하는 액션입니다. `Stake` 액션으로 에치한 NCG에 맞는 보상을 수령합니다. 보상을 받을 `avatarAddress`를 필요로 합니다. 구현 정의는 [NCIP-17]을 참조해주세요. + +```typescript +import { ClaimStakeReward } from "@planetarium/lib9c"; +import { Address } from "@planetarium/account"; + +const action = new ClaimStakeReward({ + avatarAddress: Address.fromHex('0xDE3873DB166647Cc3538ef64EAA8A0cCFD51B9fE'), +}); +``` + +[NCIP-17]: https://github.com/planetarium/NCIPs/blob/main/NCIP/ncip-17.md diff --git a/@planetarium/lib9c/docs/ko/docs/index.md b/@planetarium/lib9c/docs/ko/docs/index.md new file mode 100644 index 0000000000..854612e5ca --- /dev/null +++ b/@planetarium/lib9c/docs/ko/docs/index.md @@ -0,0 +1,27 @@ +--- +outline: deep +--- + +# 소개 + +`@planetarium/lib9c` 라이브러리는 Nine Chronicles 네트워크와 상호작용하기 위해 필요한 트랜잭션을 만드는 것을 돕기 위해 만들어졌습니다. 웹에서 사용하기 쉽게 JavaScript/TypeScript를 이용하여 작성되었습니다. 만약 당신이 Nine Chronicles 네트워크 위에서 서비스를 만들거나 자동화 봇을 만들때 굉장히 유용할 것입니다. + +부족한 액션들이 있을 수 있지만 커뮤니티에서 필요에 따라 임의로 추가하고 기여해주길 희망합니다. 관련 문서도 준비되어 있으며 만약 어렵다면 디스코드를 통해 도움을 요청해주세요. + +## 연관된 라이브러리 + +Nine Chronicles 네트워크는 Planetarium 에서 만든 Libplanet 이라는 .NET 기반 블록체인 라이브러리를 활용하여 만들어졌습니다. 그렇기에 Libplanet 팀에서 만든 `@planetarium/tx`, `@planetarium/account` 라이브러리를 활용하여 트랜잭션을 만들고 서명하는 것이 좋습니다. 해당 라이브러리들의 사용법에 대해서는 각 라이브러리의 문서를 참고 부탁드립니다. + +## 자바스크립트를 사용할 때 주의점 + +본 라이브러리는 TypeScript으로 작성된 라이브러리 입니다. 타입 체킹을 통해 충분히 검증된 값이 넘어오기를 기대합니다. JavaScript에는 이런 타입 체킹이 없고 본 라이브러리에도 동적으로 검사하는 로직이 없으므로, 자바스크립트를 사용하실 경우 이런 잘못된 값으로 인한 문제를 알아차라기 어려울 수 있음을 인지해주시길 바랍니다. + +## 디스코드 + +[![Planetarium Dev][planetarium-dev-badge]][planetarium-dev-invite-link] + +이 라이브러리는 Planetarium 조직의 DX 팀에 의해 만들어졌습니다. Planetarium Dev 디스코드 서버에 상주하고 있으며 질문에 있다면 서버의 'NINE CHRONICLES > #general', 'NINE CHRONICLES > #lib9c' 등의 채널에 남겨주시길 바랍니다. + + +[planetarium-dev-badge]: https://img.shields.io/discord/928926944937013338?color=6278DA&label=Planetarium-dev&logo=discord&logoColor=white +[planetarium-dev-invite-link]: https://discord.com/invite/RYJDyFRYY7 diff --git a/@planetarium/lib9c/docs/ko/docs/installation.md b/@planetarium/lib9c/docs/ko/docs/installation.md new file mode 100644 index 0000000000..bc11da18d0 --- /dev/null +++ b/@planetarium/lib9c/docs/ko/docs/installation.md @@ -0,0 +1,31 @@ +# 설치 + +`@planetarium/lib9c` 라이브러리는 *[jsr]* 라는 패키지 레지스트리에 배포되었습니다. 그리고 npm에 있는 jsr 패키지를 통해 설치할 수 있습니다. API 문서 또한 jsr에 의해 자동 생성 되므로 [패키지 페이지][jsr-docs] 에서 확인하실 수 있습니다. + + +[jsr]: https://jsr.io/ +[jsr-docs]: https://jsr.io/@planetarium/lib9c@0.2.0-dev.202406030026370315+cb90675a71818491e09469b27a6ad4f19f8e3ce2/doc + +## Node + +Node.js의 경우 사용하고 계신 패키지 매니저에 따라 아래와 같이 사용할 수 있습니다. + +```bash +# pnpm +npx jsr add --pnpm @planetarium/lib9c + +# Yarn +npx jsr add --yarn @planetarium/lib9c + +# npm +npx jsr add @planetarium/lib9c +``` + +## Deno + +Deno의 경우 Deno CLI로 설치할 수 있습니다. + +```bash +# deno add @planetarium/lib9c@ +deno add @planetarium/lib9c@0.2.0-dev.202406030026370315+cb90675a71818491e09469b27a6ad4f19f8e3ce2 +``` diff --git a/@planetarium/lib9c/docs/ko/docs/utility.md b/@planetarium/lib9c/docs/ko/docs/utility.md new file mode 100644 index 0000000000..7768bec070 --- /dev/null +++ b/@planetarium/lib9c/docs/ko/docs/utility.md @@ -0,0 +1,70 @@ +# 유틸리티 + +## 통화 (通貨) + +### NCG + +나인크로니클에서는 'NCG' 라고 줄여부르는 *Nine Chronicles Gold* 통화가 있습니다. 이는 몬스터 컬렉션이라고 불리는 스테이킹에 사용됩니다. 또한 아이템을 구매하거나 강화하거나, 아레나 티켓을 구매하는데 사용되기도 합니다. + +```typescript +import { NCG } from "@planetarium/lib9c"; +``` + +하지만 Nine Chronicles 은 Multiplanetary 라는 시스템 하에 Odin, Heimdall 이라는 두 네트워크를 운영하고 있습니다. 둘 다 유효한 메인넷이지만 WNCG 브릿지는 Odin에서만 가능한 특징이 있습니다. Heimdall 에서는 `NCG` 대신 `MINTERLESS_NCG` 를 사용하셔야 합니다. + +```typescript +import { MINTELESS_NCG } from "@planetarium/lib9c"; +``` + +### CRYSTAL + +'CRYSTAL' 은 아이템 레시피를 해방하고 제작하거나 아레나에 참가하는데 사용되는 통화입니다. 스테이킹 보상을 통해 얻을 수 있습니다. + +```typescript +import { CRYSTAL } from "@planetarium/lib9c"; +``` + +### MEAD + +'MEAD' 는 나인크로니클 네트워크에서 트랜잭션 수수료로 사용되는 통화입니다. + +```typescript +import { MEAD } from "@planetarium/lib9c"; +``` + +### GARAGE + +'GARAGE' 은 전송 불가한 재화를 옮길때 사용합니다. [NCIP-16](https://github.com/planetarium/NCIPs/blob/main/NCIP/ncip-16.md)을 참고해주세요. + +```typescript +import { GARAGE } from "@planetarium/lib9c"; +``` + +## 유틸리티 함수 + +### `fav` + +본래 `@planetarium/tx` 의 `FungibleAssetValue`를 만들려면 아래와 같은 코드를 작성해야 합니다. 아래 코드는 `10 CRYSTAL` 을 의미하는 `FungibleAssetValue`를 만드는 코드입니다. + +```typescript +const fav: FungibleAssetValue = { + currency: CRYSTAL, + rawValue: BigInt(new Decimal(10).mul(Decimal.pow(10, CRYSTAL.decimalPlaces)).toString()) +} +``` + +`decimal.js`로 이런 처리를 하는 이유는 `FungibleAssetValue` (이하 `FAV`) 에서 수량을 표시할 때 소수점을 달리 지원하지 않기 때문입니다. 소수점을 지원하지 않는다는 것이 정말 소수점을 지원하지 않는 것은 아니고, 실제 값은 정수로 가진채 `Currency.decimalPlaces` 의 값으로 소수점 위치를 정의합니다. + +예를 들어 `2 NCG` 를 만들때 `FAV.rawValue` 는 `200n` 입니다. 왜냐하면 `NCG.decimalPlaces` 가 2 이기 때문에 `00` 부분을 소수점 자리로 쓰고 `2` 부분은 자연수 부분으로 쓰이는 것입니다. 일반적인 소수로 표현하면 `2.00 NCG` 입니다. + +`fav`는 이런 코드를 축약해서 사용할 수 있게 해주는 유틸리티 함수입니다. 위 코드를 `fav` 함수로 표현하면 다음과 같습니다. + +```typescript +fav(NCG, 2); +``` + +하지만 부동소수점에는 오차가 있기 때문에 `number` 타입으로 소수 (小數) 를 다루는 것은 권장하지 않습니다. 소수 외에도 수의 크기에도 제한이 있기 때문에 `bigint`나 `string`, `decimal.js` 를 사용해야합니다. 만약 `decimal.js` 를 사용한다면 `.toString()` 으로 `string` 타입으로 만들어 넘겨주세요. + +```typescript +import { fav } from "@planetarium/lib9c"; +``` diff --git a/@planetarium/lib9c/docs/ko/index.md b/@planetarium/lib9c/docs/ko/index.md new file mode 100644 index 0000000000..1473b0545e --- /dev/null +++ b/@planetarium/lib9c/docs/ko/index.md @@ -0,0 +1,19 @@ +--- +# https://vitepress.dev/reference/default-theme-home-page +layout: home + +hero: + name: "@planetarium/lib9c" + text: "나인크로니클 써드파티 앱을 위한 라이브러리" + tagline: 나인크로니클 액션을 보다 쉽게 만드세요 + actions: + - theme: brand + text: 문서 + link: /ko/docs/index.md + +features: + - title: 타입스크립트 + details: 나인크로니클 프로토콜의 여러 액션들을 타입과 함께 지원합니다. + - title: 유틸리티 + details: 트랜잭션을 보다 쉽게 만들기 위한 유틸리티를 제공합니다. +--- diff --git a/@planetarium/lib9c/package.json b/@planetarium/lib9c/package.json index acfa1b5ad8..5a5d4c5206 100644 --- a/@planetarium/lib9c/package.json +++ b/@planetarium/lib9c/package.json @@ -8,7 +8,10 @@ "build": "tsup", "fmt": "biome check --apply src tests", "fmt:ci": "biome check src tests", - "test": "vitest" + "test": "vitest", + "docs:dev": "vitepress dev docs", + "docs:build": "vitepress build docs", + "docs:preview": "vitepress preview docs" }, "keywords": [], "author": "Planetarium", @@ -21,6 +24,7 @@ "tsup": "^8.0.2", "tsx": "^4.7.3", "typescript": "^5.4.5", + "vitepress": "^1.2.2", "vitest": "^1.5.2" }, "dependencies": { diff --git a/@planetarium/lib9c/src/actions/claim_items.ts b/@planetarium/lib9c/src/actions/claim_items.ts index 3b706a6fa4..919540ee52 100644 --- a/@planetarium/lib9c/src/actions/claim_items.ts +++ b/@planetarium/lib9c/src/actions/claim_items.ts @@ -9,24 +9,74 @@ import { type FungibleAssetValue, encodeFungibleAssetValue, } from "@planetarium/tx"; -import { GameAction } from "./common.js"; +import { GameAction, type GameActionArgs } from "./common.js"; +/** + * The list of claim data pairs. + * The first element of the pair is the address of the avatar to claim the item, + * and the second element is the list of the amount of item tokens to convert. + */ +export type ClaimData = [Address, FungibleAssetValue[]][]; + +/** + * The arguments of the `ClaimItems` action. + */ +export type ClaimItemsArgs = { + /** + * The payload of the action. + */ + claimData: ClaimData; + + /** + * The memo of the action. If it is not provided, it is set to `null`. + */ + memo?: string; +} & GameActionArgs; + +/** + * The `ClaimItems` action is used to convert an item token to an item. + */ export class ClaimItems extends GameAction { protected readonly type_id: string = "claim_items"; - public readonly claimData: [Address, FungibleAssetValue[]][]; + /** + * The payload of the action. + */ + public readonly claimData: ClaimData; + + /** + * The memo of the action. + */ public readonly memo: string | null; - constructor({ - claimData, - memo, - id, - }: { - claimData: [Address, FungibleAssetValue[]][]; - memo?: string; - id?: Uint8Array; - }) { - super(id); + /** + * Create a new `ClaimItems` action. + * @param params The arguments of the `ClaimItems` action. + * @example + * ```typescript + * new ClaimItems({ + claimData: [ + [ + Address.fromHex("0x2cBaDf26574756119cF705289C33710F27443767"), + [ + fav( + { + ticker: "FAV__CRYSTAL", + decimalPlaces: 18, + minters: null, + maximumSupply: null, + totalSupplyTrackable: false, + }, + 1, + ), + ], + ], + ], + }) + * ``` + */ + constructor({ claimData, memo, id }: ClaimItemsArgs) { + super({ id }); this.claimData = claimData; this.memo = memo || null; diff --git a/@planetarium/lib9c/src/actions/claim_stake_reward.ts b/@planetarium/lib9c/src/actions/claim_stake_reward.ts index 8d0efb59b4..f5274d2202 100644 --- a/@planetarium/lib9c/src/actions/claim_stake_reward.ts +++ b/@planetarium/lib9c/src/actions/claim_stake_reward.ts @@ -1,20 +1,31 @@ import type { Address } from "@planetarium/account"; import { BencodexDictionary, type Dictionary } from "@planetarium/bencodex"; -import { GameAction } from "./common.js"; +import { GameAction, type GameActionArgs } from "./common.js"; + +/** + * The arguments of the `ClaimStakeReward` action. + */ +export type ClaimStakeRewardArgs = { + /** + * The address of the avatar to claim the stake reward. + */ + avatarAddress: Address; +} & GameActionArgs; export class ClaimStakeReward extends GameAction { protected readonly type_id: string = "claim_stake_reward9"; + /** + * The address of the avatar to claim the stake reward. + */ public readonly avatarAddress: Address; - constructor({ - avatarAddress, - id, - }: { - avatarAddress: Address; - id?: Uint8Array; - }) { - super(id); + /** + * Create a new `ClaimStakeReward` action. + * @param params The arguments of the `ClaimStakeReward` action. + */ + constructor({ avatarAddress, id }: ClaimStakeRewardArgs) { + super({ id }); this.avatarAddress = avatarAddress; } diff --git a/@planetarium/lib9c/src/actions/common.ts b/@planetarium/lib9c/src/actions/common.ts index f40094096c..e621c3e245 100644 --- a/@planetarium/lib9c/src/actions/common.ts +++ b/@planetarium/lib9c/src/actions/common.ts @@ -52,10 +52,21 @@ export abstract class PolymorphicAction { protected abstract plain_value(): Value; } +/** + * The arguments for the `GameAction` constructor. + */ +export type GameActionArgs = { + /** + * The unique identifier of the action. + * If it is not provided, a new GUID will be generated. + */ + id?: Uint8Array; +}; + export abstract class GameAction extends PolymorphicAction { id: Uint8Array; - constructor(id: Uint8Array | undefined) { + constructor({ id }: GameActionArgs) { super(); if (id !== undefined && id.length !== 16) { diff --git a/@planetarium/lib9c/src/actions/daily_reward.ts b/@planetarium/lib9c/src/actions/daily_reward.ts index 99df055144..c64de8f4d8 100644 --- a/@planetarium/lib9c/src/actions/daily_reward.ts +++ b/@planetarium/lib9c/src/actions/daily_reward.ts @@ -1,20 +1,28 @@ import type { Address } from "@planetarium/account"; import { BencodexDictionary, type Dictionary } from "@planetarium/bencodex"; -import { GameAction } from "./common.js"; +import { GameAction, type GameActionArgs } from "./common.js"; +export type DailyRewardArgs = { + avatarAddress: Address; +} & GameActionArgs; + +/** + * The `DailyReward` action is used to claim the daily reward. + */ export class DailyReward extends GameAction { protected readonly type_id: string = "daily_reward7"; + /** + * The address of the avatar to claim the daily reward. + */ public readonly avatarAddress: Address; - constructor({ - avatarAddress, - id, - }: { - avatarAddress: Address; - id?: Uint8Array; - }) { - super(id); + /** + * Create a new `DailyReward` action. + * @param params The arguments of the `DailyReward` action. + */ + constructor({ avatarAddress, id }: DailyRewardArgs) { + super({ id }); this.avatarAddress = avatarAddress; } diff --git a/@planetarium/lib9c/src/actions/deliver_to_others_garages.ts b/@planetarium/lib9c/src/actions/deliver_to_others_garages.ts index e663e98cb5..8e1d90f53c 100644 --- a/@planetarium/lib9c/src/actions/deliver_to_others_garages.ts +++ b/@planetarium/lib9c/src/actions/deliver_to_others_garages.ts @@ -10,8 +10,34 @@ import { encodeFungibleAssetValue, } from "@planetarium/tx"; import type { HashDigest } from "../models/hashdigest.js"; -import { GameAction } from "./common.js"; +import { GameAction, type GameActionArgs } from "./common.js"; +export type DeliverToOtherGaragesArgs = { + /** + * The address of the recipient's agent. + */ + recipientAgentAddress: Address; + + /** + * The list of fungible asset values to deliver to the recipient's from signer's garages. + */ + fungibleAssetValues?: FungibleAssetValue[]; + + /** + * The list of pairs where the first element is the item's id and the second element is the amount of it. These will be delivered to the recipient's from signer's garages. + */ + fungibleIdAndCounts?: [HashDigest<"SHA256">, bigint][]; + + /** + * A memo to be attached to the @see DeliverToOtherGarages action. If it is not provided, it is set to `null`. + */ + memo?: string; +} & GameActionArgs; + +/** + * The `DeliverToOtherGarages` action is used to deliver fungible assets to other garages. + * @see LoadIntoMyGarages + */ export class DeliverToOtherGarages extends GameAction { protected readonly type_id: string = "deliver_to_others_garages"; @@ -20,20 +46,18 @@ export class DeliverToOtherGarages extends GameAction { public readonly fungibleIdAndCounts: [HashDigest<"SHA256">, bigint][] | null; public readonly memo: string | null; + /** + * Create a new `DeliverToOtherGarages` action. + * @param params The arguments of the `DeliverToOtherGarages` action. + */ constructor({ recipientAgentAddress, fungibleAssetValues, fungibleIdAndCounts, memo, id, - }: { - recipientAgentAddress: Address; - fungibleAssetValues?: FungibleAssetValue[]; - fungibleIdAndCounts?: [HashDigest<"SHA256">, bigint][]; - memo?: string; - id?: Uint8Array; - }) { - super(id); + }: DeliverToOtherGaragesArgs) { + super({ id }); this.recipientAgentAddress = recipientAgentAddress; this.fungibleAssetValues = fungibleAssetValues || null; diff --git a/@planetarium/lib9c/src/actions/load_into_my_garages.ts b/@planetarium/lib9c/src/actions/load_into_my_garages.ts index d24efabc13..681c12467e 100644 --- a/@planetarium/lib9c/src/actions/load_into_my_garages.ts +++ b/@planetarium/lib9c/src/actions/load_into_my_garages.ts @@ -10,8 +10,37 @@ import { encodeFungibleAssetValue, } from "@planetarium/tx"; import type { HashDigest } from "../models/hashdigest.js"; -import { GameAction } from "./common.js"; +import { GameAction, type GameActionArgs } from "./common.js"; +/** + * The arguments of the `LoadIntoMyGarages` action. + */ +export type LoadIntoMyGaragesArgs = { + /** + * The address of the avatar to load the items. + */ + avatarAddress?: Address; + + /** + * The list of pairs where the first element is 'fungible id', the item's hash and the second element is the amount to load into garages. + */ + fungibleIdAndCounts?: [HashDigest<"SHA256">, bigint][]; + + /** + * The list of pairs where the first element is the address to load into garages from and the second element is the how many fungible asset value to load into garages from the specified address. + */ + fungibleAssetValues?: [Address, FungibleAssetValue][]; + + /** + * The memo of the action. If it is not provided, it is set to `null`. + */ + memo?: string; +} & GameActionArgs; + +/** + * The `LoadIntoMyGarages` action is used to load the fungible assets and items into the signer's garages. + * @see DeliverToOtherGarages + */ export class LoadIntoMyGarages extends GameAction { protected readonly type_id: string = "load_into_my_garages"; @@ -20,20 +49,31 @@ export class LoadIntoMyGarages extends GameAction { public readonly fungibleIdAndCounts: [HashDigest<"SHA256">, bigint][] | null; public readonly memo: string | null; + /** + * Create a new `LoadIntoMyGarages` action. + * @param params The arguments of the `LoadIntoMyGarages` action. + * @example To load NCG into the signer's garages: + * ```typescript + * new LoadIntoMyGarages({ + * fungibleAssetValues: [[agentAddress, fav(NCG, 2)]], + * }) + * ``` + * @example To load items into the signer's garages: + * ```typescript + * new LoadIntoMyGarages({ + * avatarAddress, + * fungibleIdAndCounts: [[fungibleIdA, 1n]], + * }) + * ``` + */ constructor({ avatarAddress, fungibleAssetValues, fungibleIdAndCounts, memo, id, - }: { - avatarAddress?: Address; - fungibleIdAndCounts?: [HashDigest<"SHA256">, bigint][]; - fungibleAssetValues?: [Address, FungibleAssetValue][]; - memo?: string; - id?: Uint8Array; - }) { - super(id); + }: LoadIntoMyGaragesArgs) { + super({ id }); this.avatarAddress = avatarAddress || null; this.fungibleAssetValues = fungibleAssetValues || null; diff --git a/@planetarium/lib9c/src/actions/stake.ts b/@planetarium/lib9c/src/actions/stake.ts index 952463b8e8..2571b5339f 100644 --- a/@planetarium/lib9c/src/actions/stake.ts +++ b/@planetarium/lib9c/src/actions/stake.ts @@ -1,19 +1,30 @@ import { BencodexDictionary, type Dictionary } from "@planetarium/bencodex"; -import { GameAction } from "./common.js"; +import { GameAction, type GameActionArgs } from "./common.js"; +/** + * The arguments of the `Stake` action. + */ +export type StakeArgs = { + amount: bigint; +} & GameActionArgs; + +/** + * The `Stake` action is used to stake the NCG. + */ export class Stake extends GameAction { protected readonly type_id: string = "stake3"; + /** + * The amount of NCG to stake. + */ public readonly amount: bigint; - constructor({ - amount, - id, - }: { - amount: bigint; - id?: Uint8Array; - }) { - super(id); + /** + * Create a new `Stake` action. + * @param params The arguments of the `Stake` action. + */ + constructor({ amount, id }: StakeArgs) { + super({ id }); this.amount = amount; } diff --git a/@planetarium/lib9c/src/actions/transfer_asset.ts b/@planetarium/lib9c/src/actions/transfer_asset.ts index ebd6b92aa9..fe89999c42 100644 --- a/@planetarium/lib9c/src/actions/transfer_asset.ts +++ b/@planetarium/lib9c/src/actions/transfer_asset.ts @@ -9,8 +9,37 @@ import { type FungibleAssetValue, encodeFungibleAssetValue, } from "@planetarium/tx"; -import { GameAction } from "./common.js"; +import { GameAction, type GameActionArgs } from "./common.js"; +/** + * The arguments of the `TransferAsset` action. + */ +export type TransferAssetArgs = { + /** + * The sender of the fungible asset. It must be the same with the signer. + */ + sender: Address; + + /** + * The recipient of the fungible asset. + */ + recipient: Address; + + /** + * The amount of the fungible asset to transfer. + */ + amount: FungibleAssetValue; + + /** + * A memo to be attached to the @see TransferAsset action. + * In the WNCG bridge case, it should have an Ethereum address to receive WNCG. + */ + memo?: string; +} & GameActionArgs; + +/** + * The `TransferAsset` action is used to transfer a fungible asset from one address to another. + */ export class TransferAsset extends GameAction { protected readonly type_id: string = "transfer_asset5"; @@ -19,20 +48,20 @@ export class TransferAsset extends GameAction { public readonly amount: FungibleAssetValue; public readonly memo: string | null; - constructor({ - sender, - recipient, - amount, - memo, - id, - }: { - sender: Address; - recipient: Address; - amount: FungibleAssetValue; - memo?: string; - id?: Uint8Array; - }) { - super(id); + /** + * Create a new `TransferAsset` action. + * @param params The parameters to create the action. + * @example + * ```typescript + * new TransferAsset({ + * sender: Address.fromHex('0x491d9842ed8f1b5d291272cf9e7b66a7b7c90cda', true), + * recipient: Address.fromHex('0xfee0bfb15fb3fe521560cbdb308ece4457d13cfa', true), + * amount: fav(NCG, 2), + * }) + * ``` + */ + constructor({ sender, recipient, amount, memo, id }: TransferAssetArgs) { + super({ id }); this.sender = sender; this.recipient = recipient; diff --git a/@planetarium/lib9c/src/actions/transfer_assets.ts b/@planetarium/lib9c/src/actions/transfer_assets.ts index 55f10d0d7b..c119507bc8 100644 --- a/@planetarium/lib9c/src/actions/transfer_assets.ts +++ b/@planetarium/lib9c/src/actions/transfer_assets.ts @@ -11,6 +11,29 @@ import { } from "@planetarium/tx"; import { PolymorphicAction } from "./common.js"; +/** + * The arguments of the `TransferAssets` action. + */ +export type TransferAssetsArgs = { + /** + * The sender of the fungible assets. It must be the same with the signer. + */ + sender: Address; + + /** + * The list of pairs where the first element is the recipient's address and the second element is the amount of fungible assets to transfer. + */ + recipients: [Address, FungibleAssetValue][]; + + /** + * A memo to be attached to the @see TransferAssets action. + */ + memo?: string; +}; + +/** + * The `TransferAssets` action is used to transfer fungible assets from one address to multiple recipients at once. + */ export class TransferAssets extends PolymorphicAction { protected readonly type_id: string = "transfer_assets3"; @@ -18,15 +41,22 @@ export class TransferAssets extends PolymorphicAction { public readonly recipients: [Address, FungibleAssetValue][]; public readonly memo: string | null; - constructor({ - sender, - recipients, - memo, - }: { - sender: Address; - recipients: [Address, FungibleAssetValue][]; - memo?: string; - }) { + /** + * Create a new `TransferAssets` action. + * @param params The parameters to create the action. + * @example Send 2 NCG to two addresses: + * ```typescript + * const agentAddresses = [ + * Address.fromHex("0xfee0bfb15fb3fe521560cbdb308ece4457d13cfa", true), + * Address.fromHex("0x491d9842ed8f1b5d291272cf9e7b66a7b7c90cda", true), + * ]; + * new TransferAssets({ + * sender: agentAddress, + * recipients: agentAddresses.map((address) => [address, fav(NCG, 2)]) + * }), + * ``` + */ + constructor({ sender, recipients, memo }: TransferAssetsArgs) { super(); this.sender = sender; diff --git a/@planetarium/lib9c/src/index.ts b/@planetarium/lib9c/src/index.ts index b58ee3a094..afc8336e90 100644 --- a/@planetarium/lib9c/src/index.ts +++ b/@planetarium/lib9c/src/index.ts @@ -1,16 +1,36 @@ -export { ClaimStakeReward } from "./actions/claim_stake_reward.js"; -export { Stake } from "./actions/stake.js"; -export { DailyReward } from "./actions/daily_reward.js"; -export { TransferAsset } from "./actions/transfer_asset.js"; -export { TransferAssets } from "./actions/transfer_assets.js"; -export { DeliverToOtherGarages } from "./actions/deliver_to_others_garages.js"; -export { LoadIntoMyGarages } from "./actions/load_into_my_garages.js"; -export { ClaimItems } from "./actions/claim_items.js"; +export { + ClaimStakeReward, + type ClaimStakeRewardArgs, +} from "./actions/claim_stake_reward.js"; +export { Stake, type StakeArgs } from "./actions/stake.js"; +export { DailyReward, type DailyRewardArgs } from "./actions/daily_reward.js"; +export { + TransferAsset, + type TransferAssetArgs, +} from "./actions/transfer_asset.js"; +export { + TransferAssets, + type TransferAssetsArgs, +} from "./actions/transfer_assets.js"; +export { + DeliverToOtherGarages, + type DeliverToOtherGaragesArgs, +} from "./actions/deliver_to_others_garages.js"; +export { + LoadIntoMyGarages, + type LoadIntoMyGaragesArgs, +} from "./actions/load_into_my_garages.js"; +export { + ClaimItems, + type ClaimItemsArgs, + type ClaimData, +} from "./actions/claim_items.js"; export { generateGuid, uuidToGuidBytes, GameAction, PolymorphicAction, + type GameActionArgs, } from "./actions/common.js"; export { @@ -21,5 +41,5 @@ export { GARAGE, fav, } from "./models/currencies.js"; -export { HashDigest } from "./models/hashdigest.js"; +export { HashDigest, type AlgorithmNames } from "./models/hashdigest.js"; export { ODIN_GENESIS_HASH, HEIMDALL_GENESIS_HASH } from "./models/networks.js"; diff --git a/@planetarium/lib9c/src/models/currencies.ts b/@planetarium/lib9c/src/models/currencies.ts index 562fe97014..a3b875cd9c 100644 --- a/@planetarium/lib9c/src/models/currencies.ts +++ b/@planetarium/lib9c/src/models/currencies.ts @@ -2,6 +2,9 @@ import { Buffer } from "buffer"; import type { Currency, FungibleAssetValue } from "@planetarium/tx"; import { Decimal } from "decimal.js"; +/** + * The main currency of the Nine Chronicles. It should be used in the Odin mainnet network. + */ export const NCG: Currency = { ticker: "NCG", decimalPlaces: 2, @@ -23,6 +26,9 @@ export const MINTERLESS_NCG: Currency = { totalSupplyTrackable: false, }; +/** + * MEAD is the currency used for transaction fee in the Nine Chronicles. + */ export const MEAD: Currency = { ticker: "Mead", decimalPlaces: 18, @@ -31,6 +37,9 @@ export const MEAD: Currency = { totalSupplyTrackable: false, }; +/** + * CRYSTAL is the currency used for crafting and upgrading items in the Nine Chronicles. + */ export const CRYSTAL: Currency = { ticker: "CRYSTAL", decimalPlaces: 18, @@ -39,6 +48,10 @@ export const CRYSTAL: Currency = { totalSupplyTrackable: false, }; +/** + * GARAGE is the currency used to make items or fungible asset values able to transfer to others. + * See [NCIP-16](https://github.com/planetarium/NCIPs/blob/main/NCIP/ncip-16.md) + */ export const GARAGE: Currency = { ticker: "GARAGE", decimalPlaces: 18, @@ -47,6 +60,24 @@ export const GARAGE: Currency = { totalSupplyTrackable: false, }; +/** + * Creates a new `FungibleAssetValue` with the given `currency` and `number-like` values. If the `number-like` value is a `string`, it is parsed and multiplied by 10 times `currency.decimalPlaces` to return the FungibleAssetValue. The same is true if it is a `number`. However, in the case of `number`, beware of the possibility of an incorrect decimal value. The same is true for `bigint`, but due to the nature of the `bigint` type, decimals are not allowed. + * @param currency The currency of the value. + * @param numberLike The amount of the given currency. + * @returns + * @example To create a FungibleAssetValue for 1 NCG: + * ```typescript + * fav(NCG, 1); // With number + * fav(NCG, "1"); // With string + * fav(NCG, 1n); // With bigint + * ``` + * @example To create a FungibleAssetValue for 1.23 NCG: + * ```typescript + * fav(NCG, 1.23); // With number + * fav(NCG, "1.23"); // With string + * // With bigint, it cannot be created because bigint doesn't represents decimal values. + * ``` + */ export function fav( currency: Currency, numberLike: string | number | bigint, diff --git a/@planetarium/lib9c/src/models/hashdigest.ts b/@planetarium/lib9c/src/models/hashdigest.ts index f5a543e505..20586829c9 100644 --- a/@planetarium/lib9c/src/models/hashdigest.ts +++ b/@planetarium/lib9c/src/models/hashdigest.ts @@ -6,11 +6,23 @@ const algorithms = { }, } as const; type Algorithms = typeof algorithms; -type AlgorithmNames = keyof Algorithms; +/** + * The hash algorithms used by Nine Chronicles. Currently, only "SHA256" is supported. + */ +export type AlgorithmNames = keyof Algorithms; + +/** + * Represents a hash digest. It is the same with [Libplanet HashDigeset](https://docs.libplanet.io/4.6.0/api/Libplanet.Common.HashDigest-1.html). + */ export class HashDigest { private readonly raw: Uint8Array; + /** + * Create a HashDigest from a raw byte array. + * @param algorithmName The one of the algorithm names. (e.g., "SHA256") + * @param raw The raw byte array of the hash digest. + */ constructor(algorithmName: T, raw: Uint8Array) { const length = algorithms[algorithmName].length; @@ -23,6 +35,16 @@ export class HashDigest { this.raw = raw; } + /** + * Create a HashDigest from a hexadecimal string. + * @param algorithmName The one of the algorithm names. (e.g., "SHA256") + * @param hex The hexadecimal string to convert to HashDigest. + * @returns + * @example + * ```typescript + * HashDigest.fromHex("SHA256", "4582250d0da33b06779a8475d283d5dd210c683b9b999d74d03fac4f58fa6bce") + * ``` + */ static fromHex( algorithmName: T, hex: string, diff --git a/@planetarium/lib9c/src/models/networks.ts b/@planetarium/lib9c/src/models/networks.ts index 8d0b2f7117..0ff3fa114d 100644 --- a/@planetarium/lib9c/src/models/networks.ts +++ b/@planetarium/lib9c/src/models/networks.ts @@ -1,10 +1,16 @@ import { Buffer } from "buffer"; +/** + * The genesis hash of the Odin network. + */ export const ODIN_GENESIS_HASH: Uint8Array = Buffer.from( "4582250d0da33b06779a8475d283d5dd210c683b9b999d74d03fac4f58fa6bce", "hex", ); +/** + * The genesis hash of the Heimdall network. + */ export const HEIMDALL_GENESIS_HASH: Uint8Array = Buffer.from( "729fa26958648a35b53e8e3905d11ec53b1b4929bf5f499884aed7df616f5913", "hex", diff --git a/@planetarium/pnpm-lock.yaml b/@planetarium/pnpm-lock.yaml index 81d5bb7565..2adfd78e57 100644 --- a/@planetarium/pnpm-lock.yaml +++ b/@planetarium/pnpm-lock.yaml @@ -48,12 +48,97 @@ importers: typescript: specifier: ^5.4.5 version: 5.4.5 + vitepress: + specifier: ^1.2.2 + version: 1.2.2(@algolia/client-search@4.23.3)(@types/node@20.12.8)(postcss@8.4.38)(search-insights@2.14.0)(typescript@5.4.5) vitest: specifier: ^1.5.2 version: 1.5.2(@types/node@20.12.8) packages: + '@algolia/autocomplete-core@1.9.3': + resolution: {integrity: sha512-009HdfugtGCdC4JdXUbVJClA0q0zh24yyePn+KUGk3rP7j8FEe/m5Yo/z65gn6nP/cM39PxpzqKrL7A6fP6PPw==} + + '@algolia/autocomplete-plugin-algolia-insights@1.9.3': + resolution: {integrity: sha512-a/yTUkcO/Vyy+JffmAnTWbr4/90cLzw+CC3bRbhnULr/EM0fGNvM13oQQ14f2moLMcVDyAx/leczLlAOovhSZg==} + peerDependencies: + search-insights: '>= 1 < 3' + + '@algolia/autocomplete-preset-algolia@1.9.3': + resolution: {integrity: sha512-d4qlt6YmrLMYy95n5TB52wtNDr6EgAIPH81dvvvW8UmuWRgxEtY0NJiPwl/h95JtG2vmRM804M0DSwMCNZlzRA==} + peerDependencies: + '@algolia/client-search': '>= 4.9.1 < 6' + algoliasearch: '>= 4.9.1 < 6' + + '@algolia/autocomplete-shared@1.9.3': + resolution: {integrity: sha512-Wnm9E4Ye6Rl6sTTqjoymD+l8DjSTHsHboVRYrKgEt8Q7UHm9nYbqhN/i0fhUYA3OAEH7WA8x3jfpnmJm3rKvaQ==} + peerDependencies: + '@algolia/client-search': '>= 4.9.1 < 6' + algoliasearch: '>= 4.9.1 < 6' + + '@algolia/cache-browser-local-storage@4.23.3': + resolution: {integrity: sha512-vRHXYCpPlTDE7i6UOy2xE03zHF2C8MEFjPN2v7fRbqVpcOvAUQK81x3Kc21xyb5aSIpYCjWCZbYZuz8Glyzyyg==} + + '@algolia/cache-common@4.23.3': + resolution: {integrity: sha512-h9XcNI6lxYStaw32pHpB1TMm0RuxphF+Ik4o7tcQiodEdpKK+wKufY6QXtba7t3k8eseirEMVB83uFFF3Nu54A==} + + '@algolia/cache-in-memory@4.23.3': + resolution: {integrity: sha512-yvpbuUXg/+0rbcagxNT7un0eo3czx2Uf0y4eiR4z4SD7SiptwYTpbuS0IHxcLHG3lq22ukx1T6Kjtk/rT+mqNg==} + + '@algolia/client-account@4.23.3': + resolution: {integrity: sha512-hpa6S5d7iQmretHHF40QGq6hz0anWEHGlULcTIT9tbUssWUriN9AUXIFQ8Ei4w9azD0hc1rUok9/DeQQobhQMA==} + + '@algolia/client-analytics@4.23.3': + resolution: {integrity: sha512-LBsEARGS9cj8VkTAVEZphjxTjMVCci+zIIiRhpFun9jGDUlS1XmhCW7CTrnaWeIuCQS/2iPyRqSy1nXPjcBLRA==} + + '@algolia/client-common@4.23.3': + resolution: {integrity: sha512-l6EiPxdAlg8CYhroqS5ybfIczsGUIAC47slLPOMDeKSVXYG1n0qGiz4RjAHLw2aD0xzh2EXZ7aRguPfz7UKDKw==} + + '@algolia/client-personalization@4.23.3': + resolution: {integrity: sha512-3E3yF3Ocr1tB/xOZiuC3doHQBQ2zu2MPTYZ0d4lpfWads2WTKG7ZzmGnsHmm63RflvDeLK/UVx7j2b3QuwKQ2g==} + + '@algolia/client-search@4.23.3': + resolution: {integrity: sha512-P4VAKFHqU0wx9O+q29Q8YVuaowaZ5EM77rxfmGnkHUJggh28useXQdopokgwMeYw2XUht49WX5RcTQ40rZIabw==} + + '@algolia/logger-common@4.23.3': + resolution: {integrity: sha512-y9kBtmJwiZ9ZZ+1Ek66P0M68mHQzKRxkW5kAAXYN/rdzgDN0d2COsViEFufxJ0pb45K4FRcfC7+33YB4BLrZ+g==} + + '@algolia/logger-console@4.23.3': + resolution: {integrity: sha512-8xoiseoWDKuCVnWP8jHthgaeobDLolh00KJAdMe9XPrWPuf1by732jSpgy2BlsLTaT9m32pHI8CRfrOqQzHv3A==} + + '@algolia/recommend@4.23.3': + resolution: {integrity: sha512-9fK4nXZF0bFkdcLBRDexsnGzVmu4TSYZqxdpgBW2tEyfuSSY54D4qSRkLmNkrrz4YFvdh2GM1gA8vSsnZPR73w==} + + '@algolia/requester-browser-xhr@4.23.3': + resolution: {integrity: sha512-jDWGIQ96BhXbmONAQsasIpTYWslyjkiGu0Quydjlowe+ciqySpiDUrJHERIRfELE5+wFc7hc1Q5hqjGoV7yghw==} + + '@algolia/requester-common@4.23.3': + resolution: {integrity: sha512-xloIdr/bedtYEGcXCiF2muajyvRhwop4cMZo+K2qzNht0CMzlRkm8YsDdj5IaBhshqfgmBb3rTg4sL4/PpvLYw==} + + '@algolia/requester-node-http@4.23.3': + resolution: {integrity: sha512-zgu++8Uj03IWDEJM3fuNl34s746JnZOWn1Uz5taV1dFyJhVM/kTNw9Ik7YJWiUNHJQXcaD8IXD1eCb0nq/aByA==} + + '@algolia/transporter@4.23.3': + resolution: {integrity: sha512-Wjl5gttqnf/gQKJA+dafnD0Y6Yw97yvfY8R9h0dQltX1GXTgNs1zWgvtWW0tHl1EgMdhAyw189uWiZMnL3QebQ==} + + '@babel/helper-string-parser@7.24.6': + resolution: {integrity: sha512-WdJjwMEkmBicq5T9fm/cHND3+UlFa2Yj8ALLgmoSQAJZysYbBjw+azChSGPN4DSPLXOcooGRvDwZWMcF/mLO2Q==} + engines: {node: '>=6.9.0'} + + '@babel/helper-validator-identifier@7.24.6': + resolution: {integrity: sha512-4yA7s865JHaqUdRbnaxarZREuPTHrjpDT+pXoAZ1yhyo6uFnIEpS8VMu16siFOHDpZNKYv5BObhsB//ycbICyw==} + engines: {node: '>=6.9.0'} + + '@babel/parser@7.24.6': + resolution: {integrity: sha512-eNZXdfU35nJC2h24RznROuOpO94h6x8sg9ju0tT9biNtLZ2vuP8SduLqqV+/8+cebSLV9SJEAN5Z3zQbJG/M+Q==} + engines: {node: '>=6.0.0'} + hasBin: true + + '@babel/types@7.24.6': + resolution: {integrity: sha512-WaMsgi6Q8zMgMth93GvWPXkhAIEobfsIkLTacoVZoK1J0CevIPGYY2Vo5YvJGqyHqXM6P4ppOYGsIRU8MM9pFQ==} + engines: {node: '>=6.9.0'} + '@biomejs/biome@1.7.1': resolution: {integrity: sha512-wb2UNoFXcgaMdKXKT5ytsYntaogl2FSTjDt20CZynF3v7OXQUcIpTrr+be3XoOGpoZRj3Ytq9TSpmplUREXmeA==} engines: {node: '>=14.21.3'} @@ -107,6 +192,29 @@ packages: cpu: [x64] os: [win32] + '@docsearch/css@3.6.0': + resolution: {integrity: sha512-+sbxb71sWre+PwDK7X2T8+bhS6clcVMLwBPznX45Qu6opJcgRjAp7gYSDzVFp187J+feSj5dNBN1mJoi6ckkUQ==} + + '@docsearch/js@3.6.0': + resolution: {integrity: sha512-QujhqINEElrkIfKwyyyTfbsfMAYCkylInLYMRqHy7PHc8xTBQCow73tlo/Kc7oIwBrCLf0P3YhjlOeV4v8hevQ==} + + '@docsearch/react@3.6.0': + resolution: {integrity: sha512-HUFut4ztcVNmqy9gp/wxNbC7pTOHhgVVkHVGCACTuLhUKUhKAF9KYHJtMiLUJxEqiFLQiuri1fWF8zqwM/cu1w==} + peerDependencies: + '@types/react': '>= 16.8.0 < 19.0.0' + react: '>= 16.8.0 < 19.0.0' + react-dom: '>= 16.8.0 < 19.0.0' + search-insights: '>= 1 < 3' + peerDependenciesMeta: + '@types/react': + optional: true + react: + optional: true + react-dom: + optional: true + search-insights: + optional: true + '@esbuild/aix-ppc64@0.19.12': resolution: {integrity: sha512-bmoCYyWdEL3wDQIVbcyzRyeKLgk2WtWLTWz1ZIAZF/EGbNOwSA6ew3PftJ1PqMiOOGu0OyFMzG53L0zqIpPeNA==} engines: {node: '>=12'} @@ -524,18 +632,43 @@ packages: cpu: [x64] os: [win32] + '@shikijs/core@1.6.1': + resolution: {integrity: sha512-CqYyepN4SnBopaoXYwng4NO8riB5ask/LTCkhOFq+GNGtr2X+aKeD767eYdqYukeixEUvv4bXdyTYVaogj7KBw==} + + '@shikijs/transformers@1.6.1': + resolution: {integrity: sha512-m/h2Dh99XWvTzHL8MUQmEnrB+/gxDljIfgDNR00Zg941KENqORx8Hi9sKpGYjCgXoEJKASZlEMQdPnkHj9/8aQ==} + '@sinclair/typebox@0.27.8': resolution: {integrity: sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==} '@types/estree@1.0.5': resolution: {integrity: sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==} + '@types/linkify-it@5.0.0': + resolution: {integrity: sha512-sVDA58zAw4eWAffKOaQH5/5j3XeayukzDk+ewSsnv3p4yJEZHCCzMDiZM8e0OUrRvmpGZ85jf4yDHkHsgBNr9Q==} + + '@types/markdown-it@14.1.1': + resolution: {integrity: sha512-4NpsnpYl2Gt1ljyBGrKMxFYAYvpqbnnkgP/i/g+NLpjEUa3obn1XJCur9YbEXKDAkaXqsR1LbDnGEJ0MmKFxfg==} + + '@types/mdurl@2.0.0': + resolution: {integrity: sha512-RGdgjQUZba5p6QEFAVx2OGb8rQDL/cPRG7GiedRzMcJ1tYnUANBncjbSB1NRGwbvjcPeikRABz2nshyPk1bhWg==} + '@types/node@20.12.8': resolution: {integrity: sha512-NU0rJLJnshZWdE/097cdCBbyW1h4hEg0xpovcoAQYHl8dnEyp/NAOiE45pvc+Bd1Dt+2r94v2eGFpQJ4R7g+2w==} '@types/uuid@9.0.8': resolution: {integrity: sha512-jg+97EGIcY9AGHJJRaaPVgetKDsrTgbRjQ5Msgjh/DQKEFl0DtyRr/VCOyD1T2R1MNeWPK/u7JoGhlDZnKBAfA==} + '@types/web-bluetooth@0.0.20': + resolution: {integrity: sha512-g9gZnnXVq7gM7v3tJCWV/qw7w+KeOlSHAhgF9RytFyifW6AF61hdT2ucrYhPq9hLs5JIryeupHV3qGk95dH9ow==} + + '@vitejs/plugin-vue@5.0.4': + resolution: {integrity: sha512-WS3hevEszI6CEVEx28F8RjTX97k3KsrcY6kvTg7+Whm5y3oYvcqzVeGCU3hxSAn4uY2CLCkeokkGKpoctccilQ==} + engines: {node: ^18.0.0 || >=20.0.0} + peerDependencies: + vite: ^5.0.0 + vue: ^3.2.25 + '@vitest/expect@1.5.2': resolution: {integrity: sha512-rf7MTD1WCoDlN3FfYJ9Llfp0PbdtOMZ3FIF0AVkDnKbp3oiMW1c8AmvRZBcqbAhDUAvF52e9zx4WQM1r3oraVA==} @@ -551,6 +684,96 @@ packages: '@vitest/utils@1.5.2': resolution: {integrity: sha512-sWOmyofuXLJ85VvXNsroZur7mOJGiQeM0JN3/0D1uU8U9bGFM69X1iqHaRXl6R8BwaLY6yPCogP257zxTzkUdA==} + '@vue/compiler-core@3.4.27': + resolution: {integrity: sha512-E+RyqY24KnyDXsCuQrI+mlcdW3ALND6U7Gqa/+bVwbcpcR3BRRIckFoz7Qyd4TTlnugtwuI7YgjbvsLmxb+yvg==} + + '@vue/compiler-dom@3.4.27': + resolution: {integrity: sha512-kUTvochG/oVgE1w5ViSr3KUBh9X7CWirebA3bezTbB5ZKBQZwR2Mwj9uoSKRMFcz4gSMzzLXBPD6KpCLb9nvWw==} + + '@vue/compiler-sfc@3.4.27': + resolution: {integrity: sha512-nDwntUEADssW8e0rrmE0+OrONwmRlegDA1pD6QhVeXxjIytV03yDqTey9SBDiALsvAd5U4ZrEKbMyVXhX6mCGA==} + + '@vue/compiler-ssr@3.4.27': + resolution: {integrity: sha512-CVRzSJIltzMG5FcidsW0jKNQnNRYC8bT21VegyMMtHmhW3UOI7knmUehzswXLrExDLE6lQCZdrhD4ogI7c+vuw==} + + '@vue/devtools-api@7.2.1': + resolution: {integrity: sha512-6oNCtyFOrNdqm6GUkFujsCgFlpbsHLnZqq7edeM/+cxAbMyCWvsaCsIMUaz7AiluKLccCGEM8fhOsjaKgBvb7g==} + + '@vue/devtools-kit@7.2.1': + resolution: {integrity: sha512-Wak/fin1X0Q8LLIfCAHBrdaaB+R6IdpSXsDByPHbQ3BmkCP0/cIo/oEGp9i0U2+gEqD4L3V9RDjNf1S34DTzQQ==} + peerDependencies: + vue: ^3.0.0 + + '@vue/devtools-shared@7.2.1': + resolution: {integrity: sha512-PCJF4UknJmOal68+X9XHyVeQ+idv0LFujkTOIW30+GaMJqwFVN9LkQKX4gLqn61KkGMdJTzQ1bt7EJag3TI6AA==} + + '@vue/reactivity@3.4.27': + resolution: {integrity: sha512-kK0g4NknW6JX2yySLpsm2jlunZJl2/RJGZ0H9ddHdfBVHcNzxmQ0sS0b09ipmBoQpY8JM2KmUw+a6sO8Zo+zIA==} + + '@vue/runtime-core@3.4.27': + resolution: {integrity: sha512-7aYA9GEbOOdviqVvcuweTLe5Za4qBZkUY7SvET6vE8kyypxVgaT1ixHLg4urtOlrApdgcdgHoTZCUuTGap/5WA==} + + '@vue/runtime-dom@3.4.27': + resolution: {integrity: sha512-ScOmP70/3NPM+TW9hvVAz6VWWtZJqkbdf7w6ySsws+EsqtHvkhxaWLecrTorFxsawelM5Ys9FnDEMt6BPBDS0Q==} + + '@vue/server-renderer@3.4.27': + resolution: {integrity: sha512-dlAMEuvmeA3rJsOMJ2J1kXU7o7pOxgsNHVr9K8hB3ImIkSuBrIdy0vF66h8gf8Tuinf1TK3mPAz2+2sqyf3KzA==} + peerDependencies: + vue: 3.4.27 + + '@vue/shared@3.4.27': + resolution: {integrity: sha512-DL3NmY2OFlqmYYrzp39yi3LDkKxa5vZVwxWdQ3rG0ekuWscHraeIbnI8t+aZK7qhYqEqWKTUdijadunb9pnrgA==} + + '@vueuse/core@10.10.0': + resolution: {integrity: sha512-vexJ/YXYs2S42B783rI95lMt3GzEwkxzC8Hb0Ndpd8rD+p+Lk/Za4bd797Ym7yq4jXqdSyj3JLChunF/vyYjUw==} + + '@vueuse/integrations@10.10.0': + resolution: {integrity: sha512-vHGeK7X6mkdkpcm1eE9t3Cpm21pNVfZRwrjwwbrEs9XftnSgszF4831G2rei8Dt9cIYJIfFV+iyx/29muimJPQ==} + peerDependencies: + async-validator: '*' + axios: '*' + change-case: '*' + drauu: '*' + focus-trap: '*' + fuse.js: '*' + idb-keyval: '*' + jwt-decode: '*' + nprogress: '*' + qrcode: '*' + sortablejs: '*' + universal-cookie: '*' + peerDependenciesMeta: + async-validator: + optional: true + axios: + optional: true + change-case: + optional: true + drauu: + optional: true + focus-trap: + optional: true + fuse.js: + optional: true + idb-keyval: + optional: true + jwt-decode: + optional: true + nprogress: + optional: true + qrcode: + optional: true + sortablejs: + optional: true + universal-cookie: + optional: true + + '@vueuse/metadata@10.10.0': + resolution: {integrity: sha512-UNAo2sTCAW5ge6OErPEHb5z7NEAg3XcO9Cj7OK45aZXfLLH1QkexDcZD77HBi5zvEiLOm1An+p/4b5K3Worpug==} + + '@vueuse/shared@10.10.0': + resolution: {integrity: sha512-2aW33Ac0Uk0U+9yo3Ypg9s5KcR42cuehRWl7vnUHadQyFvCktseyxxEPBi1Eiq4D2yBGACOnqLZpx1eMc7g5Og==} + acorn-walk@8.3.2: resolution: {integrity: sha512-cjkyv4OtNCIeqhHrfS81QWXoCBPExR/J62oyEqepVw8WaQeSqpW2uhuLPh1m9eWhDuOo/jUXVTlifvesOWp/4A==} engines: {node: '>=0.4.0'} @@ -560,6 +783,9 @@ packages: engines: {node: '>=0.4.0'} hasBin: true + algoliasearch@4.23.3: + resolution: {integrity: sha512-Le/3YgNvjW9zxIQMRhUHuhiUjAlKY/zsdZpfq4dlLqg6mEm0nL6yk+7f2hDOtLpxsgE4jSzDmvHL7nXdBp5feg==} + ansi-regex@5.0.1: resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} engines: {node: '>=8'} @@ -653,6 +879,9 @@ packages: resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==} engines: {node: '>= 8'} + csstype@3.1.3: + resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==} + debug@4.3.4: resolution: {integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==} engines: {node: '>=6.0'} @@ -686,6 +915,10 @@ packages: emoji-regex@9.2.2: resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} + entities@4.5.0: + resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==} + engines: {node: '>=0.12'} + esbuild@0.19.12: resolution: {integrity: sha512-aARqgq8roFBj054KvQr5f1sFu0D65G+miZRCuJyJ0G13Zwx7vRar5Zhn2tkQNzIXcBrNVsv/8stehpj+GAjgbg==} engines: {node: '>=12'} @@ -696,6 +929,9 @@ packages: engines: {node: '>=12'} hasBin: true + estree-walker@2.0.2: + resolution: {integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==} + estree-walker@3.0.3: resolution: {integrity: sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==} @@ -718,6 +954,9 @@ packages: resolution: {integrity: sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==} engines: {node: '>=8'} + focus-trap@7.5.4: + resolution: {integrity: sha512-N7kHdlgsO/v+iD/dMoJKtsSqs5Dz/dXZVebRgJw23LDk+jMi/974zyiOYDziY2JPp8xivq9BmUGwIJMiuSBi7w==} + foreground-child@3.1.1: resolution: {integrity: sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg==} engines: {node: '>=14'} @@ -754,6 +993,9 @@ packages: resolution: {integrity: sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==} engines: {node: '>=10'} + hookable@5.5.3: + resolution: {integrity: sha512-Yc+BQe8SvoXH1643Qez1zqLRmbA5rCL+sSmk6TVos0LWVfNIB7PGncdlId77WzLGSIB5KaWgTaNTs2lNVEI6VQ==} + human-signals@2.1.0: resolution: {integrity: sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==} engines: {node: '>=10.17.0'} @@ -839,6 +1081,9 @@ packages: magic-string@0.30.10: resolution: {integrity: sha512-iIRwTIf0QKV3UAnYK4PU8uiEc4SRh5jX0mwpIwETPpHdhVM4f53RSwS/vXvN1JhGX+Cs7B8qIq3d6AH49O5fAQ==} + mark.js@8.11.1: + resolution: {integrity: sha512-1I+1qpDt4idfgLQG+BNWmrqku+7/2bi5nLf4YwF8y8zXvmfiTBY3PV3ZibfrjBueCByROpuBjLLFCajqkgYoLQ==} + merge-stream@2.0.0: resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==} @@ -866,6 +1111,12 @@ packages: resolution: {integrity: sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ==} engines: {node: '>=16 || 14 >=14.17'} + minisearch@6.3.0: + resolution: {integrity: sha512-ihFnidEeU8iXzcVHy74dhkxh/dn8Dc08ERl0xwoMMGqp4+LvRSCgicb+zGqWthVokQKvCSxITlh3P08OzdTYCQ==} + + mitt@3.0.1: + resolution: {integrity: sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw==} + mlly@1.6.1: resolution: {integrity: sha512-vLgaHvaeunuOXHSmEbZ9izxPx3USsk8KCQ8iC+aTlp5sKRSoZvwhHh5L9VbKSaVC6sJDqbyohIS76E2VmHIPAA==} @@ -930,6 +1181,9 @@ packages: pathval@1.1.1: resolution: {integrity: sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==} + perfect-debounce@1.0.0: + resolution: {integrity: sha512-xCy9V055GLEqoFaHoC1SoLIaLmWctgCUaBaWxDZ7/Zx4CTyX7cJQLJOok/orfjZAh9kEYpjJa4d0KcJmCbctZA==} + picocolors@1.0.0: resolution: {integrity: sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==} @@ -960,6 +1214,9 @@ packages: resolution: {integrity: sha512-Wglpdk03BSfXkHoQa3b/oulrotAkwrlLDRSOb9D0bN86FdRyE9lppSp33aHNPgBa0JKCoB+drFLZkQoRRYae5A==} engines: {node: ^10 || ^12 || >=14} + preact@10.22.0: + resolution: {integrity: sha512-RRurnSjJPj4rp5K6XoP45Ui33ncb7e4H7WiOHVpjbkvqvA3U+N8Z6Qbo0AE6leGYBV66n8EhEaFixvIu3SkxFw==} + pretty-format@29.7.0: resolution: {integrity: sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} @@ -989,6 +1246,9 @@ packages: resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==} engines: {iojs: '>=1.0.0', node: '>=0.10.0'} + rfdc@1.3.1: + resolution: {integrity: sha512-r5a3l5HzYlIC68TpmYKlxWjmOP6wiPJ1vWv2HeLhNsRZMrCkxeqxiHlQ21oXmQ4F3SiryXBHhAD7JZqvOJjFmg==} + rollup@4.16.4: resolution: {integrity: sha512-kuaTJSUbz+Wsb2ATGvEknkI12XV40vIiHmLuFlejoo7HtDok/O5eDDD0UpCVY5bBX5U5RYo8wWP83H7ZsqVEnA==} engines: {node: '>=18.0.0', npm: '>=8.0.0'} @@ -997,6 +1257,9 @@ packages: run-parallel@1.2.0: resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} + search-insights@2.14.0: + resolution: {integrity: sha512-OLN6MsPMCghDOqlCtsIsYgtsC0pnwVTyT9Mu6A3ewOj1DxvzZF6COrn2g86E/c05xbktB0XN04m/t1Z+n+fTGw==} + shebang-command@2.0.0: resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} engines: {node: '>=8'} @@ -1005,6 +1268,9 @@ packages: resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} engines: {node: '>=8'} + shiki@1.6.1: + resolution: {integrity: sha512-1Pu/A1rtsG6HZvQm4W0NExQ45e02og+rPog7PDaFDiMumZgOYnZIu4JtGQeAIfMwdbKSjJQoCUr79vDLKUUxWA==} + siginfo@2.0.0: resolution: {integrity: sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==} @@ -1027,6 +1293,10 @@ packages: resolution: {integrity: sha512-2ymg6oRBpebeZi9UUNsgQ89bhx01TcTkmNTGnNO88imTmbSgy4nfujrgVEFKWpMTEGA11EDkTt7mqObTPdigIA==} engines: {node: '>= 8'} + speakingurl@14.0.1: + resolution: {integrity: sha512-1POYv7uv2gXoyGFpBCmpDVSNV74IfsWlDW216UPjbWufNf+bSU6GdbDsxdcxtfwb4xlI3yxzOTKClUosxARYrQ==} + engines: {node: '>=0.10.0'} + stackback@0.0.2: resolution: {integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==} @@ -1065,6 +1335,9 @@ packages: engines: {node: '>=16 || 14 >=14.17'} hasBin: true + tabbable@6.2.0: + resolution: {integrity: sha512-Cat63mxsVJlzYvN51JmVXIgNoUokrIaT2zLclCXjRd8boZ0004U4KCs/sToJ75C6sdlByWxpYnb5Boif1VSFew==} + thenify-all@1.6.0: resolution: {integrity: sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==} engines: {node: '>=0.8'} @@ -1083,6 +1356,10 @@ packages: resolution: {integrity: sha512-KYad6Vy5VDWV4GH3fjpseMQ/XU2BhIYP7Vzd0LG44qRWm/Yt2WCOTicFdvmgo6gWaqooMQCawTtILVQJupKu7A==} engines: {node: '>=14.0.0'} + to-fast-properties@2.0.0: + resolution: {integrity: sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==} + engines: {node: '>=4'} + to-regex-range@5.0.1: resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} engines: {node: '>=8.0'} @@ -1173,6 +1450,46 @@ packages: terser: optional: true + vite@5.2.12: + resolution: {integrity: sha512-/gC8GxzxMK5ntBwb48pR32GGhENnjtY30G4A0jemunsBkiEZFw60s8InGpN8gkhHEkjnRK1aSAxeQgwvFhUHAA==} + engines: {node: ^18.0.0 || >=20.0.0} + hasBin: true + peerDependencies: + '@types/node': ^18.0.0 || >=20.0.0 + less: '*' + lightningcss: ^1.21.0 + sass: '*' + stylus: '*' + sugarss: '*' + terser: ^5.4.0 + peerDependenciesMeta: + '@types/node': + optional: true + less: + optional: true + lightningcss: + optional: true + sass: + optional: true + stylus: + optional: true + sugarss: + optional: true + terser: + optional: true + + vitepress@1.2.2: + resolution: {integrity: sha512-uZ3nXR5NY4nYj3RJWCo5jev9qlNZAQo5SUXu1U0QSUx84cUm/o7hCTDVjZ4njVSVui+PsV1oAbdQOg8ygbaf4w==} + hasBin: true + peerDependencies: + markdown-it-mathjax3: ^4 + postcss: ^8 + peerDependenciesMeta: + markdown-it-mathjax3: + optional: true + postcss: + optional: true + vitest@1.5.2: resolution: {integrity: sha512-l9gwIkq16ug3xY7BxHwcBQovLZG75zZL0PlsiYQbf76Rz6QGs54416UWMtC0jXeihvHvcHrf2ROEjkQRVpoZYw==} engines: {node: ^18.0.0 || >=20.0.0} @@ -1198,6 +1515,25 @@ packages: jsdom: optional: true + vue-demi@0.14.8: + resolution: {integrity: sha512-Uuqnk9YE9SsWeReYqK2alDI5YzciATE0r2SkA6iMAtuXvNTMNACJLJEXNXaEy94ECuBe4Sk6RzRU80kjdbIo1Q==} + engines: {node: '>=12'} + hasBin: true + peerDependencies: + '@vue/composition-api': ^1.0.0-rc.1 + vue: ^3.0.0-0 || ^2.6.0 + peerDependenciesMeta: + '@vue/composition-api': + optional: true + + vue@3.4.27: + resolution: {integrity: sha512-8s/56uK6r01r1icG/aEOHqyMVxd1bkYcSe9j8HcKtr/xTOFWvnzIVTehNW+5Yt89f+DLBe4A569pnZLS5HzAMA==} + peerDependencies: + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + webidl-conversions@4.0.2: resolution: {integrity: sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==} @@ -1233,6 +1569,124 @@ packages: snapshots: + '@algolia/autocomplete-core@1.9.3(@algolia/client-search@4.23.3)(algoliasearch@4.23.3)(search-insights@2.14.0)': + dependencies: + '@algolia/autocomplete-plugin-algolia-insights': 1.9.3(@algolia/client-search@4.23.3)(algoliasearch@4.23.3)(search-insights@2.14.0) + '@algolia/autocomplete-shared': 1.9.3(@algolia/client-search@4.23.3)(algoliasearch@4.23.3) + transitivePeerDependencies: + - '@algolia/client-search' + - algoliasearch + - search-insights + + '@algolia/autocomplete-plugin-algolia-insights@1.9.3(@algolia/client-search@4.23.3)(algoliasearch@4.23.3)(search-insights@2.14.0)': + dependencies: + '@algolia/autocomplete-shared': 1.9.3(@algolia/client-search@4.23.3)(algoliasearch@4.23.3) + search-insights: 2.14.0 + transitivePeerDependencies: + - '@algolia/client-search' + - algoliasearch + + '@algolia/autocomplete-preset-algolia@1.9.3(@algolia/client-search@4.23.3)(algoliasearch@4.23.3)': + dependencies: + '@algolia/autocomplete-shared': 1.9.3(@algolia/client-search@4.23.3)(algoliasearch@4.23.3) + '@algolia/client-search': 4.23.3 + algoliasearch: 4.23.3 + + '@algolia/autocomplete-shared@1.9.3(@algolia/client-search@4.23.3)(algoliasearch@4.23.3)': + dependencies: + '@algolia/client-search': 4.23.3 + algoliasearch: 4.23.3 + + '@algolia/cache-browser-local-storage@4.23.3': + dependencies: + '@algolia/cache-common': 4.23.3 + + '@algolia/cache-common@4.23.3': {} + + '@algolia/cache-in-memory@4.23.3': + dependencies: + '@algolia/cache-common': 4.23.3 + + '@algolia/client-account@4.23.3': + dependencies: + '@algolia/client-common': 4.23.3 + '@algolia/client-search': 4.23.3 + '@algolia/transporter': 4.23.3 + + '@algolia/client-analytics@4.23.3': + dependencies: + '@algolia/client-common': 4.23.3 + '@algolia/client-search': 4.23.3 + '@algolia/requester-common': 4.23.3 + '@algolia/transporter': 4.23.3 + + '@algolia/client-common@4.23.3': + dependencies: + '@algolia/requester-common': 4.23.3 + '@algolia/transporter': 4.23.3 + + '@algolia/client-personalization@4.23.3': + dependencies: + '@algolia/client-common': 4.23.3 + '@algolia/requester-common': 4.23.3 + '@algolia/transporter': 4.23.3 + + '@algolia/client-search@4.23.3': + dependencies: + '@algolia/client-common': 4.23.3 + '@algolia/requester-common': 4.23.3 + '@algolia/transporter': 4.23.3 + + '@algolia/logger-common@4.23.3': {} + + '@algolia/logger-console@4.23.3': + dependencies: + '@algolia/logger-common': 4.23.3 + + '@algolia/recommend@4.23.3': + dependencies: + '@algolia/cache-browser-local-storage': 4.23.3 + '@algolia/cache-common': 4.23.3 + '@algolia/cache-in-memory': 4.23.3 + '@algolia/client-common': 4.23.3 + '@algolia/client-search': 4.23.3 + '@algolia/logger-common': 4.23.3 + '@algolia/logger-console': 4.23.3 + '@algolia/requester-browser-xhr': 4.23.3 + '@algolia/requester-common': 4.23.3 + '@algolia/requester-node-http': 4.23.3 + '@algolia/transporter': 4.23.3 + + '@algolia/requester-browser-xhr@4.23.3': + dependencies: + '@algolia/requester-common': 4.23.3 + + '@algolia/requester-common@4.23.3': {} + + '@algolia/requester-node-http@4.23.3': + dependencies: + '@algolia/requester-common': 4.23.3 + + '@algolia/transporter@4.23.3': + dependencies: + '@algolia/cache-common': 4.23.3 + '@algolia/logger-common': 4.23.3 + '@algolia/requester-common': 4.23.3 + + '@babel/helper-string-parser@7.24.6': {} + + '@babel/helper-validator-identifier@7.24.6': {} + + '@babel/parser@7.24.6': + dependencies: + '@babel/types': 7.24.6 + + '@babel/types@7.24.6': + dependencies: + '@babel/helper-string-parser': 7.24.6 + '@babel/helper-validator-identifier': 7.24.6 + to-fast-properties: 2.0.0 + '@biomejs/biome@1.7.1': optionalDependencies: '@biomejs/cli-darwin-arm64': 1.7.1 @@ -1268,6 +1722,30 @@ snapshots: '@biomejs/cli-win32-x64@1.7.1': optional: true + '@docsearch/css@3.6.0': {} + + '@docsearch/js@3.6.0(@algolia/client-search@4.23.3)(search-insights@2.14.0)': + dependencies: + '@docsearch/react': 3.6.0(@algolia/client-search@4.23.3)(search-insights@2.14.0) + preact: 10.22.0 + transitivePeerDependencies: + - '@algolia/client-search' + - '@types/react' + - react + - react-dom + - search-insights + + '@docsearch/react@3.6.0(@algolia/client-search@4.23.3)(search-insights@2.14.0)': + dependencies: + '@algolia/autocomplete-core': 1.9.3(@algolia/client-search@4.23.3)(algoliasearch@4.23.3)(search-insights@2.14.0) + '@algolia/autocomplete-preset-algolia': 1.9.3(@algolia/client-search@4.23.3)(algoliasearch@4.23.3) + '@docsearch/css': 3.6.0 + algoliasearch: 4.23.3 + optionalDependencies: + search-insights: 2.14.0 + transitivePeerDependencies: + - '@algolia/client-search' + '@esbuild/aix-ppc64@0.19.12': optional: true @@ -1515,16 +1993,38 @@ snapshots: '@rollup/rollup-win32-x64-msvc@4.16.4': optional: true + '@shikijs/core@1.6.1': {} + + '@shikijs/transformers@1.6.1': + dependencies: + shiki: 1.6.1 + '@sinclair/typebox@0.27.8': {} '@types/estree@1.0.5': {} + '@types/linkify-it@5.0.0': {} + + '@types/markdown-it@14.1.1': + dependencies: + '@types/linkify-it': 5.0.0 + '@types/mdurl': 2.0.0 + + '@types/mdurl@2.0.0': {} + '@types/node@20.12.8': dependencies: undici-types: 5.26.5 '@types/uuid@9.0.8': {} + '@types/web-bluetooth@0.0.20': {} + + '@vitejs/plugin-vue@5.0.4(vite@5.2.12(@types/node@20.12.8))(vue@3.4.27(typescript@5.4.5))': + dependencies: + vite: 5.2.12(@types/node@20.12.8) + vue: 3.4.27(typescript@5.4.5) + '@vitest/expect@1.5.2': dependencies: '@vitest/spy': 1.5.2 @@ -1554,10 +2054,130 @@ snapshots: loupe: 2.3.7 pretty-format: 29.7.0 + '@vue/compiler-core@3.4.27': + dependencies: + '@babel/parser': 7.24.6 + '@vue/shared': 3.4.27 + entities: 4.5.0 + estree-walker: 2.0.2 + source-map-js: 1.2.0 + + '@vue/compiler-dom@3.4.27': + dependencies: + '@vue/compiler-core': 3.4.27 + '@vue/shared': 3.4.27 + + '@vue/compiler-sfc@3.4.27': + dependencies: + '@babel/parser': 7.24.6 + '@vue/compiler-core': 3.4.27 + '@vue/compiler-dom': 3.4.27 + '@vue/compiler-ssr': 3.4.27 + '@vue/shared': 3.4.27 + estree-walker: 2.0.2 + magic-string: 0.30.10 + postcss: 8.4.38 + source-map-js: 1.2.0 + + '@vue/compiler-ssr@3.4.27': + dependencies: + '@vue/compiler-dom': 3.4.27 + '@vue/shared': 3.4.27 + + '@vue/devtools-api@7.2.1(vue@3.4.27(typescript@5.4.5))': + dependencies: + '@vue/devtools-kit': 7.2.1(vue@3.4.27(typescript@5.4.5)) + transitivePeerDependencies: + - vue + + '@vue/devtools-kit@7.2.1(vue@3.4.27(typescript@5.4.5))': + dependencies: + '@vue/devtools-shared': 7.2.1 + hookable: 5.5.3 + mitt: 3.0.1 + perfect-debounce: 1.0.0 + speakingurl: 14.0.1 + vue: 3.4.27(typescript@5.4.5) + + '@vue/devtools-shared@7.2.1': + dependencies: + rfdc: 1.3.1 + + '@vue/reactivity@3.4.27': + dependencies: + '@vue/shared': 3.4.27 + + '@vue/runtime-core@3.4.27': + dependencies: + '@vue/reactivity': 3.4.27 + '@vue/shared': 3.4.27 + + '@vue/runtime-dom@3.4.27': + dependencies: + '@vue/runtime-core': 3.4.27 + '@vue/shared': 3.4.27 + csstype: 3.1.3 + + '@vue/server-renderer@3.4.27(vue@3.4.27(typescript@5.4.5))': + dependencies: + '@vue/compiler-ssr': 3.4.27 + '@vue/shared': 3.4.27 + vue: 3.4.27(typescript@5.4.5) + + '@vue/shared@3.4.27': {} + + '@vueuse/core@10.10.0(vue@3.4.27(typescript@5.4.5))': + dependencies: + '@types/web-bluetooth': 0.0.20 + '@vueuse/metadata': 10.10.0 + '@vueuse/shared': 10.10.0(vue@3.4.27(typescript@5.4.5)) + vue-demi: 0.14.8(vue@3.4.27(typescript@5.4.5)) + transitivePeerDependencies: + - '@vue/composition-api' + - vue + + '@vueuse/integrations@10.10.0(focus-trap@7.5.4)(vue@3.4.27(typescript@5.4.5))': + dependencies: + '@vueuse/core': 10.10.0(vue@3.4.27(typescript@5.4.5)) + '@vueuse/shared': 10.10.0(vue@3.4.27(typescript@5.4.5)) + vue-demi: 0.14.8(vue@3.4.27(typescript@5.4.5)) + optionalDependencies: + focus-trap: 7.5.4 + transitivePeerDependencies: + - '@vue/composition-api' + - vue + + '@vueuse/metadata@10.10.0': {} + + '@vueuse/shared@10.10.0(vue@3.4.27(typescript@5.4.5))': + dependencies: + vue-demi: 0.14.8(vue@3.4.27(typescript@5.4.5)) + transitivePeerDependencies: + - '@vue/composition-api' + - vue + acorn-walk@8.3.2: {} acorn@8.11.3: {} + algoliasearch@4.23.3: + dependencies: + '@algolia/cache-browser-local-storage': 4.23.3 + '@algolia/cache-common': 4.23.3 + '@algolia/cache-in-memory': 4.23.3 + '@algolia/client-account': 4.23.3 + '@algolia/client-analytics': 4.23.3 + '@algolia/client-common': 4.23.3 + '@algolia/client-personalization': 4.23.3 + '@algolia/client-search': 4.23.3 + '@algolia/logger-common': 4.23.3 + '@algolia/logger-console': 4.23.3 + '@algolia/recommend': 4.23.3 + '@algolia/requester-browser-xhr': 4.23.3 + '@algolia/requester-common': 4.23.3 + '@algolia/requester-node-http': 4.23.3 + '@algolia/transporter': 4.23.3 + ansi-regex@5.0.1: {} ansi-regex@6.0.1: {} @@ -1649,6 +2269,8 @@ snapshots: shebang-command: 2.0.0 which: 2.0.2 + csstype@3.1.3: {} + debug@4.3.4: dependencies: ms: 2.1.2 @@ -1671,6 +2293,8 @@ snapshots: emoji-regex@9.2.2: {} + entities@4.5.0: {} + esbuild@0.19.12: optionalDependencies: '@esbuild/aix-ppc64': 0.19.12 @@ -1723,6 +2347,8 @@ snapshots: '@esbuild/win32-ia32': 0.20.2 '@esbuild/win32-x64': 0.20.2 + estree-walker@2.0.2: {} + estree-walker@3.0.3: dependencies: '@types/estree': 1.0.5 @@ -1767,6 +2393,10 @@ snapshots: dependencies: to-regex-range: 5.0.1 + focus-trap@7.5.4: + dependencies: + tabbable: 6.2.0 + foreground-child@3.1.1: dependencies: cross-spawn: 7.0.3 @@ -1806,6 +2436,8 @@ snapshots: merge2: 1.4.1 slash: 3.0.0 + hookable@5.5.3: {} + human-signals@2.1.0: {} human-signals@5.0.0: {} @@ -1867,6 +2499,8 @@ snapshots: dependencies: '@jridgewell/sourcemap-codec': 1.4.15 + mark.js@8.11.1: {} + merge-stream@2.0.0: {} merge2@1.4.1: {} @@ -1886,6 +2520,10 @@ snapshots: minipass@7.0.4: {} + minisearch@6.3.0: {} + + mitt@3.0.1: {} + mlly@1.6.1: dependencies: acorn: 8.11.3 @@ -1942,6 +2580,8 @@ snapshots: pathval@1.1.1: {} + perfect-debounce@1.0.0: {} + picocolors@1.0.0: {} picomatch@2.3.1: {} @@ -1967,6 +2607,8 @@ snapshots: picocolors: 1.0.0 source-map-js: 1.2.0 + preact@10.22.0: {} + pretty-format@29.7.0: dependencies: '@jest/schemas': 29.6.3 @@ -1989,6 +2631,8 @@ snapshots: reusify@1.0.4: {} + rfdc@1.3.1: {} + rollup@4.16.4: dependencies: '@types/estree': 1.0.5 @@ -2015,12 +2659,18 @@ snapshots: dependencies: queue-microtask: 1.2.3 + search-insights@2.14.0: {} + shebang-command@2.0.0: dependencies: shebang-regex: 3.0.0 shebang-regex@3.0.0: {} + shiki@1.6.1: + dependencies: + '@shikijs/core': 1.6.1 + siginfo@2.0.0: {} signal-exit@3.0.7: {} @@ -2035,6 +2685,8 @@ snapshots: dependencies: whatwg-url: 7.1.0 + speakingurl@14.0.1: {} + stackback@0.0.2: {} std-env@3.7.0: {} @@ -2077,6 +2729,8 @@ snapshots: pirates: 4.0.6 ts-interface-checker: 0.1.13 + tabbable@6.2.0: {} + thenify-all@1.6.0: dependencies: thenify: 3.3.1 @@ -2091,6 +2745,8 @@ snapshots: tinyspy@2.2.1: {} + to-fast-properties@2.0.0: {} + to-regex-range@5.0.1: dependencies: is-number: 7.0.0 @@ -2169,6 +2825,62 @@ snapshots: '@types/node': 20.12.8 fsevents: 2.3.3 + vite@5.2.12(@types/node@20.12.8): + dependencies: + esbuild: 0.20.2 + postcss: 8.4.38 + rollup: 4.16.4 + optionalDependencies: + '@types/node': 20.12.8 + fsevents: 2.3.3 + + vitepress@1.2.2(@algolia/client-search@4.23.3)(@types/node@20.12.8)(postcss@8.4.38)(search-insights@2.14.0)(typescript@5.4.5): + dependencies: + '@docsearch/css': 3.6.0 + '@docsearch/js': 3.6.0(@algolia/client-search@4.23.3)(search-insights@2.14.0) + '@shikijs/core': 1.6.1 + '@shikijs/transformers': 1.6.1 + '@types/markdown-it': 14.1.1 + '@vitejs/plugin-vue': 5.0.4(vite@5.2.12(@types/node@20.12.8))(vue@3.4.27(typescript@5.4.5)) + '@vue/devtools-api': 7.2.1(vue@3.4.27(typescript@5.4.5)) + '@vue/shared': 3.4.27 + '@vueuse/core': 10.10.0(vue@3.4.27(typescript@5.4.5)) + '@vueuse/integrations': 10.10.0(focus-trap@7.5.4)(vue@3.4.27(typescript@5.4.5)) + focus-trap: 7.5.4 + mark.js: 8.11.1 + minisearch: 6.3.0 + shiki: 1.6.1 + vite: 5.2.12(@types/node@20.12.8) + vue: 3.4.27(typescript@5.4.5) + optionalDependencies: + postcss: 8.4.38 + transitivePeerDependencies: + - '@algolia/client-search' + - '@types/node' + - '@types/react' + - '@vue/composition-api' + - async-validator + - axios + - change-case + - drauu + - fuse.js + - idb-keyval + - jwt-decode + - less + - lightningcss + - nprogress + - qrcode + - react + - react-dom + - sass + - search-insights + - sortablejs + - stylus + - sugarss + - terser + - typescript + - universal-cookie + vitest@1.5.2(@types/node@20.12.8): dependencies: '@vitest/expect': 1.5.2 @@ -2202,6 +2914,20 @@ snapshots: - supports-color - terser + vue-demi@0.14.8(vue@3.4.27(typescript@5.4.5)): + dependencies: + vue: 3.4.27(typescript@5.4.5) + + vue@3.4.27(typescript@5.4.5): + dependencies: + '@vue/compiler-dom': 3.4.27 + '@vue/compiler-sfc': 3.4.27 + '@vue/runtime-dom': 3.4.27 + '@vue/server-renderer': 3.4.27(vue@3.4.27(typescript@5.4.5)) + '@vue/shared': 3.4.27 + optionalDependencies: + typescript: 5.4.5 + webidl-conversions@4.0.2: {} whatwg-url@7.1.0: diff --git a/Lib9c.Policy/Policy/BlockPolicySource.cs b/Lib9c.Policy/Policy/BlockPolicySource.cs index 946749aa62..1598b64724 100644 --- a/Lib9c.Policy/Policy/BlockPolicySource.cs +++ b/Lib9c.Policy/Policy/BlockPolicySource.cs @@ -148,6 +148,7 @@ internal IBlockPolicy GetPolicy( #endif } + // TODO: Remove BlockChain.GetNextWorldState() from below method. internal static TxPolicyViolationException? ValidateNextBlockTxRaw( BlockChain blockChain, IActionLoader actionLoader, @@ -173,7 +174,7 @@ internal IBlockPolicy GetPolicy( try { if (blockChain - .GetWorldState() + .GetNextWorldState()! .GetBalance(MeadConfig.PatronAddress, Currencies.Mead) < 1 * Currencies.Mead) { // Check Activation @@ -186,7 +187,7 @@ internal IBlockPolicy GetPolicy( { return transaction.Nonce == 0 && blockChain - .GetWorldState() + .GetNextWorldState()! .GetAccountState(ReservedAddresses.LegacyAccount) .GetState(activate.PendingAddress) is Dictionary rawPending && new PendingActivationState(rawPending).Verify(activate.Signature) @@ -211,14 +212,14 @@ internal IBlockPolicy GetPolicy( } switch (blockChain - .GetWorldState() + .GetNextWorldState()! .GetAccountState(ReservedAddresses.LegacyAccount) .GetState(transaction.Signer.Derive(ActivationKey.DeriveKey))) { case null: // Fallback for pre-migration. if (blockChain - .GetWorldState() + .GetNextWorldState()! .GetAccountState(ReservedAddresses.LegacyAccount) .GetState(ActivatedAccountsState.Address) is Dictionary asDict) { diff --git a/Lib9c.Utils/BlockHelper.cs b/Lib9c.Utils/BlockHelper.cs index a28fa9c51b..3504c95039 100644 --- a/Lib9c.Utils/BlockHelper.cs +++ b/Lib9c.Utils/BlockHelper.cs @@ -102,14 +102,13 @@ public static Block ProposeGenesisBlock( actionLoader); return BlockChain.ProposeGenesisBlock( - actionEvaluator, + privateKey: privateKey, transactions: ImmutableList.Empty .Add(Transaction.Create( 0, privateKey, null, actions.ToPlainValues())) .AddRange(systemActions.Select((sa, index) => Transaction.Create( index + 1, privateKey, null, new [] { sa.PlainValue }))), - privateKey: privateKey, timestamp: timestamp); } }