nft test ing

This commit is contained in:
owen05
2021-04-12 00:53:59 +08:00
parent 805f639c3a
commit 0bace9f613
7 changed files with 361 additions and 124 deletions

View File

@@ -63,7 +63,7 @@ module.exports = {
//================== NFT ==================== //================== NFT ====================
ConstFeeRateModel: "0xBDAcEcF886a4F0C509260d9678D5673C3E8fa4b7", ConstFeeRateModel: "0xBDAcEcF886a4F0C509260d9678D5673C3E8fa4b7",
FeeDistributor: "0x1eD92Fe9c3AE1cC427004eC27AAd96df4928B3ec", FeeDistributor: "",
Fragment: "0x64193839f8b6e85A257411a945085783cbA9976B", Fragment: "0x64193839f8b6e85A257411a945085783cbA9976B",
NFTCollateralVault: "0xFDf7604649dfBb733e784afAEdC19892706cc683", NFTCollateralVault: "0xFDf7604649dfBb733e784afAEdC19892706cc683",
DODONFTRouteHelper: "0xAE683548702be6d651e179e5F9313272bb18596A", DODONFTRouteHelper: "0xAE683548702be6d651e179e5F9313272bb18596A",
@@ -73,6 +73,6 @@ module.exports = {
NFTTokenFactory: "0x38c109aF4f3454172BA4eecf5676aA213b589e75", NFTTokenFactory: "0x38c109aF4f3454172BA4eecf5676aA213b589e75",
DODONFTRegistry: "0xF405372b7808363DCfbb5Eb81204889B7a69Aa3e", DODONFTRegistry: "0xF405372b7808363DCfbb5Eb81204889B7a69Aa3e",
DODONFTProxy: "0x622332C5e5B3E8B67Aee300184Ce024E428A89f8", DODONFTProxy: "",
} }
} }

View File

@@ -29,15 +29,15 @@ contract FeeDistributor {
uint256 public _STAKE_RESERVE_; uint256 public _STAKE_RESERVE_;
uint256 public _BASE_REWARD_RATIO_; uint256 public _BASE_REWARD_RATIO_;
mapping(address => uint256) internal _USER_BASE_REWARDS_; mapping(address => uint256) public _USER_BASE_REWARDS_;
mapping(address => uint256) internal _USER_BASE_PER_SHARE_; mapping(address => uint256) public _USER_BASE_PER_SHARE_;
uint256 public _QUOTE_REWARD_RATIO_; uint256 public _QUOTE_REWARD_RATIO_;
mapping(address => uint256) internal _USER_QUOTE_REWARDS_; mapping(address => uint256) public _USER_QUOTE_REWARDS_;
mapping(address => uint256) internal _USER_QUOTE_PER_SHARE_; mapping(address => uint256) public _USER_QUOTE_PER_SHARE_;
mapping(address => uint256) public _SHARES_;
mapping(address => uint256) internal _SHARES_;
bool internal _FEE_INITIALIZED_; bool internal _FEE_INITIALIZED_;
// ============ Event ============ // ============ Event ============
@@ -46,13 +46,13 @@ contract FeeDistributor {
event Claim(address sender, uint256 baseAmount, uint256 quoteAmount); event Claim(address sender, uint256 baseAmount, uint256 quoteAmount);
function init( function init(
address baseToken, address baseToken,
address quoteToken, address quoteToken,
address stakeToken address stakeToken
) external { ) external {
require(!_FEE_INITIALIZED_, "ALREADY_INITIALIZED"); require(!_FEE_INITIALIZED_, "ALREADY_INITIALIZED");
_FEE_INITIALIZED_ = true; _FEE_INITIALIZED_ = true;
_BASE_TOKEN_ = baseToken; _BASE_TOKEN_ = baseToken;
_QUOTE_TOKEN_ = quoteToken; _QUOTE_TOKEN_ = quoteToken;
_STAKE_TOKEN_ = stakeToken; _STAKE_TOKEN_ = stakeToken;
@@ -60,86 +60,126 @@ contract FeeDistributor {
} }
function stake(address to) external { function stake(address to) external {
_updateGlobalState(); _updateGlobalState();
_updateUserReward(to); _updateUserReward(to);
uint256 stakeVault = IERC20(_STAKE_TOKEN_).balanceOf(_STAKE_VAULT_); uint256 stakeVault = IERC20(_STAKE_TOKEN_).balanceOf(_STAKE_VAULT_);
uint256 stakeInput = stakeVault.sub(_STAKE_RESERVE_); uint256 stakeInput = stakeVault.sub(_STAKE_RESERVE_);
_addShares(stakeInput, to); _addShares(stakeInput, to);
emit Stake(to, stakeInput); emit Stake(to, stakeInput);
} }
function claim(address to) external { function claim(address to) external {
_updateGlobalState(); _updateGlobalState();
_updateUserReward(msg.sender); _updateUserReward(msg.sender);
_claim(msg.sender, to); _claim(msg.sender, to);
} }
function unstake(uint256 amount, address to, bool withClaim) external { function unstake(
require(_SHARES_[msg.sender]>=amount, "STAKE BALANCE ONT ENOUGH"); uint256 amount,
_updateGlobalState(); address to,
_updateUserReward(msg.sender); bool withClaim
) external {
require(_SHARES_[msg.sender] >= amount, "STAKE BALANCE ONT ENOUGH");
_updateGlobalState();
_updateUserReward(msg.sender);
if (withClaim) { if (withClaim) {
_claim(msg.sender, to); _claim(msg.sender, to);
} }
_removeShares(amount, msg.sender); StakeVault(_STAKE_VAULT_).transferOut(_STAKE_TOKEN_, amount, to);
StakeVault(_STAKE_VAULT_).transferOut(_STAKE_TOKEN_, amount, to); _removeShares(amount, msg.sender);
emit UnStake(msg.sender, amount);
emit UnStake(msg.sender, amount);
}
// ============ View ================
function getPendingReward(address user)
external
view
returns (uint256 baseReward, uint256 quoteReward)
{
uint256 baseInput = IERC20(_BASE_TOKEN_).balanceOf(address(this)).sub(_BASE_RESERVE_);
uint256 quoteInput = IERC20(_QUOTE_TOKEN_).balanceOf(address(this)).sub(_QUOTE_RESERVE_);
uint256 baseRwardRatio = _BASE_REWARD_RATIO_;
uint256 quoteRewardRatio = _QUOTE_REWARD_RATIO_;
if (_STAKE_RESERVE_ != 0) {
baseRwardRatio = _BASE_REWARD_RATIO_.add(
DecimalMath.divFloor(baseInput, _STAKE_RESERVE_)
);
quoteRewardRatio = _QUOTE_REWARD_RATIO_.add(
DecimalMath.divFloor(quoteInput, _STAKE_RESERVE_)
);
}
baseReward = DecimalMath
.mulFloor(_SHARES_[user], baseRwardRatio.sub(_USER_BASE_PER_SHARE_[user]))
.add(_USER_BASE_REWARDS_[user]);
quoteReward = DecimalMath
.mulFloor(_SHARES_[user], quoteRewardRatio.sub(_USER_QUOTE_PER_SHARE_[user]))
.add(_USER_QUOTE_REWARDS_[user]);
} }
// ============ Internal ============ // ============ Internal ============
function _claim(address sender, address to) internal { function _claim(address sender, address to) internal {
uint256 allBase = _USER_BASE_REWARDS_[sender]; uint256 allBase = _USER_BASE_REWARDS_[sender];
uint256 allQuote = _USER_QUOTE_REWARDS_[sender]; uint256 allQuote = _USER_QUOTE_REWARDS_[sender];
IERC20(_BASE_TOKEN_).safeTransfer(to, allBase); IERC20(_BASE_TOKEN_).safeTransfer(to, allBase);
IERC20(_QUOTE_TOKEN_).safeTransfer(to, allQuote); IERC20(_QUOTE_TOKEN_).safeTransfer(to, allQuote);
_USER_BASE_REWARDS_[sender] = 0;
_USER_BASE_REWARDS_[sender] = 0; _BASE_RESERVE_ = _BASE_RESERVE_.sub(allBase);
emit Claim(sender, allBase, allQuote); _QUOTE_RESERVE_ = _QUOTE_RESERVE_.sub(allQuote);
_USER_BASE_REWARDS_[sender] = 0;
_USER_QUOTE_REWARDS_[sender] = 0;
emit Claim(sender, allBase, allQuote);
} }
function _updateGlobalState() internal { function _updateGlobalState() internal {
uint256 baseInput = IERC20(_BASE_TOKEN_).balanceOf(address(this)).sub(_BASE_RESERVE_); uint256 baseInput = IERC20(_BASE_TOKEN_).balanceOf(address(this)).sub(_BASE_RESERVE_);
uint256 quoteInput = IERC20(_QUOTE_TOKEN_).balanceOf(address(this)).sub(_QUOTE_RESERVE_); uint256 quoteInput = IERC20(_QUOTE_TOKEN_).balanceOf(address(this)).sub(_QUOTE_RESERVE_);
_BASE_REWARD_RATIO_ = _BASE_REWARD_RATIO_.add(DecimalMath.divFloor(baseInput, _STAKE_RESERVE_));
_QUOTE_REWARD_RATIO_ = _QUOTE_REWARD_RATIO_.add(DecimalMath.divFloor(quoteInput, _STAKE_RESERVE_)); if (_STAKE_RESERVE_ != 0) {
_BASE_RESERVE_ = _BASE_RESERVE_.add(baseInput); _BASE_REWARD_RATIO_ = _BASE_REWARD_RATIO_.add(
_QUOTE_RESERVE_ = _QUOTE_RESERVE_.add(quoteInput); DecimalMath.divFloor(baseInput, _STAKE_RESERVE_)
);
_QUOTE_REWARD_RATIO_ = _QUOTE_REWARD_RATIO_.add(
DecimalMath.divFloor(quoteInput, _STAKE_RESERVE_)
);
}
_BASE_RESERVE_ = _BASE_RESERVE_.add(baseInput);
_QUOTE_RESERVE_ = _QUOTE_RESERVE_.add(quoteInput);
} }
function _updateUserReward(address user) internal { function _updateUserReward(address user) internal {
_USER_BASE_REWARDS_[user] = DecimalMath.mulFloor( _USER_BASE_REWARDS_[user] = DecimalMath
_SHARES_[user], .mulFloor(_SHARES_[user], _BASE_REWARD_RATIO_.sub(_USER_BASE_PER_SHARE_[user]))
_BASE_REWARD_RATIO_.sub(_USER_BASE_PER_SHARE_[user]) .add(_USER_BASE_REWARDS_[user]);
).add(_USER_BASE_REWARDS_[user]);
_USER_BASE_PER_SHARE_[user] = _BASE_REWARD_RATIO_; _USER_BASE_PER_SHARE_[user] = _BASE_REWARD_RATIO_;
_USER_QUOTE_REWARDS_[user] = DecimalMath.mulFloor( _USER_QUOTE_REWARDS_[user] = DecimalMath
_SHARES_[user], .mulFloor(_SHARES_[user], _QUOTE_REWARD_RATIO_.sub(_USER_QUOTE_PER_SHARE_[user]))
_QUOTE_REWARD_RATIO_.sub(_USER_QUOTE_PER_SHARE_[user]) .add(_USER_QUOTE_REWARDS_[user]);
).add(_USER_QUOTE_REWARDS_[user]);
_USER_QUOTE_PER_SHARE_[user] = _QUOTE_REWARD_RATIO_; _USER_QUOTE_PER_SHARE_[user] = _QUOTE_REWARD_RATIO_;
} }
function _addShares(uint256 amount, address to) internal { function _addShares(uint256 amount, address to) internal {
_SHARES_[to] = _SHARES_[to].add(amount); _SHARES_[to] = _SHARES_[to].add(amount);
_STAKE_RESERVE_ = IERC20(_STAKE_TOKEN_).balanceOf(_STAKE_VAULT_); _STAKE_RESERVE_ = IERC20(_STAKE_TOKEN_).balanceOf(_STAKE_VAULT_);
} }
function _removeShares(uint256 amount, address from) internal { function _removeShares(uint256 amount, address from) internal {
_SHARES_[from] = _SHARES_[from].sub(amount); _SHARES_[from] = _SHARES_[from].sub(amount);
_STAKE_RESERVE_ = IERC20(_STAKE_TOKEN_).balanceOf(_STAKE_VAULT_); _STAKE_RESERVE_ = IERC20(_STAKE_TOKEN_).balanceOf(_STAKE_VAULT_);
} }
} }
contract StakeVault is Ownable { contract StakeVault is Ownable {
using SafeERC20 for IERC20; using SafeERC20 for IERC20;
function transferOut( function transferOut(
address token, address token,
uint256 amount, uint256 amount,

View File

@@ -95,11 +95,10 @@ contract DODONFTProxy is ReentrancyGuard, InitializableOwnable {
emit CreateNFTCollateralVault(msg.sender, newVault, name, baseURI); emit CreateNFTCollateralVault(msg.sender, newVault, name, baseURI);
} }
//Stake 碎片
function createFragment( function createFragment(
address quoteToken, address quoteToken,
address vaultPreOwner, address vaultPreOwner,
address stakeToken, address stakeToken, //address(0) using frag token
uint256[] calldata dvmParams, //0 - lpFeeRate, 1 - mtFeeRate 2 - I, 3 - K uint256[] calldata dvmParams, //0 - lpFeeRate, 1 - mtFeeRate 2 - I, 3 - K
uint256[] calldata fragParams, //0 - totalSupply, 1 - ownerRatio, 2 - buyoutTimestamp uint256[] calldata fragParams, //0 - totalSupply, 1 - ownerRatio, 2 - buyoutTimestamp
bool isOpenTwap bool isOpenTwap
@@ -108,11 +107,11 @@ contract DODONFTProxy is ReentrancyGuard, InitializableOwnable {
address _quoteToken = quoteToken == _ETH_ADDRESS_ ? _WETH_ : quoteToken; address _quoteToken = quoteToken == _ETH_ADDRESS_ ? _WETH_ : quoteToken;
if(stakeToken == address(0)) { if(stakeToken == address(0)) {
newFeeDistributor = address(0); stakeToken = newFragment;
} else { }
newFeeDistributor = ICloneFactory(_CLONE_FACTORY_).clone(_FEE_TEMPLATE_);
IFeeDistributor(newFeeDistributor).init(newFragment, _quoteToken, stakeToken); newFeeDistributor = ICloneFactory(_CLONE_FACTORY_).clone(_FEE_TEMPLATE_);
} IFeeDistributor(newFeeDistributor).init(newFragment, _quoteToken, stakeToken);
{ {
uint256[] memory _dvmParams = dvmParams; uint256[] memory _dvmParams = dvmParams;
@@ -161,7 +160,9 @@ contract DODONFTProxy is ReentrancyGuard, InitializableOwnable {
uint256 stakeAmount, uint256 stakeAmount,
uint8 flag // 0 - ERC20, 1 - ETH uint8 flag // 0 - ERC20, 1 - ETH
) external payable preventReentrant { ) external payable preventReentrant {
_deposit(msg.sender, feeDistributor, IFeeDistributor(feeDistributor)._STAKE_TOKEN_(), stakeAmount, flag == 1); address stakeVault = IFeeDistributor(feeDistributor)._STAKE_VAULT_();
require(stakeVault != address(0), "DODONFTProxy:STAKE_VAULT_EMPTY");
_deposit(msg.sender, stakeVault, IFeeDistributor(feeDistributor)._STAKE_TOKEN_(), stakeAmount, flag == 1);
IFeeDistributor(feeDistributor).stake(msg.sender); IFeeDistributor(feeDistributor).stake(msg.sender);
emit Stake(msg.sender, feeDistributor, stakeAmount); emit Stake(msg.sender, feeDistributor, stakeAmount);
} }

View File

@@ -18,4 +18,6 @@ interface IFeeDistributor {
function _STAKE_TOKEN_() external view returns(address); function _STAKE_TOKEN_() external view returns(address);
function _STAKE_VAULT_() external view returns(address);
} }

View File

@@ -4,12 +4,11 @@
SPDX-License-Identifier: Apache-2.0 SPDX-License-Identifier: Apache-2.0
*/ */
import { decimalStr, mweiStr } from '../utils/Converter'; import { decimalStr, mweiStr, fromWei } from '../utils/Converter';
import { logGas } from '../utils/Log'; import { logGas } from '../utils/Log';
import { NFTContext, getDODONftContext } from '../utils/NFTContext'; import { NFTContext, getDODONftContext } from '../utils/NFTContext';
import { assert } from 'chai'; import { assert } from 'chai';
import * as contracts from '../utils/Contracts'; import * as contracts from '../utils/Contracts';
import { Contract } from 'web3-eth-contract';
let author: string; let author: string;
let user1: string; let user1: string;
@@ -23,26 +22,73 @@ async function init(ctx: NFTContext): Promise<void> {
await ctx.mintTestToken(user1, ctx.USDT, mweiStr("10000")); await ctx.mintTestToken(user1, ctx.USDT, mweiStr("10000"));
await ctx.mintTestToken(user2, ctx.USDT, mweiStr("10000")); await ctx.mintTestToken(user2, ctx.USDT, mweiStr("10000"));
await ctx.approveProxy(user1); await ctx.approveProxy(ctx.USDT, user1);
await ctx.approveProxy(user2); await ctx.approveProxy(ctx.USDT, user2);
} }
async function createNFTVault(ctx: NFTContext) { async function getFeeGlobalState(ctx: NFTContext, feeAddress: string, baseToken, quoteToken, stakeToken) {
var tx = await ctx.NFTProxy.methods.createNFTCollateralVault( let feeInstance = contracts.getContractWithAddress(contracts.NFT_FEE, feeAddress);
"DODONFT", let baseReserve = await feeInstance.methods._BASE_RESERVE_().call();
"https://app.dodoex.io" let quoteReserve = await feeInstance.methods._QUOTE_RESERVE_().call();
).send(ctx.sendParam(author)); let baseBalance = await baseToken.methods.balanceOf(feeAddress).call();
let quoteBalance = await quoteToken.methods.balanceOf(feeAddress).call();
let stakeVault = await feeInstance.methods._STAKE_VAULT_().call();
let stakeBalance = await stakeToken.methods.balanceOf(stakeVault).call();
let stakeReserve = await feeInstance.methods._STAKE_RESERVE_().call();
let baseRatio = await feeInstance.methods._BASE_REWARD_RATIO_().call();
let quoteRatio = await feeInstance.methods._QUOTE_REWARD_RATIO_().call();
return tx.events['CreateNFTCollateralVault']['returnValues']['vault']; console.log("fee baseBalance:" + fromWei(baseBalance, 'ether') + " quoteBalance:" + fromWei(quoteBalance, 'mwei') + " vault stakeBalance:" + fromWei(stakeBalance, 'ether'));
console.log("fee baseReserve:" + fromWei(baseReserve, 'ether') + " quoteReserve:" + fromWei(quoteReserve, 'mwei') + " stakeReserve:" + fromWei(stakeReserve, 'ether'));
console.log("baseRatio:" + fromWei(baseRatio, 'ether') + " quoteRatio:" + fromWei(quoteRatio, 'mwei'));
return {
"baseReserve": baseReserve,
"quoteReserve": quoteReserve,
"stakeReserve": stakeReserve,
"baseBalance": baseBalance,
"quoteBalance": quoteBalance,
"stakeBalance": stakeBalance,
"baseRatio": baseRatio,
"quoteRatio": quoteRatio
}
} }
async function createERC721(ctx:NFTContext) { async function getFeeUserState(ctx: NFTContext, feeAddress: string, userAddress: string) {
var tx = await ctx.NFTTokenFacotry.methods.createERC721( let feeInstance = contracts.getContractWithAddress(contracts.NFT_FEE, feeAddress);
"https://app.dodoex.io" let userShares = await feeInstance.methods._SHARES_(userAddress).call();
).send(ctx.sendParam(author)); let [baseRewards, quoteRewards] = await feeInstance.methods.getPendingReward(userAddress).call();
return tx.events['NewERC721']['returnValues']['erc721']; let userBasePerShares = await feeInstance.methods._USER_BASE_PER_SHARE_(userAddress).call();
let userQuotePerShares = await feeInstance.methods._USER_QUOTE_PER_SHARE_(userAddress).call();
console.log("user shares:" + fromWei(userShares, 'ether'));
console.log("user baseRewards:" + fromWei(baseRewards, 'ether') + " userQuoteRewards:" + fromWei(quoteRewards, 'mwei'));
console.log("user basePerShares:" + fromWei(userBasePerShares, 'ether') + " userQuotePerShares:" + fromWei(userQuotePerShares, 'mwei'));
return {
"userShares": userShares,
"userBaseRewards": baseRewards,
"userQuoteRewards": quoteRewards,
"userBasePerShares": userBasePerShares,
"userQuotePerShares": userQuotePerShares
}
} }
async function mockTrade(ctx: NFTContext, dvmAddress: string, dvmInstance, fragInstance) {
await ctx.transferQuoteToDVM(ctx.USDT, dvmAddress, user1, mweiStr("20"));
await dvmInstance.methods.sellQuote(user1).send(ctx.sendParam(user1));
await ctx.transferBaseToDVM(fragInstance, dvmAddress, user1, decimalStr("10"));
await dvmInstance.methods.sellBase(user1).send(ctx.sendParam(user1));
await ctx.transferQuoteToDVM(ctx.USDT, dvmAddress, user2, mweiStr("80"));
await dvmInstance.methods.sellQuote(user2).send(ctx.sendParam(user2));
await ctx.transferBaseToDVM(fragInstance, dvmAddress, user2, decimalStr("20"));
await dvmInstance.methods.sellBase(user2).send(ctx.sendParam(user2));
}
describe("DODONFT", () => { describe("DODONFT", () => {
let snapshotId: string; let snapshotId: string;
@@ -74,41 +120,43 @@ describe("DODONFT", () => {
}); });
it("createTokenAndTransferToVault", async () => { it("createTokenAndTransferToVault", async () => {
var erc721Address = await createERC721(ctx); var erc721Address = await ctx.createERC721(ctx, author);
var vaultAddress = await createNFTVault(ctx); var vaultAddress = await ctx.createNFTVault(ctx, author);
var nftVaultInstance = contracts.getContractWithAddress(contracts.NFT_VAULT, vaultAddress); var nftVaultInstance = contracts.getContractWithAddress(contracts.NFT_VAULT, vaultAddress);
var erc721Instance = contracts.getContractWithAddress(contracts.ERC721, erc721Address); var erc721Instance = contracts.getContractWithAddress(contracts.ERC721, erc721Address);
await erc721Instance.methods.safeTransferFrom(author, vaultAddress, 0).send(ctx.sendParam(author)); await erc721Instance.methods.safeTransferFrom(author, vaultAddress, 0).send(ctx.sendParam(author));
var nftIndex = await nftVaultInstance.methods.getIdByTokenIdAndAddr(erc721Address,0).call(); var nftIndex = await nftVaultInstance.methods.getIdByTokenIdAndAddr(erc721Address, 0).call();
var nftInfo = await nftVaultInstance.methods.getNftInfoById(nftIndex).call(); var nftInfo = await nftVaultInstance.methods.getNftInfoById(nftIndex).call();
assert(nftInfo.amount, '1') assert(nftInfo.amount, '1')
assert(nftInfo.tokenId, '0') assert(nftInfo.tokenId, '0')
}); });
it.only("createFragment", async () => { it("createFragment", async () => {
var erc721Address = await createERC721(ctx); var erc721Address = await ctx.createERC721(ctx, author);
var vaultAddress = await createNFTVault(ctx); var vaultAddress = await ctx.createNFTVault(ctx, author);
var nftVaultInstance = contracts.getContractWithAddress(contracts.NFT_VAULT, vaultAddress); var nftVaultInstance = contracts.getContractWithAddress(contracts.NFT_VAULT, vaultAddress);
var erc721Instance = contracts.getContractWithAddress(contracts.ERC721, erc721Address); var erc721Instance = contracts.getContractWithAddress(contracts.ERC721, erc721Address);
await erc721Instance.methods.safeTransferFrom(author, vaultAddress, 0).send(ctx.sendParam(author)); await erc721Instance.methods.safeTransferFrom(author, vaultAddress, 0).send(ctx.sendParam(author));
var quoteToken = "0x156595bAF85D5C29E91d959889B022d952190A64"; // var quoteToken = "0x156595bAF85D5C29E91d959889B022d952190A64";
var vaultPreOwner = "0xaac153c1344cA14497A5dd22b1F70C28793625aa"; // var vaultPreOwner = "0xaac153c1344cA14497A5dd22b1F70C28793625aa";
var stakeToken = "0x854b0f89BAa9101e49Bfb357A38071C9db5d0DFa"; // var stakeToken = "0x854b0f89BAa9101e49Bfb357A38071C9db5d0DFa";
// var quoteToken = ctx.USDT.options.address; var quoteToken = ctx.USDT.options.address;
// var vaultPreOwner = author; var vaultPreOwner = author;
// var stakeToken = "0x0000000000000000000000000000000000000000"; var stakeToken = "0x0000000000000000000000000000000000000000";
var dvmParams = [ var dvmParams = [
"0", "0", //lpFeeRate
"10000000000000000", decimalStr("0.01"), //mtFeeRate
"1000000", mweiStr("1"), // I
"1000000000000000000" decimalStr("1") // K
]; ];
var fragParams = [ var fragParams = [
"100000000000000000000000000", decimalStr("100000000"), //totalSupply
"200000000000000000", decimalStr("0.2"), //ownerRatio
"1617976800" Math.floor(new Date().getTime() / 1000 + 60 * 60) //buyoutTimeStamp 1h later
] ]
var isOpenTwap = false var isOpenTwap = false
var callData = ctx.NFTProxy.methods.createFragment( var callData = ctx.NFTProxy.methods.createFragment(
quoteToken, quoteToken,
@@ -118,35 +166,96 @@ describe("DODONFT", () => {
fragParams, fragParams,
isOpenTwap isOpenTwap
).encodeABI(); ).encodeABI();
console.log("data:",callData); console.log("data:", callData);
// var tx = await logGas(await nftVaultInstance.methods.createFragment( await logGas(await nftVaultInstance.methods.createFragment(
// ctx.NFTProxy.options.address, ctx.NFTProxy.options.address,
// callData callData
// ), ctx.sendParam(author), "createFragment"); ), ctx.sendParam(author), "createFragment");
// console.log("tx:",tx); let [fragAddress, , dvmAddress] = await ctx.getRegistry(ctx, vaultAddress);
var dvmInstance = contracts.getContractWithAddress(contracts.DVM_NAME, dvmAddress);
var midPrice = await dvmInstance.methods.getMidPrice().call();
assert(midPrice, mweiStr("1"));
let newVaultOwner = await nftVaultInstance.methods._OWNER_().call();
assert(fragAddress, newVaultOwner);
}); });
it("stakeToFeeDistributor", async () => { it.only("stakeToFeeDistributor", async () => {
let [vaultAddress, fragAddress, feeAddress, dvmAddress] = await ctx.createFragment(ctx, author, null, null, null);
}); var nftFeeInstance = contracts.getContractWithAddress(contracts.NFT_FEE, feeAddress);
var dvmInstance = contracts.getContractWithAddress(contracts.DVM_NAME, dvmAddress);
var fragInstance = contracts.getContractWithAddress(contracts.NFT_FRAG, fragAddress);
await ctx.approveProxy(fragInstance, user1);
await ctx.approveProxy(fragInstance, user2);
//mock trading
//stake
await mockTrade(ctx, dvmAddress, dvmInstance, fragInstance);
it("dvm-trade", async () => { await logGas(await ctx.NFTProxy.methods.stakeToFeeDistributor(
feeAddress,
decimalStr("5"),
0
), ctx.sendParam(user1), "stakeToFeeDistributor");
}); await logGas(await ctx.NFTProxy.methods.stakeToFeeDistributor(
feeAddress,
decimalStr("10"),
0
), ctx.sendParam(user2), "stakeToFeeDistributor");
it("claim", async () => { await mockTrade(ctx, dvmAddress, dvmInstance, fragInstance);
}); await logGas(await ctx.NFTProxy.methods.stakeToFeeDistributor(
feeAddress,
decimalStr("10"),
0
), ctx.sendParam(user1), "stakeToFeeDistributor");
it("unstake", async () => { await logGas(await ctx.NFTProxy.methods.stakeToFeeDistributor(
feeAddress,
decimalStr("20"),
0
), ctx.sendParam(user2), "stakeToFeeDistributor");
let globalObj = await getFeeGlobalState(ctx, feeAddress, fragInstance, ctx.USDT, fragInstance);
assert(globalObj['quoteBalance'], mweiStr("0.6"));
assert(globalObj['stakeReserve'], decimalStr("45"));
let user1Obj = await getFeeUserState(ctx, feeAddress, user1);
assert(user1Obj['userQuoteRewards'], mweiStr("0.1"));
assert(user1Obj['userShares'], decimalStr("15"));
let user2Obj = await getFeeUserState(ctx, feeAddress, user2);
assert(user2Obj['userBaseRewards'], decimalStr("0.66666480000453957"));
assert(user2Obj['userShares'], decimalStr("30"));
//claim
var user1BaseBalanceStart = await fragInstance.methods.balanceOf(user1).call()
await logGas(await nftFeeInstance.methods.claim(user1), ctx.sendParam(user1), "claim");
var user1BaseBalanceEnd = await fragInstance.methods.balanceOf(user1).call()
user1Obj = await getFeeUserState(ctx, feeAddress, user1);
await getFeeGlobalState(ctx, feeAddress, fragInstance, ctx.USDT, fragInstance);
assert(user1Obj['userQuoteRewards'], "0");
assert(globalObj['quoteBalance'], mweiStr("0.5"));
assert(user1BaseBalanceEnd - user1BaseBalanceStart, "333332400002269700");
//unstake
var user2BaseBalanceStart = await fragInstance.methods.balanceOf(user2).call()
await logGas(await nftFeeInstance.methods.unstake(decimalStr("30"),user2, true), ctx.sendParam(user2), "unstake");
var user2BaseBalanceEnd = await fragInstance.methods.balanceOf(user2).call()
user2Obj = await getFeeUserState(ctx, feeAddress, user2);
await getFeeGlobalState(ctx, feeAddress, fragInstance, ctx.USDT, fragInstance);
assert(user2Obj['userQuoteRewards'], "0");
assert(globalObj['quoteBalance'], mweiStr("0.3"));
assert(globalObj['stakeReserve'], mweiStr("15"));
assert(globalObj['stakeBalance'], mweiStr("15"));
assert(user2BaseBalanceEnd - user2BaseBalanceStart, "30666664800004540000");
}); });
it("buyout", async () => { it("buyout", async () => {
}); });
it("redeem", async () => { it("redeem", async () => {

View File

@@ -24,7 +24,7 @@ export class NFTContext {
EVM: EVM; EVM: EVM;
Web3: Web3; Web3: Web3;
NFTTokenFacotry: Contract; NFTTokenFacotry: Contract;
NFTRegister: Contract; NFTRegister: Contract;
CollatteralVault: Contract; CollatteralVault: Contract;
Fragment: Contract; Fragment: Contract;
@@ -33,10 +33,11 @@ export class NFTContext {
NFTProxy: Contract; NFTProxy: Contract;
DODOApprove: Contract; DODOApprove: Contract;
DODOApproveProxy: Contract; DODOApproveProxy: Contract;
//token //token
USDT: Contract; USDT: Contract;
WETH: Contract; WETH: Contract;
DODO: Contract;
Deployer: string; Deployer: string;
Maintainer: string; Maintainer: string;
@@ -59,6 +60,11 @@ export class NFTContext {
["USDT Token", "USDT", 6] ["USDT Token", "USDT", 6]
); );
this.DODO = await contracts.newContract(
contracts.MINTABLE_ERC20_CONTRACT_NAME,
["DODO Token", "DODO", 6]
);
var cloneFactory = await contracts.newContract( var cloneFactory = await contracts.newContract(
contracts.CLONE_FACTORY_CONTRACT_NAME contracts.CLONE_FACTORY_CONTRACT_NAME
); );
@@ -116,6 +122,8 @@ export class NFTContext {
await this.NFTProxy.methods.initOwner(this.Deployer).send(this.sendParam(this.Deployer)); await this.NFTProxy.methods.initOwner(this.Deployer).send(this.sendParam(this.Deployer));
await this.NFTRegister.methods.addAmindList(this.NFTProxy.options.address).send(this.sendParam(this.Deployer));
await this.DODOApprove.methods.init(this.Deployer, this.DODOApproveProxy.options.address).send(this.sendParam(this.Deployer)); await this.DODOApprove.methods.init(this.Deployer, this.DODOApproveProxy.options.address).send(this.sendParam(this.Deployer));
await this.DODOApproveProxy.methods.init(this.Deployer, [this.NFTProxy.options.address]).send(this.sendParam(this.Deployer)); await this.DODOApproveProxy.methods.init(this.Deployer, [this.NFTProxy.options.address]).send(this.sendParam(this.Deployer));
@@ -136,14 +144,91 @@ export class NFTContext {
await token.methods.mint(to, amount).send(this.sendParam(this.Deployer)); await token.methods.mint(to, amount).send(this.sendParam(this.Deployer));
} }
async approveProxy(account: string) { async approveProxy(token, account: string) {
await this.USDT.methods await token.methods
.approve(this.DODOApprove.options.address, MAX_UINT256)
.send(this.sendParam(account));
await this.WETH.methods
.approve(this.DODOApprove.options.address, MAX_UINT256) .approve(this.DODOApprove.options.address, MAX_UINT256)
.send(this.sendParam(account)); .send(this.sendParam(account));
} }
async getRegistry(ctx: NFTContext, vaultAddress: string) {
let fragAddress = await ctx.NFTRegister.methods._VAULT_FRAG_REGISTRY_(vaultAddress).call();
let feeDistrubitor = await ctx.NFTRegister.methods._FRAG_FEE_REGISTRY_(fragAddress).call();
let fragInstance = contracts.getContractWithAddress(contracts.NFT_FRAG, fragAddress);
let dvmAddress = await fragInstance.methods._DVM_().call();
return [fragAddress, feeDistrubitor, dvmAddress];
}
async createNFTVault(ctx: NFTContext, author: string) {
var tx = await ctx.NFTProxy.methods.createNFTCollateralVault(
"DODONFT",
"https://app.dodoex.io"
).send(ctx.sendParam(author));
return tx.events['CreateNFTCollateralVault']['returnValues']['vault'];
}
async createERC721(ctx: NFTContext, author: string) {
var tx = await ctx.NFTTokenFacotry.methods.createERC721(
"https://app.dodoex.io"
).send(ctx.sendParam(author));
return tx.events['NewERC721']['returnValues']['erc721'];
}
async createFragment(ctx: NFTContext, author: string, dvmParams, fragParams, addrs) {
var erc721Address = await this.createERC721(ctx, author);
var vaultAddress = await this.createNFTVault(ctx, author);
var nftVaultInstance = contracts.getContractWithAddress(contracts.NFT_VAULT, vaultAddress);
var erc721Instance = contracts.getContractWithAddress(contracts.ERC721, erc721Address);
await erc721Instance.methods.safeTransferFrom(author, vaultAddress,0).send(ctx.sendParam(author));
if (dvmParams == null) {
dvmParams = [
"0", //lpFeeRate
decimalStr("0.01"), //mtFeeRate
mweiStr("1"), // I
decimalStr("1") // K
];
}
if (fragParams == null) {
fragParams = [
decimalStr("100000000"), //totalSupply
decimalStr("0.2"), //ownerRatio
Math.floor(new Date().getTime() / 1000 + 60 * 60) //buyoutTimeStamp 1h later
]
}
if (addrs == null) {
addrs = []
addrs.push(ctx.USDT.options.address);//quoteToken
addrs.push(author);//vaultPreOwner
addrs.push("0x0000000000000000000000000000000000000000");//stakeToken
}
var callData = ctx.NFTProxy.methods.createFragment(
addrs[0],
addrs[1],
addrs[2],
dvmParams,
fragParams,
false
).encodeABI();
await nftVaultInstance.methods.createFragment(
ctx.NFTProxy.options.address,
callData
).send(ctx.sendParam(author));
let [fragAddress, feeAddress, dvmAddress] = await this.getRegistry(ctx, vaultAddress);
return [vaultAddress, fragAddress, feeAddress, dvmAddress, callData]
}
async transferBaseToDVM(baseToken, dvm: string, account: string, amount: string) {
await baseToken.methods.transfer(dvm, amount).send(this.sendParam(account))
}
async transferQuoteToDVM(quoteToken, dvm: string, account: string, amount: string) {
await quoteToken.methods.transfer(dvm, amount).send(this.sendParam(account))
}
} }
export async function getDODONftContext(weth: string): Promise<NFTContext> { export async function getDODONftContext(weth: string): Promise<NFTContext> {

View File

@@ -1,5 +1,5 @@
#!/bin/bash #!/bin/bash
# truffle compile --all truffle compile --all
if [ "$1"x = "proxy-dpp"x ] if [ "$1"x = "proxy-dpp"x ]
then then