diff --git a/config/kovan-config.js b/config/kovan-config.js index bad5d8f..faf3e37 100644 --- a/config/kovan-config.js +++ b/config/kovan-config.js @@ -63,21 +63,21 @@ module.exports = { //================== NFT ==================== ConstFeeRateModel: "0xBDAcEcF886a4F0C509260d9678D5673C3E8fa4b7", - FeeDistributor: "0xdE39C2901e72A883f7446951fB533219F3622b87", - Fragment: "0x40F3bBe2f8C5F2E5f4adFf7d51f652F2B9F77315", - NFTCollateralVault: "0xFDf7604649dfBb733e784afAEdC19892706cc683", + FeeDistributor: "0xC7da6C32E301C042C2237ca04aa4BB6D2e5C86B1", + Fragment: "0xc83c4aFdF216C7D0E15D50B9e1658298320A9551", + NFTCollateralVault: "0x7e83d9d94837eE82F0cc18a691da6f42F03F1d86", DODONFTRouteHelper: "0xAE683548702be6d651e179e5F9313272bb18596A", - InitializableERC721: "0x7563414479593394460d1bbaFE2Fc3E29D804007", - InitializableERC1155: "0xb971B0df71fB1778351F25a0e3bfe0C3eF06E1d1", - NFTTokenFactory: "0x38c109aF4f3454172BA4eecf5676aA213b589e75", + InitializableERC721: "0x62dC4615AC755959a82b6D22FA5652A037284c0b", + InitializableERC1155: "0xfa391c0Ed6898e0C6186605d69e877f1317Bb506", + NFTTokenFactory: "0xdeBB45aCffF3b5e610C1EdF45DFaaea0030EAdaF", DODONFTRegistry: "0xF405372b7808363DCfbb5Eb81204889B7a69Aa3e", - DODONFTProxy: "0x0727dEd495E35f4bA4F5D64794145152301Db23f", + DODONFTProxy: "0x8812E32b31530d21D1fE70A45bBa66bbEB3641C5", //================= MysteryBox ================= - MysteryBoxV1: "0x87457A7FDFE0a4A57aABB369A21690bF67b8dDbD", + MysteryBoxV1: "", RandomGenerator: "0x53F54E4760FA5f839e5624782D032495613DF218", RandomPool: [ "0xa2e0ef85618732d80e5ef362773da1c92e8b1c57", diff --git a/contracts/DODOMysteryBox/MysteryBoxV1.sol b/contracts/DODOMysteryBox/MysteryBoxV1.sol index eddbd1b..ee80226 100644 --- a/contracts/DODOMysteryBox/MysteryBoxV1.sol +++ b/contracts/DODOMysteryBox/MysteryBoxV1.sol @@ -28,7 +28,6 @@ contract MysteryBoxV1 is ERC721URIStorage, InitializableOwnable { uint256 public _TICKET_UNIT_ = 1; // ticket consumed in a single lottery uint256[] public _TOKEN_IDS_; - uint256 public _ID_POINT_; address public _RANDOM_GENERATOR_; @@ -92,6 +91,11 @@ contract MysteryBoxV1 is ERC721URIStorage, InitializableOwnable { _TOTAL_TICKETS_ = _TOTAL_TICKETS_.sub(ticketNum); } + // ================= View =================== + function getTickets(address account) view external returns(uint256) { + return _USER_TICKETS_[account]; + } + // =============== Internal ================ function _redeemSinglePrize(address to) internal { @@ -103,7 +107,7 @@ contract MysteryBoxV1 is ERC721URIStorage, InitializableOwnable { _TOKEN_IDS_[random] = _TOKEN_IDS_[range - 1]; } _TOKEN_IDS_.pop(); - safeTransferFrom(address(this), to, prizeId, ""); + _safeTransfer(address(this), to, prizeId, ""); emit RedeemPrize(to, prizeId); } @@ -143,13 +147,12 @@ contract MysteryBoxV1 is ERC721URIStorage, InitializableOwnable { emit Withdraw(msg.sender, amount); } - function batchMint(string[] calldata urls) external onlyOwner { - for(uint256 i = 0; i < urls.length; i++) { - _mint(address(this), _ID_POINT_); - _TOKEN_IDS_.push(_ID_POINT_); - _setTokenURI(_ID_POINT_, urls[i]); - _ID_POINT_++; + function batchMint(uint256[] calldata ids, string[] calldata urls) external onlyOwner { + for(uint256 i = 0; i < ids.length; i++) { + _mint(address(this), ids[i]); + _TOKEN_IDS_.push(ids[i]); + _setTokenURI(ids[i], urls[i]); } - emit BatchMint(urls.length); + emit BatchMint(ids.length); } } diff --git a/deploy-nft.txt b/deploy-nft.txt index d46b08d..de30ebd 100644 --- a/deploy-nft.txt +++ b/deploy-nft.txt @@ -182,3 +182,19 @@ Deploy type: MysteryBoxV1 RandomGeneratorAddress: 0x7e21BFAcDB5062C071Fad17451E85f070DDa5d8F MysteryBoxV1Address: 0x215BD4d983c571a840b89028CC005B6FF0734EbE Init MysteryBoxV1 Tx: 0x15439f29a1c7b446f2d0dcda7f21dcfdd2ce3c197e8c0a5d1338621ecdb9ddab +==================================================== +network type: kovan +Deploy time: 2021/4/16 下午12:14:20 +Deploy type: NFT +multiSigAddress: 0x7e83d9d94837eE82F0cc18a691da6f42F03F1d86 +ERC721Address: 0x62dC4615AC755959a82b6D22FA5652A037284c0b +ERC1155Address: 0xfa391c0Ed6898e0C6186605d69e877f1317Bb506 +NFTTokenFactoryAddress: 0xdeBB45aCffF3b5e610C1EdF45DFaaea0030EAdaF +NFTCollateralVaultAddress: 0xC08D918400859272442CC71fc8cC3b1a69835B4a +FragmentAddress: 0xc83c4aFdF216C7D0E15D50B9e1658298320A9551 +FeeDistributorAddress: 0xC7da6C32E301C042C2237ca04aa4BB6D2e5C86B1 +DODONFTProxyAddress: 0x8812E32b31530d21D1fE70A45bBa66bbEB3641C5 +Init DODONFTProxyAddress Tx: 0x96a1a4b9f8cdf4f6c56a2aa8298f2def0f7b87c493f172268fdd59c8aa617bc6 +DODOApproveProxy unlockAddProxy tx: 0x8ef2e4693a45af5fd1fcdf9f5d8e544331148ddcf1551250244599430a0524a0 +DODOApproveProxy addDODOProxy tx: 0x275aa8ec28849aa7e0b2c9b18eb3877797d027713be5f92764da8cf55f6d5eca +Add AdminList on DODONFTRegistry Tx: 0x4cc991762645beb448c3315369452d4af2e02b507b97d3638ba876d30b46d2f4 diff --git a/test/DODONFT/mysteryBoxV1.test.ts b/test/DODONFT/mysteryBoxV1.test.ts index 5c322b3..d0e69a4 100644 --- a/test/DODONFT/mysteryBoxV1.test.ts +++ b/test/DODONFT/mysteryBoxV1.test.ts @@ -4,12 +4,13 @@ SPDX-License-Identifier: Apache-2.0 */ -import { decimalStr, mweiStr, fromWei } from '../utils/Converter'; +import { decimalStr, fromWei } from '../utils/Converter'; import { logGas } from '../utils/Log'; import { DVMContext, getDVMContext } from '../utils/DVMContext'; import { assert } from 'chai'; import * as contracts from '../utils/Contracts'; import { Contract } from 'web3-eth-contract'; +const truffleAssert = require('truffle-assertions'); let owner: string; let user1: string; @@ -63,10 +64,11 @@ async function init(ctx: DVMContext): Promise { ).send(ctx.sendParam(owner)); } -async function getTokenIdAndUrlByUser(user: string) { +async function getTokenIdAndUrlByUser(user: string, logInfo?: string) { var tokenIds = [] var urls = [] var balance = await MysteryBoxV1.methods.balanceOf(user).call(); + console.log(logInfo); for (var i = 0; i < balance; i++) { var curTokenId = await MysteryBoxV1.methods.tokenOfOwnerByIndex(user, i).call() tokenIds.push(curTokenId); @@ -77,6 +79,28 @@ async function getTokenIdAndUrlByUser(user: string) { return [tokenIds, urls]; } +async function getTicketsInfo(user: string): Promise<[string, string]> { + var totalTickets = await MysteryBoxV1.methods._TOTAL_TICKETS_().call(); + var userTickets = await MysteryBoxV1.methods.getTickets(user).call(); + console.log("User Tickets:" + userTickets + " totalTickets:" + totalTickets); + return [totalTickets, userTickets]; +} + +async function getGlobalState(): Promise<[string, string]> { + var curSelling = await MysteryBoxV1.methods._CUR_SELLING_TICKETS_().call(); + var curPrice = await MysteryBoxV1.methods._CUR_PRCIE_().call(); + console.log("CurSellingTickets:" + curSelling + " CurPrice:" + fromWei(curPrice, 'ether')); + + return [curSelling, curPrice]; +} + +async function batchMint(ctx: DVMContext) { + var ids = [] + for (var i = 0; i < urls.length; i++) { + ids.push(i); + } + await logGas(await MysteryBoxV1.methods.batchMint(ids, urls), ctx.sendParam(owner), "batchMint-10"); +} describe("DODOMysteryBox", () => { let snapshotId: string; @@ -102,30 +126,91 @@ describe("DODOMysteryBox", () => { }); describe("DODO MysteryBoxV1", () => { - it.only("batchMint", async () => { - await logGas(await MysteryBoxV1.methods.batchMint(urls), ctx.sendParam(owner), "batchMint-10"); + it("batchMint", async () => { + var ids = [] + for (var i = 0; i < urls.length; i++) { + ids.push(i); + } + await logGas(await MysteryBoxV1.methods.batchMint(ids, urls), ctx.sendParam(owner), "batchMint-10"); let [tokenIds,]: any = await getTokenIdAndUrlByUser(MysteryBoxV1.options.address); assert(10, tokenIds.length); }); it("buyTicket", async () => { - await MysteryBoxV1.methods.updateSellingInfo(100, decimalStr("0.5")).send(ctx.sendParam(owner)); + await MysteryBoxV1.methods.updateSellingInfo(100, decimalStr("0.01")).send(ctx.sendParam(owner)); + await truffleAssert.reverts( + MysteryBoxV1.methods.buyTicket().send(ctx.sendParam(user1, "0.001")), + "BNB_NOT_ENOUGH" + ) + await logGas(await MysteryBoxV1.methods.buyTicket(), ctx.sendParam(user1, "0.5"), "buyTickets"); + await logGas(await MysteryBoxV1.methods.buyTicket(), ctx.sendParam(user2, "0.4"), "buyTickets"); + await truffleAssert.reverts( + MysteryBoxV1.methods.buyTicket().send(ctx.sendParam(user1, "0.2")), + "TICKETS_NOT_ENOUGH" + ) + let [, userTickets] = await getTicketsInfo(user1) + assert(userTickets, "50") + let [curSelling0] = await getGlobalState() + assert(curSelling0, "10") - //两阶段卖币 + await MysteryBoxV1.methods.updateSellingInfo(200, decimalStr("0.02")).send(ctx.sendParam(owner)); + await logGas(await MysteryBoxV1.methods.buyTicket(), ctx.sendParam(user1, "1"), "buyTickets"); + [, userTickets] = await getTicketsInfo(user1) + assert(userTickets, "100") + let [curSelling1] = await getGlobalState(); + assert(curSelling1, "150") //withdraw + var b_ETH = await ctx.Web3.eth.getBalance(owner); + var tx = await MysteryBoxV1.methods.withdraw().send(ctx.sendParam(owner)) + var a_ETH = await ctx.Web3.eth.getBalance(owner); + console.log("b_ETH:" + fromWei(b_ETH, 'ether') + " a_ETH:" + fromWei(a_ETH, 'ether')); + assert.equal( + tx.events['Withdraw'].returnValues['amount'], + decimalStr("1.9") + ); }); it("redeemPrize", async () => { - //redeem + await batchMint(ctx); - //列表查询 + await MysteryBoxV1.methods.updateSellingInfo(100, decimalStr("0.1")).send(ctx.sendParam(owner)); + await logGas(await MysteryBoxV1.methods.buyTicket(), ctx.sendParam(user1, "0.5"), "buyTickets"); + await getTicketsInfo(user1) + await getGlobalState() + await getTokenIdAndUrlByUser(user1, "redeemPrize前") + await getTokenIdAndUrlByUser(MysteryBoxV1.options.address, "盲盒合约:redeemPrize前") + + await logGas(await MysteryBoxV1.methods.redeemPrize(3), ctx.sendParam(user1), "redeemPrice"); + await getTicketsInfo(user1) + await getGlobalState() + await getTokenIdAndUrlByUser(user1, "第一次redeemPrize后") + + await logGas(await MysteryBoxV1.methods.redeemPrize(2), ctx.sendParam(user1), "redeemPrice"); + let [, userTickets] = await getTicketsInfo(user1) + assert(userTickets, "0"); + await getGlobalState() + await getTokenIdAndUrlByUser(user1, "第二次redeemPrize后") + let [tokenIds,] = await getTokenIdAndUrlByUser(MysteryBoxV1.options.address, "盲盒合约:redeemPrize后") + assert(tokenIds, "5"); }); it("transferNFT", async () => { + await batchMint(ctx); + await MysteryBoxV1.methods.updateSellingInfo(100, decimalStr("0.1")).send(ctx.sendParam(owner)); + await logGas(await MysteryBoxV1.methods.buyTicket(), ctx.sendParam(user1, "0.5"), "buyTickets"); + await logGas(await MysteryBoxV1.methods.redeemPrize(1), ctx.sendParam(user1), "redeemPrice"); + let [tokenId0,] = await getTokenIdAndUrlByUser(user1, "user1 转前") + assert(tokenId0.length == 1) + await getTokenIdAndUrlByUser(user2, "user2 转前") + await logGas(await MysteryBoxV1.methods.safeTransferFrom(user1, user2, tokenId0[0]), ctx.sendParam(user1), "transferNFT"); + + await getTokenIdAndUrlByUser(user1, "user1 转后") + let [tokenId1,] = await getTokenIdAndUrlByUser(user2, "user2 转后") + assert(tokenId1.length == 1) }); }); });