From 56f72c403d0b0f18d1cf92d04364d125d6547646 Mon Sep 17 00:00:00 2001 From: Pandelis Symeonidis <54764628+Pandelissym@users.noreply.github.com> Date: Mon, 18 Dec 2023 12:05:23 +0100 Subject: [PATCH] Fix kread bundle publishing (#112) ## Description This PR fixes the issue with publishing the kread bundles. To fix it `agoric published` has been replaced by the `installBundles` script in the `agoric/contract/scripts/` folder. The script connects to the chain using Cosmos StargateClient library and sends a transaction to the correct endpoint with the bundle as payload. This is along the lines of what happens under the hood of `agoric publish` as well but for some reason that seems to be broken currently. For funding the gas fees of the transaction, the same account is used that funds the transactions to publish the committee bundles and sends proposals for the kread-committee and kread. Also, in this PR: - Added some extra steps to `make kread-committee` (and no-build version) that fetches the address that is to be funded from the `AGORIC_SDK_PATH/packages/cosmic-swingset/t1/8000/` folder and funds it. This way we no longer need to run `kread-committee`, copy the logged address and fund it. - Reverted back to the old folder structure where the contract code lives in `src` instead of the versioned folder structere. ## Related Issues Fixes #111 ## Checklist Make sure all items are checked before submitting the pull request. Remove any items that are not applicable. - [x] I have used agoric's linter on my code (https://github.com/Agoric/agoric-sdk/discussions/8274) - [x] I have updated the documentation to reflect the changes (if applicable). - [x] I have added/updated unit tests to cover the changes. - [x] All existing tests pass. --- agoric/Makefile | 10 +- agoric/README.md | 13 +- agoric/contract/package.json | 6 + agoric/contract/scripts/installBundles.js | 101 + agoric/contract/src/{kreadV1 => }/errors.js | 0 agoric/contract/src/{kreadV1 => }/index.js | 0 .../{kreadV1 => }/kreadCommitteeCharter.js | 0 agoric/contract/src/{kreadV1 => }/kreadKit.js | 0 agoric/contract/src/kreadV1/README.md | 164 -- agoric/contract/src/kreadV2/errors.js | 34 - agoric/contract/src/kreadV2/index.js | 181 -- .../src/kreadV2/kreadCommitteeCharter.js | 145 -- agoric/contract/src/kreadV2/kreadKit.js | 1832 ----------------- agoric/contract/src/kreadV2/market-metrics.js | 77 - agoric/contract/src/kreadV2/text.js | 7 - agoric/contract/src/kreadV2/type-guards.js | 248 --- agoric/contract/src/kreadV2/types.js | 295 --- agoric/contract/src/kreadV2/utils.js | 109 - .../src/{kreadV1 => }/market-metrics.js | 0 .../src/proposal/kread-committee-script.js | 2 +- .../src/proposal/start-kread-script.js | 2 +- agoric/contract/src/{kreadV1 => }/text.js | 0 .../contract/src/{kreadV1 => }/type-guards.js | 0 agoric/contract/src/{kreadV1 => }/types.js | 0 agoric/contract/src/{kreadV1 => }/utils.js | 0 agoric/contract/test/bootstrap.js | 2 +- agoric/contract/test/flow.js | 2 +- .../bootstrap/bootstrap-inventory.js | 2 +- .../bootstrap/bootstrap-market.js | 2 +- .../bootstrap/bootstrap-upgradable.js | 24 +- agoric/contract/test/swingsetTests/flow.js | 2 +- .../test/swingsetTests/swingset-setup.js | 16 +- .../test/swingsetTests/test-upgrade.js | 18 +- agoric/contract/test/swingsetTests/types.js | 2 +- agoric/contract/test/test-inventory.js | 2 +- agoric/contract/test/test-market.js | 2 +- agoric/yarn.lock | 199 +- 37 files changed, 356 insertions(+), 3143 deletions(-) create mode 100644 agoric/contract/scripts/installBundles.js rename agoric/contract/src/{kreadV1 => }/errors.js (100%) rename agoric/contract/src/{kreadV1 => }/index.js (100%) rename agoric/contract/src/{kreadV1 => }/kreadCommitteeCharter.js (100%) rename agoric/contract/src/{kreadV1 => }/kreadKit.js (100%) delete mode 100644 agoric/contract/src/kreadV1/README.md delete mode 100644 agoric/contract/src/kreadV2/errors.js delete mode 100644 agoric/contract/src/kreadV2/index.js delete mode 100644 agoric/contract/src/kreadV2/kreadCommitteeCharter.js delete mode 100644 agoric/contract/src/kreadV2/kreadKit.js delete mode 100644 agoric/contract/src/kreadV2/market-metrics.js delete mode 100644 agoric/contract/src/kreadV2/text.js delete mode 100644 agoric/contract/src/kreadV2/type-guards.js delete mode 100644 agoric/contract/src/kreadV2/types.js delete mode 100644 agoric/contract/src/kreadV2/utils.js rename agoric/contract/src/{kreadV1 => }/market-metrics.js (100%) rename agoric/contract/src/{kreadV1 => }/text.js (100%) rename agoric/contract/src/{kreadV1 => }/type-guards.js (100%) rename agoric/contract/src/{kreadV1 => }/types.js (100%) rename agoric/contract/src/{kreadV1 => }/utils.js (100%) diff --git a/agoric/Makefile b/agoric/Makefile index 86cbe3d08..eb4498710 100644 --- a/agoric/Makefile +++ b/agoric/Makefile @@ -87,6 +87,10 @@ clean: # 5. make provision-fee-collector # 6. start the KREAd contract using 'KREAD_COMMITTEE_NAME='kread' KREAD_COMMITTEE_ADDRESSES='{"voter": "agoric1ersatz"}' make start-kread' kread-committee: dist/kread-committee-info.json + cd $(COSMIC_SWINGSET_PATH); \ + make fund-acct ACCT_ADDR=$$(head t1/8000/ag-cosmos-helper-address) FUNDS=1000000000000uist; \ + make fund-acct ACCT_ADDR=$$(head t1/8000/ag-cosmos-helper-address) FUNDS=1000000000000ubld; \ + cd $(AG_DIR); \ jq -r '.bundles[]' dist/kread-committee-info.json | sort -u > kread-committee-bundles.out for b in `cat kread-committee-bundles.out` ; do \ $(AGORIC_CMD) publish --node 127.0.0.1:26657 $$b --chain-id agoriclocal --home $(COSMIC_SWINGSET_PATH)/t1/8000 ; \ @@ -98,13 +102,17 @@ kread-committee: dist/kread-committee-info.json start-kread: dist/start-kread-info.json jq -r '.bundles[]' dist/start-kread-info.json | sort -u > start-kread-bundles.out for b in `cat start-kread-bundles.out` ; do \ - $(AGORIC_CMD) publish --node 127.0.0.1:26657 $$b --chain-id agoriclocal --home $(COSMIC_SWINGSET_PATH)/t1/8000 ; \ + node contract/scripts/installBundles.js $(COSMIC_SWINGSET_PATH) $$b ; \ done cd $(COSMIC_SWINGSET_PATH); \ make scenario2-core-eval EVAL_PERMIT=$(AG_DIR)/dist/start-kread-permit.json \ EVAL_CODE=$(AG_DIR)/dist/start-kread.js EVAL_CLEAN=$(AG_DIR)/dist/start-kread.js.t scenario2-vote VOTE_PROPOSAL=$(NEXT_PROPOSAL) \ kread-committee-no-build: + cd $(COSMIC_SWINGSET_PATH); \ + make fund-acct ACCT_ADDR=$$(head t1/8000/ag-cosmos-helper-address) FUNDS=1000000000000uist; \ + make fund-acct ACCT_ADDR=$$(head t1/8000/ag-cosmos-helper-address) FUNDS=1000000000000ubld; \ + cd $(AG_DIR); \ jq -r '.bundles[]' dist/kread-committee-info.json | sort -u > kread-committee-bundles.out for b in `cat kread-committee-bundles.out` ; do \ $(AGORIC_CMD) publish --node 127.0.0.1:26657 $$b --chain-id agoriclocal --home $(COSMIC_SWINGSET_PATH)/t1/8000 ; \ diff --git a/agoric/README.md b/agoric/README.md index 5c841813e..db8494f60 100644 --- a/agoric/README.md +++ b/agoric/README.md @@ -11,18 +11,11 @@ ensure you are in the agoric folder otherwise cd to agoric folder 1. Start the chain 1. make local-testnet -2. Update KEPLR_ADDRESS in Makefile.paths - 1. try to `make kread-committee` - 2. it will fail but look for `"sender","value":"agoric1` to find the address - 1. if it fails for another reason, you may need to run `make reset-client-local-testnet` - 3. copy that address into Makefile.paths.local for KEPLR_ADDRESS -3. fund the account - 1. make fund-account -4. make the committee +2. make the committee 1. make kread-committee -5. provision the fee collector wallet +3. provision the fee collector wallet 1. make provision-fee-collector -6. start the KREAd contract +4. start the KREAd contract 1. make clean start-kread To confirm it started, diff --git a/agoric/contract/package.json b/agoric/contract/package.json index a49301559..f3ef935ec 100644 --- a/agoric/contract/package.json +++ b/agoric/contract/package.json @@ -33,6 +33,7 @@ }, "dependencies": { "@agoric/assert": "agoric-upgrade-11", + "@agoric/cosmic-proto": "agoric-upgrade-11", "@agoric/deploy-script-support": "agoric-upgrade-11", "@agoric/ertp": "agoric-upgrade-11", "@agoric/governance": "agoric-upgrade-11", @@ -44,6 +45,11 @@ "@agoric/vats": "agoric-upgrade-11", "@agoric/zoe": "agoric-upgrade-11", "@agoric/zone": "agoric-upgrade-11", + "@cosmjs/crypto": "^0.32.1", + "@cosmjs/encoding": "^0.32.1", + "@cosmjs/math": "^0.32.1", + "@cosmjs/proto-signing": "^0.32.1", + "@cosmjs/stargate": "^0.31.1", "@endo/bundle-source": "^2.5.2-upstream-rollup", "@endo/eventual-send": "^0.17.2", "@endo/far": "^0.2.18", diff --git a/agoric/contract/scripts/installBundles.js b/agoric/contract/scripts/installBundles.js new file mode 100644 index 000000000..3eeebd900 --- /dev/null +++ b/agoric/contract/scripts/installBundles.js @@ -0,0 +1,101 @@ +/* eslint-disable no-undef */ +import { fromBech32 } from '@cosmjs/encoding'; +import { SigningStargateClient, defaultRegistryTypes } from '@cosmjs/stargate'; +import { DirectSecp256k1HdWallet, Registry, coins } from '@cosmjs/proto-signing'; +import { Decimal } from '@cosmjs/math'; +import { stringToPath } from '@cosmjs/crypto'; +import { MsgInstallBundle } from '@agoric/cosmic-proto/swingset/msgs.js'; +import * as fs from 'fs'; + +const RPC = 'http://localhost:26657'; + +const hdPath = (coinType = 118, account = 0) => + stringToPath(`m/44'/${coinType}'/${account}'/0/0`); + +export const registry = new Registry([ + ...defaultRegistryTypes, + ['/agoric.swingset.MsgInstallBundle', MsgInstallBundle], +]); + +const Agoric = { + Bech32MainPrefix: 'agoric', + CoinType: 564, +}; + +const makeFeeObject = ({ denom, amount, gas }) => ({ + amount: coins(amount || 0, denom || 'uist'), + gas: gas ? String(gas) : 'auto', +}); + +/** + * Gets the wallet from the mnemonic and uses it to connect to the chain using a stargate client + * + * @param {string} walletMnemonic the mnemonic of the wallet that signs the transaction + * @returns A stargate client + */ +const initializeStargateClient = async (walletMnemonic) => { + const wallet = await DirectSecp256k1HdWallet.fromMnemonic(walletMnemonic, { + prefix: Agoric.Bech32MainPrefix, + hdPaths: [hdPath(Agoric.CoinType, 0), hdPath(Agoric.CoinType, 1)], + }); + + return SigningStargateClient.connectWithSigner(RPC, wallet, { + registry, + gasPrice: { + denom: 'uist', + amount: Decimal.fromUserInput('50000000', 0), + }, + }); +}; + +/** + * Parse bundle, get wallet and send transaction + * over stargate to install the bundle on chain + */ +async function installBundle() { + const cosmicSwingsetPath = process.argv[2]; + const bundlePath = process.argv[3]; + + const bundleText = await fs.readFileSync(bundlePath, 'utf-8'); + const walletAddress = (await fs.readFileSync( + `${cosmicSwingsetPath}/t1/8000/ag-cosmos-helper-address`, + 'utf-8', + )).trim(); + const walletMnemonic = (await fs.readFileSync( + `${cosmicSwingsetPath}/t1/8000/ag-solo-mnemonic`, + 'utf-8', + )).trim(); + + const proposalMsg = { + typeUrl: '/agoric.swingset.MsgInstallBundle', + value: { + bundle: bundleText, + submitter: fromBech32(walletAddress).data, + }, + }; + + const stargateClient = await initializeStargateClient( + walletMnemonic + ); + + if (!stargateClient) { + throw new Error('stargateClient not found'); + } + + const estimate = await stargateClient.simulate( + walletAddress, + [proposalMsg], + undefined, + ); + const adjustment = 1.3; + const gas = Math.ceil(estimate * adjustment); + const txResult = await stargateClient.signAndBroadcast( + walletAddress, + [proposalMsg], + makeFeeObject({ gas }), + ); + + console.log(txResult) +} + +await installBundle(); diff --git a/agoric/contract/src/kreadV1/errors.js b/agoric/contract/src/errors.js similarity index 100% rename from agoric/contract/src/kreadV1/errors.js rename to agoric/contract/src/errors.js diff --git a/agoric/contract/src/kreadV1/index.js b/agoric/contract/src/index.js similarity index 100% rename from agoric/contract/src/kreadV1/index.js rename to agoric/contract/src/index.js diff --git a/agoric/contract/src/kreadV1/kreadCommitteeCharter.js b/agoric/contract/src/kreadCommitteeCharter.js similarity index 100% rename from agoric/contract/src/kreadV1/kreadCommitteeCharter.js rename to agoric/contract/src/kreadCommitteeCharter.js diff --git a/agoric/contract/src/kreadV1/kreadKit.js b/agoric/contract/src/kreadKit.js similarity index 100% rename from agoric/contract/src/kreadV1/kreadKit.js rename to agoric/contract/src/kreadKit.js diff --git a/agoric/contract/src/kreadV1/README.md b/agoric/contract/src/kreadV1/README.md deleted file mode 100644 index 9a33799dc..000000000 --- a/agoric/contract/src/kreadV1/README.md +++ /dev/null @@ -1,164 +0,0 @@ -# KREAd contract - -# index.js -Contains initialization of `kreadKit` with correct data such as: -* Paths used for storage nodes of data to be availabe through RPC -* Creation of asset mint capabilities (`characters` and `items`) -* creation of `storageNode` access -* Creation of ratios based on provided `terms` - -And eventually exposes the `creatorFacet` and `publicFacet` - -# kreadKit.js -The brunt of all KREAd functionality lives here, this utilises the capabilities granted by `index.js` to provide the end-user the ability interact with the contract and the storage-proposal to create and initialize it correctly. - -The kit consists of initialization and 6 facets: `character`, `item`, `market`, `helper`, `public` and the `creator` - -## init -setup all durable storage for the data required by the contract, this consists of the following: -* `characters`: all characters that have been minted by end-users -* `baseCharacters`: all currently available (not been minted) `baseCharacters` -* `items`: all items that have been minted by the artist through publishing an item collection AND the items assigned (and minted) on character mint -* `baseItems`: `baseItems` the items that can be assigned (and minted) on character mint -* `characterMarket`: all characters that have currently been put up for sale by end-users -* `itemMarket`: all items that are currenctly for sale, either first-sales by the artist or secondary sales by end-users - -It also holds metric data more ephemeral, reset on contract upgrade and to be revived through the proposal. - - -## helper -The helper facet exposes functions that are shared between all facets listed here. - -## character -This contains all functions related to characters and the management of them, it contains the following helper functions: -* `calculateLevel` -* `validateInventoryState`: ensures that the inventory state is no breaking any rules (does not contain multiple items with the same category, this automatically limits the size of the inventory to 10 as these categories are the only ones allowed) -* `isNameUnique` -* `getRandomBaseIndex`: gets a random number based on the indexes left in the `baseCharacter` storage -* `makeInventoryRecorderKit` - -and the following functions that are exposed to the end-user through the public facet: -* `mint`: mints a new character NFT with the name provided by the end-users through offer-args, it also requires a `30000000 uist` give in `Price` in the proposal as a mint fee. This character mint will do the following things on contract: - * pick a random base index to retrieve from the `baseCharacter` storage to assign to this NFT (it is removed after) - * create an empty seat to represent the inventory - * mint 2 character NFT keys, to be used as access to this characters specific inventory. 1 is sent to the user 1 is sent to the inventory seat - * create a storage node path (`inventoryRecorderKit`) based on the name of the NFT (the name is sanitized using a regex + string length of max `20`) - * mint the starting items to the character using the `item` facet `mint` function - * distribute the payed mint fee to the royalty and platform addresses and payout the NFT - * update durable storage with: `character` entry, update collection (`market`) metrics - * write the inventory update to the inventory Path - * write the character update to the character vstorage -* `equip`: takes a `characterKey` + an `item` in give and a `characterKey` in want. equip will do the following things on contract: - * ensure character exists and the correct keys are being swapped - * adds the item to the current allocation, tests whether this allocation is a valid state, if not errors out otherwise it continues - * does a reallocation of funds to the correct seats - * updates the inventory recorder with the updated inventory -* `unequip`: takes a `characterKey` in give and an `item` + a `characterKey` in want. unequip will do the following things on contract: - * ensure character exists and the correct keys are being swapped - * does a reallocation of funds to the correct seats - * updates the inventory recorder with the updated inventory -* `swap`: takes a `characterKey` + `item` in give and an `item` + a `characterKey` in want - * ensure character exists and the correct keys are being swapped - * changes the current allocation based on the items being swapped around, tests whether this allocation is a valid state, if not errors out otherwise it continues - * does a reallocation of funds to the correct seats - * updates the inventory recorder with the updated inventory -* `unequipAll`: takes a `characterKey` in give and all `items` + a `characterKey` in want. unequipAll will do the following things on contract: - * ensure character exists and the correct keys are being swapped - * does a reallocation of all items to the user seat + further reallocation to the correct seats - * updates the inventory recorder with the updated inventory - -## item -This contains all functions related to items and the management of them, it contains the following creatorFacet functions: -* `initializeBaseItems` -* `mintBatch`: mints a batch of items defined as an array of `item objects` + `supply` to the seat that made called invitation. Mintbatch will do the following on contract: - * create amounts for provided items - * creates SFTs for each item, supply being provided by array of objects - * all minted items are added as entries in the durable storage `items` - * all item updates are written to the `items` vstorage path - * market metrics are updated based on what was minted - -and the following functions that are used by other assets through the public facet: -* `mintDefaultBatch`: mints the 3 `baseItems` that are given to each character. This mintDefaultBatch will do the following things on contract: - * pick a random common item from the common bases - * pick a second random common item from the common bases, but filter on category (we do not want to mint multiple of the same categories to a character as that invalidates the inventory) - * pick a third item, this time from the legendary bases and filter out both categories picked already. - * mint these items to the inventory seat - * all minted items are added as entries in the durable storage `items` - * all item updates are written to the `items` vstorage path - * market metrics are updated based on what was minted - -## market -This contains all functions related to marketplace and the management of them. - -It contains the following helper functions: -* `handleExitCharacter` and `handleExitItem`: these are long living promises that listen to the exit status of marketplace listings, this allows the end-users to call exit offer from anywhere (wallet-ui etc..). This removes the entry from durable storage and updates the market storage node with the updated list of things for sale. -* `updateMetrics`: uses util functions in `market-metrics.js` to calculate and update metrics - -It contains the following creatorFacet functions: -* `publishItemCollection`: mints a batch of items defined as an array of `item objects` + `supply` and the `salePrice` to the seat that called invitation. Mintbatch will do the following on contract: - * mints the items - * defines the fees (royalty and platform) - * creates marketplace entries and lists them as `isFirstSale = true` - * all minted items are added as entries in the durable storage `market-items` - * all marketplace updates are written to the `market-items` vstorage path updating the currently for sale items - * market metrics are updated based on what was put on sale - -and the following functions that are exposed to the end-user through the public facet: -* `sellItem`: puts an item on the marketplace based on the `item` and price in give. This sellItem will do the following things on contract: - * ensure brand is the defined paymentbrand we set - * calculate the fees required when buying the item - * create a marketplace entry and add it to the market durable storage - * update the market recorder with the updated list of items for sale - * update the metrics based on the item put for sale - * start an exit subscriber for the item -* `sellCharacter`: puts a character on the marketplace based on the `character` and price in give. This sellCharacter does the same as `sellItem` to the contract, only changin what storage node and durable storage to update. -* `buyItem`: attempts to buy an item listed on the marketplace based on the entryId in the offer args + price in give and `item` in want. This buyItem will do the following things on contract: - * ensure the sell record exists - * define whether it is first or secondary sale and use the correct function - * `buyFirstSale` and `buySecondarySale` differences: Seat does not exit on first sale, fees are different on first sale - * ensure the give price is higher than the price listed + the fees - * ensure the want item is the correct item - * reallocate funds - * remove marketplace ntry from market durable storage - * update the market recorder with the updated list of items for sale - * update the metrics based on the item just bought -* `buyCharacter`: attempts to buy a character on the marketplace based on the `character` in want and the price in give. This buyCharacter does the same as `sellItem` to the contract however, it only consists of secondary sale objects and it changes what storage node and durable storage to update. - -## public -This contains wrappers for all functions that are needed for end-users to create their invitations from the UI. - -It contains the following helper functions for tests: - * `getCharacters`: - * `getCharacterInventory`: - * `getCharactersForSale`: - * `getItemsForSale`: - * `getMarketMetrics`: - * `getCharacterLevel`: - -It contains the following wrapped functions for end-users: - * `makeMintCharacterInvitation`: - * `makeMintItemInvitation`: - * `makeEquipInvitation`: - * `makeUnequipInvitation`: - * `makeUnequipAllInvitation`: - * `makeItemSwapInvitation`: - * `makeSellCharacterInvitation`: - * `makeBuyCharacterInvitation`: - * `makeSellItemInvitation`: - * `makeBuyItemInvitation`: - - -## creator -This contains wrappers for all functions that are needed to setup the contract correctly and ensure it can be upgraded/restarted correctly. - -It contains the following helper functions for tests: - * `makeMintItemInvitation`: - - -It contains the following wrapped functions for contract start and governance: - * `initializeMetrics`: initializes the metrics with a base value - * `reviveMarketExitSubscribers`: loops over all marketplace entries in durable storage and calls the function to start the exit subscriber - * `initializeBaseAssets`: provides the `baseCharacters` and `baseAssets`. This will do the following things on contract: - * add the list of base characters to durable storage with a numbered key - * add the base items to the corresponding rarity list and adds this to durable storage - * `makePublishItemCollectionInvitation`: publishes a new item collection diff --git a/agoric/contract/src/kreadV2/errors.js b/agoric/contract/src/kreadV2/errors.js deleted file mode 100644 index 9fb323040..000000000 --- a/agoric/contract/src/kreadV2/errors.js +++ /dev/null @@ -1,34 +0,0 @@ -export const errors = { - noConfig: `Configuration not found, use creatorFacet.initConfig() to enable this method`, - noNameArg: `Name argument required`, - allMinted: `All characters have been minted`, - invalidName: `Invalid name. String should only contain ASCII alphanumerics, underscores, and/or dashes.`, - mintFeeTooLow: `Provided mint fee is too low`, - unkwonwnArgInMintOffer: `Mint Character's offer "want" must only contain property "name"`, - noWantInOffer: `Offer must include "want" terms in the form of { want: { name: }}`, - nameTaken: (name) => - `Name ${name} is already in use, please select a different name`, - depositToSeatFailed: `Could not deposit nft into Seat`, - depositToFacetFailed: `Could not deposit nft into userFacet`, - character404: `Character not found`, - inventory404: `Character inventory not found`, - notifier404: `Character inventory notifier not found`, - updateMarketError: `There was a problem updating the market`, - privateState404: `Character private state not found`, - noKeyInInventory: `Could not find character key in inventory`, - invalidInventoryKey: `Brand of Inventory Key does not match the correct Issuer`, - inventoryKeyMismatch: `Wanted Key and Inventory Key do not match`, - noItemsRequested: `Offer missing requested item`, - duplicateCategoryInInventory: `Inventory cannot contain multiple items of the same category`, - seedInvalid: `Seed must be a number`, - itemNotInMarket: `Could not find Item in market`, - characterNotInMarket: `Could not find Character in market`, - invalidArg: `Invalid Argument`, - missingStorageNode: `Missing Storage Node, notifications are not enabled`, - sellerSeatMismatch: `Wanted Item amount does not match item in sellerSeat`, - insufficientFunds: `Provided payment is lower than the asking price for this Item`, - itemNotFound: (item) => `Couldn't find item record for ${item}`, - incorrectPaymentBrand: (paymentBrand) => - `Incorrect payment brand. Please use ${paymentBrand}`, - rearrangeError: 'Reallocating assets between seats failed' -}; diff --git a/agoric/contract/src/kreadV2/index.js b/agoric/contract/src/kreadV2/index.js deleted file mode 100644 index 1bcb3e26b..000000000 --- a/agoric/contract/src/kreadV2/index.js +++ /dev/null @@ -1,181 +0,0 @@ -/* eslint-disable no-undef */ -// @ts-check -import '@agoric/zoe/exported.js'; - -import { AmountMath, AssetKind } from '@agoric/ertp'; -import { M } from '@agoric/store'; -import { provideAll } from '@agoric/zoe/src/contractSupport/durability.js'; -import { prepareRecorderKitMakers } from '@agoric/zoe/src/contractSupport/recorder.js'; -import { makeRatio } from '@agoric/zoe/src/contractSupport/ratio.js'; -import { InvitationShape } from '@agoric/zoe/src/typeGuards.js'; -import { handleParamGovernance } from '@agoric/governance'; - -import { prepareKreadKit, provideKreadKitRecorderKits } from './kreadKit.js'; -import { provide } from '@agoric/vat-data'; -import { provideRecorderKits } from './utils.js'; - -/** - * This contract handles the mint of KREAd characters, - * along with its corresponding item inventories and keys. - * It also allows for equiping and unequiping items to - * and from the inventory, using a token as access - */ - -/** @typedef {import('@agoric/vat-data').Baggage} Baggage */ -/** @typedef {import('@agoric/time/src/types').Clock} Clock */ -/** @typedef {import('./type-guards.js').RatioObject} RatioObject */ - -/** @type {ContractMeta} */ -export const meta = { - privateArgsShape: M.splitRecord({ - initialPoserInvitation: InvitationShape, - seed: M.number(), - clock: M.eref(M.remotable('Clock')), - powers: { - storageNode: M.remotable('StorageNode'), - marshaller: M.remotable('Marshaller'), - }, - }), - customTermsShape: M.splitRecord({ - royaltyRate: { - numerator: M.lte(100n), - denominator: M.eq(100n), - }, - platformFeeRate: { - numerator: M.lte(100n), - denominator: M.eq(100n), - }, - mintFee: M.nat(), - mintRoyaltyRate: { - numerator: M.lte(100n), - denominator: M.eq(100n), - }, - mintPlatformFeeRate: { - numerator: M.lte(100n), - denominator: M.eq(100n), - }, - royaltyDepositFacet: M.any(), - platformFeeDepositFacet: M.any(), - assetNames: M.splitRecord({ character: M.string(), item: M.string() }), - }), -}; -harden(meta); - -/** - * @param {ZCF>} zcf - * @param {{ - * seed: number - * powers: { storageNode: StorageNode, marshaller: Marshaller }, - * clock: Clock - * defaultCharacters: object[], - * defaultItems: object[], - * initialPoserInvitation: Invitation - * }} privateArgs - * - * @param {Baggage} baggage - */ -export const prepare = async (zcf, privateArgs, baggage) => { - const terms = zcf.getTerms(); - - // TODO: move to proposal - const assetNames = terms.assetNames; - - // Setting up the mint capabilities here in the prepare function, as discussed with Turadg - // durability is not a concern with these, and defining them here, passing on what's needed - // ensures that the capabilities are where they need to be - const { characterMint, itemMint } = await provideAll(baggage, { - characterMint: () => - zcf.makeZCFMint(assetNames.character, AssetKind.COPY_BAG), - itemMint: () => zcf.makeZCFMint(assetNames.item, AssetKind.COPY_BAG), - }); - - const characterIssuerRecord = characterMint.getIssuerRecord(); - const itemIssuerRecord = itemMint.getIssuerRecord(); - - const { powers, clock, seed } = privateArgs; - - const { - mintFee, - royaltyRate, - platformFeeRate, - mintRoyaltyRate, - mintPlatformFeeRate, - royaltyDepositFacet, - platformFeeDepositFacet, - minUncommonRating, - brands: { Money: paymentBrand }, - } = terms; - - const { makeRecorderKit } = prepareRecorderKitMakers( - baggage, - powers.marshaller, - ); - - const recorderKits = await provideKreadKitRecorderKits( - baggage, - powers.storageNode, - makeRecorderKit, - ); - - assert(paymentBrand, 'missing paymentBrand'); - const mintFeeAmount = AmountMath.make(paymentBrand, mintFee); - - const objectToRatio = (brand, { numerator, denominator }) => { - return makeRatio(numerator, brand, denominator, brand); - }; - const mintRoyaltyRateRatio = objectToRatio(paymentBrand, mintRoyaltyRate); - const mintPlatformFeeRatio = objectToRatio(paymentBrand, mintPlatformFeeRate); - const royaltyRateRatio = objectToRatio(paymentBrand, royaltyRate); - const platformFeeRatio = objectToRatio(paymentBrand, platformFeeRate); - - const makeKreadKit = prepareKreadKit( - baggage, - zcf, - { - seed, - mintFeeAmount, - royaltyRate: royaltyRateRatio, - platformFeeRate: platformFeeRatio, - mintRoyaltyRate: mintRoyaltyRateRatio, - mintPlatformFeeRate: mintPlatformFeeRatio, - royaltyDepositFacet, - platformFeeDepositFacet, - paymentBrand, - minUncommonRating, - }, - harden({ - recorderKits, - characterMint, - characterIssuerRecord, - itemIssuerRecord, - itemMint, - clock, - storageNode: powers.storageNode, - makeRecorderKit, - }), - ); - - const kreadKit = provide(baggage, 'kitSingleton', () => makeKreadKit()); - - const { makeDurableGovernorFacet } = handleParamGovernance( - zcf, - privateArgs.initialPoserInvitation, - {}, - ); - - const { governorFacet } = makeDurableGovernorFacet( - baggage, - kreadKit.creator, - { - publishItemCollection: (price, itemsToSell) => - kreadKit.creator.publishItemCollection(price, itemsToSell), - }, - ); - return harden({ - creatorFacet: governorFacet, - // no governed parameters, so no need to augment. - publicFacet: kreadKit.public, - }); -}; - -harden(prepare); diff --git a/agoric/contract/src/kreadV2/kreadCommitteeCharter.js b/agoric/contract/src/kreadV2/kreadCommitteeCharter.js deleted file mode 100644 index 14ce22e31..000000000 --- a/agoric/contract/src/kreadV2/kreadCommitteeCharter.js +++ /dev/null @@ -1,145 +0,0 @@ -// @jessie-check - -import { M } from '@agoric/store'; -import { TimestampShape } from '@agoric/time'; -import { prepareExo, provideDurableMapStore } from '@agoric/vat-data'; -import '@agoric/zoe/exported.js'; -import { - InstallationShape, - InstanceHandleShape, -} from '@agoric/zoe/src/typeGuards.js'; -import { E } from '@endo/far'; - -import '@agoric/governance/exported.js'; -import '@agoric/zoe/src/contracts/exported.js'; - -/** - * @file This contract makes it possible for those who govern the KREAd contract - * to call for votes to pause offers. - */ - -export const INVITATION_MAKERS_DESC = 'charter member invitation'; - -/** @type {ContractMeta} */ -export const meta = { - customTermsShape: { - binaryVoteCounterInstallation: InstallationShape, - }, - upgradability: 'canUpgrade', -}; -harden(meta); - -/** - * @param {ZCF<{ binaryVoteCounterInstallation: Installation }>} zcf - * @param {undefined} privateArgs - * @param {import('@agoric/vat-data').Baggage} baggage - */ -export const start = async (zcf, privateArgs, baggage) => { - const { binaryVoteCounterInstallation: counter } = zcf.getTerms(); - /** @type {MapStore>} */ - const instanceToGovernor = provideDurableMapStore( - baggage, - 'instanceToGovernor', - ); - - const makeOfferFilterInvitation = (instance, strings, deadline) => { - const voteOnOfferFilterHandler = (seat) => { - seat.exit(); - - const governor = instanceToGovernor.get(instance); - return E(governor).voteOnOfferFilter(counter, deadline, strings); - }; - - return zcf.makeInvitation(voteOnOfferFilterHandler, 'vote on offer filter'); - }; - - /** - * @param {Instance} instance - * @param {string} methodName - * @param {string[]} methodArgs - * @param {import('@agoric/time').TimestampValue} deadline - */ - const makeApiInvocationInvitation = ( - instance, - methodName, - methodArgs, - deadline, - ) => { - const handler = (seat) => { - seat.exit(); - - const governor = instanceToGovernor.get(instance); - return E(governor).voteOnApiInvocation( - methodName, - methodArgs, - counter, - deadline, - ); - }; - return zcf.makeInvitation(handler, 'vote on API invocation'); - }; - - const MakerI = M.interface('Charter InvitationMakers', { - VoteOnPauseOffers: M.call( - InstanceHandleShape, - M.arrayOf(M.string()), - TimestampShape, - ).returns(M.promise()), - VoteOnApiCall: M.call( - InstanceHandleShape, - M.string(), - M.arrayOf(M.any()), - TimestampShape, - ).returns(M.promise()), - }); - - // durable so that when this contract is upgraded this ocap held - // by committee members (from their invitations) stay capable - const invitationMakers = prepareExo( - baggage, - 'Charter Invitation Makers', - MakerI, - { - VoteOnPauseOffers: makeOfferFilterInvitation, - VoteOnApiCall: makeApiInvocationInvitation, - }, - ); - - const charterMemberHandler = (seat) => { - seat.exit(); - return harden({ invitationMakers }); - }; - - const CharterCreatorI = M.interface('Charter creatorFacet', { - addInstance: M.call(InstanceHandleShape, M.any()) - .optional(M.string()) - .returns(), - makeCharterMemberInvitation: M.call().returns(M.promise()), - }); - - const creatorFacet = prepareExo( - baggage, - 'Charter creatorFacet', - CharterCreatorI, - { - /** - * @param {Instance} governedInstance - * @param {GovernorCreatorFacet} governorFacet - * @param {string} [label] for diagnostic use only - */ - addInstance: (governedInstance, governorFacet, label) => { - console.log('charter: adding instance', label); - instanceToGovernor.init(governedInstance, governorFacet); - }, - makeCharterMemberInvitation: () => - zcf.makeInvitation(charterMemberHandler, INVITATION_MAKERS_DESC), - }, - ); - - return harden({ creatorFacet }); -}; -harden(start); - -/** - * @typedef {import('@agoric/zoe/src/zoeService/utils.js').StartedInstanceKit} KreadCharterStartResult - */ diff --git a/agoric/contract/src/kreadV2/kreadKit.js b/agoric/contract/src/kreadV2/kreadKit.js deleted file mode 100644 index bc4e8acaa..000000000 --- a/agoric/contract/src/kreadV2/kreadKit.js +++ /dev/null @@ -1,1832 +0,0 @@ -/* eslint-disable no-bitwise */ -/* eslint-disable no-undef */ -// @ts-check -import { updateCollectionMetrics } from './market-metrics.js'; -import { assert, details as X } from '@agoric/assert'; -import { AmountMath, BrandShape } from '@agoric/ertp'; -import { prepareExoClassKit, M } from '@agoric/vat-data'; -import { makeDurableZone } from '@agoric/zone/durable.js'; - -import { E } from '@endo/eventual-send'; -import { errors } from './errors.js'; -import { - makeCharacterNftObjs, - makeCopyBagAmountShape, - addAllToMap, - provideRecorderKits, -} from './utils.js'; - -import { text } from './text.js'; -import { makeCopyBag, mustMatch } from '@agoric/store'; -import { - CharacterI, - HelperI, - ItemI, - MarketI, - PublicI, - CreatorI, - CharacterGuardBagShape, - ItemGuard, - ItemGuardBagShape, - ItemRecorderGuard, - MarketRecorderGuard, - MarketMetricsGuard, - RarityGuard, - BaseCharacterGuard, - MarketEntryGuard, - CharacterEntryGuard, - CharacterRecorderGuard, -} from './type-guards.js'; -import { atomicRearrange } from '@agoric/zoe/src/contractSupport/index.js'; -import { multiplyBy } from '@agoric/zoe/src/contractSupport/ratio.js'; - -import '@agoric/zoe/exported.js'; - -/** - * this provides the exoClassKit for our upgradable KREAd contract - * Utilizes capabilities from the prepare function suchs as mints - * timer service and values from the privateArgs - * - * - * @param {import('@agoric/vat-data').Baggage} baggage - * @param {ZCF} zcf - * @param {{ - * seed: number, - * mintFeeAmount: Amount<'nat'>, - * royaltyRate: Ratio, - * platformFeeRate: Ratio, - * mintRoyaltyRate: Ratio, - * mintPlatformFeeRate: Ratio, - * royaltyDepositFacet: DepositFacet, - * platformFeeDepositFacet: DepositFacet, - * paymentBrand: Brand, - * minUncommonRating: number - * }} privateArgs - * @param {{ - * characterIssuerRecord: IssuerRecord<"copyBag"> - * characterMint: ZCFMint<"copyBag"> - * itemIssuerRecord: IssuerRecord<"copyBag"> - * itemMint: ZCFMint<"copyBag"> - * clock: import('@agoric/time/src/types.js').Clock - * makeRecorderKit: import('@agoric/zoe/src/contractSupport').MakeRecorderKit, - * recorderKits: { - * characterKit: import('@agoric/zoe/src/contractSupport/recorder.js').RecorderKit; - * itemKit: import('@agoric/zoe/src/contractSupport/recorder.js').RecorderKit; - * marketCharacterKit: import('@agoric/zoe/src/contractSupport/recorder.js').RecorderKit; - * marketItemKit: import('@agoric/zoe/src/contractSupport/recorder.js').RecorderKit; - * marketCharacterMetricsKit: import('@agoric/zoe/src/contractSupport/recorder.js').RecorderKit; - * marketItemMetricsKit: import('@agoric/zoe/src/contractSupport/recorder.js').RecorderKit; - * }; - * }} powers - */ -export const prepareKreadKit = ( - baggage, - zcf, - { - seed, - mintFeeAmount, - royaltyRate, - platformFeeRate, - mintRoyaltyRate, - mintPlatformFeeRate, - royaltyDepositFacet, - platformFeeDepositFacet, - paymentBrand, - minUncommonRating, - }, - { - characterIssuerRecord, - characterMint, - itemIssuerRecord, - itemMint, - clock, - makeRecorderKit, - recorderKits: { - characterKit, - itemKit, - marketCharacterKit, - marketCharacterMetricsKit, - marketItemKit, - marketItemMetricsKit, - }, - }, -) => { - const { brand: characterBrand } = characterIssuerRecord; - const { brand: itemBrand } = itemIssuerRecord; - - const marketItemNode = marketItemKit.recorder.getStorageNode(); - const marketCharacterNode = marketCharacterKit.recorder.getStorageNode(); - - const characterNode = characterKit.recorder.getStorageNode(); - - const characterShape = makeCopyBagAmountShape( - characterBrand, - CharacterGuardBagShape, - ); - const itemShape = makeCopyBagAmountShape(itemBrand, ItemGuardBagShape); - - return prepareExoClassKit( - baggage, - 'KreadKit', - { - helper: HelperI, - character: CharacterI, - item: ItemI, - market: MarketI, - public: PublicI, - creator: CreatorI, - }, - () => { - const zone = makeDurableZone(baggage); - return { - character: harden({ - entries: zone.mapStore('characters', { - keyShape: M.string(), - valueShape: M.or(CharacterEntryGuard, M.arrayOf(M.string())), - }), - bases: zone.mapStore('baseCharacters', { - keyShape: M.number(), - valueShape: BaseCharacterGuard, - }), - }), - item: harden({ - entries: zone.mapStore('items', { - keyShape: M.number(), - valueShape: ItemRecorderGuard, - }), - bases: zone.mapStore('baseItems', { - keyShape: RarityGuard, - valueShape: M.arrayOf(ItemGuard), - }), - }), - market: harden({ - characterEntries: zone.mapStore('characterMarket', { - keyShape: M.string(), - valueShape: MarketEntryGuard, - }), - itemEntries: zone.mapStore('itemMarket', { - keyShape: M.number(), - valueShape: MarketEntryGuard, - }), - metrics: zone.mapStore('marketMetrics', { - keyShape: M.or('character', 'item'), - valueShape: MarketMetricsGuard, - }), - }), - }; - }, - { - helper: { - async getTimeStamp() { - return E(clock).getCurrentTimestamp(); - }, - randomNumber() { - seed |= 0; - seed = (seed + 0x6d2b79f5) | 0; - let t = Math.imul(seed ^ (seed >>> 15), 1 | seed); - // eslint-disable-next-line operator-assignment - t = (t + Math.imul(t ^ (t >>> 7), 61 | t)) ^ t; - return ((t ^ (t >>> 14)) >>> 0) / 4294967296; - }, - }, - character: { - calculateLevel(name) { - const character = this.state.character.entries.get(name); - let level = character.character.level; - - const itemLevels = character.inventory - .getAmountAllocated('Item') - .value.payload.map(([value, _supply]) => { - return value.level; - }); - - level = itemLevels.reduce((acc, value) => acc + value, level); - return level; - }, - validateInventoryState(inventoryState) { - const itemTypes = inventoryState.map((item) => item.category); - return itemTypes.length === new Set(itemTypes).size; - }, - isNameUnique(name) { - return !this.state.character.entries.has(name); - }, - getRandomBaseIndex() { - const { helper } = this.facets; - const { character: characterState } = this.state; - const number = Math.floor( - helper.randomNumber() * characterState.bases.getSize(), - ); - return Array.from(characterState.bases.keys())[number]; - }, - initializeBaseCharacters(baseCharacters) { - const { character: characterState } = this.state; - if (characterState.bases.getSize() > 0) return; - addAllToMap(characterState.bases, baseCharacters); - }, - async makeInventoryRecorderKit(path) { - const node = await E(characterNode).makeChildNode( - `inventory-${path}`, - ); - return makeRecorderKit(node, M.arrayOf([ItemGuard, M.nat()])); - }, - mint() { - const handler = async (seat, offerArgs) => { - const { - helper, - character: characterFacet, - item, - market: marketFacet, - } = this.facets; - - const { character: characterState } = this.state; - - const { give } = seat.getProposal(); - mustMatch( - offerArgs, - M.splitRecord({ - name: M.string(harden({ stringLengthLimit: 20 })), - }), - 'offerArgs', - ); - - const newCharacterName = offerArgs.name; - - AmountMath.isGTE(give.Price, mintFeeAmount) || - assert.fail(errors.mintFeeTooLow); - - !characterState.entries.get('names').includes(newCharacterName) || - assert.fail(errors.nameTaken(newCharacterName)); - - characterState.bases.getSize() > 0 || - assert.fail(errors.allMinted); - - const re = /^[a-zA-Z0-9_-]*$/; - (re.test(newCharacterName) && newCharacterName !== 'names') || - assert.fail(errors.invalidName); - - const baseIndex = characterFacet.getRandomBaseIndex(); - const baseCharacter = characterState.bases.get(baseIndex); - - characterState.bases.delete(baseIndex); - - characterState.entries.set( - 'names', - harden([ - ...characterState.entries.get('names'), - newCharacterName, - ]), - ); - - // for @jessie.js/safe-await-operator - await null; - try { - const currentTime = await helper.getTimeStamp(); - - const [newCharacterAmount1, newCharacterAmount2] = - makeCharacterNftObjs( - newCharacterName, - baseCharacter, - characterState.entries.getSize(), - currentTime, - ).map((character) => - AmountMath.make( - characterBrand, - makeCopyBag(harden([[character, 1n]])), - ), - ); - - const { zcfSeat, userSeat } = zcf.makeEmptySeatKit(); - - const { zcfSeat: inventorySeat } = zcf.makeEmptySeatKit(); - // Mint character to user seat & inventorySeat - characterMint.mintGains({ Asset: newCharacterAmount1 }, seat); - characterMint.mintGains( - { CharacterKey: newCharacterAmount2 }, - inventorySeat, - ); - - const inventoryKit = - await characterFacet.makeInventoryRecorderKit(newCharacterName); - - await item.mintDefaultBatch(inventorySeat); - - const royaltyFee = multiplyBy(give.Price, mintRoyaltyRate); - const platformFee = multiplyBy(give.Price, mintPlatformFeeRate); - - /** @type {TransferPart[]} */ - const transfers = []; - transfers.push([ - seat, - zcfSeat, - { Price: royaltyFee }, - { Royalty: royaltyFee }, - ]); - transfers.push([ - seat, - zcfSeat, - { Price: platformFee }, - { PlatformFee: platformFee }, - ]); - - try { - atomicRearrange(zcf, harden(transfers)); - } catch (e) { - assert.fail(errors.rearrangeError); - } - - seat.exit(); - zcfSeat.exit(); - - const payouts = await E(userSeat).getPayouts(); - const royaltyPayout = await payouts.Royalty; - const platformFeePayout = await payouts.PlatformFee; - - await E(royaltyDepositFacet).receive(royaltyPayout); - await E(platformFeeDepositFacet).receive(platformFeePayout); - - // Add to state - const character = { - name: newCharacterName, - character: newCharacterAmount1.value.payload[0][0], - inventory: inventorySeat, - inventoryKit, - history: [ - { - type: 'mint', - data: newCharacterAmount1.value[0], - timestamp: currentTime, - }, - ], - }; - - addAllToMap(characterState.entries, [ - [character.name, harden(character)], - ]); - - // update metrics - marketFacet.updateMetrics('character', { - collectionSize: true, - averageLevel: { - type: 'add', - value: character.character.level, - }, - }); - - characterKit.recorder.write( - // write `character` minus `seat` prop - (({ seat: _omitSeat, ...char }) => char)(character), - ); - - // TODO: consider refactoring what we put in the inventory node - inventoryKit.recorder.write( - inventorySeat.getAmountAllocated('Item').value.payload, - ); - - return text.mintCharacterReturn; - } catch (e) { - // restore base char deletion and and name entry - addAllToMap(characterState.bases, [[baseIndex, baseCharacter]]); - characterState.entries.set( - 'names', - harden( - characterState.entries - .get('names') - .filter((name) => name !== newCharacterName), - ), - ); - return e; - } - }; - return zcf.makeInvitation( - handler, - 'mintCharacterNfts', - undefined, - undefined, - ); - }, - equip() { - const handler = (seat) => { - const { character: characterFacet } = this.facets; - const { character: characterState } = this.state; - - // Retrieve Items and Inventory key from user seat - const providedItemAmount = seat.getAmountAllocated('Item'); - const providedCharacterKeyAmount = - seat.getAmountAllocated('CharacterKey1'); - const providedCharacterKey = - providedCharacterKeyAmount.value.payload[0][0]; - const characterName = providedCharacterKey.name; - - // Find characterRecord entry based on provided key - const characterRecord = characterState.entries.get(characterName); - const inventorySeat = characterRecord.inventory; - - const { want } = seat.getProposal(); - const { CharacterKey2: wantedCharacter } = want; - - // Get current Character Key from inventorySeat - const inventoryCharacterKey = - inventorySeat.getAmountAllocated('CharacterKey'); - inventoryCharacterKey || assert.fail(errors.noKeyInInventory); - - AmountMath.isEqual( - wantedCharacter, - inventoryCharacterKey, - characterBrand, - ) || assert.fail(errors.inventoryKeyMismatch); - - // Ensure inventory STATE will be valid before reallocation - let inventory = inventorySeat - .getCurrentAllocation() - .Item.value.payload.map(([value, _supply]) => value); - if (providedItemAmount.value.payload[0]) - inventory = [ - ...inventory, - providedItemAmount.value.payload[0][0], - ]; - - characterFacet.validateInventoryState(inventory) || - assert.fail(errors.duplicateCategoryInInventory); - - /** @type {TransferPart[]} */ - const transfers = []; - transfers.push([seat, inventorySeat, { Item: providedItemAmount }]); - transfers.push([ - seat, - inventorySeat, - { CharacterKey1: providedCharacterKeyAmount }, - { CharacterKey: providedCharacterKeyAmount }, - ]); - transfers.push([ - inventorySeat, - seat, - { CharacterKey: inventoryCharacterKey }, - { CharacterKey2: inventoryCharacterKey }, - ]); - - try { - atomicRearrange(zcf, harden(transfers)); - } catch (e) { - assert.fail(errors.rearrangeError); - } - - characterRecord.inventoryKit.recorder.write( - inventorySeat.getAmountAllocated('Item').value.payload, - ); - - seat.exit(); - - return text.equipReturn; - }; - return zcf.makeInvitation( - handler, - 'addToInventory', - undefined, - M.splitRecord({ - give: { - CharacterKey1: M.splitRecord(characterShape), - Item: M.splitRecord(itemShape), - }, - want: { - CharacterKey2: M.splitRecord(characterShape), - }, - }), - ); - }, - unequip() { - const handler = async (seat) => { - const { character: characterState } = this.state; - - // Retrieve Character key from user seat - const providedCharacterKeyAmount = - seat.getAmountAllocated('CharacterKey1'); - const providedCharacterKey = - providedCharacterKeyAmount.value.payload[0][0]; - const characterName = providedCharacterKey.name; - - // Find character record entry based on provided key - const characterRecord = characterState.entries.get(characterName); - const inventorySeat = characterRecord.inventory; - providedCharacterKey || - assert.fail(errors.invalidCharacterKey); - - // Get reference to the wanted items and key - const { want } = seat.getProposal(); - const { Item: requestedItems, CharacterKey2: wantedCharacter } = - want; - - const inventoryCharacterKey = - inventorySeat.getAmountAllocated('CharacterKey'); - inventoryCharacterKey || assert.fail(errors.noKeyInInventory); - - // Ensure requested key and inventory key match - - AmountMath.isEqual( - wantedCharacter, - inventoryCharacterKey, - characterBrand, - ) || assert.fail(errors.inventoryKeyMismatch); - - /** @type {TransferPart[]} */ - const transfers = []; - transfers.push([inventorySeat, seat, { Item: requestedItems }]); - transfers.push([ - seat, - inventorySeat, - { CharacterKey1: providedCharacterKeyAmount }, - { CharacterKey: providedCharacterKeyAmount }, - ]); - transfers.push([ - inventorySeat, - seat, - { CharacterKey: wantedCharacter }, - { CharacterKey2: wantedCharacter }, - ]); - - try { - atomicRearrange(zcf, harden(transfers)); - } catch (e) { - assert.fail(errors.rearrangeError); - } - - characterRecord.inventoryKit.recorder.write( - inventorySeat.getAmountAllocated('Item').value.payload, - ); - - seat.exit(); - return text.unequipReturn; - }; - - return zcf.makeInvitation( - handler, - 'removeFromInventory', - undefined, - M.splitRecord({ - give: { - CharacterKey1: M.splitRecord(characterShape), - }, - want: { - CharacterKey2: M.splitRecord(characterShape), - Item: M.splitRecord(itemShape), - }, - }), - ); - }, - swap() { - const handler = (seat) => { - const { character: characterFacet } = this.facets; - const { character: characterState } = this.state; - - // Retrieve Items and Inventory key from user seat - const providedItemAmount = seat.getAmountAllocated('Item1'); - const providedCharacterKeyAmount = - seat.getAmountAllocated('CharacterKey1'); - const providedCharacterKey = - providedCharacterKeyAmount.value.payload[0][0]; - // const providedItems = providedItemAmount.value; - const characterName = providedCharacterKey.name; - - // Find character record entry based on provided key - const characterRecord = characterState.entries.get(characterName); - const inventorySeat = characterRecord.inventory; - providedCharacterKey || - assert.fail(errors.invalidCharacterKey); - - const { want } = seat.getProposal(); - const { - CharacterKey2: wantedCharacterAmount, - Item2: wantedItemsAmount, - } = want; - - // Ensure requested key and inventory key match - const inventoryCharacterKey = - inventorySeat.getAmountAllocated('CharacterKey'); - inventoryCharacterKey || assert.fail(errors.noKeyInInventory); - - AmountMath.isEqual( - wantedCharacterAmount, - inventoryCharacterKey, - characterBrand, - ) || assert.fail(errors.inventoryKeyMismatch); - - // Ensure inventory STATE is valid before reallocation - let inventory = inventorySeat - .getCurrentAllocation() - .Item.value.payload.map(([value, _supply]) => value); - - if (wantedItemsAmount.value.payload[0]) - inventory = inventory.filter( - (item) => - item.category !== - wantedItemsAmount.value.payload[0][0].category, - ); - if (providedItemAmount.value.payload[0]) - inventory = [ - ...inventory, - providedItemAmount.value.payload[0][0], - ]; - - characterFacet.validateInventoryState(inventory) || - assert.fail(errors.duplicateCategoryInInventory); - - /** @type {TransferPart[]} */ - const transfers = []; - transfers.push([ - seat, - inventorySeat, - { Item1: providedItemAmount }, - { Item: providedItemAmount }, - ]); - transfers.push([ - inventorySeat, - seat, - { Item: wantedItemsAmount }, - { Item2: wantedItemsAmount }, - ]); - transfers.push([ - seat, - inventorySeat, - { CharacterKey1: providedCharacterKeyAmount }, - { CharacterKey: providedCharacterKeyAmount }, - ]); - transfers.push([ - inventorySeat, - seat, - { CharacterKey: wantedCharacterAmount }, - { CharacterKey2: wantedCharacterAmount }, - ]); - - try { - atomicRearrange(zcf, harden(transfers)); - } catch (e) { - assert.fail(errors.rearrangeError); - } - - characterRecord.inventoryKit.recorder.write( - inventorySeat.getAmountAllocated('Item').value.payload, - ); - seat.exit(); - }; - - return zcf.makeInvitation( - handler, - 'itemInventorySwap', - undefined, - M.splitRecord({ - give: { - CharacterKey1: M.splitRecord(characterShape), - Item1: M.splitRecord(itemShape), - }, - want: M.splitRecord( - { - CharacterKey2: M.splitRecord(characterShape), - }, - { Item2: M.splitRecord(itemShape) }, - ), - }), - ); - }, - unequipAll() { - const handler = (seat) => { - const { character: characterState } = this.state; - - // Retrieve Character key from user seat - const providedCharacterKeyAmount = - seat.getAmountAllocated('CharacterKey1'); - const providedCharacterKey = - providedCharacterKeyAmount.value.payload[0][0]; - const characterName = providedCharacterKey.name; - - // Find character record entry based on provided key - const characterRecord = characterState.entries.get(characterName); - const inventorySeat = characterRecord.inventory; - providedCharacterKey || - assert.fail(errors.invalidCharacterKey); - - // Get reference to the wanted item - const { want } = seat.getProposal(); - const { CharacterKey2: wantedCharacter } = want; - - // Get Character Key from inventorySeat - const inventoryCharacterKey = - inventorySeat.getAmountAllocated('CharacterKey'); - inventoryCharacterKey || assert.fail(errors.noKeyInInventory); - - const items = inventorySeat.getAmountAllocated('Item', itemBrand); - - AmountMath.isEqual( - wantedCharacter, - inventoryCharacterKey, - characterBrand, - ) || assert.fail(errors.inventoryKeyMismatch); - - /** @type {TransferPart[]} */ - const transfers = []; - transfers.push([inventorySeat, seat, { Item: items }]); - transfers.push([ - seat, - inventorySeat, - { CharacterKey1: providedCharacterKeyAmount }, - { CharacterKey: providedCharacterKeyAmount }, - ]); - transfers.push([ - inventorySeat, - seat, - { CharacterKey: wantedCharacter }, - { CharacterKey2: wantedCharacter }, - ]); - - try { - atomicRearrange(zcf, harden(transfers)); - } catch (e) { - assert.fail(errors.rearrangeError); - } - seat.exit(); - - characterRecord.inventoryKit.recorder.write( - inventorySeat.getAmountAllocated('Item').value.payload, - ); - }; - - return zcf.makeInvitation( - handler, - 'removeAllItemsFromInventory', - undefined, - M.splitRecord({ - give: { - CharacterKey1: M.splitRecord(characterShape), - }, - want: { - CharacterKey2: M.splitRecord(characterShape), - }, - }), - ); - }, - }, - item: { - initializeBaseItems(baseItems) { - const { item: itemState } = this.state; - if (itemState.bases.getSize() > 0) return; - - const common = []; - const uncommonToLegendary = []; - - baseItems.forEach((item) => { - if (item.rarity < minUncommonRating) common.push(item); - else uncommonToLegendary.push(item); - }); - - addAllToMap(itemState.bases, [ - ['common', harden(common)], - ['uncommonToLegendary', harden(uncommonToLegendary)], - ]); - }, - // Mints the default set of items to a seat that doesn't exit - async mintDefaultBatch(seat) { - const { helper, market: marketFacet } = this.facets; - const { item: itemState } = this.state; - - let commonBases = itemState.bases.get('common'); - const index1 = Math.floor(helper.randomNumber() * commonBases.length); - const item1 = commonBases[index1]; - - commonBases = commonBases.filter( - (item) => item.category !== item1.category, - ); - const index2 = Math.floor(helper.randomNumber() * commonBases.length); - const item2 = commonBases[index2]; - - commonBases = commonBases.filter( - (item) => item.category !== item1.category, - ); - - const index3 = Math.floor(helper.randomNumber() * commonBases.length); - const item3 = commonBases[index3]; - - const uncommonToLegendary = itemState.bases - .get('uncommonToLegendary') - .filter( - (item) => - item.category !== item1.category && - item.category !== item2.category, - ); - const index4 = Math.floor( - helper.randomNumber() * uncommonToLegendary.length, - ); - const item4 = uncommonToLegendary[index4]; - - const items = [item1, item2, item3, item4]; - - const currentTime = await helper.getTimeStamp(); - - const newItemAmount = AmountMath.make( - itemBrand, - makeCopyBag(harden(items.map((item) => [item, 1n]))), - ); - - await itemMint.mintGains({ Item: newItemAmount }, seat); - - let id = itemState.entries.getSize(); - - items.forEach((i) => { - const item = { - id, - item: i, - history: [ - { - type: 'mint', - data: i, - timestamp: currentTime, - }, - ], - }; - - addAllToMap(itemState.entries, [[id, harden(item)]]); - itemKit.recorder.write(item); - - id += 1; - // update metrics - marketFacet.updateMetrics('item', { - collectionSize: true, - averageLevel: { - type: 'add', - value: item.item.level, - }, - }); - }); - - return text.mintItemReturn; - }, - /** - * - * @param {ZCFSeat} seat - * @param {[Item, bigint][]} itemBatch - * @returns {Promise} - */ - async mintBatch(seat, itemBatch) { - const { helper, market: marketFacet } = this.facets; - const { item: itemState } = this.state; - - const currentTime = await helper.getTimeStamp(); - - const newItemAmount = AmountMath.make( - itemBrand, - makeCopyBag(harden(itemBatch)), - ); - - await itemMint.mintGains({ Item: newItemAmount }, seat); - - let id = itemState.entries.getSize(); - - itemBatch.forEach((copyBagEntry) => { - const [itemAsset, itemSupply] = copyBagEntry; - - for (let n = 0; n < itemSupply; n += 1) { - const item = { - id, - item: itemAsset, - history: [ - { - type: 'mint', - data: itemAsset, - timestamp: currentTime, - }, - ], - }; - - addAllToMap(itemState.entries, [[id, harden(item)]]); - itemKit.recorder.write(item); - - id += 1; - // update metrics - marketFacet.updateMetrics('item', { - collectionSize: true, - averageLevel: { - type: 'add', - value: item.item.level, - }, - }); - } - }); - - return text.mintItemReturn; - }, - mint() { - const handler = async (seat) => { - const { helper, market: marketFacet } = this.facets; - const { item: itemState } = this.state; - - const { want } = seat.getProposal(); - - const currentTime = await helper.getTimeStamp(); - - const items = want.Item.value.payload.map(([item, supply]) => { - return [item, supply]; - }); - const newItemAmount = AmountMath.make( - itemBrand, - makeCopyBag(harden(items)), - ); - - itemMint.mintGains({ Asset: newItemAmount }, seat); - - seat.exit(); - - let id = itemState.entries.getSize(); - - items.forEach((j) => { - const i = j[0]; - const item = { - id, - item: i, - // Potentially have separate durable stores for the history - history: [ - { - type: 'mint', - data: i, - timestamp: currentTime, - }, - ], - }; - - addAllToMap(itemState.entries, [[id, harden(item)]]); - itemKit.recorder.write(item); - - id += 1; - // update metrics - marketFacet.updateMetrics('item', { - collectionSize: true, - averageLevel: { - type: 'add', - value: item.item.level, - }, - }); - }); - - return text.mintItemReturn; - }; - - return zcf.makeInvitation( - handler, - 'mintItemNfts', - undefined, - M.splitRecord({ - want: { - Item: M.splitRecord(itemShape), - }, - }), - ); - }, - }, - market: { - handleExitCharacter(entry) { - const { market } = this.state; - const { market: marketFacet, character: characterFacet } = - this.facets; - - const { seat, asset, recorderKit } = entry; - const characterLevel = characterFacet.calculateLevel(asset.name); - - const subscriber = E(seat).getSubscriber(); - void E.when(E(subscriber).getUpdateSince(), () => { - marketFacet.updateMetrics('character', { - marketplaceAverageLevel: { - type: 'remove', - value: characterLevel, - }, - }); - - market.characterEntries.delete(asset.name); - - void marketFacet.deleteNode(recorderKit.recorder.getStorageNode()); - }); - }, - handleExitItem(entry) { - const { market } = this.state; - const { market: marketFacet } = this.facets; - - const { seat, asset, id, recorderKit } = entry; - - const subscriber = E(seat).getSubscriber(); - E.when(E(subscriber).getUpdateSince(), () => { - marketFacet.updateMetrics('item', { - marketplaceAverageLevel: { - type: 'remove', - value: asset.level, - }, - }); - - market.itemEntries.delete(id); - void marketFacet.deleteNode(recorderKit.recorder.getStorageNode()); - }); - }, - /** - * @param {string} collection - * @param {UpdateMetrics} updateMetrics - * @returns {void} - */ - updateMetrics(collection, updateMetrics) { - const updatedMetrics = updateCollectionMetrics( - collection, - this.state, - updateMetrics, - ); - if (collection === 'character') { - void marketCharacterMetricsKit.recorder.write(updatedMetrics); - } else if (collection === 'item') { - void marketItemMetricsKit.recorder.write(updatedMetrics); - } - }, - async makeMarketItemRecorderKit(id) { - const path = `item-${String(id)}`; - const node = await E(marketItemNode).makeChildNode(path); - return makeRecorderKit(node, MarketRecorderGuard); - }, - async makeMarketCharacterRecorderKit(id) { - const path = `character-${id}`; - const node = await E(marketCharacterNode).makeChildNode(path); - return makeRecorderKit(node, MarketRecorderGuard); - }, - /** - * Caveat assumes parent is either `marketCharacterNode` or - * `marketItemNode` and only the latter has 'character' anywhere in its - * path. - * - * @param {StorageNode} node - */ - // STOPGAP until https://github.com/Agoric/agoric-sdk/issues/7405 is available in Mainnet - async deleteNode(node) { - const path = await E(node).getPath(); - const segments = path.split('.'); - const parent = path.includes('character') - ? marketCharacterNode - : marketItemNode; - const childSegment = segments.at(-1); - assert(childSegment, `missing child path segment in ${path}`); - const deletable = E(parent).makeChildNode(childSegment, { - sequence: false, - }); - await E(deletable).setValue(''); - }, - sellItem() { - const handler = async (seat) => { - const { market } = this.state; - const { market: marketFacet } = this.facets; - - // Inspect allocation of Character keyword in seller seat - const itemInSellSeat = seat.getAmountAllocated('Item'); - const { want } = seat.getProposal(); - - paymentBrand === want.Price.brand || - assert.fail(errors.incorrectPaymentBrand(paymentBrand)); - const askingPrice = { - brand: want.Price.brand, - value: want.Price.value, - }; - const royalty = multiplyBy(want.Price, royaltyRate); - const platformFee = multiplyBy(want.Price, platformFeeRate); - - const id = this.state.market.metrics.get('item').putForSaleCount; - - const entryRecorder = await marketFacet.makeMarketItemRecorderKit( - id, - ); - - const asset = itemInSellSeat.value.payload[0][0]; - // Add to store array - const newEntry = harden({ - seat, - askingPrice, - royalty, - platformFee, - id, - asset, - recorderKit: entryRecorder, - isFirstSale: false, - }); - - // update metrics - marketFacet.updateMetrics('item', { - marketplaceAverageLevel: { - type: 'add', - value: asset.level, - }, - }); - - addAllToMap(market.itemEntries, [[newEntry.id, newEntry]]); - - const { seat: _omitSeat, recorderKit, ...entry } = newEntry; - recorderKit.recorder.write(entry); - marketFacet.updateMetrics('item', { putForSaleCount: true }); - - marketFacet.handleExitItem(newEntry); - }; - - return zcf.makeInvitation( - handler, - 'Sell Item in KREAd marketplace', - undefined, - M.splitRecord({ - give: { - Item: M.splitRecord(itemShape), - }, - want: { - Price: M.splitRecord({ - brand: BrandShape, - value: M.nat(), - }), - }, - }), - ); - }, - sellCharacter() { - const handler = async (seat) => { - const { market } = this.state; - const { character: characterFacet, market: marketFacet } = - this.facets; - - // Inspect allocation of Character keyword in seller seat - const characterInSellSeat = seat.getAmountAllocated('Character'); - const { want } = seat.getProposal(); - - paymentBrand === want.Price.brand || - assert.fail(errors.incorrectPaymentBrand(paymentBrand)); - const askingPrice = { - brand: want.Price.brand, - value: want.Price.value, - }; - const royalty = multiplyBy(want.Price, royaltyRate); - const platformFee = multiplyBy(want.Price, platformFeeRate); - - const character = characterInSellSeat.value.payload[0][0]; - - const entryRecorder = - await marketFacet.makeMarketCharacterRecorderKit(character.name); - - // Add to store array - const newEntry = { - seat, - askingPrice, - royalty, - platformFee, - id: character.name, - asset: character, - recorderKit: entryRecorder, - isFirstSale: false, - }; - - // update metrics - const characterLevel = characterFacet.calculateLevel( - character.name, - ); - marketFacet.updateMetrics('character', { - marketplaceAverageLevel: { - type: 'add', - value: characterLevel, - }, - }); - - addAllToMap(market.characterEntries, [ - [newEntry.id, harden(newEntry)], - ]); - - const { seat: _omitSeat, recorderKit, ...entry } = newEntry; - recorderKit.recorder.write(entry); - marketFacet.updateMetrics('character', { putForSaleCount: true }); - - marketFacet.handleExitCharacter(newEntry); - }; - - return zcf.makeInvitation( - handler, - 'Sell Character in KREAd marketplace', - undefined, - M.splitRecord({ - give: { - Character: M.splitRecord(characterShape), - }, - want: { - Price: M.splitRecord({ - brand: BrandShape, - value: M.nat(), - }), - }, - }), - ); - }, - buyItem() { - const handler = async (buyerSeat, offerArgs) => { - const { market: marketFacet } = this.facets; - const { market } = this.state; - - // Find store record based on wanted character - const sellRecord = market.itemEntries.get(offerArgs.entryId); - sellRecord || - assert.fail(errors.itemNotFound(offerArgs.entryId)); - - const result = await (sellRecord.isFirstSale - ? marketFacet.buyFirstSaleItem( - sellRecord.seat, - buyerSeat, - sellRecord, - ) - : marketFacet.buySecondarySaleItem( - sellRecord.seat, - buyerSeat, - sellRecord, - )); - result.success || assert.fail(result.error); - }; - - return zcf.makeInvitation( - handler, - 'Buy Item in KREAd marketplace', - undefined, - M.splitRecord({ - give: { - Price: M.splitRecord({ - brand: BrandShape, - value: M.nat(), - }), - }, - want: { - Item: M.splitRecord(itemShape), - }, - }), - ); - }, - /** - * - * @param {ZCFSeat} sellerSeat - * @param {ZCFSeat} buyerSeat - * @param {ItemMarketRecord} sellRecord - * @returns {Promise} - */ - async buyFirstSaleItem(sellerSeat, buyerSeat, sellRecord) { - const { market: marketFacet } = this.facets; - const { market } = this.state; - - const { want, give } = buyerSeat.getProposal(); - const { Item: wantedItemAmount } = want; - - const itemForSaleAmount = harden({ - brand: itemBrand, - value: makeCopyBag([[sellRecord.asset, 1n]]), - }); - const itemForSalePrice = sellRecord.askingPrice; - // Inspect Price keyword from buyer seat - const { Price: providedMoneyAmount } = give; - - if ( - !AmountMath.isEqual(wantedItemAmount, itemForSaleAmount, itemBrand) - ) { - return { - success: false, - error: errors.sellerSeatMismatch, - }; - } - - if ( - !AmountMath.isGTE( - providedMoneyAmount, - AmountMath.add( - AmountMath.add(sellRecord.askingPrice, sellRecord.royalty), - sellRecord.platformFee, - ), - paymentBrand, - ) - ) { - return { - success: false, - error: errors.insufficientFunds, - }; - } - - const { zcfSeat, userSeat } = zcf.makeEmptySeatKit(); - - /** @type {TransferPart[]} */ - const transfers = []; - // Transfer item: seller -> buyer - transfers.push([sellerSeat, buyerSeat, { Item: itemForSaleAmount }]); - // Transfer artist royalty: buyer -> artist - transfers.push([ - buyerSeat, - zcfSeat, - { Price: sellRecord.royalty }, - { Royalty: sellRecord.royalty }, - ]); - // Transfer KREAd fees: buyer -> KREAd - transfers.push([ - buyerSeat, - zcfSeat, - { Price: sellRecord.platformFee }, - { PlatformFee: sellRecord.platformFee }, - ]); - - // Transfer askingPrice: buyer -> artist - transfers.push([ - buyerSeat, - zcfSeat, - { - Price: AmountMath.subtract( - providedMoneyAmount, - AmountMath.add(sellRecord.royalty, sellRecord.platformFee), - ), - }, - ]); - - try { - atomicRearrange(zcf, harden(transfers)); - } catch (e) { - assert.fail(errors.rearrangeError); - } - buyerSeat.exit(); - zcfSeat.exit(); - - const payouts = await E(userSeat).getPayouts(); - const royaltyPayout = await payouts.Royalty; - const platformFeePayout = await payouts.PlatformFee; - - await E(royaltyDepositFacet).receive(royaltyPayout); - await E(platformFeeDepositFacet).receive(platformFeePayout); - - const askingPricePayout = await payouts.Price; - await E(royaltyDepositFacet).receive(askingPricePayout); - - // Remove entry from market - marketFacet.updateMetrics('item', { - marketplaceAverageLevel: { - type: 'remove', - value: sellRecord.asset.level, - }, - }); - - market.itemEntries.delete(sellRecord.id); - void marketFacet.deleteNode( - sellRecord.recorderKit.recorder.getStorageNode(), - ); - - // update metrics - marketFacet.updateMetrics('item', { - amountSold: true, - latestSalePrice: Number(itemForSalePrice.value), - }); - return { - success: true, - error: '', - }; - }, - /** - * - * @param {ZCFSeat} sellerSeat - * @param {ZCFSeat} buyerSeat - * @param {ItemMarketRecord} sellRecord - * @returns {Promise} - */ - async buySecondarySaleItem(sellerSeat, buyerSeat, sellRecord) { - const { market: marketFacet } = this.facets; - - const { want, give } = buyerSeat.getProposal(); - const { Item: wantedItemAmount } = want; - - const itemForSaleAmount = sellerSeat.getProposal().give.Item; - const itemForSalePrice = sellerSeat.getProposal().want.Price; - - // Inspect Price keyword from buyer seat - const { Price: providedMoneyAmount } = give; - - if ( - !AmountMath.isEqual(wantedItemAmount, itemForSaleAmount, itemBrand) - ) { - return { - success: false, - error: errors.sellerSeatMismatch, - }; - } - - if ( - !AmountMath.isGTE( - providedMoneyAmount, - AmountMath.add( - AmountMath.add(sellRecord.askingPrice, sellRecord.royalty), - sellRecord.platformFee, - ), - paymentBrand, - ) - ) { - return { - success: false, - error: errors.insufficientFunds, - }; - } - - const { zcfSeat, userSeat } = zcf.makeEmptySeatKit(); - - /** @type {TransferPart[]} */ - const transfers = []; - // Transfer item: seller -> buyer - transfers.push([sellerSeat, buyerSeat, { Item: itemForSaleAmount }]); - // Transfer artist royalty: buyer -> artist - transfers.push([ - buyerSeat, - zcfSeat, - { Price: sellRecord.royalty }, - { Royalty: sellRecord.royalty }, - ]); - // Transfer KREAd fees: buyer -> KREAd - transfers.push([ - buyerSeat, - zcfSeat, - { Price: sellRecord.platformFee }, - { PlatformFee: sellRecord.platformFee }, - ]); - - // Transfer askingPrice: buyer -> seller - transfers.push([ - buyerSeat, - sellerSeat, - { - Price: AmountMath.subtract( - providedMoneyAmount, - AmountMath.add(sellRecord.royalty, sellRecord.platformFee), - ), - }, - ]); - - try { - atomicRearrange(zcf, harden(transfers)); - } catch (e) { - assert.fail(errors.rearrangeError); - } - - buyerSeat.exit(); - sellerSeat.exit(); - zcfSeat.exit(); - - const payouts = await E(userSeat).getPayouts(); - const royaltyPayout = await payouts.Royalty; - const platformFeePayout = await payouts.PlatformFee; - - await E(royaltyDepositFacet).receive(royaltyPayout); - await E(platformFeeDepositFacet).receive(platformFeePayout); - - // update metrics - marketFacet.updateMetrics('item', { - amountSold: true, - latestSalePrice: Number(itemForSalePrice.value), - }); - return { - success: true, - error: '', - }; - }, - buyCharacter() { - const handler = async (buyerSeat) => { - const { market: marketFacet } = this.facets; - const { market, character: characterState } = this.state; - - // Inspect Character keyword in buyer seat - const { want, give } = buyerSeat.getProposal(); - const { Character: wantedCharacterAmount } = want; - const character = wantedCharacterAmount.value.payload[0][0]; - - // Find characterRecord entry based on wanted character - const characterRecord = characterState.entries.get(character.name); - characterRecord || assert.fail(errors.character404); - - // Find store record based on wanted character - const sellRecord = market.characterEntries.get(character.name); - - sellRecord || assert.fail(errors.character404); - const sellerSeat = sellRecord.seat; - - // Inspect Price keyword from buyer seat - const { Price: providedMoneyAmount } = give; - const { Character: characterForSaleAmount } = - sellerSeat.getProposal().give; - - AmountMath.isEqual( - wantedCharacterAmount, - characterForSaleAmount, - characterBrand, - ) || assert.fail(errors.sellerSeatMismatch); - - const characterForSalePrice = sellRecord.askingPrice; - - AmountMath.isGTE( - providedMoneyAmount, - AmountMath.add( - AmountMath.add(sellRecord.askingPrice, sellRecord.royalty), - sellRecord.platformFee, - ), - paymentBrand, - ) || assert.fail(errors.insufficientFunds); - const { zcfSeat, userSeat } = zcf.makeEmptySeatKit(); - - /** @type {TransferPart[]} */ - const transfers = []; - transfers.push([ - sellerSeat, - buyerSeat, - { Character: characterForSaleAmount }, - ]); - transfers.push([ - buyerSeat, - zcfSeat, - { Price: sellRecord.royalty }, - { Royalty: sellRecord.royalty }, - ]); - transfers.push([ - buyerSeat, - zcfSeat, - { Price: sellRecord.platformFee }, - { PlatformFee: sellRecord.platformFee }, - ]); - transfers.push([ - buyerSeat, - sellerSeat, - { - Price: AmountMath.subtract( - providedMoneyAmount, - AmountMath.add(sellRecord.royalty, sellRecord.platformFee), - ), - }, - ]); - - try { - atomicRearrange(zcf, harden(transfers)); - } catch (e) { - assert.fail(errors.rearrangeError); - } - zcfSeat.exit(); - - const payouts = await E(userSeat).getPayouts(); - const royaltyPayout = await payouts.Royalty; - const platformFeePayout = await payouts.PlatformFee; - - await E(royaltyDepositFacet).receive(royaltyPayout); - await E(platformFeeDepositFacet).receive(platformFeePayout); - - // update metrics - marketFacet.updateMetrics('character', { - amountSold: true, - latestSalePrice: Number(characterForSalePrice.value), - }); - - buyerSeat.exit(); - sellerSeat.exit(); - }; - - return zcf.makeInvitation( - handler, - 'Buy Character in KREAd marketplace', - undefined, - M.splitRecord({ - give: { - Price: M.splitRecord({ - brand: BrandShape, - value: M.nat(), - }), - }, - want: { - Character: M.splitRecord(characterShape), - }, - }), - ); - }, - }, - creator: { - makeMintItemInvitation() { - const { item } = this.facets; - return item.mint(); - }, - initializeMetrics() { - const { market } = this.state; - if (market.metrics.getSize() > 0) return; - - addAllToMap( - market.metrics, - ['character', 'item'].map((key) => [ - key, - harden({ - collectionSize: 0, - averageLevel: 0, - marketplaceAverageLevel: 0, - amountSold: 0, - latestSalePrice: 0, - putForSaleCount: 0, - }), - ]), - ); - - marketCharacterMetricsKit.recorder.write( - market.metrics.get('character'), - ); - marketItemMetricsKit.recorder.write(market.metrics.get('item')); - }, - reviveMarketExitSubscribers() { - const { market } = this.state; - const { market: marketFacet } = this.facets; - - const characters = Array.from(market.characterEntries.values()); - characters.forEach((entry) => marketFacet.handleExitCharacter(entry)); - - const items = Array.from(market.itemEntries.values()); - items.forEach((entry) => marketFacet.handleExitItem(entry)); - }, - initializeBaseAssets(baseCharacters, baseItems) { - const { character, item } = this.facets; - character.initializeBaseCharacters(baseCharacters); - item.initializeBaseItems(baseItems); - }, - initializeCharacterNamesEntries() { - const { character } = this.state; - if (!character.entries.has('names')) { - character.entries.init('names', harden([])); - } - }, - /** - * - * @param {Amount} price - * @param {[Item, bigint][]} itemsToSell - */ - async publishItemCollection(price, itemsToSell) { - const { market } = this.state; - const { market: marketFacet, item } = this.facets; - - const { zcfSeat: internalSellSeat } = zcf.makeEmptySeatKit(); - await item.mintBatch(internalSellSeat, itemsToSell); - - const askingPrice = { - brand: price.brand, - value: price.value, - }; - const royalty = multiplyBy(price, royaltyRate); - const platformFee = multiplyBy(price, platformFeeRate); - const claimedIdAndRecorder = await Promise.all( - itemsToSell.map(async (copyBagEntry) => { - const [_, itemSupply] = copyBagEntry; - const supplyRange = Array.from(Array(Number(itemSupply)).keys()); - const idAndRecorder = await Promise.all( - supplyRange.map(async () => { - // putForSaleCount is incremented by updateMetrics() with each iteration of this loop - const id = - this.state.market.metrics.get('item').putForSaleCount; - await marketFacet.updateMetrics('item', { - putForSaleCount: true, - }); - const entryRecorder = - await marketFacet.makeMarketItemRecorderKit(id); - return [id, entryRecorder]; - }), - ); - return idAndRecorder; - }), - ); - - itemsToSell.forEach(async (copyBagEntry, i) => { - const [itemAsset, itemSupply] = copyBagEntry; - - for (let n = 0; n < itemSupply; n += 1) { - const [id, entryRecorder] = claimedIdAndRecorder[i][n]; - // Add to store array - const newEntry = { - seat: internalSellSeat, - askingPrice, - royalty, - platformFee, - id, - asset: itemAsset, - recorderKit: entryRecorder, - isFirstSale: true, - }; - - // update metrics - marketFacet.updateMetrics('item', { - marketplaceAverageLevel: { - type: 'add', - value: itemAsset.level, - }, - }); - - addAllToMap(market.itemEntries, [ - [newEntry.id, harden(newEntry)], - ]); - const { seat: _omitSeat, recorderKit, ...entry } = newEntry; - recorderKit.recorder.write(entry); - } - }); - }, - }, - public: { - makeMintCharacterInvitation() { - const { character } = this.facets; - return character.mint(); - }, - getCharacters() { - const characters = Array.from( - this.state.character.entries.values(), - ).filter((x) => !Array.isArray(x)); - return characters; - }, - getCharacterInventory(name) { - const character = this.state.character.entries.get(name); - const { inventory } = character; - const items = inventory.getAmountAllocated('Item', itemBrand).value - .payload; - return { items }; - }, - makeEquipInvitation() { - const { character } = this.facets; - return character.equip(); - }, - makeUnequipInvitation() { - const { character } = this.facets; - return character.unequip(); - }, - makeItemSwapInvitation() { - const { character } = this.facets; - return character.swap(); - }, - makeUnequipAllInvitation() { - const { character } = this.facets; - return character.unequipAll(); - }, - makeSellCharacterInvitation() { - const { market } = this.facets; - return market.sellCharacter(); - }, - makeBuyCharacterInvitation() { - const { market } = this.facets; - return market.buyCharacter(); - }, - getCharactersForSale() { - const characters = Array.from( - this.state.market.characterEntries.values(), - ); - return characters; - }, - makeSellItemInvitation() { - const { market } = this.facets; - return market.sellItem(); - }, - makeBuyItemInvitation() { - const { market } = this.facets; - return market.buyItem(); - }, - getItemsForSale() { - const items = Array.from(this.state.market.itemEntries.values()); - return items; - }, - getMarketMetrics() { - const { market } = this.state; - return { - character: market.metrics.get('character'), - item: market.metrics.get('item'), - }; - }, - getCharacterLevel(name) { - const { character } = this.facets; - return character.calculateLevel(name); - }, - }, - }, - ); -}; - -harden(prepareKreadKit); - -/** - * - * @param {import('@agoric/vat-data').Baggage} baggage - * @param {StorageNode} storageNode - * @param {import('@agoric/zoe/src/contractSupport/recorder.js').MakeRecorderKit} makeRecorderKit - * @returns - */ -export const provideKreadKitRecorderKits = ( - baggage, - storageNode, - makeRecorderKit, -) => - provideRecorderKits( - baggage, - storageNode, - makeRecorderKit, - { - infoKit: 'info', - characterKit: 'character', - itemKit: 'item', - marketCharacterKit: 'market-characters', - marketItemKit: 'market-items', - marketCharacterMetricsKit: 'market-metrics-character', - marketItemMetricsKit: 'market-metrics-item', - }, - { - characterKit: CharacterRecorderGuard, - itemKit: ItemRecorderGuard, - marketCharacterKit: M.arrayOf(MarketRecorderGuard), - marketItemKit: M.arrayOf(MarketRecorderGuard), - marketCharacterMetricsKit: MarketMetricsGuard, - marketItemMetricsKit: MarketMetricsGuard, - }, - ); diff --git a/agoric/contract/src/kreadV2/market-metrics.js b/agoric/contract/src/kreadV2/market-metrics.js deleted file mode 100644 index b79f34693..000000000 --- a/agoric/contract/src/kreadV2/market-metrics.js +++ /dev/null @@ -1,77 +0,0 @@ -/** - * adds a value to the average - * - * @param {number} average - * @param {number} size - * @param {number} value - * @returns {number} - */ -function addToAverage(average, size, value) { - return (average * size + value) / (size + 1); -} - -/** - * Removes a value from the average - * - * @param {number} average - * @param {number} size - * @param {number} value - * @returns {number} - */ -function removeFromAverage(average, size, value) { - if (size === 1) { - return 0; - } - return (size * average - value) / (size - 1); -} - -/** - * Updates an average based on add or remove - * - * @param {string} type - * @param {number} average - * @param {number} size - * @param {number} value - */ -function updateAverage(type, average, size, value) { - if (type === 'add') { - return addToAverage(average, size, value); - } else if (type === 'remove') { - return removeFromAverage(average, size, value); - } -} - -/** - * Updates character metrics - * - * @param {string} collection - * @param {object} state - * @param {UpdateMetrics} updateMetrics - */ -export const updateCollectionMetrics = (collection, state, updateMetrics) => { - const metrics = { ...state.market.metrics.get(collection) }; - if (updateMetrics.averageLevel) { - metrics.averageLevel = updateAverage( - updateMetrics.averageLevel.type, - metrics.averageLevel, - metrics.collectionSize, - updateMetrics.averageLevel.value, - ); - } - if (updateMetrics.marketplaceAverageLevel) { - metrics.marketplaceAverageLevel = updateAverage( - updateMetrics.marketplaceAverageLevel.type, - metrics.marketplaceAverageLevel, - state.market[`${collection}Entries`].getSize(), - updateMetrics.marketplaceAverageLevel.value, - ); - } - if (updateMetrics.latestSalePrice) - metrics.latestSalePrice = updateMetrics.latestSalePrice; - if (updateMetrics.collectionSize) metrics.collectionSize += 1; - if (updateMetrics.amountSold) metrics.amountSold += 1; - if (updateMetrics.putForSaleCount) metrics.putForSaleCount += 1; - - state.market.metrics.set(collection, metrics); - return metrics; -}; diff --git a/agoric/contract/src/kreadV2/text.js b/agoric/contract/src/kreadV2/text.js deleted file mode 100644 index 686a6d290..000000000 --- a/agoric/contract/src/kreadV2/text.js +++ /dev/null @@ -1,7 +0,0 @@ -export const text = { - mintCharacterReturn: 'Character NFT minted successfully!', - mintItemReturn: 'Item NFT(s) minted successfully!', - tokenFacetReturn: 'Success', - equipReturn: 'Item(s) were equipped successfully', - unequipReturn: 'Item(s) were unequipped successfully', -}; diff --git a/agoric/contract/src/kreadV2/type-guards.js b/agoric/contract/src/kreadV2/type-guards.js deleted file mode 100644 index 62cf989ad..000000000 --- a/agoric/contract/src/kreadV2/type-guards.js +++ /dev/null @@ -1,248 +0,0 @@ -import { M } from '@agoric/store'; -import { BrandShape } from '@agoric/ertp'; - -export const HelperI = M.interface( - 'helper', - {}, - // not exposed so sloppy okay - { sloppy: true }, -); - -export const BaseCharacterGuard = M.splitRecord({ - title: M.string(), - description: M.string(), - origin: M.string(), - level: M.gte(0), - artistMetadata: M.string(), - image: M.string(), - characterTraits: M.string(), -}); - -export const CharacterGuard = M.splitRecord({ - title: M.string(), - description: M.string(), - origin: M.string(), - level: M.gte(0), - artistMetadata: M.string(), - image: M.string(), - characterTraits: M.string(), - name: M.string({ stringLengthLimit: 20 }), - keyId: M.number(), - id: M.gte(0), - date: M.record(), -}); - -export const RatioObject = { - numerator: M.nat(), - denominator: M.nat(), -}; - -export const CharacterGuardBagShape = M.bagOf(CharacterGuard); - -export const ItemGuard = M.splitRecord({ - name: M.string(), - category: M.or( - 'hair', - 'headPiece', - 'mask', - 'filter1', - 'filter2', - 'perk1', - 'perk2', - 'garment', - 'patch', - 'background', - ), - description: M.string(), - functional: M.boolean(), - origin: M.string(), - image: M.string(), - thumbnail: M.string(), - rarity: M.gte(0), - level: M.gte(0), - filtering: M.gte(0), - weight: M.gte(0), - sense: M.gte(0), - reserves: M.gte(0), - durability: M.gte(0), - colors: M.arrayOf(M.string()), - artistMetadata: M.string(), -}); - -export const RarityGuard = M.or('common', 'uncommonToLegendary'); - -export const ItemGuardBagShape = M.bagOf(ItemGuard); - -export const MarketMetricsGuard = M.splitRecord({ - amountSold: M.gte(0), - collectionSize: M.gte(0), - averageLevel: M.gte(0), - marketplaceAverageLevel: M.gte(0), - latestSalePrice: M.gte(0), - putForSaleCount: M.gte(0), -}); - -export const UpdateMarketMetricsGuard = M.splitRecord( - {}, - { - amountSold: M.boolean(), - collectionSize: M.boolean(), - averageLevel: M.splitRecord({ - type: M.or('add', 'remove'), - value: M.gte(0), - }), - marketplaceAverageLevel: M.splitRecord({ - type: M.or('add', 'remove'), - value: M.gte(0), - }), - latestSalePrice: M.gte(0), - putForSaleCount: M.boolean(), - }, -); - -export const PublicI = M.interface('public', { - // Mint - makeMintCharacterInvitation: M.call().returns(M.promise()), - // Inventory - makeEquipInvitation: M.call().returns(M.promise()), - makeUnequipInvitation: M.call().returns(M.promise()), - makeUnequipAllInvitation: M.call().returns(M.promise()), - makeItemSwapInvitation: M.call().returns(M.promise()), - // Market - makeSellCharacterInvitation: M.call().returns(M.promise()), - makeBuyCharacterInvitation: M.call().returns(M.promise()), - makeSellItemInvitation: M.call().returns(M.promise()), - makeBuyItemInvitation: M.call().returns(M.promise()), - // Getters - getCharacters: M.call().returns(M.array()), - getCharacterInventory: M.call().returns(M.splitRecord({ items: M.array() })), - getCharactersForSale: M.call().returns(M.array()), - getItemsForSale: M.call().returns(M.array()), - getMarketMetrics: M.call().returns(M.record()), - getCharacterLevel: M.call(M.string()).returns(M.gte(0)), -}); - -export const CreatorI = M.interface('creator', { - makeMintItemInvitation: M.call().returns(M.promise()), - initializeMetrics: M.call().returns(), - reviveMarketExitSubscribers: M.call().returns(), - initializeBaseAssets: M.call( - M.arrayOf([M.number(), BaseCharacterGuard]), - M.arrayOf(ItemGuard), - ).returns(), - initializeCharacterNamesEntries: M.call().returns(), - publishItemCollection: M.call().returns(M.promise()), -}); - -export const CharacterI = M.interface('character', { - mint: M.call().returns(M.promise()), - equip: M.call().returns(M.promise()), - unequip: M.call().returns(M.promise()), - unequipAll: M.call().returns(M.promise()), - swap: M.call().returns(M.promise()), - validateInventoryState: M.call().returns(M.boolean()), - isNameUnique: M.call(M.string()).returns(M.boolean()), - getRandomBaseIndex: M.call().returns(M.any()), - calculateLevel: M.call(M.string()).returns(M.gte(0)), - makeInventoryRecorderKit: M.call(M.string()).returns( - M.promise(M.remotable('Notifier')), - ), - initializeBaseCharacters: M.call( - M.arrayOf([M.number(), BaseCharacterGuard]), - ).returns(), -}); - -export const ItemI = M.interface('item', { - mint: M.call().returns(M.promise()), - mintDefaultBatch: M.call().returns(M.promise(M.string())), - mintBatch: M.call().returns(M.promise(M.string())), - initializeBaseItems: M.call(M.arrayOf(ItemGuard)).returns(), -}); - -export const MarketRecorderGuard = M.or( - M.splitRecord({ - id: M.or(M.gte(0), M.string()), - askingPrice: M.splitRecord({ - brand: BrandShape, - value: M.nat(), - }), - royalty: M.splitRecord({ - brand: BrandShape, - value: M.nat(), - }), - platformFee: M.splitRecord({ - brand: BrandShape, - value: M.nat(), - }), - asset: M.or(CharacterGuard, ItemGuard), - isFirstSale: M.boolean(), - // history: M.arrayOf(HistoryGuard), - }), - M.string(''), -); - -export const MarketEntryGuard = M.splitRecord({ - id: M.or(M.gte(0), M.string()), - seat: M.eref(M.remotable('Seat')), - recorderKit: M.record(), // TODO: figure out how to type recorderkits - askingPrice: M.splitRecord({ - brand: BrandShape, - value: M.nat(), - }), - royalty: M.splitRecord({ - brand: BrandShape, - value: M.nat(), - }), - platformFee: M.splitRecord({ - brand: BrandShape, - value: M.nat(), - }), - asset: M.or(CharacterGuard, ItemGuard), - isFirstSale: M.boolean(), - // history: M.arrayOf(HistoryGuard), -}); - -export const MarketI = M.interface('market', { - sellItem: M.call().returns(M.promise()), - buyItem: M.call().returns(M.promise()), - buyFirstSaleItem: M.call().returns(M.promise()), - buySecondarySaleItem: M.call().returns(M.promise()), - handleExitItem: M.call(MarketEntryGuard).returns(), - handleExitCharacter: M.call(MarketEntryGuard).returns(), - makeMarketItemRecorderKit: M.call(M.number()).returns(M.promise()), - makeMarketCharacterRecorderKit: M.call(M.string()).returns(M.promise()), - deleteNode: M.call(M.remotable('StorageNode')).returns(M.promise(/* void */)), - sellCharacter: M.call().returns(M.promise()), - buyCharacter: M.call().returns(M.promise()), - updateMetrics: M.call( - M.or('character', 'item'), - UpdateMarketMetricsGuard, - ).returns(), -}); - -export const HistoryGuard = M.splitRecord({ - type: M.string(), - data: M.any(), - timestamp: M.record(), -}); - -export const CharacterEntryGuard = M.splitRecord({ - name: M.string(), - character: CharacterGuard, - inventory: M.eref(M.remotable('Seat')), - inventoryKit: M.record(), // TODO: figure out how to type recorderkits - history: M.arrayOf(HistoryGuard), -}); - -export const CharacterRecorderGuard = M.splitRecord({ - name: M.string(), - character: CharacterGuard, - inventoryKit: M.record(), // TODO: figure out how to type recorderkits - history: M.arrayOf(HistoryGuard), -}); - -export const ItemRecorderGuard = M.splitRecord({ - id: M.gte(0), - item: ItemGuard, - history: M.arrayOf(HistoryGuard), -}); diff --git a/agoric/contract/src/kreadV2/types.js b/agoric/contract/src/kreadV2/types.js deleted file mode 100644 index f39049a7f..000000000 --- a/agoric/contract/src/kreadV2/types.js +++ /dev/null @@ -1,295 +0,0 @@ -// @ts-check - -/** - * @typedef {{ - * mintFee: bigint, - * royaltyRate: RatioObject, - * platformFeeRate: RatioObject, - * mintRoyaltyRate: RatioObject, - * mintPlatformFeeRate: RatioObject, - * royaltyDepositFacet: DepositFacet, - * platformFeeDepositFacet: DepositFacet, - * assetNames: { character: string, item: string }, - * minUncommonRating: number - * }} KREAdTerms - */ - -/** - * Holds contract data - * - * @typedef {{ - * config: Config - * assetMints: AssetMints - * tokenInfo: TokenInfo - * notifiers: Notifiers - * characters: CharacterRecord[] - * items: ItemRecord[] - * randomNumber?: Function - * market: Market - * ready: boolean - * boardId?: string - * }} State - * - * Assets - * @typedef {{ - * character: ZCFMint<"copyBag"> - * item: ZCFMint<"copyBag"> - * }} AssetMints - * - * @typedef {{ - * character: CharacterMarketRecord[] - * item: ItemMarketRecord[] - * }} Market - * - * @typedef {{ - * character: { - * name: string - * brand: Brand - * issuer: Issuer<'set'> - * } - * item: { - * name: string - * brand: Brand - * issuer: Issuer<'set'> - * } - * }} TokenInfo - * - * @typedef {{ - * sellerSeat: ZCFSeat - * name: string - * character: object[] - * askingPrice: any - * }} CharacterMarketRecord - * - * @typedef {{ - * sellerSeat: ZCFSeat - * id: string - * asset: object[] - * askingPrice: any - * isFirstSale: boolean - * royalty: Amount - * platformFee: Amount - * recorderKit: import("./utils.js").RecorderKit - * }} ItemMarketRecord - * - * @typedef {{ - * storageNode: StorageNode - * marshaller: Marshaller - * }} Powers - * - * @typedef {{ - * tokenData: { - * characters: object[] - * items: object[] - * } - * defaultPaymentToken?: { - * brand: Brand<"nat"> - * issuer: Issuer<"nat"> - * } - * timerService: import('@agoric/time/src/types').TimerService - * powers: Powers - * }} Config - * - * @typedef {{ - * market: { - * characters: { - * subscriber: StoredSubscriber - * publisher: Publisher - * } - * items: { - * subscriber: StoredSubscriber - * publisher: Publisher - * } - * } - * inventory: { - * subscriber: StoredSubscriber - * publisher: Publisher - * } - * info: { - * subscriber: StoredSubscriber - * publisher: Publisher - * } - * }} Notifiers - * - * @typedef {{ - * name: string - * character: object - * inventory: ZCFSeat - * seat?: ZCFSeat - * notifier?: Notifier - * publisher: Publisher - * }} CharacterRecord - * - * @typedef {{ - * noseline?: Item; - * midBackground?: Item; - * mask?: Item; - * headPiece?: Item; - * hair?: Item; - * frontMask?: Item; - * liquid?: Item; - * background?: Item; - * airReservoir?: Item; - * clothing?: Item; - * }} DefaultItem - * - * @typedef {{ - * id: bigint - * character: object - * inventory: ZCFSeat - * seat?: ZCFSeat - * sell: { - * instance: Instance - * publicFacet: any - * price: bigint - * } - * }} CharacterInMarket - * - * @typedef {{ - * name: string; - * category: string; - * id: string; - * description: string; - * image: string; - * level: number; - * rarity: number; - * effectiveness?: number; - * layerComplexity?: number; - * forged: string; - * baseMaterial: string; - * colors: string[]; - * projectDescription: string; - * price: number; - * details: any; - * date: string; - * activity: any[]; - * }} Item - * - * @typedef {{ - * id: bigint - * item: object - * }} ItemRecord - * - * @typedef {{ - * id: bigint - * item: Item - * sell: { - * instance: Instance - * publicFacet: any - * price: bigint - * } - * }} ItemInMarket - * - * // PRIVATE STORAGE - * @typedef {{ - * id: bigint; - * add?: string[]; - * remove?: string[]; - * }} InventoryEvent - * - * @typedef {{ - * seat?: ZCFSeat; - * name: string; - * history: InventoryEvent[]; - * }} InventoryKeyRecord - * - * @typedef {InventoryKeyRecord[]} InventoryKeyStorage - * - * - * @typedef {{ - * isReady: () => boolean - * isConfigReady: () => boolean - * inventory: (name: string) => { items: Item[] } - * inventoryPublisher: (name: string) => Publisher - * characterKey: (name: string) => { key: Amount } - * characterCount: () => number - * itemCount: () => number - * character: (name: string) => CharacterRecord - * time: () => Promise - * randomBaseCharacter: () => object - * assetInfo: () => TokenInfo - * defaultItems: () => any[] - * powers: () => Powers - * config: () => Config - * randomItem: () => object - * marketPublisher: () => { - * characters: { - * subscriber: StoredSubscriber - * publisher: Publisher - * } - * items: { - * subscriber: StoredSubscriber - * publisher: Publisher - * } - * } - * }} KreadState_get - * - * @typedef {{ - * powers: (powers: Powers, notifiers: Notifiers) => void - * publishKreadInfo: (boardId: string, publicFacet: object) => void - * }} KreadState_set - * - * @typedef {{ - * characters: (characters: CharacterRecord[]) => void - * items: (items: ItemRecord[]) => void - * updateConfig: (newConfig: Config) => void - * }} KreadState_add - * - * @typedef {{ nameIsUnique: NameIsUniqueFn }} KreadState_validate - * - * @typedef {{ - * isReady: () => boolean - * isValidName: () => boolean - * getInventory: (name: string) => { items: Item[] } - * getCharacterKey: (name: string) => { key: Amount } - * getCount: () => { characters: bigint, items: bigint } - * getCharacter: (name: string) => CharacterRecord - * getTime: () => Promise - * getRandomBaseCharacter: () => object - * getTokenInfo: () => TokenInfo - * getDefaultItems: () => any[] - * getPowers: () => Powers | undefined - * getConfig: () => Config - * getRandomItem: () => object - * getCharacterCount: () => number - * getItemCount: () => number - * getCharacterMarket: () => CharacterMarketRecord[] - * getCharacterMarketRange: () => CharacterMarketRecord[] - * getItemMarket: () => ItemMarketRecord[] - * getItemMarketRange: () => ItemMarketRecord[] - * }} KreadState_public - * - * @typedef {{ - * get: KreadState_get - * set: KreadState_set - * add: KreadState_add - * validate: KreadState_validate - * public: KreadState_public - * }} KreadState - * - * @typedef {(name: string) => boolean} NameIsUniqueFn - * - * @typedef {Partial<{ - * averageLevel: UpdateAverage - * marketplaceAverageLevel: UpdateAverage - * latestSalePrice: number - * collectionSize: boolean - * amountSold: boolean, - * putForSaleCount: boolean - * }>} UpdateMetrics - * - * @typedef {{ - * type: ("add" | "remove") - * value: number - * }} UpdateAverage - * - * @typedef {{ - * numerator: bigint, - * denominator: bigint, - * }} RatioObject - * - * @typedef {{ - * success: boolean, - * error: string, - * }} HelperFunctionReturn - */ diff --git a/agoric/contract/src/kreadV2/utils.js b/agoric/contract/src/kreadV2/utils.js deleted file mode 100644 index 39fe4f110..000000000 --- a/agoric/contract/src/kreadV2/utils.js +++ /dev/null @@ -1,109 +0,0 @@ -// @ts-check -import { allValues, objectMap } from '@agoric/internal'; -import { E } from '@endo/eventual-send'; -import { M, matches, getCopyMapEntries } from '@endo/patterns'; - -const { Fail } = assert; - -/** - * @param {string} name - * @param {object} randomCharacterBase - * @param {number} newCharacterId - * @param {object} currentTime - * @returns {object[]} - */ -export const makeCharacterNftObjs = ( - name, - randomCharacterBase, - newCharacterId, - currentTime, -) => { - // Merge random base character with name input, id, and keyId - const newCharacter1 = { - ...randomCharacterBase, - date: currentTime, - id: newCharacterId, - name, - keyId: 1, - }; - const newCharacter2 = { - ...newCharacter1, - keyId: 2, - }; - return [newCharacter1, newCharacter2]; -}; - -/** - * @param {import('@agoric/vat-data').Baggage} baggage - * @param {ERef} storageNode - * @param {import('@agoric/zoe/src/contractSupport').MakeRecorderKit} makeRecorderKit - * @param {{[key: string]: string}} paths - * @param {{[key: string]: Pattern}} typeMatchers - * @returns {Promise<{[key: string]: import('@agoric/zoe/src/contractSupport').RecorderKit}>} - */ -export const provideRecorderKits = async ( - baggage, - storageNode, - makeRecorderKit, - paths, - typeMatchers, -) => { - // console.log('provideRecorderKits', paths, typeMatchers); - const keys = Object.keys(paths); - // assume if any keys are defined they all are - const inBaggage = baggage.has(keys[0]); - if (inBaggage) { - const obj = objectMap( - paths, - /** @type {(value: any, key: string) => any} */ - (_, k) => baggage.get(k), - ); - return Promise.resolve(harden(obj)); - } - - const keyedPromises = objectMap(paths, async (_path, key) => { - const node = await E(storageNode).makeChildNode(paths[key]); - return makeRecorderKit(node, typeMatchers[key]); - }); - - return allValues(keyedPromises).then((keyedVals) => { - for (const [k, v] of Object.entries(keyedVals)) { - baggage.init(k, v); - } - return keyedVals; - }); -}; - -/** - * @param {Brand} brand must be a 'nat' brand, not checked - * @param {NatValue} [min] - */ -export const makeNatAmountShape = (brand, min) => - harden({ brand, value: min ? M.gte(min) : M.nat() }); - -/** - * @param {Brand} brand must be a 'nat' brand, not checked - * @param {Pattern} shape - */ -export const makeCopyBagAmountShape = (brand, shape) => - harden({ brand, value: shape }); - -// Added in https://github.com/Agoric/agoric-sdk/issues/7632 but not yet available on Mainnet -// Adapted from https://github.com/Agoric/agoric-sdk/blob/3ff341c28af26f7879a02b4a7a228b545d552e4a/packages/swingset-liveslots/src/collectionManager.js#L645 -const isCopyMap = (m) => matches(m, M.map()); -export const addAllToMap = (map, mapEntries) => { - if (typeof mapEntries[Symbol.iterator] !== 'function') { - if (Object.isFrozen(mapEntries) && isCopyMap(mapEntries)) { - mapEntries = getCopyMapEntries(mapEntries); - } else { - Fail`provided data source is not iterable: ${mapEntries}`; - } - } - for (const [key, value] of mapEntries) { - if (map.has(key)) { - map.set(key, value); - } else { - map.init(key, value, true); - } - } -}; diff --git a/agoric/contract/src/kreadV1/market-metrics.js b/agoric/contract/src/market-metrics.js similarity index 100% rename from agoric/contract/src/kreadV1/market-metrics.js rename to agoric/contract/src/market-metrics.js diff --git a/agoric/contract/src/proposal/kread-committee-script.js b/agoric/contract/src/proposal/kread-committee-script.js index 380182e62..2925d23ca 100644 --- a/agoric/contract/src/proposal/kread-committee-script.js +++ b/agoric/contract/src/proposal/kread-committee-script.js @@ -31,7 +31,7 @@ export const defaultProposalBuilder = async ( committeeName, kreadCommitteeCharterRef: publishRef( install( - '../kreadV1/kreadCommitteeCharter.js', + '../kreadCommitteeCharter.js', '../bundles/bundle-kreadCommitteeCharter.js', { persist: true, diff --git a/agoric/contract/src/proposal/start-kread-script.js b/agoric/contract/src/proposal/start-kread-script.js index 267225d71..f6af89d72 100644 --- a/agoric/contract/src/proposal/start-kread-script.js +++ b/agoric/contract/src/proposal/start-kread-script.js @@ -28,7 +28,7 @@ export const defaultProposalBuilder = async ( royaltyAddr, platformFeeAddr, kreadKitRef: publishRef( - install('../kreadV1/index.js', '../bundles/bundle-kreadKit.js', { + install('../index.js', '../bundles/bundle-kreadKit.js', { persist: true, }), ), diff --git a/agoric/contract/src/kreadV1/text.js b/agoric/contract/src/text.js similarity index 100% rename from agoric/contract/src/kreadV1/text.js rename to agoric/contract/src/text.js diff --git a/agoric/contract/src/kreadV1/type-guards.js b/agoric/contract/src/type-guards.js similarity index 100% rename from agoric/contract/src/kreadV1/type-guards.js rename to agoric/contract/src/type-guards.js diff --git a/agoric/contract/src/kreadV1/types.js b/agoric/contract/src/types.js similarity index 100% rename from agoric/contract/src/kreadV1/types.js rename to agoric/contract/src/types.js diff --git a/agoric/contract/src/kreadV1/utils.js b/agoric/contract/src/utils.js similarity index 100% rename from agoric/contract/src/kreadV1/utils.js rename to agoric/contract/src/utils.js diff --git a/agoric/contract/test/bootstrap.js b/agoric/contract/test/bootstrap.js index 8fad24f1a..6607e2650 100644 --- a/agoric/contract/test/bootstrap.js +++ b/agoric/contract/test/bootstrap.js @@ -51,7 +51,7 @@ export const bootstrapContext = async (conf = undefined) => { const timerService = buildManualTimer(); // Bundle and install contract - const contractBundle = await bundleSource('./src/kreadV1/index.js'); + const contractBundle = await bundleSource('./src/index.js'); const installation = await E(zoe).install(contractBundle); const privateArgs = { powers: { diff --git a/agoric/contract/test/flow.js b/agoric/contract/test/flow.js index 4fa6d7b64..d25a07298 100644 --- a/agoric/contract/test/flow.js +++ b/agoric/contract/test/flow.js @@ -1,4 +1,4 @@ -import { errors } from '../src/kreadV2/errors.js'; +import { errors } from '../src/errors.js'; import { text } from './text.js'; import { defaultItems } from './items.js'; diff --git a/agoric/contract/test/swingsetTests/bootstrap/bootstrap-inventory.js b/agoric/contract/test/swingsetTests/bootstrap/bootstrap-inventory.js index c71a9fa12..974d3e4a0 100644 --- a/agoric/contract/test/swingsetTests/bootstrap/bootstrap-inventory.js +++ b/agoric/contract/test/swingsetTests/bootstrap/bootstrap-inventory.js @@ -3,7 +3,7 @@ import { flow } from '../flow.js'; import { E } from '@endo/eventual-send'; import { makeCopyBag, mustMatch } from '@agoric/store'; import { AmountMath } from '@agoric/ertp'; -import { errors } from '../../../src/kreadV2/errors.js'; +import { errors } from '../../../src/errors.js'; export async function setupInventoryTests(context) { await addCharacterToContext(context); diff --git a/agoric/contract/test/swingsetTests/bootstrap/bootstrap-market.js b/agoric/contract/test/swingsetTests/bootstrap/bootstrap-market.js index 5be921f8a..1096d5ae1 100644 --- a/agoric/contract/test/swingsetTests/bootstrap/bootstrap-market.js +++ b/agoric/contract/test/swingsetTests/bootstrap/bootstrap-market.js @@ -4,7 +4,7 @@ import { flow } from '../flow.js'; import { makeCopyBag, mustMatch } from '@agoric/store'; import { addCharacterToContext, addItemToContext } from './utils.js'; import { makeKreadUser } from './make-bootstrap-users.js'; -import { errors } from '../../../src/kreadV2/errors.js'; +import { errors } from '../../../src/errors.js'; import { multiplyBy } from '@agoric/zoe/src/contractSupport/ratio.js'; import { defaultItems } from '../items.js'; import { TimerBrandShape } from '@agoric/time'; diff --git a/agoric/contract/test/swingsetTests/bootstrap/bootstrap-upgradable.js b/agoric/contract/test/swingsetTests/bootstrap/bootstrap-upgradable.js index 84fe338d9..673a0f139 100644 --- a/agoric/contract/test/swingsetTests/bootstrap/bootstrap-upgradable.js +++ b/agoric/contract/test/swingsetTests/bootstrap/bootstrap-upgradable.js @@ -76,7 +76,7 @@ import { mint } from './bootstrap-null-upgrade.js'; const trace = makeTracer('kreadBootUpgrade'); const kreadV1BundleName = 'kreadV1'; -const kreadV2BundleName = 'kreadV2'; +// const kreadV2BundleName = 'kreadV2'; export const buildRootObject = async () => { let vatAdmin; @@ -85,7 +85,7 @@ export const buildRootObject = async () => { let governedInstance; /** @type {Context} */ let context; - /** @type {import('@agoric/governance/tools/puppetContractGovernor').PuppetContractGovernorKit} */ + /** @type {import('@agoric/governance/tools/puppetContractGovernor').PuppetContractGovernorKit} */ let governorFacets; const storageKit = makeFakeStorageKit('kread'); @@ -492,16 +492,16 @@ export const buildRootObject = async () => { assert.equal(upgradeResult.incarnationNumber, 1); trace('null upgrade completed'); }, - upgradeV2: async () => { - const bundleId = await E(vatAdmin).getBundleIDByName(kreadV2BundleName); - const kreadAdminFacet = await E( - governorFacets.creatorFacet, - ).getAdminFacet(); - const upgradeResult = await E(kreadAdminFacet).upgradeContract(bundleId, { - ...staticPrivateArgs, - initialPoserInvitation, - }); - }, + // upgradeV2: async () => { + // const bundleId = await E(vatAdmin).getBundleIDByName(kreadV2BundleName); + // const kreadAdminFacet = await E( + // governorFacets.creatorFacet, + // ).getAdminFacet(); + // const upgradeResult = await E(kreadAdminFacet).upgradeContract(bundleId, { + // ...staticPrivateArgs, + // initialPoserInvitation, + // }); + // }, testFunctionalityBeforeUpgrade: async () => { await testFunctionalityBeforeUpgrade(context); }, diff --git a/agoric/contract/test/swingsetTests/flow.js b/agoric/contract/test/swingsetTests/flow.js index a304f8912..e65a79049 100644 --- a/agoric/contract/test/swingsetTests/flow.js +++ b/agoric/contract/test/swingsetTests/flow.js @@ -1,4 +1,4 @@ -import { errors } from '../../src/kreadV2/errors.js'; +import { errors } from '../../src/errors.js'; import { text } from './text.js'; import { defaultItems } from './items.js'; diff --git a/agoric/contract/test/swingsetTests/swingset-setup.js b/agoric/contract/test/swingsetTests/swingset-setup.js index 1ab48e3ad..5ddf745fa 100644 --- a/agoric/contract/test/swingsetTests/swingset-setup.js +++ b/agoric/contract/test/swingsetTests/swingset-setup.js @@ -6,7 +6,7 @@ import { assert } from '@agoric/assert'; const bfile = (name) => new URL(name, import.meta.url).pathname; const kreadV1BundleName = 'kreadV1'; -const kreadV2BundleName = 'kreadV2'; +// const kreadV2BundleName = 'kreadV2'; let c; @@ -66,16 +66,16 @@ export async function setup() { }, [kreadV1BundleName]: { sourceSpec: await importMetaResolve( - '../../src/kreadV1/index.js', - import.meta.url, - ).then((href) => new URL(href).pathname), - }, - [kreadV2BundleName]: { - sourceSpec: await importMetaResolve( - '../../src/kreadV2/index.js', + '../../src/index.js', import.meta.url, ).then((href) => new URL(href).pathname), }, + // [kreadV2BundleName]: { + // sourceSpec: await importMetaResolve( + // '../../src/kreadV2/index.js', + // import.meta.url, + // ).then((href) => new URL(href).pathname), + // }, }, }; diff --git a/agoric/contract/test/swingsetTests/test-upgrade.js b/agoric/contract/test/swingsetTests/test-upgrade.js index 5948ac6aa..3ea8cce2f 100644 --- a/agoric/contract/test/swingsetTests/test-upgrade.js +++ b/agoric/contract/test/swingsetTests/test-upgrade.js @@ -37,14 +37,14 @@ test.serial('test functionality before upgrade', async (t) => { t.is(result, 'fulfilled'); }); -test.serial('upgrade to V2', async (t) => { - const [result] = await run('upgradeV2'); - t.is(result, 'fulfilled'); -}); +// test.serial('upgrade to V2', async (t) => { +// const [result] = await run('upgradeV2'); +// t.is(result, 'fulfilled'); +// }); -test.serial('test functionality after upgrade', async (t) => { - const [result] = await run('testFunctionalityAfterUpgrade'); - t.is(result, 'fulfilled'); -}); +// test.serial('test functionality after upgrade', async (t) => { +// const [result] = await run('testFunctionalityAfterUpgrade'); +// t.is(result, 'fulfilled'); +// }); -// test.serial() +// // test.serial() diff --git a/agoric/contract/test/swingsetTests/types.js b/agoric/contract/test/swingsetTests/types.js index e7732a3bd..c6b3821bc 100644 --- a/agoric/contract/test/swingsetTests/types.js +++ b/agoric/contract/test/swingsetTests/types.js @@ -75,7 +75,7 @@ * creatorFacet: unknown; * contractAssets: ContractAssets; * publicFacet: unknown; - * governorFacets: import('@agoric/governance/tools/puppetContractGovernor').PuppetContractGovernorKit; + * governorFacets: import('@agoric/governance/tools/puppetContractGovernor').PuppetContractGovernorKit; * zoe: ZoeService; * purses: { * character: any diff --git a/agoric/contract/test/test-inventory.js b/agoric/contract/test/test-inventory.js index 6db4bd063..694ac24cf 100644 --- a/agoric/contract/test/test-inventory.js +++ b/agoric/contract/test/test-inventory.js @@ -6,7 +6,7 @@ import { bootstrapContext } from './bootstrap.js'; import { flow } from './flow.js'; import { addCharacterToBootstrap, addItemToBootstrap } from './setup.js'; import { makeCopyBag } from '@agoric/store'; -import { errors } from '../src/kreadV2/errors.js'; +import { errors } from '../src/errors.js'; test.before(async (t) => { const bootstrap = await bootstrapContext(); diff --git a/agoric/contract/test/test-market.js b/agoric/contract/test/test-market.js index b4a3bd82e..079b84f99 100644 --- a/agoric/contract/test/test-market.js +++ b/agoric/contract/test/test-market.js @@ -7,7 +7,7 @@ import { flow } from './flow.js'; import { makeKreadUser } from './make-user.js'; import { addCharacterToBootstrap, addItemToBootstrap } from './setup.js'; import { makeCopyBag } from '@agoric/store'; -import { errors } from '../src/kreadV2/errors.js'; +import { errors } from '../src/errors.js'; import { defaultItems } from './items.js'; import { multiplyBy } from '@agoric/zoe/src/contractSupport/ratio.js'; diff --git a/agoric/yarn.lock b/agoric/yarn.lock index 0971bc1aa..2cac3abec 100644 --- a/agoric/yarn.lock +++ b/agoric/yarn.lock @@ -67,7 +67,7 @@ "@endo/promise-kit" "0.2.56" node-fetch "^2.6.0" -"@agoric/cosmic-proto@^0.3.0": +"@agoric/cosmic-proto@^0.3.0", "@agoric/cosmic-proto@agoric-upgrade-11": version "0.3.0" resolved "https://registry.yarnpkg.com/@agoric/cosmic-proto/-/cosmic-proto-0.3.0.tgz#c9d31d3946c91fbb1630f89d8ba63a662bcdacc5" integrity sha512-cIunby6gs53sGkHx3ALraREbfVQXvsIcObMjQQ0/tZt5HVqwoS7Y1Qj1Xl0ZZvqE8B1Zyk7QMDj829mbTII+9g== @@ -890,6 +890,26 @@ "@cosmjs/math" "^0.30.1" "@cosmjs/utils" "^0.30.1" +"@cosmjs/amino@^0.31.3": + version "0.31.3" + resolved "https://registry.yarnpkg.com/@cosmjs/amino/-/amino-0.31.3.tgz#0f4aa6bd68331c71bd51b187fa64f00eb075db0a" + integrity sha512-36emtUq895sPRX8PTSOnG+lhJDCVyIcE0Tr5ct59sUbgQiI14y43vj/4WAlJ/utSOxy+Zhj9wxcs4AZfu0BHsw== + dependencies: + "@cosmjs/crypto" "^0.31.3" + "@cosmjs/encoding" "^0.31.3" + "@cosmjs/math" "^0.31.3" + "@cosmjs/utils" "^0.31.3" + +"@cosmjs/amino@^0.32.1": + version "0.32.1" + resolved "https://registry.yarnpkg.com/@cosmjs/amino/-/amino-0.32.1.tgz#412ea151ee064757d8c8746f8a8975dc73ee175f" + integrity sha512-5l2xQ2XuAhV/B3kTIMPBcVZ/OQ+9Yyddzw/lIVs4qE5e/oBI0PVNWXw1oyR0wgfGHrMUxgKjsoOOqE2IbXVyCw== + dependencies: + "@cosmjs/crypto" "^0.32.1" + "@cosmjs/encoding" "^0.32.1" + "@cosmjs/math" "^0.32.1" + "@cosmjs/utils" "^0.32.1" + "@cosmjs/cosmwasm-stargate@^0.30.0": version "0.30.1" resolved "https://registry.yarnpkg.com/@cosmjs/cosmwasm-stargate/-/cosmwasm-stargate-0.30.1.tgz#6f9ca310f75433a3e30d683bc6aa24eadb345d79" @@ -920,6 +940,32 @@ elliptic "^6.5.4" libsodium-wrappers "^0.7.6" +"@cosmjs/crypto@^0.31.3": + version "0.31.3" + resolved "https://registry.yarnpkg.com/@cosmjs/crypto/-/crypto-0.31.3.tgz#c752cb6d682fdc735dcb45a2519f89c56ba16c26" + integrity sha512-vRbvM9ZKR2017TO73dtJ50KxoGcFzKtKI7C8iO302BQ5p+DuB+AirUg1952UpSoLfv5ki9O416MFANNg8UN/EQ== + dependencies: + "@cosmjs/encoding" "^0.31.3" + "@cosmjs/math" "^0.31.3" + "@cosmjs/utils" "^0.31.3" + "@noble/hashes" "^1" + bn.js "^5.2.0" + elliptic "^6.5.4" + libsodium-wrappers-sumo "^0.7.11" + +"@cosmjs/crypto@^0.32.1": + version "0.32.1" + resolved "https://registry.yarnpkg.com/@cosmjs/crypto/-/crypto-0.32.1.tgz#81202a10cbd36394a390454d954d782482537a5b" + integrity sha512-AsKucEg5o8evU0wXF/lDwX+ZSwCKF4bbc57nFzraHywlp3sNu4dfPPURoMrT0r7kT7wQZAy4Pdnvmm9nnCCm/Q== + dependencies: + "@cosmjs/encoding" "^0.32.1" + "@cosmjs/math" "^0.32.1" + "@cosmjs/utils" "^0.32.1" + "@noble/hashes" "^1" + bn.js "^5.2.0" + elliptic "^6.5.4" + libsodium-wrappers-sumo "^0.7.11" + "@cosmjs/encoding@^0.30.0", "@cosmjs/encoding@^0.30.1": version "0.30.1" resolved "https://registry.yarnpkg.com/@cosmjs/encoding/-/encoding-0.30.1.tgz#b5c4e0ef7ceb1f2753688eb96400ed70f35c6058" @@ -929,6 +975,24 @@ bech32 "^1.1.4" readonly-date "^1.0.0" +"@cosmjs/encoding@^0.31.3": + version "0.31.3" + resolved "https://registry.yarnpkg.com/@cosmjs/encoding/-/encoding-0.31.3.tgz#2519d9c9ae48368424971f253775c4580b54c5aa" + integrity sha512-6IRtG0fiVYwyP7n+8e54uTx2pLYijO48V3t9TLiROERm5aUAIzIlz6Wp0NYaI5he9nh1lcEGJ1lkquVKFw3sUg== + dependencies: + base64-js "^1.3.0" + bech32 "^1.1.4" + readonly-date "^1.0.0" + +"@cosmjs/encoding@^0.32.1": + version "0.32.1" + resolved "https://registry.yarnpkg.com/@cosmjs/encoding/-/encoding-0.32.1.tgz#1755c96e063bebef07a3f2d32971e90fb9ea4e3a" + integrity sha512-x60Lfds+Eq42rVV29NaoIAson3kBhATBI3zPp7X3GJTryBc5HFHQ6L/976tE1WB2DrvkfUdWS3ayCMVOY/qm1g== + dependencies: + base64-js "^1.3.0" + bech32 "^1.1.4" + readonly-date "^1.0.0" + "@cosmjs/faucet-client@^0.30.0": version "0.30.1" resolved "https://registry.yarnpkg.com/@cosmjs/faucet-client/-/faucet-client-0.30.1.tgz#81406128830ba47ae824a912144a28a7fe70300d" @@ -944,6 +1008,14 @@ "@cosmjs/stream" "^0.30.1" xstream "^11.14.0" +"@cosmjs/json-rpc@^0.31.3": + version "0.31.3" + resolved "https://registry.yarnpkg.com/@cosmjs/json-rpc/-/json-rpc-0.31.3.tgz#11e5cf0f6d9ab426dff470bb8d68d5d31cd6ab13" + integrity sha512-7LVYerXjnm69qqYR3uA6LGCrBW2EO5/F7lfJxAmY+iII2C7xO3a0vAjMSt5zBBh29PXrJVS6c2qRP22W1Le2Wg== + dependencies: + "@cosmjs/stream" "^0.31.3" + xstream "^11.14.0" + "@cosmjs/math@^0.30.0", "@cosmjs/math@^0.30.1": version "0.30.1" resolved "https://registry.yarnpkg.com/@cosmjs/math/-/math-0.30.1.tgz#8b816ef4de5d3afa66cb9fdfb5df2357a7845b8a" @@ -951,6 +1023,20 @@ dependencies: bn.js "^5.2.0" +"@cosmjs/math@^0.31.3": + version "0.31.3" + resolved "https://registry.yarnpkg.com/@cosmjs/math/-/math-0.31.3.tgz#767f7263d12ba1b9ed2f01f68d857597839fd957" + integrity sha512-kZ2C6glA5HDb9hLz1WrftAjqdTBb3fWQsRR+Us2HsjAYdeE6M3VdXMsYCP5M3yiihal1WDwAY2U7HmfJw7Uh4A== + dependencies: + bn.js "^5.2.0" + +"@cosmjs/math@^0.32.1": + version "0.32.1" + resolved "https://registry.yarnpkg.com/@cosmjs/math/-/math-0.32.1.tgz#e748b1f8bb20a927f5fe8311615911ed63c7334e" + integrity sha512-sqJgDjPh49rxe06apzwKYLxAw4LLFKmEd4yQtHqH16BxVVUrvK5UH9TEBpUrRErdjqENowekecDCDBZspGXHNA== + dependencies: + bn.js "^5.2.0" + "@cosmjs/proto-signing@^0.30.0", "@cosmjs/proto-signing@^0.30.1": version "0.30.1" resolved "https://registry.yarnpkg.com/@cosmjs/proto-signing/-/proto-signing-0.30.1.tgz#f0dda372488df9cd2677150b89b3e9c72b3cb713" @@ -964,6 +1050,31 @@ cosmjs-types "^0.7.1" long "^4.0.0" +"@cosmjs/proto-signing@^0.31.3": + version "0.31.3" + resolved "https://registry.yarnpkg.com/@cosmjs/proto-signing/-/proto-signing-0.31.3.tgz#20440b7b96fb2cd924256a10e656fd8d4481cdcd" + integrity sha512-24+10/cGl6lLS4VCrGTCJeDRPQTn1K5JfknzXzDIHOx8THR31JxA7/HV5eWGHqWgAbudA7ccdSvEK08lEHHtLA== + dependencies: + "@cosmjs/amino" "^0.31.3" + "@cosmjs/crypto" "^0.31.3" + "@cosmjs/encoding" "^0.31.3" + "@cosmjs/math" "^0.31.3" + "@cosmjs/utils" "^0.31.3" + cosmjs-types "^0.8.0" + long "^4.0.0" + +"@cosmjs/proto-signing@^0.32.1": + version "0.32.1" + resolved "https://registry.yarnpkg.com/@cosmjs/proto-signing/-/proto-signing-0.32.1.tgz#39de3c1758b2e3ae862d77fe4cb80b1dd6bc229f" + integrity sha512-IHJMXQ8XnfzR5K1hWb8VV/jEfJof6BL2mgGIA7X4hSPegwoVfb9hnFKPEPgFjGCTTvGZ8SfnCdXxpsOjianVIA== + dependencies: + "@cosmjs/amino" "^0.32.1" + "@cosmjs/crypto" "^0.32.1" + "@cosmjs/encoding" "^0.32.1" + "@cosmjs/math" "^0.32.1" + "@cosmjs/utils" "^0.32.1" + cosmjs-types "^0.9.0" + "@cosmjs/socket@^0.30.1": version "0.30.1" resolved "https://registry.yarnpkg.com/@cosmjs/socket/-/socket-0.30.1.tgz#00b22f4b5e2ab01f4d82ccdb7b2e59536bfe5ce0" @@ -974,6 +1085,16 @@ ws "^7" xstream "^11.14.0" +"@cosmjs/socket@^0.31.3": + version "0.31.3" + resolved "https://registry.yarnpkg.com/@cosmjs/socket/-/socket-0.31.3.tgz#52086380f4de2fc3514b90b0484b4b1c4c50e39e" + integrity sha512-aqrDGGi7os/hsz5p++avI4L0ZushJ+ItnzbqA7C6hamFSCJwgOkXaOUs+K9hXZdX4rhY7rXO4PH9IH8q09JkTw== + dependencies: + "@cosmjs/stream" "^0.31.3" + isomorphic-ws "^4.0.1" + ws "^7" + xstream "^11.14.0" + "@cosmjs/stargate@^0.30.0", "@cosmjs/stargate@^0.30.1": version "0.30.1" resolved "https://registry.yarnpkg.com/@cosmjs/stargate/-/stargate-0.30.1.tgz#e1b22e1226cffc6e93914a410755f1f61057ba04" @@ -992,6 +1113,24 @@ protobufjs "~6.11.3" xstream "^11.14.0" +"@cosmjs/stargate@^0.31.1": + version "0.31.3" + resolved "https://registry.yarnpkg.com/@cosmjs/stargate/-/stargate-0.31.3.tgz#a2b38e398097a00f897dbd8f02d4d347d8fed818" + integrity sha512-53NxnzmB9FfXpG4KjOUAYAvWLYKdEmZKsutcat/u2BrDXNZ7BN8jim/ENcpwXfs9/Og0K24lEIdvA4gsq3JDQw== + dependencies: + "@confio/ics23" "^0.6.8" + "@cosmjs/amino" "^0.31.3" + "@cosmjs/encoding" "^0.31.3" + "@cosmjs/math" "^0.31.3" + "@cosmjs/proto-signing" "^0.31.3" + "@cosmjs/stream" "^0.31.3" + "@cosmjs/tendermint-rpc" "^0.31.3" + "@cosmjs/utils" "^0.31.3" + cosmjs-types "^0.8.0" + long "^4.0.0" + protobufjs "~6.11.3" + xstream "^11.14.0" + "@cosmjs/stream@^0.30.0", "@cosmjs/stream@^0.30.1": version "0.30.1" resolved "https://registry.yarnpkg.com/@cosmjs/stream/-/stream-0.30.1.tgz#ba038a2aaf41343696b1e6e759d8e03a9516ec1a" @@ -999,6 +1138,13 @@ dependencies: xstream "^11.14.0" +"@cosmjs/stream@^0.31.3": + version "0.31.3" + resolved "https://registry.yarnpkg.com/@cosmjs/stream/-/stream-0.31.3.tgz#53428fd62487ec08fc3886a50a3feeb8b2af2e66" + integrity sha512-8keYyI7X0RjsLyVcZuBeNjSv5FA4IHwbFKx7H60NHFXszN8/MvXL6aZbNIvxtcIHHsW7K9QSQos26eoEWlAd+w== + dependencies: + xstream "^11.14.0" + "@cosmjs/tendermint-rpc@^0.30.0", "@cosmjs/tendermint-rpc@^0.30.1": version "0.30.1" resolved "https://registry.yarnpkg.com/@cosmjs/tendermint-rpc/-/tendermint-rpc-0.30.1.tgz#c16378892ba1ac63f72803fdf7567eab9d4f0aa0" @@ -1015,11 +1161,37 @@ readonly-date "^1.0.0" xstream "^11.14.0" +"@cosmjs/tendermint-rpc@^0.31.3": + version "0.31.3" + resolved "https://registry.yarnpkg.com/@cosmjs/tendermint-rpc/-/tendermint-rpc-0.31.3.tgz#d1a2bc5b3c98743631c9b55888589d352403c9b3" + integrity sha512-s3TiWkPCW4QceTQjpYqn4xttUJH36mTPqplMl+qyocdqk5+X5mergzExU/pHZRWQ4pbby8bnR7kMvG4OC1aZ8g== + dependencies: + "@cosmjs/crypto" "^0.31.3" + "@cosmjs/encoding" "^0.31.3" + "@cosmjs/json-rpc" "^0.31.3" + "@cosmjs/math" "^0.31.3" + "@cosmjs/socket" "^0.31.3" + "@cosmjs/stream" "^0.31.3" + "@cosmjs/utils" "^0.31.3" + axios "^0.21.2" + readonly-date "^1.0.0" + xstream "^11.14.0" + "@cosmjs/utils@^0.30.0", "@cosmjs/utils@^0.30.1": version "0.30.1" resolved "https://registry.yarnpkg.com/@cosmjs/utils/-/utils-0.30.1.tgz#6d92582341be3c2ec8d82090253cfa4b7f959edb" integrity sha512-KvvX58MGMWh7xA+N+deCfunkA/ZNDvFLw4YbOmX3f/XBIkqrVY7qlotfy2aNb1kgp6h4B6Yc8YawJPDTfvWX7g== +"@cosmjs/utils@^0.31.3": + version "0.31.3" + resolved "https://registry.yarnpkg.com/@cosmjs/utils/-/utils-0.31.3.tgz#f97bbfda35ad69e80cd5c7fe0a270cbda16db1ed" + integrity sha512-VBhAgzrrYdIe0O5IbKRqwszbQa7ZyQLx9nEQuHQ3HUplQW7P44COG/ye2n6AzCudtqxmwdX7nyX8ta1J07GoqA== + +"@cosmjs/utils@^0.32.1": + version "0.32.1" + resolved "https://registry.yarnpkg.com/@cosmjs/utils/-/utils-0.32.1.tgz#0f7f7cbbe38c4a7fd852e698bad4d811fba5f80a" + integrity sha512-PV9pa0cVPFCNgfQKEOc6RcNFHr5wMQLcDqWoo/ekIoj1AfzAaqnojdnL80u1C9Qf+vOfRGIXubqiU7Tl7QZuig== + "@dabh/diagnostics@^2.0.2": version "2.0.3" resolved "https://registry.yarnpkg.com/@dabh/diagnostics/-/diagnostics-2.0.3.tgz#7f7e97ee9a725dffc7808d93668cc984e1dc477a" @@ -2932,6 +3104,19 @@ cosmjs-types@^0.7.1: long "^4.0.0" protobufjs "~6.11.2" +cosmjs-types@^0.8.0: + version "0.8.0" + resolved "https://registry.yarnpkg.com/cosmjs-types/-/cosmjs-types-0.8.0.tgz#2ed78f3e990f770229726f95f3ef5bf9e2b6859b" + integrity sha512-Q2Mj95Fl0PYMWEhA2LuGEIhipF7mQwd9gTQ85DdP9jjjopeoGaDxvmPa5nakNzsq7FnO1DMTatXTAx6bxMH7Lg== + dependencies: + long "^4.0.0" + protobufjs "~6.11.2" + +cosmjs-types@^0.9.0: + version "0.9.0" + resolved "https://registry.yarnpkg.com/cosmjs-types/-/cosmjs-types-0.9.0.tgz#c3bc482d28c7dfa25d1445093fdb2d9da1f6cfcc" + integrity sha512-MN/yUe6mkJwHnCFfsNPeCfXVhyxHYW6c/xDUzrSbBycYzw++XvWDMJArXp2pLdgD6FQ8DW79vkPjeNKVrXaHeQ== + cross-spawn@^7.0.0, cross-spawn@^7.0.2, cross-spawn@^7.0.3: version "7.0.3" resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6" @@ -4775,6 +4960,18 @@ levn@^0.4.1: prelude-ls "^1.2.1" type-check "~0.4.0" +libsodium-sumo@^0.7.13: + version "0.7.13" + resolved "https://registry.yarnpkg.com/libsodium-sumo/-/libsodium-sumo-0.7.13.tgz#533b97d2be44b1277e59c1f9f60805978ac5542d" + integrity sha512-zTGdLu4b9zSNLfovImpBCbdAA4xkpkZbMnSQjP8HShyOutnGjRHmSOKlsylh1okao6QhLiz7nG98EGn+04cZjQ== + +libsodium-wrappers-sumo@^0.7.11: + version "0.7.13" + resolved "https://registry.yarnpkg.com/libsodium-wrappers-sumo/-/libsodium-wrappers-sumo-0.7.13.tgz#a33aea845a0bb56db067548f04feba28c730ab8e" + integrity sha512-lz4YdplzDRh6AhnLGF2Dj2IUj94xRN6Bh8T0HLNwzYGwPehQJX6c7iYVrFUPZ3QqxE0bqC+K0IIqqZJYWumwSQ== + dependencies: + libsodium-sumo "^0.7.13" + libsodium-wrappers@^0.7.6: version "0.7.13" resolved "https://registry.yarnpkg.com/libsodium-wrappers/-/libsodium-wrappers-0.7.13.tgz#83299e06ee1466057ba0e64e532777d2929b90d3"