From 0fd5e160dd9401ecde826db2c6e1caf384c53544 Mon Sep 17 00:00:00 2001 From: ZenVoich Date: Tue, 13 Jun 2023 11:50:03 +0400 Subject: [PATCH 01/23] remove Shuffle module --- src/CanisterAssets/lib.mo | 45 ++++++++++++++++++-------------- src/CanisterAssets/types.mo | 14 +++++----- src/Http/lib.mo | 2 +- src/Http/types.mo | 2 -- src/Sale/lib.mo | 2 +- src/Sale/types.mo | 2 -- src/main.mo | 52 +++++++++++++------------------------ src/utils.mo | 18 +++++++++++++ 8 files changed, 71 insertions(+), 66 deletions(-) diff --git a/src/CanisterAssets/lib.mo b/src/CanisterAssets/lib.mo index c0317f6..5122cd3 100644 --- a/src/CanisterAssets/lib.mo +++ b/src/CanisterAssets/lib.mo @@ -19,6 +19,7 @@ module { *********/ var _assets = Buffer.Buffer(0); + var _isShuffled = false; // placeholder returned instead of asset when there is reveal delay and not yet revealed var _placeholder : Types.AssetV2 = { @@ -56,14 +57,15 @@ module { }; if (chunkIndex == 0) { - return ?#v2({ + return ?#v3({ placeholder = _placeholder; assetsCount = _assets.size(); assetsChunk; + isShuffled = _isShuffled; }); } else if (chunkIndex < getChunkCount()) { - return ?#v2_chunk({ assetsChunk }); + return ?#v3_chunk({ assetsChunk }); } else { null; @@ -71,35 +73,27 @@ module { }; public func loadStableChunk(chunk : Types.StableChunk) { - let toV2 = func(assets : [Types.Asset]) : [Types.AssetV2] { - Array.map(assets, func(asset) { - { - asset with - payloadUrl = null; - thumbnailUrl = null; - }; - }); - }; - switch (chunk) { - // v1 -> v2 - case (?#v1(data)) { + // v2 -> v3 + case (?#v2(data)) { _assets := Buffer.Buffer(data.assetsCount); - _assets.append(Buffer.fromArray(toV2(data.assetsChunk))); + _assets.append(Buffer.fromArray(data.assetsChunk)); _updateBiggestAssetSize(data.assetsChunk); + _isShuffled := true; }; - case (?#v1_chunk(data)) { - _assets.append(Buffer.fromArray(toV2(data.assetsChunk))); + case (?#v2_chunk(data)) { + _assets.append(Buffer.fromArray(data.assetsChunk)); _updateBiggestAssetSize(data.assetsChunk); }; - // v2 - case (?#v2(data)) { + // v3 + case (?#v3(data)) { _placeholder := data.placeholder; _assets := Buffer.Buffer(data.assetsCount); _assets.append(Buffer.fromArray(data.assetsChunk)); _updateBiggestAssetSize(data.assetsChunk); + _isShuffled := data.isShuffled; }; - case (?#v2_chunk(data)) { + case (?#v3_chunk(data)) { _assets.append(Buffer.fromArray(data.assetsChunk)); _updateBiggestAssetSize(data.assetsChunk); }; @@ -218,6 +212,17 @@ module { _placeholder := asset; }; + public func shuffleAssets() : async () { + assert (Utils.toNanos(config.revealDelay) > 0 and not _isShuffled); + let seed : Blob = await Random.blob(); + Utils.shuffleBuffer(_assets, seed); + _isShuffled := true; + }; + + public func isShuffled() : Bool { + _isShuffled; + }; + /******************* * INTERNAL METHODS * *******************/ diff --git a/src/CanisterAssets/types.mo b/src/CanisterAssets/types.mo index 1d914c4..2750965 100644 --- a/src/CanisterAssets/types.mo +++ b/src/CanisterAssets/types.mo @@ -2,19 +2,21 @@ import Tokens "../Tokens"; module { public type StableChunk = ?{ - #v1: { + #v2: { + placeholder : AssetV2; assetsCount : Nat; - assetsChunk : [Asset]; + assetsChunk : [AssetV2]; }; - #v1_chunk: { - assetsChunk : [Asset]; + #v2_chunk: { + assetsChunk : [AssetV2]; }; - #v2: { + #v3: { placeholder : AssetV2; assetsCount : Nat; assetsChunk : [AssetV2]; + isShuffled : Bool; }; - #v2_chunk: { + #v3_chunk: { assetsChunk : [AssetV2]; }; }; diff --git a/src/Http/lib.mo b/src/Http/lib.mo index e66709f..65918b5 100644 --- a/src/Http/lib.mo +++ b/src/Http/lib.mo @@ -45,7 +45,7 @@ module { case (?tokenid) { // start custom // if not revealed yet, return placeholder - if (Utils.toNanos(config.revealDelay) > 0 and not deps._Shuffle.isShuffled()) { + if (Utils.toNanos(config.revealDelay) > 0 and not deps._Assets.isShuffled()) { let placeholder = deps._Assets.getPlaceholder(); return _processFile("placeholder", placeholder.payload, placeholder.payloadUrl); }; diff --git a/src/Http/types.mo b/src/Http/types.mo index 45bf8f0..b8818b4 100644 --- a/src/Http/types.mo +++ b/src/Http/types.mo @@ -1,7 +1,6 @@ import Assets "../CanisterAssets"; import Marketplace "../Marketplace"; import Sale "../Sale"; -import Shuffle "../Shuffle"; import Tokens "../Tokens"; module { @@ -41,7 +40,6 @@ module { public type Dependencies = { _Assets : Assets.Factory; - _Shuffle : Shuffle.Factory; _Tokens : Tokens.Factory; _Marketplace : Marketplace.Factory; _Sale : Sale.Factory; diff --git a/src/Sale/lib.mo b/src/Sale/lib.mo index 918c37e..56a6ac9 100644 --- a/src/Sale/lib.mo +++ b/src/Sale/lib.mo @@ -177,7 +177,7 @@ module { }; // shuffle indices let seed : Blob = await Random.blob(); - _tokensForSale := deps._Shuffle.shuffleTokens(_tokensForSale, seed); + Utils.shuffleBuffer(_tokensForSale, seed); }; public func airdropTokens(caller : Principal) : () { diff --git a/src/Sale/types.mo b/src/Sale/types.mo index 2df2dc4..1d53a4c 100644 --- a/src/Sale/types.mo +++ b/src/Sale/types.mo @@ -3,7 +3,6 @@ import Time "mo:base/Time"; import Cap "mo:cap/Cap"; import ExtCore "../toniq-labs/ext/Core"; -import Shuffle "../Shuffle"; import Tokens "../Tokens"; import Disburser "../Disburser"; import Types "../types"; @@ -47,7 +46,6 @@ module { public type Dependencies = { _Cap : Cap.Cap; _Tokens : Tokens.Factory; - _Shuffle : Shuffle.Factory; _Disburser : Disburser.Factory; }; diff --git a/src/main.mo b/src/main.mo index 9d67593..0ba3fc5 100644 --- a/src/main.mo +++ b/src/main.mo @@ -65,6 +65,13 @@ shared ({ caller = init_minter }) actor class Canister(cid : Principal, initArgs shuffle : ShuffleTypes.StableChunk; disburser : DisburserTypes.StableChunk; }; + #v2 : { + tokens : TokenTypes.StableChunk; + sale : SaleTypes.StableChunk; + marketplace : MarketplaceTypes.StableChunk; + assets : AssetsTypes.StableChunk; + disburser : DisburserTypes.StableChunk; + }; }; /**************** @@ -73,24 +80,6 @@ shared ({ caller = init_minter }) actor class Canister(cid : Principal, initArgs stable var _stableChunks : [var StableChunk] = [var]; - // Tokens - private stable var _tokenState : Any = (); - - // Sale - private stable var _saleState : Any = (); - - // Marketplace - private stable var _marketplaceState : Any = (); - - // Assets - private stable var _assetsState : Any = (); - - // Shuffle - private stable var _shuffleState : Any = (); - - // Disburser - private stable var _disburserState : Any = (); - // Cap private stable var rootBucketId : ?Text = null; @@ -137,24 +126,30 @@ shared ({ caller = init_minter }) actor class Canister(cid : Principal, initArgs }; func _toStableChunk(chunkSize : Nat, chunkIndex : Nat) : StableChunk { - #v1({ + #v2({ tokens = _Tokens.toStableChunk(chunkSize, chunkIndex); sale = _Sale.toStableChunk(chunkSize, chunkIndex); marketplace = _Marketplace.toStableChunk(chunkSize, chunkIndex); assets = _Assets.toStableChunk(chunkSize, chunkIndex); - shuffle = _Shuffle.toStableChunk(chunkSize, chunkIndex); disburser = _Disburser.toStableChunk(chunkSize, chunkIndex); }); }; func _loadStableChunk(chunk : StableChunk) { switch (chunk) { + // v1 -> v2 case (#v1(data)) { _Tokens.loadStableChunk(data.tokens); _Sale.loadStableChunk(data.sale); _Marketplace.loadStableChunk(data.marketplace); _Assets.loadStableChunk(data.assets); - _Shuffle.loadStableChunk(data.shuffle); + _Disburser.loadStableChunk(data.disburser); + }; + case (#v2(data)) { + _Tokens.loadStableChunk(data.tokens); + _Sale.loadStableChunk(data.sale); + _Marketplace.loadStableChunk(data.marketplace); + _Assets.loadStableChunk(data.assets); _Disburser.loadStableChunk(data.disburser); }; }; @@ -200,7 +195,7 @@ shared ({ caller = init_minter }) actor class Canister(cid : Principal, initArgs }, ); - if (Utils.toNanos(config.revealDelay) > 0 and not _Shuffle.isShuffled()) { + if (Utils.toNanos(config.revealDelay) > 0 and not _Assets.isShuffled()) { let revealTime = config.publicSaleStart + Utils.toNanos(config.revealDelay); let delay = Int.abs(Int.max(0, revealTime - Time.now())); @@ -214,7 +209,7 @@ shared ({ caller = init_minter }) actor class Canister(cid : Principal, initArgs _revealTimerId := Timer.setTimer( #nanoseconds(delay + randDelay), func() : async () { - ignore _Shuffle.shuffleAssets(); + await _Assets.shuffleAssets(); }, ); }; @@ -343,21 +338,11 @@ shared ({ caller = init_minter }) actor class Canister(cid : Principal, initArgs _Assets.addAssets(caller, assets); }; - // Shuffle - let _Shuffle = Shuffle.Factory( - config, - { - _Assets; - _Tokens; - }, - ); - // Sale let _Sale = Sale.Factory( config, { _Cap; - _Shuffle; _Tokens; _Disburser; }, @@ -589,7 +574,6 @@ shared ({ caller = init_minter }) actor class Canister(cid : Principal, initArgs { _Assets; _Marketplace; - _Shuffle; _Tokens; _Sale; }, diff --git a/src/utils.mo b/src/utils.mo index c1a747a..cb0959d 100644 --- a/src/utils.mo +++ b/src/utils.mo @@ -170,4 +170,22 @@ module { case (#days(d)) d * 1000_000_000 * 60 * 60 * 24; }; }; + + // shuffle buffer in place + public func shuffleBuffer(buffer : Buffer.Buffer, seed : Blob) { + // use that seed to create random number generator + let randGen = prngStrong(seed); + // get the number of available tokens + var currentIndex : Nat = buffer.size(); + + while (currentIndex > 0) { + // use a random number to calculate a random index between 0 and currentIndex + var randomIndex = randGen.next() % currentIndex; + assert (randomIndex < currentIndex); + currentIndex -= 1; + let temporaryValue = buffer.get(currentIndex); + buffer.put(currentIndex, buffer.get(randomIndex)); + buffer.put(randomIndex, temporaryValue); + }; + }; }; From a538d61888c5dbbf30cb491085a33bc9f5099d1c Mon Sep 17 00:00:00 2001 From: ZenVoich Date: Mon, 3 Jul 2023 13:55:31 +0400 Subject: [PATCH 02/23] update declarations --- declarations/main/staging.did | 50 +++++++++++++++++------------- declarations/main/staging.did.d.ts | 30 ++++++++++++------ declarations/main/staging.did.js | 23 ++++++++------ 3 files changed, 61 insertions(+), 42 deletions(-) diff --git a/declarations/main/staging.did b/declarations/main/staging.did index 02ebbb8..d9abcce 100644 --- a/declarations/main/staging.did +++ b/declarations/main/staging.did @@ -183,11 +183,6 @@ type StableChunk__2 = opt type StableChunk__1 = opt variant { - v1: record { - assetsChunk: vec Asset; - assetsCount: nat; - }; - v1_chunk: record {assetsChunk: vec Asset;}; v2: record { assetsChunk: vec AssetV2; @@ -195,17 +190,35 @@ type StableChunk__1 = placeholder: AssetV2; }; v2_chunk: record {assetsChunk: vec AssetV2;}; + v3: + record { + assetsChunk: vec AssetV2; + assetsCount: nat; + isShuffled: bool; + placeholder: AssetV2; + }; + v3_chunk: record {assetsChunk: vec AssetV2;}; }; -type StableChunk = variant { - v1: - record { - assets: StableChunk__1; - disburser: StableChunk__2; - marketplace: StableChunk__3; - sale: StableChunk__4; - shuffle: StableChunk__5; - tokens: StableChunk__6; - };}; +type StableChunk = + variant { + v1: + record { + assets: StableChunk__1; + disburser: StableChunk__2; + marketplace: StableChunk__3; + sale: StableChunk__4; + shuffle: StableChunk__5; + tokens: StableChunk__6; + }; + v2: + record { + assets: StableChunk__1; + disburser: StableChunk__2; + marketplace: StableChunk__3; + sale: StableChunk__4; + tokens: StableChunk__6; + }; + }; type Settlement = record { buyer: AccountIdentifier__2; @@ -733,13 +746,6 @@ type AssetV2 = thumbnail: opt File; thumbnailUrl: opt text; }; -type Asset = - record { - metadata: opt File; - name: text; - payload: File; - thumbnail: opt File; - }; type AccountIdentifier__7 = text; type AccountIdentifier__6 = text; type AccountIdentifier__5 = text; diff --git a/declarations/main/staging.did.d.ts b/declarations/main/staging.did.d.ts index 639e749..7b4662d 100644 --- a/declarations/main/staging.did.d.ts +++ b/declarations/main/staging.did.d.ts @@ -9,12 +9,6 @@ export type AccountIdentifier__4 = string; export type AccountIdentifier__5 = string; export type AccountIdentifier__6 = string; export type AccountIdentifier__7 = string; -export interface Asset { - 'thumbnail' : [] | [File], - 'metadata' : [] | [File], - 'name' : string, - 'payload' : File, -} export interface AssetV2 { 'thumbnail' : [] | [File], 'payloadUrl' : [] | [string], @@ -408,18 +402,34 @@ export type StableChunk = { 'tokens' : StableChunk__6, 'shuffle' : StableChunk__5, } + } | + { + 'v2' : { + 'marketplace' : StableChunk__3, + 'assets' : StableChunk__1, + 'sale' : StableChunk__4, + 'disburser' : StableChunk__2, + 'tokens' : StableChunk__6, + } }; export type StableChunk__1 = [] | [ - { 'v1' : { 'assetsChunk' : Array, 'assetsCount' : bigint } } | - { + { 'v2' : { 'assetsChunk' : Array, 'assetsCount' : bigint, 'placeholder' : AssetV2, } } | - { 'v1_chunk' : { 'assetsChunk' : Array } } | - { 'v2_chunk' : { 'assetsChunk' : Array } } + { + 'v3' : { + 'assetsChunk' : Array, + 'assetsCount' : bigint, + 'placeholder' : AssetV2, + 'isShuffled' : boolean, + } + } | + { 'v2_chunk' : { 'assetsChunk' : Array } } | + { 'v3_chunk' : { 'assetsChunk' : Array } } ]; export type StableChunk__2 = [] | [ { 'v1' : { 'disbursements' : Array } } diff --git a/declarations/main/staging.did.js b/declarations/main/staging.did.js index 4efcb26..0d0b868 100644 --- a/declarations/main/staging.did.js +++ b/declarations/main/staging.did.js @@ -103,25 +103,21 @@ export const idlFactory = ({ IDL }) => { 'v1_chunk' : IDL.Record({ 'transactionChunk' : IDL.Vec(Transaction) }), }) ); - const Asset = IDL.Record({ - 'thumbnail' : IDL.Opt(File), - 'metadata' : IDL.Opt(File), - 'name' : IDL.Text, - 'payload' : File, - }); const StableChunk__1 = IDL.Opt( IDL.Variant({ - 'v1' : IDL.Record({ - 'assetsChunk' : IDL.Vec(Asset), + 'v2' : IDL.Record({ + 'assetsChunk' : IDL.Vec(AssetV2), 'assetsCount' : IDL.Nat, + 'placeholder' : AssetV2, }), - 'v2' : IDL.Record({ + 'v3' : IDL.Record({ 'assetsChunk' : IDL.Vec(AssetV2), 'assetsCount' : IDL.Nat, 'placeholder' : AssetV2, + 'isShuffled' : IDL.Bool, }), - 'v1_chunk' : IDL.Record({ 'assetsChunk' : IDL.Vec(Asset) }), 'v2_chunk' : IDL.Record({ 'assetsChunk' : IDL.Vec(AssetV2) }), + 'v3_chunk' : IDL.Record({ 'assetsChunk' : IDL.Vec(AssetV2) }), }) ); const AccountIdentifier__5 = IDL.Text; @@ -241,6 +237,13 @@ export const idlFactory = ({ IDL }) => { 'tokens' : StableChunk__6, 'shuffle' : StableChunk__5, }), + 'v2' : IDL.Record({ + 'marketplace' : StableChunk__3, + 'assets' : StableChunk__1, + 'sale' : StableChunk__4, + 'disburser' : StableChunk__2, + 'tokens' : StableChunk__6, + }), }); const TokenIdentifier = IDL.Text; const AccountIdentifier__1 = IDL.Text; From b0740082f15c888a9319d192afbdf224d5aa9abb Mon Sep 17 00:00:00 2001 From: ZenVoich Date: Mon, 3 Jul 2023 14:10:27 +0400 Subject: [PATCH 03/23] remove bulk sale code --- src/Sale/lib.mo | 48 ++++++++++------------------------------------- src/Sale/types.mo | 2 +- 2 files changed, 11 insertions(+), 39 deletions(-) diff --git a/src/Sale/lib.mo b/src/Sale/lib.mo index 19ec8e8..b2913b6 100644 --- a/src/Sale/lib.mo +++ b/src/Sale/lib.mo @@ -196,7 +196,7 @@ module { _tokensForSale.size(); }; - public func reserve(amount : Nat64, quantity : Nat64, address : Types.AccountIdentifier, _subaccountNOTUSED : Types.SubAccount) : Result.Result<(Types.AccountIdentifier, Nat64), Text> { + public func reserve(amountNOTUSED : Nat64, quantityNOTUSED : Nat64, address : Types.AccountIdentifier, _subaccountNOTUSED : Types.SubAccount) : Result.Result<(Types.AccountIdentifier, Nat64), Text> { switch (config.sale) { case (#duration(duration)) { if (Time.now() > config.publicSaleStart + Utils.toNanos(duration)) { @@ -220,43 +220,19 @@ module { if (availableTokens() == 0) { return #err("No more NFTs available right now!"); }; - if (availableTokens() < Nat64.toNat(quantity)) { - return #err("Not enough NFTs available!"); - }; - if (quantity == 0) { - return #err("Quantity must be greater than 0"); - }; - var total : Nat64 = (getAddressPrice(address) * quantity); - var bp = getAddressBulkPrice(address); - var lastq : Nat64 = 1; - // check the bulk prices available - for (a in bp.vals()) { - // if there is a precise match, the end price is in the bulk price tuple - // and we can replace total - if (a.0 == quantity) { - total := a.1; - }; - lastq := a.0; - }; - // we check that no one can buy more than specified in the bulk prices - if (quantity > lastq) { - return #err("Quantity error"); - }; - if (total > amount) { - return #err("Price mismatch!"); - }; + let price = getAddressPrice(address); let subaccount = getNextSubAccount(); let paymentAddress : Types.AccountIdentifier = AID.fromPrincipal(config.canister, ?subaccount); // we only reserve the tokens here, they deducted from the available tokens // after payment. otherwise someone could stall the sale by reserving all // the tokens without paying for them - let tokens : [Types.TokenIndex] = tempNextTokens(quantity); + let tokens : [Types.TokenIndex] = tempNextTokens(1); _salesSettlements.put( paymentAddress, { tokens = tokens; - price = total; + price = price; subaccount = subaccount; buyer = address; expires = Time.now() + Utils.toNanos(Option.get(config.escrowDelay, #minutes(2))); @@ -277,7 +253,7 @@ module { case (null) {}; }; - #ok((paymentAddress, total)); + #ok((paymentAddress, price)); }; public func retrieve(caller : Principal, paymentaddress : Types.AccountIdentifier) : async* Result.Result<(), Text> { @@ -510,7 +486,7 @@ module { endTime = endTime; whitelistTime = config.publicSaleStart; whitelist = isWhitelisted(address); - bulkPricing = getAddressBulkPrice(address); + bulkPricing = [(1, getAddressPrice(address))]; openEdition = openEdition; } : Types.SaleSettings; }; @@ -536,12 +512,8 @@ module { Array.freeze(Array.init(Nat64.toNat(qty), 0)); }; - func getAddressPrice(address : Types.AccountIdentifier) : Nat64 { - getAddressBulkPrice(address)[0].1; - }; - // Set different price types here - func getAddressBulkPrice(address : Types.AccountIdentifier) : [(Nat64, Nat64)] { + func getAddressPrice(address : Types.AccountIdentifier) : Nat64 { // dutch auction switch (config.dutchAuction) { case (?dutchAuction) { @@ -553,7 +525,7 @@ module { let publicSale = dutchAuction.target == #publicSale and not isWhitelisted(address); if (everyone or whitelist or publicSale) { - return [(1, getCurrentDutchAuctionPrice(dutchAuction))]; + return getCurrentDutchAuctionPrice(dutchAuction); }; }; case (null) {}; @@ -566,12 +538,12 @@ module { // is always the first one. switch (getEligibleWhitelist(address, true)) { case (?whitelist) { - return [(1, whitelist.price)]; + return whitelist.price; }; case (_) {}; }; - return [(1, config.salePrice)]; + return config.salePrice; }; func getCurrentDutchAuctionPrice(dutchAuction : RootTypes.DutchAuction) : Nat64 { diff --git a/src/Sale/types.mo b/src/Sale/types.mo index 2df2dc4..70e03a4 100644 --- a/src/Sale/types.mo +++ b/src/Sale/types.mo @@ -102,7 +102,7 @@ module { whitelistTime : Time; whitelist : Bool; totalToSell : Nat; - bulkPricing : [(Nat64, Nat64)]; + bulkPricing : [(Nat64, Nat64)]; // always [(1, )] openEdition : Bool; }; }; From ae5436399404a8b4f9b89706953a925d15c4b81e Mon Sep 17 00:00:00 2001 From: ZenVoich Date: Mon, 3 Jul 2023 14:14:43 +0400 Subject: [PATCH 04/23] refactor --- src/Marketplace/lib.mo | 2 +- src/Sale/lib.mo | 2 +- src/main.mo | 8 ++++---- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/Marketplace/lib.mo b/src/Marketplace/lib.mo index 5fa6e67..2c78375 100644 --- a/src/Marketplace/lib.mo +++ b/src/Marketplace/lib.mo @@ -107,7 +107,7 @@ module { * PUBLIC INTERFACE * ********************/ - public func lock(caller : Principal, tokenid : Types.TokenIdentifier, price : Nat64, address : Types.AccountIdentifier, _subaccountNOTUSED : Types.SubAccount, frontendIdentifier : ?Text) : async* Result.Result { + public func lock(caller : Principal, tokenid : Types.TokenIdentifier, price : Nat64, address : Types.AccountIdentifier, frontendIdentifier : ?Text) : async* Result.Result { if (ExtCore.TokenIdentifier.isPrincipal(tokenid, config.canister) == false) { return #err(#InvalidToken(tokenid)); }; diff --git a/src/Sale/lib.mo b/src/Sale/lib.mo index b2913b6..69564c1 100644 --- a/src/Sale/lib.mo +++ b/src/Sale/lib.mo @@ -196,7 +196,7 @@ module { _tokensForSale.size(); }; - public func reserve(amountNOTUSED : Nat64, quantityNOTUSED : Nat64, address : Types.AccountIdentifier, _subaccountNOTUSED : Types.SubAccount) : Result.Result<(Types.AccountIdentifier, Nat64), Text> { + public func reserve(address : Types.AccountIdentifier) : Result.Result<(Types.AccountIdentifier, Nat64), Text> { switch (config.sale) { case (#duration(duration)) { if (Time.now() > config.publicSaleStart + Utils.toNanos(duration)) { diff --git a/src/main.mo b/src/main.mo index 5b35657..fcbcf37 100644 --- a/src/main.mo +++ b/src/main.mo @@ -394,10 +394,10 @@ shared ({ caller = init_minter }) actor class Canister(cid : Principal, initArgs _Sale.enableSale(caller); }; - public func reserve(amount : Nat64, quantity : Nat64, address : SaleTypes.AccountIdentifier, _subaccountNOTUSED : SaleTypes.SubAccount) : async Result.Result<(SaleTypes.AccountIdentifier, Nat64), Text> { + public func reserve(amountNOTUSED : Nat64, quantityNOTUSED : Nat64, address : SaleTypes.AccountIdentifier, _subaccountNOTUSED : SaleTypes.SubAccount) : async Result.Result<(SaleTypes.AccountIdentifier, Nat64), Text> { _trapIfRestoreEnabled(); canistergeekMonitor.collectMetrics(); - _Sale.reserve(amount, quantity, address, _subaccountNOTUSED); + _Sale.reserve(address); }; public shared ({ caller }) func retrieve(paymentaddress : SaleTypes.AccountIdentifier) : async Result.Result<(), Text> { @@ -450,11 +450,11 @@ shared ({ caller = init_minter }) actor class Canister(cid : Principal, initArgs // updates // lock token and get address to pay - public shared ({ caller }) func lock(tokenid : MarketplaceTypes.TokenIdentifier, price : Nat64, address : MarketplaceTypes.AccountIdentifier, subaccount : MarketplaceTypes.SubAccount, frontendIdentifier : ?Text) : async Result.Result { + public shared ({ caller }) func lock(tokenid : MarketplaceTypes.TokenIdentifier, price : Nat64, address : MarketplaceTypes.AccountIdentifier, subaccountNOTUSED : MarketplaceTypes.SubAccount, frontendIdentifier : ?Text) : async Result.Result { _trapIfRestoreEnabled(); canistergeekMonitor.collectMetrics(); // no caller check, anyone can lock - await* _Marketplace.lock(caller, tokenid, price, address, subaccount, frontendIdentifier); + await* _Marketplace.lock(caller, tokenid, price, address, frontendIdentifier); }; // check payment and settle transfer token to user From 166eeab53e0ab8a2f4e0b72766b4d84d140c57c1 Mon Sep 17 00:00:00 2001 From: ZenVoich Date: Tue, 4 Jul 2023 14:15:50 +0400 Subject: [PATCH 05/23] return price check on reserve --- src/Sale/lib.mo | 7 ++++++- src/main.mo | 4 ++-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/src/Sale/lib.mo b/src/Sale/lib.mo index 69564c1..69d137f 100644 --- a/src/Sale/lib.mo +++ b/src/Sale/lib.mo @@ -196,7 +196,7 @@ module { _tokensForSale.size(); }; - public func reserve(address : Types.AccountIdentifier) : Result.Result<(Types.AccountIdentifier, Nat64), Text> { + public func reserve(amount : Nat64, address : Types.AccountIdentifier) : Result.Result<(Types.AccountIdentifier, Nat64), Text> { switch (config.sale) { case (#duration(duration)) { if (Time.now() > config.publicSaleStart + Utils.toNanos(duration)) { @@ -220,10 +220,15 @@ module { if (availableTokens() == 0) { return #err("No more NFTs available right now!"); }; + let price = getAddressPrice(address); let subaccount = getNextSubAccount(); let paymentAddress : Types.AccountIdentifier = AID.fromPrincipal(config.canister, ?subaccount); + if (amount != price) { + return #err("Price mismatch!"); + }; + // we only reserve the tokens here, they deducted from the available tokens // after payment. otherwise someone could stall the sale by reserving all // the tokens without paying for them diff --git a/src/main.mo b/src/main.mo index fcbcf37..bd974b4 100644 --- a/src/main.mo +++ b/src/main.mo @@ -394,10 +394,10 @@ shared ({ caller = init_minter }) actor class Canister(cid : Principal, initArgs _Sale.enableSale(caller); }; - public func reserve(amountNOTUSED : Nat64, quantityNOTUSED : Nat64, address : SaleTypes.AccountIdentifier, _subaccountNOTUSED : SaleTypes.SubAccount) : async Result.Result<(SaleTypes.AccountIdentifier, Nat64), Text> { + public func reserve(amount : Nat64, quantityNOTUSED : Nat64, address : SaleTypes.AccountIdentifier, _subaccountNOTUSED : SaleTypes.SubAccount) : async Result.Result<(SaleTypes.AccountIdentifier, Nat64), Text> { _trapIfRestoreEnabled(); canistergeekMonitor.collectMetrics(); - _Sale.reserve(address); + _Sale.reserve(amount, address); }; public shared ({ caller }) func retrieve(paymentaddress : SaleTypes.AccountIdentifier) : async Result.Result<(), Text> { From 5f7c90426b72ce8ab14b4fb0a007ca680de90a27 Mon Sep 17 00:00:00 2001 From: ZenVoich Date: Fri, 7 Jul 2023 12:24:32 +0400 Subject: [PATCH 06/23] fix 'backup-assets' e2e test --- test/backup-assets/backup-assets.test.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/backup-assets/backup-assets.test.ts b/test/backup-assets/backup-assets.test.ts index f23ed50..81bae71 100644 --- a/test/backup-assets/backup-assets.test.ts +++ b/test/backup-assets/backup-assets.test.ts @@ -36,8 +36,8 @@ describe('backup', () => { it('check a.json', async () => { let data = JSON.parse(readFileSync(__dirname + '/../../backup/data/a.json').toString()); - expect(data[0]['v1']['assets'][0]['v2']['assetsChunk']).toHaveLength(7); - expect(data[0]['v1']['assets'][0]['v2']['assetsCount']).toBe('###bigint:7'); + expect(data[0]['v2']['assets'][0]['v2']['assetsChunk']).toHaveLength(7); + expect(data[0]['v2']['assets'][0]['v2']['assetsCount']).toBe('###bigint:7'); }); }); From e3480302e49b9b132936516e4b4d65cb070e4de3 Mon Sep 17 00:00:00 2001 From: ZenVoich Date: Fri, 7 Jul 2023 12:34:54 +0400 Subject: [PATCH 07/23] fix 'backup-assets' e2e test --- test/backup-assets/backup-assets.test.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/backup-assets/backup-assets.test.ts b/test/backup-assets/backup-assets.test.ts index 81bae71..ca02255 100644 --- a/test/backup-assets/backup-assets.test.ts +++ b/test/backup-assets/backup-assets.test.ts @@ -36,8 +36,8 @@ describe('backup', () => { it('check a.json', async () => { let data = JSON.parse(readFileSync(__dirname + '/../../backup/data/a.json').toString()); - expect(data[0]['v2']['assets'][0]['v2']['assetsChunk']).toHaveLength(7); - expect(data[0]['v2']['assets'][0]['v2']['assetsCount']).toBe('###bigint:7'); + expect(data[0]['v2']['assets'][0]['v3']['assetsChunk']).toHaveLength(7); + expect(data[0]['v2']['assets'][0]['v3']['assetsCount']).toBe('###bigint:7'); }); }); From 7fa3094caac1683fbd7ea4dde3030c72cb3faebe Mon Sep 17 00:00:00 2001 From: ZenVoich Date: Tue, 11 Jul 2023 13:16:42 +0400 Subject: [PATCH 08/23] add seller and buyer frontend to transaction record --- src/Http/lib.mo | 4 ++-- src/Marketplace/lib.mo | 41 ++++++++++++++++++++++++++++++---------- src/Marketplace/types.mo | 23 ++++++++++++++++++++++ src/main.mo | 2 +- 4 files changed, 57 insertions(+), 13 deletions(-) diff --git a/src/Http/lib.mo b/src/Http/lib.mo index e66709f..76d2375 100644 --- a/src/Http/lib.mo +++ b/src/Http/lib.mo @@ -124,10 +124,10 @@ module { // Just show index var soldValue : Nat = Nat64.toNat( - Array.foldLeft( + Array.foldLeft( Buffer.toArray(deps._Marketplace.getTransactions()), 0, - func(b : Nat64, a : MarketplaceTypes.Transaction) : Nat64 { + func(b : Nat64, a : MarketplaceTypes.TransactionV2) : Nat64 { b + a.price; }, ), diff --git a/src/Marketplace/lib.mo b/src/Marketplace/lib.mo index 369a914..86c3b46 100644 --- a/src/Marketplace/lib.mo +++ b/src/Marketplace/lib.mo @@ -33,7 +33,7 @@ module { * STATE * *********/ - var _transactions : Buffer.Buffer = Buffer.Buffer(0); + var _transactions : Buffer.Buffer = Buffer.Buffer(0); var _tokenSettlement : TrieMap.TrieMap = TrieMap.TrieMap(ExtCore.TokenIndex.equal, ExtCore.TokenIndex.hash); var _tokenListing : TrieMap.TrieMap = TrieMap.TrieMap(ExtCore.TokenIndex.equal, ExtCore.TokenIndex.hash); @@ -56,29 +56,46 @@ module { }; if (chunkIndex == 0) { - return ?#v1({ + return ?#v2({ transactionCount = _transactions.size(); transactionChunk; tokenSettlement = Iter.toArray(_tokenSettlement.entries()); tokenListing = Iter.toArray(_tokenListing.entries()); - frontends = []; }); } else if (chunkIndex < getChunkCount(chunkSize)) { - return ?#v1_chunk({ transactionChunk }); + return ?#v2_chunk({ transactionChunk }); } else { null; }; }; public func loadStableChunk(chunk : Types.StableChunk) { + func txV1toV2(transaction : Types.Transaction) : Types.TransactionV2 { + { + transaction with + sellerFrontend = null; + buyerFrontend = null; + } + }; + switch (chunk) { + // v1 -> v2 case (?#v1(data)) { - _transactions := Buffer.Buffer(data.transactionCount); - _transactions.append(Buffer.fromArray(data.transactionChunk)); + _transactions := Buffer.Buffer(data.transactionCount); + _transactions.append(Buffer.fromArray(Array.map(data.transactionChunk, txV1toV2))); _tokenSettlement := TrieMap.fromEntries(data.tokenSettlement.vals(), ExtCore.TokenIndex.equal, ExtCore.TokenIndex.hash); _tokenListing := TrieMap.fromEntries(data.tokenListing.vals(), ExtCore.TokenIndex.equal, ExtCore.TokenIndex.hash); }; case (?#v1_chunk(data)) { + _transactions.append(Buffer.fromArray(Array.map(data.transactionChunk, txV1toV2))); + }; + case (?#v2(data)) { + _transactions := Buffer.Buffer(data.transactionCount); + _transactions.append(Buffer.fromArray(data.transactionChunk)); + _tokenSettlement := TrieMap.fromEntries(data.tokenSettlement.vals(), ExtCore.TokenIndex.equal, ExtCore.TokenIndex.hash); + _tokenListing := TrieMap.fromEntries(data.tokenListing.vals(), ExtCore.TokenIndex.equal, ExtCore.TokenIndex.hash); + }; + case (?#v2_chunk(data)) { _transactions.append(Buffer.fromArray(data.transactionChunk)); }; case (null) {}; @@ -95,6 +112,8 @@ module { price = fuzz.nat64.random(); buyer = fuzz.text.randomAlphanumeric(32); time = fuzz.int.randomRange(1670000000000000000, 2670000000000000000); + sellerFrontend = null; + buyerFrontend = null; }); }; @@ -286,6 +305,8 @@ module { price = settlement.price; buyer = settlement.buyer; time = Time.now(); + buyerFrontend = settlement.buyerFrontend; + sellerFrontend = settlement.sellerFrontend; }); _tokenListing.delete(token); _tokenSettlement.delete(token); @@ -379,7 +400,7 @@ module { }; }; - public func transactions() : [Types.Transaction] { + public func transactions() : [Types.TransactionV2] { Buffer.toArray(_transactions); }; @@ -412,10 +433,10 @@ module { }; public func stats() : (Nat64, Nat64, Nat64, Nat64, Nat, Nat, Nat) { - var res : (Nat64, Nat64, Nat64) = Array.foldLeft( + var res : (Nat64, Nat64, Nat64) = Array.foldLeft( Buffer.toArray(_transactions), (0, 0, 0), - func(b : (Nat64, Nat64, Nat64), a : Types.Transaction) : (Nat64, Nat64, Nat64) { + func(b : (Nat64, Nat64, Nat64), a : Types.TransactionV2) : (Nat64, Nat64, Nat64) { var total : Nat64 = b.0 + a.price; var high : Nat64 = b.1; var low : Nat64 = b.2; @@ -502,7 +523,7 @@ module { _transactions.size(); }; - public func getTransactions() : Buffer.Buffer { + public func getTransactions() : Buffer.Buffer { return _transactions; }; diff --git a/src/Marketplace/types.mo b/src/Marketplace/types.mo index 0d7f0c8..8f759f1 100644 --- a/src/Marketplace/types.mo +++ b/src/Marketplace/types.mo @@ -10,6 +10,7 @@ import Disburser "../Disburser"; module { public type StableChunk = ?{ + // v1 #v1: { transactionCount : Nat; transactionChunk : [Transaction]; @@ -20,6 +21,16 @@ module { #v1_chunk: { transactionChunk : [Transaction]; }; + // v2 + #v2: { + transactionCount : Nat; + transactionChunk : [TransactionV2]; + tokenSettlement : [(TokenIndex, Settlement)]; + tokenListing : [(TokenIndex, Listing)]; + }; + #v2_chunk: { + transactionChunk : [TransactionV2]; + }; }; public type Frontend = { @@ -41,6 +52,18 @@ module { price : Nat64; buyer : AccountIdentifier; time : Time; + sellerFrontend : ?Text; + buyerFrontend : ?Text; + }; + + public type TransactionV2 = { + token : TokenIdentifier; + seller : Principal; + price : Nat64; + buyer : AccountIdentifier; + time : Time; + sellerFrontend : ?Text; + buyerFrontend : ?Text; }; public type Settlement = { diff --git a/src/main.mo b/src/main.mo index 5b35657..6b6c036 100644 --- a/src/main.mo +++ b/src/main.mo @@ -494,7 +494,7 @@ shared ({ caller = init_minter }) actor class Canister(cid : Principal, initArgs _Marketplace.details(token); }; - public query func transactions() : async [MarketplaceTypes.Transaction] { + public query func transactions() : async [MarketplaceTypes.TransactionV2] { _Marketplace.transactions(); }; From 9ad8b83781dc49affc8eebae3fa7e433a5d87e5c Mon Sep 17 00:00:00 2001 From: ZenVoich Date: Tue, 11 Jul 2023 14:08:18 +0400 Subject: [PATCH 09/23] remove `bulkPricing` field; remove unused args from `reserve` --- declarations/main/staging.did | 6 +----- declarations/main/staging.did.d.ts | 6 +----- declarations/main/staging.did.js | 7 +------ package.json | 2 +- src/Sale/lib.mo | 7 +------ src/Sale/types.mo | 1 - src/main.mo | 4 ++-- test/backup-restore/backup-restore.test.ts | 4 ---- test/fees/0-fees.test.ts | 2 +- test/fees/1-different-frontends.test.ts | 8 ++++--- test/open-edition/open-edition.test.ts | 2 +- test/pending-sale/pending-sale.test.ts | 3 +-- test/public-sale/public-sale.test.ts | 2 +- test/utils.ts | 2 +- test/whitelist-slots/whitelist-slots.test.ts | 22 +++++++++++++++----- 15 files changed, 34 insertions(+), 44 deletions(-) diff --git a/declarations/main/staging.did b/declarations/main/staging.did index 02ebbb8..bc38f42 100644 --- a/declarations/main/staging.did +++ b/declarations/main/staging.did @@ -234,10 +234,6 @@ type SaleTransaction = }; type SaleSettings = record { - bulkPricing: vec record { - nat64; - nat64; - }; endTime: Time__2; openEdition: bool; price: nat64; @@ -683,7 +679,7 @@ type Canister = disbursements: nat; failedSettlements: nat; }) query; - reserve: (nat64, nat64, AccountIdentifier__5, SubAccount__1) -> (Result_5); + reserve: (AccountIdentifier__5) -> (Result_5); restoreChunk: (StableChunk) -> (); retrieve: (AccountIdentifier__5) -> (Result_4); saleTransactions: () -> (vec SaleTransaction) query; diff --git a/declarations/main/staging.did.d.ts b/declarations/main/staging.did.d.ts index 639e749..d75a495 100644 --- a/declarations/main/staging.did.d.ts +++ b/declarations/main/staging.did.d.ts @@ -84,10 +84,7 @@ export interface Canister { [], { 'failedSettlements' : bigint, 'disbursements' : bigint } >, - 'reserve' : ActorMethod< - [bigint, bigint, AccountIdentifier__5, SubAccount__1], - Result_5 - >, + 'reserve' : ActorMethod<[AccountIdentifier__5], Result_5>, 'restoreChunk' : ActorMethod<[StableChunk], undefined>, 'retrieve' : ActorMethod<[AccountIdentifier__5], Result_4>, 'saleTransactions' : ActorMethod<[], Array>, @@ -369,7 +366,6 @@ export interface SaleSettings { 'endTime' : Time__2, 'totalToSell' : bigint, 'sold' : bigint, - 'bulkPricing' : Array<[bigint, bigint]>, 'whitelistTime' : Time__2, 'salePrice' : bigint, 'remaining' : bigint, diff --git a/declarations/main/staging.did.js b/declarations/main/staging.did.js index 4efcb26..1f56c6d 100644 --- a/declarations/main/staging.did.js +++ b/declarations/main/staging.did.js @@ -463,7 +463,6 @@ export const idlFactory = ({ IDL }) => { 'endTime' : Time__2, 'totalToSell' : IDL.Nat, 'sold' : IDL.Nat, - 'bulkPricing' : IDL.Vec(IDL.Tuple(IDL.Nat64, IDL.Nat64)), 'whitelistTime' : Time__2, 'salePrice' : IDL.Nat64, 'remaining' : IDL.Nat, @@ -599,11 +598,7 @@ export const idlFactory = ({ IDL }) => { ], ['query'], ), - 'reserve' : IDL.Func( - [IDL.Nat64, IDL.Nat64, AccountIdentifier__5, SubAccount__1], - [Result_5], - [], - ), + 'reserve' : IDL.Func([AccountIdentifier__5], [Result_5], []), 'restoreChunk' : IDL.Func([StableChunk], [], []), 'retrieve' : IDL.Func([AccountIdentifier__5], [Result_4], []), 'saleTransactions' : IDL.Func([], [IDL.Vec(SaleTransaction)], ['query']), diff --git a/package.json b/package.json index 6398fe2..f51aa4a 100644 --- a/package.json +++ b/package.json @@ -25,7 +25,7 @@ "vitest": "vitest run --threads false --isolate false", "vitest:watch": "vitest watch", "env": "ts-node ./test/apply-env.ts", - "test": "dfx build staging && vitest run --threads false --isolate false --reporter verbose", + "test": "dfx build staging && vitest run --threads false --isolate false --reporter verbose --bail 1", "backup": "ts-node ./backup/backup.ts", "restore": "ts-node ./backup/restore.ts", "test-br": "npm run deploy-test && ts-node ./backup/test.ts", diff --git a/src/Sale/lib.mo b/src/Sale/lib.mo index 69d137f..c90524b 100644 --- a/src/Sale/lib.mo +++ b/src/Sale/lib.mo @@ -196,7 +196,7 @@ module { _tokensForSale.size(); }; - public func reserve(amount : Nat64, address : Types.AccountIdentifier) : Result.Result<(Types.AccountIdentifier, Nat64), Text> { + public func reserve(address : Types.AccountIdentifier) : Result.Result<(Types.AccountIdentifier, Nat64), Text> { switch (config.sale) { case (#duration(duration)) { if (Time.now() > config.publicSaleStart + Utils.toNanos(duration)) { @@ -225,10 +225,6 @@ module { let subaccount = getNextSubAccount(); let paymentAddress : Types.AccountIdentifier = AID.fromPrincipal(config.canister, ?subaccount); - if (amount != price) { - return #err("Price mismatch!"); - }; - // we only reserve the tokens here, they deducted from the available tokens // after payment. otherwise someone could stall the sale by reserving all // the tokens without paying for them @@ -491,7 +487,6 @@ module { endTime = endTime; whitelistTime = config.publicSaleStart; whitelist = isWhitelisted(address); - bulkPricing = [(1, getAddressPrice(address))]; openEdition = openEdition; } : Types.SaleSettings; }; diff --git a/src/Sale/types.mo b/src/Sale/types.mo index 70e03a4..88b5f03 100644 --- a/src/Sale/types.mo +++ b/src/Sale/types.mo @@ -102,7 +102,6 @@ module { whitelistTime : Time; whitelist : Bool; totalToSell : Nat; - bulkPricing : [(Nat64, Nat64)]; // always [(1, )] openEdition : Bool; }; }; diff --git a/src/main.mo b/src/main.mo index bd974b4..759c22f 100644 --- a/src/main.mo +++ b/src/main.mo @@ -394,10 +394,10 @@ shared ({ caller = init_minter }) actor class Canister(cid : Principal, initArgs _Sale.enableSale(caller); }; - public func reserve(amount : Nat64, quantityNOTUSED : Nat64, address : SaleTypes.AccountIdentifier, _subaccountNOTUSED : SaleTypes.SubAccount) : async Result.Result<(SaleTypes.AccountIdentifier, Nat64), Text> { + public func reserve(address : SaleTypes.AccountIdentifier) : async Result.Result<(SaleTypes.AccountIdentifier, Nat64), Text> { _trapIfRestoreEnabled(); canistergeekMonitor.collectMetrics(); - _Sale.reserve(amount, address); + _Sale.reserve(address); }; public shared ({ caller }) func retrieve(paymentaddress : SaleTypes.AccountIdentifier) : async Result.Result<(), Text> { diff --git a/test/backup-restore/backup-restore.test.ts b/test/backup-restore/backup-restore.test.ts index 88ac7f4..50a9d57 100644 --- a/test/backup-restore/backup-restore.test.ts +++ b/test/backup-restore/backup-restore.test.ts @@ -15,10 +15,6 @@ describe('backup', () => { let chunkSize = 1500n; let user = new User(''); - it('apply env', async () => { - await applyEnv('restore'); - }); - it('try to restore with restoreEnabled = false', async () => { await expect(user.mainActor.restoreChunk({v1: { marketplace: [], diff --git a/test/fees/0-fees.test.ts b/test/fees/0-fees.test.ts index 4596768..be3266b 100644 --- a/test/fees/0-fees.test.ts +++ b/test/fees/0-fees.test.ts @@ -32,7 +32,7 @@ describe('sale and royalty fees', () => { it('buy from sale', async () => { let settings = await seller.mainActor.salesSettings(seller.accountId); - let res = await seller.mainActor.reserve(settings.price, 1n, seller.accountId, new Uint8Array); + let res = await seller.mainActor.reserve(seller.accountId); expect(res).toHaveProperty('ok'); diff --git a/test/fees/1-different-frontends.test.ts b/test/fees/1-different-frontends.test.ts index 2df44a8..11988fc 100644 --- a/test/fees/1-different-frontends.test.ts +++ b/test/fees/1-different-frontends.test.ts @@ -18,10 +18,12 @@ describe('list and buy on different marketplace frontends', async () => { let jellyFee = env.marketplace2_fee; let seller = new User; - await seller.mintICP(initialBalance); - let buyer = new User; - await buyer.mintICP(initialBalance); + + it('mint ICP', async () => { + await seller.mintICP(initialBalance); + await buyer.mintICP(initialBalance); + }); it('buy from sale', async () => { await buyFromSale(seller); diff --git a/test/open-edition/open-edition.test.ts b/test/open-edition/open-edition.test.ts index 7f45fa1..c7f7c5d 100644 --- a/test/open-edition/open-edition.test.ts +++ b/test/open-edition/open-edition.test.ts @@ -30,7 +30,7 @@ describe('open edition', () => { test('try to buy when sale ended', async () => { let user = new User; let settings = await user.mainActor.salesSettings(user.accountId); - let res = await user.mainActor.reserve(settings.price, 1n, user.accountId, new Uint8Array); + let res = await user.mainActor.reserve(user.accountId); expect(res).toHaveProperty('err'); expect(res['err']).toContain('sale has ended'); }); diff --git a/test/pending-sale/pending-sale.test.ts b/test/pending-sale/pending-sale.test.ts index 4306a28..9681f40 100644 --- a/test/pending-sale/pending-sale.test.ts +++ b/test/pending-sale/pending-sale.test.ts @@ -15,7 +15,6 @@ describe('pending sale', () => { expect(res.startTime).toBe(env.whitelistSlot1_start); expect(res.whitelistTime).toBe(env.publicSaleStart); expect(res.whitelist).toBe(false); - expect(res.bulkPricing).toEqual([[1n, env.salePrice]]); }); test('check salesSettings price for whitelistTier0 address', async () => { @@ -57,7 +56,7 @@ describe('pending sale', () => { test('try to reserve token', async () => { let user = new User; - let res = await user.mainActor.reserve(1_000_000n, 1n, user.accountId, new Uint8Array); + let res = await user.mainActor.reserve(user.accountId); expect(res['err']).toContain('sale has not started'); }); }); \ No newline at end of file diff --git a/test/public-sale/public-sale.test.ts b/test/public-sale/public-sale.test.ts index e9cdc64..880e5f9 100644 --- a/test/public-sale/public-sale.test.ts +++ b/test/public-sale/public-sale.test.ts @@ -21,7 +21,7 @@ describe('public sale', () => { await user.mintICP(1000_000_000n); let settings = await user.mainActor.salesSettings(user.accountId); - let res = await user.mainActor.reserve(settings.price, 1n, user.accountId, new Uint8Array); + let res = await user.mainActor.reserve(user.accountId); expect(res).toHaveProperty('ok'); diff --git a/test/utils.ts b/test/utils.ts index 0a705ec..758237c 100644 --- a/test/utils.ts +++ b/test/utils.ts @@ -19,7 +19,7 @@ export function applyFees(amount: bigint, fees: bigint[]) { export async function buyFromSale(user: User) { let settings = await user.mainActor.salesSettings(user.accountId); - let res = await user.mainActor.reserve(settings.price, 1n, user.accountId, new Uint8Array); + let res = await user.mainActor.reserve(user.accountId); expect(res).toHaveProperty('ok'); diff --git a/test/whitelist-slots/whitelist-slots.test.ts b/test/whitelist-slots/whitelist-slots.test.ts index bd151c9..134e2de 100644 --- a/test/whitelist-slots/whitelist-slots.test.ts +++ b/test/whitelist-slots/whitelist-slots.test.ts @@ -59,7 +59,7 @@ describe('whitelist slot 1', () => { let user = lucky[3]; let settings = await user.mainActor.salesSettings(user.accountId); - let res = await user.mainActor.reserve(settings.price, 1n, user.accountId, new Uint8Array); + let res = await user.mainActor.reserve(user.accountId); expect(res).toHaveProperty('err'); }); @@ -67,7 +67,7 @@ describe('whitelist slot 1', () => { test('user from slot 2 try to buy during slot 1', async () => { let user = whitelistTier1[0]; - let res = await user.mainActor.reserve(env.whitelistTier0Price, 1n, user.accountId, new Uint8Array); + let res = await user.mainActor.reserve(user.accountId); expect(res).toHaveProperty('err'); }); }); @@ -93,7 +93,7 @@ describe('whitelist slot 2', () => { let settings = await user.mainActor.salesSettings(user.accountId); expect(settings.price).toBe(env.salePrice); - let res = await user.mainActor.reserve(env.whitelistTier0Price, 1n, user.accountId, new Uint8Array); + let res = await user.mainActor.reserve(user.accountId); expect(res).toHaveProperty('err'); }); @@ -113,8 +113,20 @@ describe('whitelist slot 2', () => { await user.mintICP(100_000_000_000n); // try to buy at tier 1 price - let res = await user.mainActor.reserve(env.whitelistTier0Price, 1n, user.accountId, new Uint8Array); - expect(res).toHaveProperty('err'); + let res = await user.mainActor.reserve(user.accountId); + expect(res).toHaveProperty('ok'); + + if ('ok' in res) { + let paymentAddress = res.ok[0]; + let paymentAmount = res.ok[1]; + expect(paymentAddress.length).toBe(64); + expect(paymentAmount).toBe(env.whitelistTier0Price); + + await user.sendICP(paymentAddress, paymentAmount - 1n); + let retrieveRes = await user.mainActor.retrieve(paymentAddress); + expect(retrieveRes).toHaveProperty('err'); + expect(retrieveRes['err']).toMatch(/Insufficient funds/i); + } // should be tier 2 price let settings = await user.mainActor.salesSettings(user.accountId); From 7fbe2ae520bd932ee8834a88ebe7898ad26a2c84 Mon Sep 17 00:00:00 2001 From: ZenVoich Date: Tue, 11 Jul 2023 14:13:18 +0400 Subject: [PATCH 10/23] update declarations --- declarations/main/staging.did | 28 +++++++++++++++++++++++++++- declarations/main/staging.did.d.ts | 24 ++++++++++++++++++++++-- declarations/main/staging.did.js | 20 +++++++++++++++++++- 3 files changed, 68 insertions(+), 4 deletions(-) diff --git a/declarations/main/staging.did b/declarations/main/staging.did index 02ebbb8..e58a637 100644 --- a/declarations/main/staging.did +++ b/declarations/main/staging.did @@ -44,11 +44,23 @@ type TransferRequest = to: User; token: TokenIdentifier; }; +type TransactionV2 = + record { + buyer: AccountIdentifier__2; + buyerFrontend: opt text; + price: nat64; + seller: principal; + sellerFrontend: opt text; + time: Time__1; + token: TokenIdentifier__1; + }; type Transaction = record { buyer: AccountIdentifier__2; + buyerFrontend: opt text; price: nat64; seller: principal; + sellerFrontend: opt text; time: Time__1; token: TokenIdentifier__1; }; @@ -176,6 +188,20 @@ type StableChunk__3 = transactionCount: nat; }; v1_chunk: record {transactionChunk: vec Transaction;}; + v2: + record { + tokenListing: vec record { + TokenIndex__1; + Listing; + }; + tokenSettlement: vec record { + TokenIndex__1; + Settlement; + }; + transactionChunk: vec TransactionV2; + transactionCount: nat; + }; + v2_chunk: record {transactionChunk: vec TransactionV2;}; }; type StableChunk__2 = opt variant { @@ -706,7 +732,7 @@ type Canister = toAccountIdentifier: (text, nat) -> (AccountIdentifier__4) query; tokens: (AccountIdentifier__3) -> (Result_1) query; tokens_ext: (AccountIdentifier__3) -> (Result) query; - transactions: () -> (vec Transaction) query; + transactions: () -> (vec TransactionV2) query; transfer: (TransferRequest) -> (TransferResponse); updateCanistergeekInformation: (UpdateInformationRequest) -> (); updateThumb: (text, File) -> (opt nat); diff --git a/declarations/main/staging.did.d.ts b/declarations/main/staging.did.d.ts index 639e749..caa703c 100644 --- a/declarations/main/staging.did.d.ts +++ b/declarations/main/staging.did.d.ts @@ -111,7 +111,7 @@ export interface Canister { 'toAccountIdentifier' : ActorMethod<[string, bigint], AccountIdentifier__4>, 'tokens' : ActorMethod<[AccountIdentifier__3], Result_1>, 'tokens_ext' : ActorMethod<[AccountIdentifier__3], Result>, - 'transactions' : ActorMethod<[], Array>, + 'transactions' : ActorMethod<[], Array>, 'transfer' : ActorMethod<[TransferRequest], TransferResponse>, 'updateCanistergeekInformation' : ActorMethod< [UpdateInformationRequest], @@ -434,7 +434,16 @@ export type StableChunk__3 = [] | [ 'transactionCount' : bigint, } } | - { 'v1_chunk' : { 'transactionChunk' : Array } } + { + 'v2' : { + 'tokenSettlement' : Array<[TokenIndex__1, Settlement]>, + 'tokenListing' : Array<[TokenIndex__1, Listing]>, + 'transactionChunk' : Array, + 'transactionCount' : bigint, + } + } | + { 'v1_chunk' : { 'transactionChunk' : Array } } | + { 'v2_chunk' : { 'transactionChunk' : Array } } ]; export type StableChunk__4 = [] | [ { @@ -507,9 +516,20 @@ export type TokenIndex__2 = number; export type TokenIndex__3 = number; export type TokenIndex__4 = number; export interface Transaction { + 'sellerFrontend' : [] | [string], 'token' : TokenIdentifier__1, 'time' : Time__1, 'seller' : Principal, + 'buyerFrontend' : [] | [string], + 'buyer' : AccountIdentifier__2, + 'price' : bigint, +} +export interface TransactionV2 { + 'sellerFrontend' : [] | [string], + 'token' : TokenIdentifier__1, + 'time' : Time__1, + 'seller' : Principal, + 'buyerFrontend' : [] | [string], 'buyer' : AccountIdentifier__2, 'price' : bigint, } diff --git a/declarations/main/staging.did.js b/declarations/main/staging.did.js index 4efcb26..56d5588 100644 --- a/declarations/main/staging.did.js +++ b/declarations/main/staging.did.js @@ -85,9 +85,20 @@ export const idlFactory = ({ IDL }) => { }); const TokenIdentifier__1 = IDL.Text; const Transaction = IDL.Record({ + 'sellerFrontend' : IDL.Opt(IDL.Text), 'token' : TokenIdentifier__1, 'time' : Time__1, 'seller' : IDL.Principal, + 'buyerFrontend' : IDL.Opt(IDL.Text), + 'buyer' : AccountIdentifier__2, + 'price' : IDL.Nat64, + }); + const TransactionV2 = IDL.Record({ + 'sellerFrontend' : IDL.Opt(IDL.Text), + 'token' : TokenIdentifier__1, + 'time' : Time__1, + 'seller' : IDL.Principal, + 'buyerFrontend' : IDL.Opt(IDL.Text), 'buyer' : AccountIdentifier__2, 'price' : IDL.Nat64, }); @@ -100,7 +111,14 @@ export const idlFactory = ({ IDL }) => { 'transactionChunk' : IDL.Vec(Transaction), 'transactionCount' : IDL.Nat, }), + 'v2' : IDL.Record({ + 'tokenSettlement' : IDL.Vec(IDL.Tuple(TokenIndex__1, Settlement)), + 'tokenListing' : IDL.Vec(IDL.Tuple(TokenIndex__1, Listing)), + 'transactionChunk' : IDL.Vec(TransactionV2), + 'transactionCount' : IDL.Nat, + }), 'v1_chunk' : IDL.Record({ 'transactionChunk' : IDL.Vec(Transaction) }), + 'v2_chunk' : IDL.Record({ 'transactionChunk' : IDL.Vec(TransactionV2) }), }) ); const Asset = IDL.Record({ @@ -638,7 +656,7 @@ export const idlFactory = ({ IDL }) => { ), 'tokens' : IDL.Func([AccountIdentifier__3], [Result_1], ['query']), 'tokens_ext' : IDL.Func([AccountIdentifier__3], [Result], ['query']), - 'transactions' : IDL.Func([], [IDL.Vec(Transaction)], ['query']), + 'transactions' : IDL.Func([], [IDL.Vec(TransactionV2)], ['query']), 'transfer' : IDL.Func([TransferRequest], [TransferResponse], []), 'updateCanistergeekInformation' : IDL.Func( [UpdateInformationRequest], From 1ed5725adeb908e3ce3cb5faec52a04b65d78d31 Mon Sep 17 00:00:00 2001 From: ZenVoich Date: Tue, 11 Jul 2023 14:17:41 +0400 Subject: [PATCH 11/23] fix whitelist-slots e2e test --- test/whitelist-slots/whitelist-slots.test.ts | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/test/whitelist-slots/whitelist-slots.test.ts b/test/whitelist-slots/whitelist-slots.test.ts index 134e2de..970b7fb 100644 --- a/test/whitelist-slots/whitelist-slots.test.ts +++ b/test/whitelist-slots/whitelist-slots.test.ts @@ -108,7 +108,7 @@ describe('whitelist slot 2', () => { await buyFromSale(user); }); - test('user from both tiers did not buy during slot 1 and should be able to buy during slot 2 at tier 2 price', async () => { + test('user from both tiers did not buy during slot 1 try to buy at tier 1 price during slot 2', async () => { let user = lucky[5]; await user.mintICP(100_000_000_000n); @@ -127,6 +127,11 @@ describe('whitelist slot 2', () => { expect(retrieveRes).toHaveProperty('err'); expect(retrieveRes['err']).toMatch(/Insufficient funds/i); } + }); + + test('user from both tiers did not buy during slot 1 and should be able to buy during slot 2 at tier 2 price', async () => { + let user = lucky[6]; + await user.mintICP(100_000_000_000n); // should be tier 2 price let settings = await user.mainActor.salesSettings(user.accountId); From be44969f802485a81c3aa72c4a3e541523a3780e Mon Sep 17 00:00:00 2001 From: ZenVoich Date: Wed, 12 Jul 2023 15:36:08 +0400 Subject: [PATCH 12/23] fix whitelist-slots e2e test --- test/whitelist-slots/whitelist-slots.test.ts | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/test/whitelist-slots/whitelist-slots.test.ts b/test/whitelist-slots/whitelist-slots.test.ts index 970b7fb..7adcd4a 100644 --- a/test/whitelist-slots/whitelist-slots.test.ts +++ b/test/whitelist-slots/whitelist-slots.test.ts @@ -118,11 +118,8 @@ describe('whitelist slot 2', () => { if ('ok' in res) { let paymentAddress = res.ok[0]; - let paymentAmount = res.ok[1]; - expect(paymentAddress.length).toBe(64); - expect(paymentAmount).toBe(env.whitelistTier0Price); - await user.sendICP(paymentAddress, paymentAmount - 1n); + await user.sendICP(paymentAddress, env.whitelistTier0Price); let retrieveRes = await user.mainActor.retrieve(paymentAddress); expect(retrieveRes).toHaveProperty('err'); expect(retrieveRes['err']).toMatch(/Insufficient funds/i); From 461fc856c4d592aa5ba865f3739862107a49f95e Mon Sep 17 00:00:00 2001 From: ZenVoich Date: Wed, 12 Jul 2023 16:37:37 +0400 Subject: [PATCH 13/23] add mops; add unit tests for Utils.shuffleBuffer --- .github/workflows/test.yml | 2 + .gitignore | 3 +- README.md | 16 ++++-- mops.toml | 10 ++++ package.json | 8 ++- test/{ => e2e}/apply-env.ts | 0 .../backup-assets/backup-assets.test.ts | 2 +- test/{ => e2e}/backup-assets/env.ts | 0 .../backup-restore/backup-restore.test.ts | 2 +- test/{ => e2e}/backup-restore/env.ts | 0 test/{ => e2e}/consts.ts | 0 test/{ => e2e}/create-agent.ts | 0 test/{ => e2e}/default-env.ts | 0 test/{ => e2e}/fees/0-fees.test.ts | 0 .../fees/1-different-frontends.test.ts | 0 test/{ => e2e}/fees/env.ts | 0 test/{ => e2e}/generate-identity.ts | 0 test/{ => e2e}/highload-sale/env.ts | 0 .../highload-sale/highload-sale.test.ts | 0 test/{ => e2e}/initArgs.template.did | 0 test/{ => e2e}/marketplace/env.ts | 0 .../{ => e2e}/marketplace/list-delist.test.ts | 0 .../marketplace/list-lock-delist.test.ts | 0 ...tplace-buy-with-insufficient-funds.test.ts | 0 .../marketplace/marketplace-buy.test.ts | 0 .../{ => e2e}/marketplace/marketplace.test.ts | 0 test/{ => e2e}/multi-asset/env.ts | 0 .../{ => e2e}/multi-asset/multi-asset.test.ts | 0 test/{ => e2e}/open-edition/env.ts | 0 .../open-edition/open-edition.test.ts | 0 test/{ => e2e}/pending-sale/access.test.ts | 0 test/{ => e2e}/pending-sale/env.ts | 0 .../pending-sale/pending-sale.test.ts | 0 test/{ => e2e}/public-sale/env.ts | 0 .../{ => e2e}/public-sale/public-sale.test.ts | 0 test/{ => e2e}/restore/env.ts | 0 test/{ => e2e}/setup.ts | 0 .../single-asset-delayed-reveal/env.ts | 0 .../single-asset-delayed-reveal.test.ts | 0 test/{ => e2e}/single-asset/env.ts | 0 .../single-asset/single-asset.test.ts | 0 test/{ => e2e}/sold-out/env.ts | 0 test/{ => e2e}/sold-out/sold-out.test.ts | 0 test/{ => e2e}/user.ts | 10 ++-- test/{ => e2e}/utils.ts | 2 +- test/{ => e2e}/well-known-users.ts | 0 test/{ => e2e}/whitelist-sale/env.ts | 0 .../whitelist-sale/whitelist-sale.test.ts | 0 test/{ => e2e}/whitelist-slots/env.ts | 0 .../whitelist-slots/whitelist-slots.test.ts | 0 test/unit/shuffleBuffer.test.mo | 55 +++++++++++++++++++ vite.config.ts | 4 +- 52 files changed, 95 insertions(+), 19 deletions(-) create mode 100644 mops.toml rename test/{ => e2e}/apply-env.ts (100%) rename test/{ => e2e}/backup-assets/backup-assets.test.ts (97%) rename test/{ => e2e}/backup-assets/env.ts (100%) rename test/{ => e2e}/backup-restore/backup-restore.test.ts (97%) rename test/{ => e2e}/backup-restore/env.ts (100%) rename test/{ => e2e}/consts.ts (100%) rename test/{ => e2e}/create-agent.ts (100%) rename test/{ => e2e}/default-env.ts (100%) rename test/{ => e2e}/fees/0-fees.test.ts (100%) rename test/{ => e2e}/fees/1-different-frontends.test.ts (100%) rename test/{ => e2e}/fees/env.ts (100%) rename test/{ => e2e}/generate-identity.ts (100%) rename test/{ => e2e}/highload-sale/env.ts (100%) rename test/{ => e2e}/highload-sale/highload-sale.test.ts (100%) rename test/{ => e2e}/initArgs.template.did (100%) rename test/{ => e2e}/marketplace/env.ts (100%) rename test/{ => e2e}/marketplace/list-delist.test.ts (100%) rename test/{ => e2e}/marketplace/list-lock-delist.test.ts (100%) rename test/{ => e2e}/marketplace/marketplace-buy-with-insufficient-funds.test.ts (100%) rename test/{ => e2e}/marketplace/marketplace-buy.test.ts (100%) rename test/{ => e2e}/marketplace/marketplace.test.ts (100%) rename test/{ => e2e}/multi-asset/env.ts (100%) rename test/{ => e2e}/multi-asset/multi-asset.test.ts (100%) rename test/{ => e2e}/open-edition/env.ts (100%) rename test/{ => e2e}/open-edition/open-edition.test.ts (100%) rename test/{ => e2e}/pending-sale/access.test.ts (100%) rename test/{ => e2e}/pending-sale/env.ts (100%) rename test/{ => e2e}/pending-sale/pending-sale.test.ts (100%) rename test/{ => e2e}/public-sale/env.ts (100%) rename test/{ => e2e}/public-sale/public-sale.test.ts (100%) rename test/{ => e2e}/restore/env.ts (100%) rename test/{ => e2e}/setup.ts (100%) rename test/{ => e2e}/single-asset-delayed-reveal/env.ts (100%) rename test/{ => e2e}/single-asset-delayed-reveal/single-asset-delayed-reveal.test.ts (100%) rename test/{ => e2e}/single-asset/env.ts (100%) rename test/{ => e2e}/single-asset/single-asset.test.ts (100%) rename test/{ => e2e}/sold-out/env.ts (100%) rename test/{ => e2e}/sold-out/sold-out.test.ts (100%) rename test/{ => e2e}/user.ts (83%) rename test/{ => e2e}/utils.ts (97%) rename test/{ => e2e}/well-known-users.ts (100%) rename test/{ => e2e}/whitelist-sale/env.ts (100%) rename test/{ => e2e}/whitelist-sale/whitelist-sale.test.ts (100%) rename test/{ => e2e}/whitelist-slots/env.ts (100%) rename test/{ => e2e}/whitelist-slots/whitelist-slots.test.ts (100%) create mode 100644 test/unit/shuffleBuffer.test.mo diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 265b953..141a74e 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -19,6 +19,8 @@ jobs: with: vessel-version: 0.6.3 dfx-version: 0.14.1 + - name: install mops + run: npm i -g ic-mops - name: test run: | dfx identity use anonymous diff --git a/.gitignore b/.gitignore index 83a4976..b0f000c 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,6 @@ .dfx .vessel +.mops *.pem .venv registry.json @@ -7,7 +8,7 @@ tokens.json __pycache__ node_modules backup/data/* -test/initArgs.did +test/e2e/initArgs.did # remove or comment out the lines below in your forked NFT collection repository initArgs.did diff --git a/README.md b/README.md index ffb3d08..9deae53 100644 --- a/README.md +++ b/README.md @@ -152,19 +152,25 @@ First, start a local replica npm run replica ``` -To deploy and run all tests +Deploy and run all unit and e2e tests ``` npm run test ``` -To deploy and run specific tests +Run only unit tests ``` -npm run test pending-sale +npm run test:unit ``` -To run tests without deployment (useful when writing tests) +Deploy and run specific e2e tests + +``` +npm run test:e2e pending-sale +``` + +Run tests without deployment (useful when writing tests) ``` npm run vitest @@ -176,7 +182,7 @@ or npm run vitest:watch ``` -or to run specific test suite +or run specific test suite ``` npm run vitest pending-sale diff --git a/mops.toml b/mops.toml new file mode 100644 index 0000000..d5e4988 --- /dev/null +++ b/mops.toml @@ -0,0 +1,10 @@ +# used only for unit testing +[dependencies] +base = "0.9.3" +cap = "https://github.com/Psychedelic/cap-motoko-library#v1.0.4" +accountid = "https://github.com/aviate-labs/principal.mo#v0.2.6" +canistergeek = "https://github.com/usergeek/canistergeek-ic-motoko#v0.0.7" + +[dev-dependencies] +test = "1.0.1" +fuzz = "0.1.0" \ No newline at end of file diff --git a/package.json b/package.json index 6398fe2..6615ee7 100644 --- a/package.json +++ b/package.json @@ -12,7 +12,7 @@ "deploy-test": "npm run reinstall:ledger -- -qq && npm run reinstall:test -- -qq", "deploy:staging": "dfx canister create staging && DFX_MOC_PATH=\"$(vessel bin)/moc\" dfx deploy staging --argument \"$(cat initArgs.local.did)\"", "reinstall:staging": "dfx canister create staging && DFX_MOC_PATH=\"$(vessel bin)/moc\" dfx deploy staging --mode reinstall -y --argument \"$(cat initArgs.local.did)\"", - "reinstall:test": "DFX_MOC_PATH=\"$(vessel bin)/moc\" dfx deploy test --mode reinstall -y --argument \"$(cat test/initArgs.did)\"", + "reinstall:test": "DFX_MOC_PATH=\"$(vessel bin)/moc\" dfx deploy test --mode reinstall -y --argument \"$(cat test/e2e/initArgs.did)\"", "upgrade:staging": "dfx canister stop staging && DFX_MOC_PATH=\"$(vessel bin)/moc\" dfx deploy staging --upgrade-unchanged --argument \"$(cat initArgs.local.did)\" && dfx canister start staging", "deploy:ledger": "npm run private-dids && dfx canister create ledger && DFX_MOC_PATH=\"$(vessel bin)/moc\" dfx deploy ledger --argument '(record {minting_account = \"e82226d3101bd8525111e2c6501a79365f2484d82d3f2be96269b78fe200eeaa\"; initial_values = vec { record { \"'${WALLET_ADDRESS:-8b61ff722d7e6321eb99bb607ab0cf323b3c64b43d6a13c245c8a4e197f7b38b}'\"; record { e8s=1_000_000_000_000_000 } }; }; send_whitelist = vec {}})' && npm run public-dids", "reinstall:ledger": "npm run private-dids && dfx canister create ledger && DFX_MOC_PATH=\"$(vessel bin)/moc\" dfx deploy ledger --mode reinstall -y --argument '(record {minting_account = \"e82226d3101bd8525111e2c6501a79365f2484d82d3f2be96269b78fe200eeaa\"; initial_values = vec { record { \"'${WALLET_ADDRESS:-8b61ff722d7e6321eb99bb607ab0cf323b3c64b43d6a13c245c8a4e197f7b38b}'\"; record { e8s=1_000_000_000_000_000 } }; }; send_whitelist = vec {}})' && npm run public-dids", @@ -24,8 +24,10 @@ "mint:test-2": "dfx canister call test addAsset '(record {name = \"privat0\";payload = record {ctype = \"text/html\"; data = vec {blob \"hello world0!\"} } })' && dfx canister call test addAsset '(record {name = \"privat1\";payload = record {ctype = \"text/html\"; data = vec {blob \"hello world1!\"} } })' && dfx canister call test initMint && dfx canister call test shuffleTokensForSale && dfx canister call test enableSale", "vitest": "vitest run --threads false --isolate false", "vitest:watch": "vitest watch", - "env": "ts-node ./test/apply-env.ts", - "test": "dfx build staging && vitest run --threads false --isolate false --reporter verbose", + "env": "ts-node ./test/e2e/apply-env.ts", + "test:e2e": "dfx build staging && vitest run --threads false --isolate false --reporter verbose", + "test:unit": "mops test", + "test": "npm run test:unit && npm run test:e2e", "backup": "ts-node ./backup/backup.ts", "restore": "ts-node ./backup/restore.ts", "test-br": "npm run deploy-test && ts-node ./backup/test.ts", diff --git a/test/apply-env.ts b/test/e2e/apply-env.ts similarity index 100% rename from test/apply-env.ts rename to test/e2e/apply-env.ts diff --git a/test/backup-assets/backup-assets.test.ts b/test/e2e/backup-assets/backup-assets.test.ts similarity index 97% rename from test/backup-assets/backup-assets.test.ts rename to test/e2e/backup-assets/backup-assets.test.ts index ca02255..a093ed6 100644 --- a/test/backup-assets/backup-assets.test.ts +++ b/test/e2e/backup-assets/backup-assets.test.ts @@ -5,7 +5,7 @@ import { readFileSync } from 'fs'; import { User } from '../user'; import { applyEnv } from '../apply-env'; -import canisterIds from '../../.dfx/local/canister_ids.json'; +import canisterIds from '../../../.dfx/local/canister_ids.json'; let canisterId = canisterIds.test.local; diff --git a/test/backup-assets/env.ts b/test/e2e/backup-assets/env.ts similarity index 100% rename from test/backup-assets/env.ts rename to test/e2e/backup-assets/env.ts diff --git a/test/backup-restore/backup-restore.test.ts b/test/e2e/backup-restore/backup-restore.test.ts similarity index 97% rename from test/backup-restore/backup-restore.test.ts rename to test/e2e/backup-restore/backup-restore.test.ts index 88ac7f4..409a118 100644 --- a/test/backup-restore/backup-restore.test.ts +++ b/test/e2e/backup-restore/backup-restore.test.ts @@ -5,7 +5,7 @@ import { readFileSync } from 'fs'; import { User } from '../user'; import { applyEnv } from '../apply-env'; -import canisterIds from '../../.dfx/local/canister_ids.json'; +import canisterIds from '../../../.dfx/local/canister_ids.json'; let canisterId = canisterIds.test.local; diff --git a/test/backup-restore/env.ts b/test/e2e/backup-restore/env.ts similarity index 100% rename from test/backup-restore/env.ts rename to test/e2e/backup-restore/env.ts diff --git a/test/consts.ts b/test/e2e/consts.ts similarity index 100% rename from test/consts.ts rename to test/e2e/consts.ts diff --git a/test/create-agent.ts b/test/e2e/create-agent.ts similarity index 100% rename from test/create-agent.ts rename to test/e2e/create-agent.ts diff --git a/test/default-env.ts b/test/e2e/default-env.ts similarity index 100% rename from test/default-env.ts rename to test/e2e/default-env.ts diff --git a/test/fees/0-fees.test.ts b/test/e2e/fees/0-fees.test.ts similarity index 100% rename from test/fees/0-fees.test.ts rename to test/e2e/fees/0-fees.test.ts diff --git a/test/fees/1-different-frontends.test.ts b/test/e2e/fees/1-different-frontends.test.ts similarity index 100% rename from test/fees/1-different-frontends.test.ts rename to test/e2e/fees/1-different-frontends.test.ts diff --git a/test/fees/env.ts b/test/e2e/fees/env.ts similarity index 100% rename from test/fees/env.ts rename to test/e2e/fees/env.ts diff --git a/test/generate-identity.ts b/test/e2e/generate-identity.ts similarity index 100% rename from test/generate-identity.ts rename to test/e2e/generate-identity.ts diff --git a/test/highload-sale/env.ts b/test/e2e/highload-sale/env.ts similarity index 100% rename from test/highload-sale/env.ts rename to test/e2e/highload-sale/env.ts diff --git a/test/highload-sale/highload-sale.test.ts b/test/e2e/highload-sale/highload-sale.test.ts similarity index 100% rename from test/highload-sale/highload-sale.test.ts rename to test/e2e/highload-sale/highload-sale.test.ts diff --git a/test/initArgs.template.did b/test/e2e/initArgs.template.did similarity index 100% rename from test/initArgs.template.did rename to test/e2e/initArgs.template.did diff --git a/test/marketplace/env.ts b/test/e2e/marketplace/env.ts similarity index 100% rename from test/marketplace/env.ts rename to test/e2e/marketplace/env.ts diff --git a/test/marketplace/list-delist.test.ts b/test/e2e/marketplace/list-delist.test.ts similarity index 100% rename from test/marketplace/list-delist.test.ts rename to test/e2e/marketplace/list-delist.test.ts diff --git a/test/marketplace/list-lock-delist.test.ts b/test/e2e/marketplace/list-lock-delist.test.ts similarity index 100% rename from test/marketplace/list-lock-delist.test.ts rename to test/e2e/marketplace/list-lock-delist.test.ts diff --git a/test/marketplace/marketplace-buy-with-insufficient-funds.test.ts b/test/e2e/marketplace/marketplace-buy-with-insufficient-funds.test.ts similarity index 100% rename from test/marketplace/marketplace-buy-with-insufficient-funds.test.ts rename to test/e2e/marketplace/marketplace-buy-with-insufficient-funds.test.ts diff --git a/test/marketplace/marketplace-buy.test.ts b/test/e2e/marketplace/marketplace-buy.test.ts similarity index 100% rename from test/marketplace/marketplace-buy.test.ts rename to test/e2e/marketplace/marketplace-buy.test.ts diff --git a/test/marketplace/marketplace.test.ts b/test/e2e/marketplace/marketplace.test.ts similarity index 100% rename from test/marketplace/marketplace.test.ts rename to test/e2e/marketplace/marketplace.test.ts diff --git a/test/multi-asset/env.ts b/test/e2e/multi-asset/env.ts similarity index 100% rename from test/multi-asset/env.ts rename to test/e2e/multi-asset/env.ts diff --git a/test/multi-asset/multi-asset.test.ts b/test/e2e/multi-asset/multi-asset.test.ts similarity index 100% rename from test/multi-asset/multi-asset.test.ts rename to test/e2e/multi-asset/multi-asset.test.ts diff --git a/test/open-edition/env.ts b/test/e2e/open-edition/env.ts similarity index 100% rename from test/open-edition/env.ts rename to test/e2e/open-edition/env.ts diff --git a/test/open-edition/open-edition.test.ts b/test/e2e/open-edition/open-edition.test.ts similarity index 100% rename from test/open-edition/open-edition.test.ts rename to test/e2e/open-edition/open-edition.test.ts diff --git a/test/pending-sale/access.test.ts b/test/e2e/pending-sale/access.test.ts similarity index 100% rename from test/pending-sale/access.test.ts rename to test/e2e/pending-sale/access.test.ts diff --git a/test/pending-sale/env.ts b/test/e2e/pending-sale/env.ts similarity index 100% rename from test/pending-sale/env.ts rename to test/e2e/pending-sale/env.ts diff --git a/test/pending-sale/pending-sale.test.ts b/test/e2e/pending-sale/pending-sale.test.ts similarity index 100% rename from test/pending-sale/pending-sale.test.ts rename to test/e2e/pending-sale/pending-sale.test.ts diff --git a/test/public-sale/env.ts b/test/e2e/public-sale/env.ts similarity index 100% rename from test/public-sale/env.ts rename to test/e2e/public-sale/env.ts diff --git a/test/public-sale/public-sale.test.ts b/test/e2e/public-sale/public-sale.test.ts similarity index 100% rename from test/public-sale/public-sale.test.ts rename to test/e2e/public-sale/public-sale.test.ts diff --git a/test/restore/env.ts b/test/e2e/restore/env.ts similarity index 100% rename from test/restore/env.ts rename to test/e2e/restore/env.ts diff --git a/test/setup.ts b/test/e2e/setup.ts similarity index 100% rename from test/setup.ts rename to test/e2e/setup.ts diff --git a/test/single-asset-delayed-reveal/env.ts b/test/e2e/single-asset-delayed-reveal/env.ts similarity index 100% rename from test/single-asset-delayed-reveal/env.ts rename to test/e2e/single-asset-delayed-reveal/env.ts diff --git a/test/single-asset-delayed-reveal/single-asset-delayed-reveal.test.ts b/test/e2e/single-asset-delayed-reveal/single-asset-delayed-reveal.test.ts similarity index 100% rename from test/single-asset-delayed-reveal/single-asset-delayed-reveal.test.ts rename to test/e2e/single-asset-delayed-reveal/single-asset-delayed-reveal.test.ts diff --git a/test/single-asset/env.ts b/test/e2e/single-asset/env.ts similarity index 100% rename from test/single-asset/env.ts rename to test/e2e/single-asset/env.ts diff --git a/test/single-asset/single-asset.test.ts b/test/e2e/single-asset/single-asset.test.ts similarity index 100% rename from test/single-asset/single-asset.test.ts rename to test/e2e/single-asset/single-asset.test.ts diff --git a/test/sold-out/env.ts b/test/e2e/sold-out/env.ts similarity index 100% rename from test/sold-out/env.ts rename to test/e2e/sold-out/env.ts diff --git a/test/sold-out/sold-out.test.ts b/test/e2e/sold-out/sold-out.test.ts similarity index 100% rename from test/sold-out/sold-out.test.ts rename to test/e2e/sold-out/sold-out.test.ts diff --git a/test/user.ts b/test/e2e/user.ts similarity index 83% rename from test/user.ts rename to test/e2e/user.ts index 0f86e5e..6dce905 100644 --- a/test/user.ts +++ b/test/e2e/user.ts @@ -7,14 +7,14 @@ import { generateIdentity } from './generate-identity'; import { createAgent } from './create-agent'; // @ts-ignore -import { idlFactory as idlFactoryMain } from '../declarations/main/staging.did.js'; -import { _SERVICE as _SERVICE_MAIN } from '../declarations/main/staging.did'; +import { idlFactory as idlFactoryMain } from '../../declarations/main/staging.did.js'; +import { _SERVICE as _SERVICE_MAIN } from '../../declarations/main/staging.did'; // @ts-ignore -import { idlFactory as idlFactoryIcp } from '../declarations/ledger/ledger.did.js'; -import { _SERVICE as _SERVICE_ICP } from '../declarations/ledger/ledger.did'; +import { idlFactory as idlFactoryIcp } from '../../declarations/ledger/ledger.did.js'; +import { _SERVICE as _SERVICE_ICP } from '../../declarations/ledger/ledger.did'; -import canisterIds from '../.dfx/local/canister_ids.json'; +import canisterIds from '../../.dfx/local/canister_ids.json'; export class User { diff --git a/test/utils.ts b/test/e2e/utils.ts similarity index 97% rename from test/utils.ts rename to test/e2e/utils.ts index 0a705ec..4666a6e 100644 --- a/test/utils.ts +++ b/test/e2e/utils.ts @@ -2,7 +2,7 @@ import { Principal } from "@dfinity/principal"; import { expect } from "vitest"; import { User } from "./user"; -import canisterIds from '../.dfx/local/canister_ids.json'; +import canisterIds from '../../.dfx/local/canister_ids.json'; import { AccountIdentifier } from "@dfinity/nns"; export function feeOf(amount: bigint, fee: bigint) { diff --git a/test/well-known-users.ts b/test/e2e/well-known-users.ts similarity index 100% rename from test/well-known-users.ts rename to test/e2e/well-known-users.ts diff --git a/test/whitelist-sale/env.ts b/test/e2e/whitelist-sale/env.ts similarity index 100% rename from test/whitelist-sale/env.ts rename to test/e2e/whitelist-sale/env.ts diff --git a/test/whitelist-sale/whitelist-sale.test.ts b/test/e2e/whitelist-sale/whitelist-sale.test.ts similarity index 100% rename from test/whitelist-sale/whitelist-sale.test.ts rename to test/e2e/whitelist-sale/whitelist-sale.test.ts diff --git a/test/whitelist-slots/env.ts b/test/e2e/whitelist-slots/env.ts similarity index 100% rename from test/whitelist-slots/env.ts rename to test/e2e/whitelist-slots/env.ts diff --git a/test/whitelist-slots/whitelist-slots.test.ts b/test/e2e/whitelist-slots/whitelist-slots.test.ts similarity index 100% rename from test/whitelist-slots/whitelist-slots.test.ts rename to test/e2e/whitelist-slots/whitelist-slots.test.ts diff --git a/test/unit/shuffleBuffer.test.mo b/test/unit/shuffleBuffer.test.mo new file mode 100644 index 0000000..5e51a37 --- /dev/null +++ b/test/unit/shuffleBuffer.test.mo @@ -0,0 +1,55 @@ +import Buffer "mo:base/Buffer"; +import Debug "mo:base/Debug"; +import Random "mo:base/Random"; + +import {test; suite} "mo:test/async"; +import Fuzz "mo:fuzz"; +import Utils "../../src/utils"; + +let fuzz = Fuzz.Fuzz(); + +await suite("Utils.shuffleBuffer should shuffle buffer in place", func() : async () { + await test("0 items", func() : async () { + let seed = await Random.blob(); + let ar = []; + let buf = Buffer.fromArray(ar); + + assert(Buffer.toArray(buf) == ar); + Utils.shuffleBuffer(buf, seed); + assert(Buffer.toArray(buf) == ar); + }); + + await test("1 item", func() : async () { + let seed = await Random.blob(); + let ar = [0]; + let buf = Buffer.fromArray(ar); + + assert(Buffer.toArray(buf) == ar); + Utils.shuffleBuffer(buf, seed); + assert(Buffer.toArray(buf) == ar); + }); + + await test("10 items", func() : async () { + let seed = await Random.blob(); + let ar = fuzz.array.randomArray(10, fuzz.nat8.random); + let buf = Buffer.fromArray(ar); + + assert(Buffer.toArray(buf) == ar); + Debug.print(debug_show(Buffer.toArray(buf))); + + Utils.shuffleBuffer(buf, seed); + + assert(Buffer.toArray(buf) != ar); + Debug.print(debug_show(Buffer.toArray(buf))); + }); + + await test("10_000 items", func() : async () { + let seed = await Random.blob(); + let ar = fuzz.array.randomArray(10_000, fuzz.nat8.random); + let buf = Buffer.fromArray(ar); + + assert(Buffer.toArray(buf) == ar); + Utils.shuffleBuffer(buf, seed); + assert(Buffer.toArray(buf) != ar); + }); +}); \ No newline at end of file diff --git a/vite.config.ts b/vite.config.ts index 0c9d9d8..07161d2 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -4,11 +4,11 @@ import {defineConfig} from 'vite'; export default defineConfig({ test: { testTimeout: 1000 * 60 * 2, - setupFiles: ['./test/setup.ts'], + setupFiles: ['./test/e2e/setup.ts'], exclude: [ '**/node_modules/**', '**/.{git,dfx,vessel}/**', - 'test/restore/restore.test.ts', // contains only env.ts + 'test/e2e/restore/restore.test.ts', // contains only env.ts ], }, }); \ No newline at end of file From e26d476d0ac598768c72b35f23e1c62e5a2ff71a Mon Sep 17 00:00:00 2001 From: ZenVoich Date: Wed, 12 Jul 2023 16:39:53 +0400 Subject: [PATCH 14/23] fix workflow --- .github/workflows/test.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 141a74e..b0c8bdc 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -21,6 +21,8 @@ jobs: dfx-version: 0.14.1 - name: install mops run: npm i -g ic-mops + - name: install mops packages + run: mops install - name: test run: | dfx identity use anonymous From 5d4ac03a7c07d934ae4f05caeaaea350a3fcc92c Mon Sep 17 00:00:00 2001 From: ZenVoich Date: Wed, 12 Jul 2023 16:51:08 +0400 Subject: [PATCH 15/23] mops base = "0.8.1" --- mops.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mops.toml b/mops.toml index d5e4988..b5ae1f1 100644 --- a/mops.toml +++ b/mops.toml @@ -1,6 +1,6 @@ # used only for unit testing [dependencies] -base = "0.9.3" +base = "0.8.1" cap = "https://github.com/Psychedelic/cap-motoko-library#v1.0.4" accountid = "https://github.com/aviate-labs/principal.mo#v0.2.6" canistergeek = "https://github.com/usergeek/canistergeek-ic-motoko#v0.0.7" From d2223c1e67ce3c5b3d86e3638684a0f36c2b15dd Mon Sep 17 00:00:00 2001 From: ZenVoich Date: Wed, 12 Jul 2023 17:09:16 +0400 Subject: [PATCH 16/23] fix backup e2e tests --- test/e2e/backup-assets/backup-assets.test.ts | 4 ++-- test/e2e/backup-restore/backup-restore.test.ts | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/test/e2e/backup-assets/backup-assets.test.ts b/test/e2e/backup-assets/backup-assets.test.ts index a093ed6..2af28ca 100644 --- a/test/e2e/backup-assets/backup-assets.test.ts +++ b/test/e2e/backup-assets/backup-assets.test.ts @@ -35,7 +35,7 @@ describe('backup', () => { }); it('check a.json', async () => { - let data = JSON.parse(readFileSync(__dirname + '/../../backup/data/a.json').toString()); + let data = JSON.parse(readFileSync(__dirname + '/../../../backup/data/a.json').toString()); expect(data[0]['v2']['assets'][0]['v3']['assetsChunk']).toHaveLength(7); expect(data[0]['v2']['assets'][0]['v3']['assetsCount']).toBe('###bigint:7'); }); @@ -73,7 +73,7 @@ describe('restore', () => { }); it('compare a.json and b.json', async () => { - if (readFileSync(__dirname + '/../../backup/data/a.json').toString() !== readFileSync(__dirname + '/../../backup/data/b.json').toString()) { + if (readFileSync(__dirname + '/../../../backup/data/a.json').toString() !== readFileSync(__dirname + '/../../../backup/data/b.json').toString()) { throw 'a.json and b.json backups are different!'; } }); diff --git a/test/e2e/backup-restore/backup-restore.test.ts b/test/e2e/backup-restore/backup-restore.test.ts index 409a118..4abdd91 100644 --- a/test/e2e/backup-restore/backup-restore.test.ts +++ b/test/e2e/backup-restore/backup-restore.test.ts @@ -76,7 +76,7 @@ describe('restore', () => { }); it('compare a.json and b.json', async () => { - if (readFileSync(__dirname + '/../../backup/data/a.json').toString() !== readFileSync(__dirname + '/../../backup/data/b.json').toString()) { + if (readFileSync(__dirname + '/../../../backup/data/a.json').toString() !== readFileSync(__dirname + '/../../../backup/data/b.json').toString()) { throw 'a.json and b.json backups are different!'; } }); From b33e549cc631e6671bde202d798d50a96e85f4e6 Mon Sep 17 00:00:00 2001 From: ZenVoich Date: Thu, 13 Jul 2023 11:51:45 +0400 Subject: [PATCH 17/23] add transactionsPaged method --- src/main.mo | 9 ++++++--- src/utils.mo | 27 ++++++++++++++++++++++++++- 2 files changed, 32 insertions(+), 4 deletions(-) diff --git a/src/main.mo b/src/main.mo index 5b35657..cadb23f 100644 --- a/src/main.mo +++ b/src/main.mo @@ -33,7 +33,7 @@ import DisburserTypes "Disburser/types"; import Utils "./utils"; import Types "./types"; -shared ({ caller = init_minter }) actor class Canister(cid : Principal, initArgs : Types.InitArgs) = myCanister { +shared ({ caller = init_minter }) actor class Canister(cid : Principal, initArgs : Types.InitArgs) { let config = { initArgs with canister = cid; @@ -278,8 +278,7 @@ shared ({ caller = init_minter }) actor class Canister(cid : Principal, initArgs _trapIfRestoreEnabled(); canistergeekMonitor.collectMetrics(); assert (caller == init_minter); - let pid = Principal.fromActor(myCanister); - let tokenContractId = Principal.toText(pid); + let tokenContractId = Principal.toText(cid); try { rootBucketId := await _Cap.handshake( @@ -498,6 +497,10 @@ shared ({ caller = init_minter }) actor class Canister(cid : Principal, initArgs _Marketplace.transactions(); }; + public query func transactionsPaged(pageIndex : Nat, chunkSize : Nat) : async ([MarketplaceTypes.Transaction], Nat) { + Utils.getPage(_Marketplace.transactions(), pageIndex, chunkSize); + }; + public query func settlements() : async [(MarketplaceTypes.TokenIndex, MarketplaceTypes.AccountIdentifier, Nat64)] { _Marketplace.settlements(); }; diff --git a/src/utils.mo b/src/utils.mo index c1a747a..4554c2f 100644 --- a/src/utils.mo +++ b/src/utils.mo @@ -3,8 +3,9 @@ import Blob "mo:base/Blob"; import Hash "mo:base/Hash"; import Int8 "mo:base/Int8"; import Iter "mo:base/Iter"; -import Nat32 "mo:base/Nat32"; +import Nat "mo:base/Nat"; import Nat8 "mo:base/Nat8"; +import Nat32 "mo:base/Nat32"; import Nat64 "mo:base/Nat64"; import Prim "mo:prim"; import Principal "mo:base/Principal"; @@ -170,4 +171,28 @@ module { case (#days(d)) d * 1000_000_000 * 60 * 60 * 24; }; }; + + func _getPageItems(items : [T], pageIndex : Nat, limit : Nat) : [T] { + let start = pageIndex * limit; + let end = Nat.min(start + limit, items.size()); + let size = end - start; + + if (size == 0) { + return []; + }; + + let buf = Buffer.Buffer(size); + for (i in Iter.range(start, end - 1)) { + buf.add(items[i]); + }; + + Buffer.toArray(buf); + }; + + public func getPage(items : [T], pageIndex : Nat, limit : Nat) : ([T], Nat) { + ( + _getPageItems(items, pageIndex, limit), + items.size() / limit + (if (items.size() % limit == 0) 0 else 1), + ); + }; }; From bbdeca65f729245065f05983307d59bb05cafc70 Mon Sep 17 00:00:00 2001 From: ZenVoich Date: Thu, 13 Jul 2023 11:53:40 +0400 Subject: [PATCH 18/23] ts-node -> tsx --- package-lock.json | 1 - package.json | 11 +++++------ 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/package-lock.json b/package-lock.json index 94e5dbb..2bedd2d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -15,7 +15,6 @@ "chunk": "^0.0.3", "minimist": "^1.2.8", "pem-file": "^1.0.1", - "ts-node": "^10.9.1", "tsx": "^3.12.7", "typescript": "^4.9.4", "vite": "^4.3.9", diff --git a/package.json b/package.json index 6398fe2..0957750 100644 --- a/package.json +++ b/package.json @@ -24,12 +24,12 @@ "mint:test-2": "dfx canister call test addAsset '(record {name = \"privat0\";payload = record {ctype = \"text/html\"; data = vec {blob \"hello world0!\"} } })' && dfx canister call test addAsset '(record {name = \"privat1\";payload = record {ctype = \"text/html\"; data = vec {blob \"hello world1!\"} } })' && dfx canister call test initMint && dfx canister call test shuffleTokensForSale && dfx canister call test enableSale", "vitest": "vitest run --threads false --isolate false", "vitest:watch": "vitest watch", - "env": "ts-node ./test/apply-env.ts", + "env": "tsx ./test/apply-env.ts", "test": "dfx build staging && vitest run --threads false --isolate false --reporter verbose", - "backup": "ts-node ./backup/backup.ts", - "restore": "ts-node ./backup/restore.ts", - "test-br": "npm run deploy-test && ts-node ./backup/test.ts", - "test-br-assets": "ts-node ./backup/test-assets.ts", + "backup": "tsx ./backup/backup.ts", + "restore": "tsx ./backup/restore.ts", + "test-br": "npm run deploy-test && tsx ./backup/test.ts", + "test-br-assets": "tsx ./backup/test-assets.ts", "deploy": "tsx ./deploy/deploy.ts", "upgrade-production": "dfx canister --network ic stop production && DFX_MOC_PATH=\"$(vessel bin)/moc\" dfx deploy --network ic production --upgrade-unchanged --argument \"$(cat initArgs.did)\" && dfx canister --network ic start production", "": "" @@ -45,7 +45,6 @@ "chunk": "^0.0.3", "minimist": "^1.2.8", "pem-file": "^1.0.1", - "ts-node": "^10.9.1", "tsx": "^3.12.7", "typescript": "^4.9.4", "vite": "^4.3.9", From f17e431fe36e9e4a973e3186361a625affe3fee1 Mon Sep 17 00:00:00 2001 From: ZenVoich Date: Thu, 13 Jul 2023 16:01:12 +0400 Subject: [PATCH 19/23] remove requirement to use anonymous identity to run tests --- .github/workflows/test.yml | 1 - README.md | 6 ------ backup/restore.ts | 9 +++++++++ deploy/deploy.ts | 2 +- 4 files changed, 10 insertions(+), 8 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 2de7fd6..c66b5dd 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -21,7 +21,6 @@ jobs: dfx-version: 0.14.1 - name: test run: | - dfx identity use anonymous npm install npm run replica:no-delay npm run test diff --git a/README.md b/README.md index ffb3d08..a7744bc 100644 --- a/README.md +++ b/README.md @@ -140,12 +140,6 @@ So when executing `mintNFT`, the `to` address is taken from `registry.json` and Each test suite is deployed with its own env settings. -You need to switch to an anonymous identity to run the tests. - -``` -dfx identity use anonymouse -``` - First, start a local replica ``` diff --git a/backup/restore.ts b/backup/restore.ts index 98751a8..06bb081 100644 --- a/backup/restore.ts +++ b/backup/restore.ts @@ -2,6 +2,7 @@ import fs from 'fs'; import path from 'path'; import minimist from 'minimist'; import { Principal } from '@dfinity/principal'; +import { ExecSyncOptions, execSync } from 'child_process'; import { getActor } from './actor'; import { type StableChunk } from '../declarations/main/staging.did'; @@ -25,6 +26,14 @@ if (!fs.existsSync(filePath)) { throw new Error(`File ${filePath} not found`); } +if (!pemData && network == 'local') { + let execOptions = {stdio: ['inherit', 'pipe', 'inherit']} as ExecSyncOptions; + let identityName = execSync('dfx identity whoami').toString().trim(); + if (identityName !== 'anonymous') { + pemData = execSync(`dfx identity export ${identityName}`, execOptions).toString(); + } +} + let identity = pemData && decode(pemData); let mainActor = getActor(network, canisterId, identity); diff --git a/deploy/deploy.ts b/deploy/deploy.ts index 4c79560..63b25c5 100644 --- a/deploy/deploy.ts +++ b/deploy/deploy.ts @@ -29,7 +29,7 @@ let withCyclesArg = argv['with-cycles'] ? `--with-cycles=${argv['with-cycles']}` let nftCanisterName = network == 'production' ? 'production' : 'staging'; let assetsDir = path.resolve(__dirname, '../assets'); -let identityName = execSync('dfx identity whoami').toString(); +let identityName = execSync('dfx identity whoami').toString().trim(); let pemData = execSync(`dfx identity export ${identityName}`, execOptions).toString(); let identity = decode(pemData); let actor = getActor(network, identity); From 6bca3b108808e165d3c698f10a662c5f42a5288a Mon Sep 17 00:00:00 2001 From: ZenVoich Date: Fri, 14 Jul 2023 12:53:13 +0400 Subject: [PATCH 20/23] fix restore test --- test/backup-restore/backup-restore.test.ts | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/test/backup-restore/backup-restore.test.ts b/test/backup-restore/backup-restore.test.ts index 88ac7f4..8b764d4 100644 --- a/test/backup-restore/backup-restore.test.ts +++ b/test/backup-restore/backup-restore.test.ts @@ -20,14 +20,9 @@ describe('backup', () => { }); it('try to restore with restoreEnabled = false', async () => { - await expect(user.mainActor.restoreChunk({v1: { - marketplace: [], - assets: [], - sale: [], - disburser: [], - tokens: [], - shuffle: [], - }})).rejects.toThrow(/Restore disabled/); + expect(() => { + execSync(`dfx canister call staging restoreChunk '(variant {v1 = record {}})'`) + }).toThrow(/Restore disabled/); }); it(`grow up to ${growSize * BigInt(growCount)}`, async () => { From 5f20e0fdd88ba951ca592da6fa3bd22d4ea99c27 Mon Sep 17 00:00:00 2001 From: ZenVoich Date: Fri, 14 Jul 2023 13:41:53 +0400 Subject: [PATCH 21/23] fix restore test --- test/backup-restore/backup-restore.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/backup-restore/backup-restore.test.ts b/test/backup-restore/backup-restore.test.ts index 8b764d4..71c4cb5 100644 --- a/test/backup-restore/backup-restore.test.ts +++ b/test/backup-restore/backup-restore.test.ts @@ -21,7 +21,7 @@ describe('backup', () => { it('try to restore with restoreEnabled = false', async () => { expect(() => { - execSync(`dfx canister call staging restoreChunk '(variant {v1 = record {}})'`) + execSync(`dfx canister call test restoreChunk '(variant {v1 = record {}})'`) }).toThrow(/Restore disabled/); }); From fba75eb608fe86d781b927e220dd06b4050c4d12 Mon Sep 17 00:00:00 2001 From: ZenVoich Date: Tue, 18 Jul 2023 15:07:33 +0400 Subject: [PATCH 22/23] workflow: use aviate-labs/setup-dfx@v0.2.6 --- .github/workflows/test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index c66b5dd..45f31dc 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -15,7 +15,7 @@ jobs: - uses: actions/setup-node@v3 with: node-version: 18 - - uses: aviate-labs/setup-dfx@v0.2.5 + - uses: aviate-labs/setup-dfx@v0.2.6 with: vessel-version: 0.6.3 dfx-version: 0.14.1 From e31e3433e9acf7ac9912e8740be092fb5225f405 Mon Sep 17 00:00:00 2001 From: ZenVoich Date: Wed, 19 Jul 2023 17:07:30 +0400 Subject: [PATCH 23/23] remove --trap-on-call-error --- dfx.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dfx.json b/dfx.json index 95e791e..38d8600 100644 --- a/dfx.json +++ b/dfx.json @@ -44,7 +44,7 @@ "defaults": { "build": { "packtool": "vessel sources", - "args": "--trap-on-call-error" + "args": "" } } }