nft test ing
This commit is contained in:
@@ -63,7 +63,7 @@ module.exports = {
|
||||
|
||||
//================== NFT ====================
|
||||
ConstFeeRateModel: "0xBDAcEcF886a4F0C509260d9678D5673C3E8fa4b7",
|
||||
FeeDistributor: "0x1eD92Fe9c3AE1cC427004eC27AAd96df4928B3ec",
|
||||
FeeDistributor: "",
|
||||
Fragment: "0x64193839f8b6e85A257411a945085783cbA9976B",
|
||||
NFTCollateralVault: "0xFDf7604649dfBb733e784afAEdC19892706cc683",
|
||||
DODONFTRouteHelper: "0xAE683548702be6d651e179e5F9313272bb18596A",
|
||||
@@ -73,6 +73,6 @@ module.exports = {
|
||||
NFTTokenFactory: "0x38c109aF4f3454172BA4eecf5676aA213b589e75",
|
||||
|
||||
DODONFTRegistry: "0xF405372b7808363DCfbb5Eb81204889B7a69Aa3e",
|
||||
DODONFTProxy: "0x622332C5e5B3E8B67Aee300184Ce024E428A89f8",
|
||||
DODONFTProxy: "",
|
||||
}
|
||||
}
|
||||
@@ -29,15 +29,15 @@ contract FeeDistributor {
|
||||
uint256 public _STAKE_RESERVE_;
|
||||
|
||||
uint256 public _BASE_REWARD_RATIO_;
|
||||
mapping(address => uint256) internal _USER_BASE_REWARDS_;
|
||||
mapping(address => uint256) internal _USER_BASE_PER_SHARE_;
|
||||
|
||||
uint256 public _QUOTE_REWARD_RATIO_;
|
||||
mapping(address => uint256) internal _USER_QUOTE_REWARDS_;
|
||||
mapping(address => uint256) internal _USER_QUOTE_PER_SHARE_;
|
||||
mapping(address => uint256) public _USER_BASE_REWARDS_;
|
||||
mapping(address => uint256) public _USER_BASE_PER_SHARE_;
|
||||
|
||||
uint256 public _QUOTE_REWARD_RATIO_;
|
||||
mapping(address => uint256) public _USER_QUOTE_REWARDS_;
|
||||
mapping(address => uint256) public _USER_QUOTE_PER_SHARE_;
|
||||
|
||||
mapping(address => uint256) public _SHARES_;
|
||||
|
||||
mapping(address => uint256) internal _SHARES_;
|
||||
|
||||
bool internal _FEE_INITIALIZED_;
|
||||
|
||||
// ============ Event ============
|
||||
@@ -46,13 +46,13 @@ contract FeeDistributor {
|
||||
event Claim(address sender, uint256 baseAmount, uint256 quoteAmount);
|
||||
|
||||
function init(
|
||||
address baseToken,
|
||||
address quoteToken,
|
||||
address stakeToken
|
||||
address baseToken,
|
||||
address quoteToken,
|
||||
address stakeToken
|
||||
) external {
|
||||
require(!_FEE_INITIALIZED_, "ALREADY_INITIALIZED");
|
||||
_FEE_INITIALIZED_ = true;
|
||||
|
||||
|
||||
_BASE_TOKEN_ = baseToken;
|
||||
_QUOTE_TOKEN_ = quoteToken;
|
||||
_STAKE_TOKEN_ = stakeToken;
|
||||
@@ -60,86 +60,126 @@ contract FeeDistributor {
|
||||
}
|
||||
|
||||
function stake(address to) external {
|
||||
_updateGlobalState();
|
||||
_updateUserReward(to);
|
||||
uint256 stakeVault = IERC20(_STAKE_TOKEN_).balanceOf(_STAKE_VAULT_);
|
||||
uint256 stakeInput = stakeVault.sub(_STAKE_RESERVE_);
|
||||
_addShares(stakeInput, to);
|
||||
emit Stake(to, stakeInput);
|
||||
_updateGlobalState();
|
||||
_updateUserReward(to);
|
||||
uint256 stakeVault = IERC20(_STAKE_TOKEN_).balanceOf(_STAKE_VAULT_);
|
||||
uint256 stakeInput = stakeVault.sub(_STAKE_RESERVE_);
|
||||
_addShares(stakeInput, to);
|
||||
emit Stake(to, stakeInput);
|
||||
}
|
||||
|
||||
function claim(address to) external {
|
||||
_updateGlobalState();
|
||||
_updateUserReward(msg.sender);
|
||||
_claim(msg.sender, to);
|
||||
_updateGlobalState();
|
||||
_updateUserReward(msg.sender);
|
||||
_claim(msg.sender, to);
|
||||
}
|
||||
|
||||
function unstake(uint256 amount, address to, bool withClaim) external {
|
||||
require(_SHARES_[msg.sender]>=amount, "STAKE BALANCE ONT ENOUGH");
|
||||
_updateGlobalState();
|
||||
_updateUserReward(msg.sender);
|
||||
function unstake(
|
||||
uint256 amount,
|
||||
address to,
|
||||
bool withClaim
|
||||
) external {
|
||||
require(_SHARES_[msg.sender] >= amount, "STAKE BALANCE ONT ENOUGH");
|
||||
_updateGlobalState();
|
||||
_updateUserReward(msg.sender);
|
||||
|
||||
if (withClaim) {
|
||||
_claim(msg.sender, to);
|
||||
}
|
||||
if (withClaim) {
|
||||
_claim(msg.sender, to);
|
||||
}
|
||||
|
||||
_removeShares(amount, msg.sender);
|
||||
StakeVault(_STAKE_VAULT_).transferOut(_STAKE_TOKEN_, amount, to);
|
||||
emit UnStake(msg.sender, amount);
|
||||
StakeVault(_STAKE_VAULT_).transferOut(_STAKE_TOKEN_, amount, to);
|
||||
_removeShares(amount, msg.sender);
|
||||
|
||||
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 ============
|
||||
|
||||
function _claim(address sender, address to) internal {
|
||||
uint256 allBase = _USER_BASE_REWARDS_[sender];
|
||||
uint256 allQuote = _USER_QUOTE_REWARDS_[sender];
|
||||
IERC20(_BASE_TOKEN_).safeTransfer(to, allBase);
|
||||
IERC20(_QUOTE_TOKEN_).safeTransfer(to, allQuote);
|
||||
_USER_BASE_REWARDS_[sender] = 0;
|
||||
_USER_BASE_REWARDS_[sender] = 0;
|
||||
emit Claim(sender, allBase, allQuote);
|
||||
uint256 allBase = _USER_BASE_REWARDS_[sender];
|
||||
uint256 allQuote = _USER_QUOTE_REWARDS_[sender];
|
||||
IERC20(_BASE_TOKEN_).safeTransfer(to, allBase);
|
||||
IERC20(_QUOTE_TOKEN_).safeTransfer(to, allQuote);
|
||||
|
||||
_BASE_RESERVE_ = _BASE_RESERVE_.sub(allBase);
|
||||
_QUOTE_RESERVE_ = _QUOTE_RESERVE_.sub(allQuote);
|
||||
_USER_BASE_REWARDS_[sender] = 0;
|
||||
_USER_QUOTE_REWARDS_[sender] = 0;
|
||||
|
||||
emit Claim(sender, allBase, allQuote);
|
||||
}
|
||||
|
||||
function _updateGlobalState() internal {
|
||||
uint256 baseInput = IERC20(_BASE_TOKEN_).balanceOf(address(this)).sub(_BASE_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_));
|
||||
_BASE_RESERVE_ = _BASE_RESERVE_.add(baseInput);
|
||||
_QUOTE_RESERVE_ = _QUOTE_RESERVE_.add(quoteInput);
|
||||
uint256 baseInput = IERC20(_BASE_TOKEN_).balanceOf(address(this)).sub(_BASE_RESERVE_);
|
||||
uint256 quoteInput = IERC20(_QUOTE_TOKEN_).balanceOf(address(this)).sub(_QUOTE_RESERVE_);
|
||||
|
||||
if (_STAKE_RESERVE_ != 0) {
|
||||
_BASE_REWARD_RATIO_ = _BASE_REWARD_RATIO_.add(
|
||||
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 {
|
||||
_USER_BASE_REWARDS_[user] = DecimalMath.mulFloor(
|
||||
_SHARES_[user],
|
||||
_BASE_REWARD_RATIO_.sub(_USER_BASE_PER_SHARE_[user])
|
||||
).add(_USER_BASE_REWARDS_[user]);
|
||||
_USER_BASE_REWARDS_[user] = DecimalMath
|
||||
.mulFloor(_SHARES_[user], _BASE_REWARD_RATIO_.sub(_USER_BASE_PER_SHARE_[user]))
|
||||
.add(_USER_BASE_REWARDS_[user]);
|
||||
|
||||
_USER_BASE_PER_SHARE_[user] = _BASE_REWARD_RATIO_;
|
||||
|
||||
_USER_QUOTE_REWARDS_[user] = DecimalMath.mulFloor(
|
||||
_SHARES_[user],
|
||||
_QUOTE_REWARD_RATIO_.sub(_USER_QUOTE_PER_SHARE_[user])
|
||||
).add(_USER_QUOTE_REWARDS_[user]);
|
||||
_USER_QUOTE_REWARDS_[user] = DecimalMath
|
||||
.mulFloor(_SHARES_[user], _QUOTE_REWARD_RATIO_.sub(_USER_QUOTE_PER_SHARE_[user]))
|
||||
.add(_USER_QUOTE_REWARDS_[user]);
|
||||
|
||||
_USER_QUOTE_PER_SHARE_[user] = _QUOTE_REWARD_RATIO_;
|
||||
}
|
||||
|
||||
function _addShares(uint256 amount, address to) internal {
|
||||
_SHARES_[to] = _SHARES_[to].add(amount);
|
||||
_STAKE_RESERVE_ = IERC20(_STAKE_TOKEN_).balanceOf(_STAKE_VAULT_);
|
||||
_SHARES_[to] = _SHARES_[to].add(amount);
|
||||
_STAKE_RESERVE_ = IERC20(_STAKE_TOKEN_).balanceOf(_STAKE_VAULT_);
|
||||
}
|
||||
|
||||
function _removeShares(uint256 amount, address from) internal {
|
||||
_SHARES_[from] = _SHARES_[from].sub(amount);
|
||||
_STAKE_RESERVE_ = IERC20(_STAKE_TOKEN_).balanceOf(_STAKE_VAULT_);
|
||||
_SHARES_[from] = _SHARES_[from].sub(amount);
|
||||
_STAKE_RESERVE_ = IERC20(_STAKE_TOKEN_).balanceOf(_STAKE_VAULT_);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
contract StakeVault is Ownable {
|
||||
using SafeERC20 for IERC20;
|
||||
|
||||
|
||||
function transferOut(
|
||||
address token,
|
||||
uint256 amount,
|
||||
|
||||
@@ -95,11 +95,10 @@ contract DODONFTProxy is ReentrancyGuard, InitializableOwnable {
|
||||
emit CreateNFTCollateralVault(msg.sender, newVault, name, baseURI);
|
||||
}
|
||||
|
||||
//Stake 碎片
|
||||
function createFragment(
|
||||
address quoteToken,
|
||||
address vaultPreOwner,
|
||||
address stakeToken,
|
||||
address stakeToken, //address(0) using frag token
|
||||
uint256[] calldata dvmParams, //0 - lpFeeRate, 1 - mtFeeRate 2 - I, 3 - K
|
||||
uint256[] calldata fragParams, //0 - totalSupply, 1 - ownerRatio, 2 - buyoutTimestamp
|
||||
bool isOpenTwap
|
||||
@@ -108,11 +107,11 @@ contract DODONFTProxy is ReentrancyGuard, InitializableOwnable {
|
||||
address _quoteToken = quoteToken == _ETH_ADDRESS_ ? _WETH_ : quoteToken;
|
||||
|
||||
if(stakeToken == address(0)) {
|
||||
newFeeDistributor = address(0);
|
||||
} else {
|
||||
newFeeDistributor = ICloneFactory(_CLONE_FACTORY_).clone(_FEE_TEMPLATE_);
|
||||
IFeeDistributor(newFeeDistributor).init(newFragment, _quoteToken, stakeToken);
|
||||
}
|
||||
stakeToken = newFragment;
|
||||
}
|
||||
|
||||
newFeeDistributor = ICloneFactory(_CLONE_FACTORY_).clone(_FEE_TEMPLATE_);
|
||||
IFeeDistributor(newFeeDistributor).init(newFragment, _quoteToken, stakeToken);
|
||||
|
||||
{
|
||||
uint256[] memory _dvmParams = dvmParams;
|
||||
@@ -161,7 +160,9 @@ contract DODONFTProxy is ReentrancyGuard, InitializableOwnable {
|
||||
uint256 stakeAmount,
|
||||
uint8 flag // 0 - ERC20, 1 - ETH
|
||||
) 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);
|
||||
emit Stake(msg.sender, feeDistributor, stakeAmount);
|
||||
}
|
||||
|
||||
@@ -18,4 +18,6 @@ interface IFeeDistributor {
|
||||
|
||||
function _STAKE_TOKEN_() external view returns(address);
|
||||
|
||||
function _STAKE_VAULT_() external view returns(address);
|
||||
|
||||
}
|
||||
|
||||
@@ -4,12 +4,11 @@
|
||||
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 { NFTContext, getDODONftContext } from '../utils/NFTContext';
|
||||
import { assert } from 'chai';
|
||||
import * as contracts from '../utils/Contracts';
|
||||
import { Contract } from 'web3-eth-contract';
|
||||
|
||||
let author: 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(user2, ctx.USDT, mweiStr("10000"));
|
||||
|
||||
await ctx.approveProxy(user1);
|
||||
await ctx.approveProxy(user2);
|
||||
await ctx.approveProxy(ctx.USDT, user1);
|
||||
await ctx.approveProxy(ctx.USDT, user2);
|
||||
}
|
||||
|
||||
async function createNFTVault(ctx: NFTContext) {
|
||||
var tx = await ctx.NFTProxy.methods.createNFTCollateralVault(
|
||||
"DODONFT",
|
||||
"https://app.dodoex.io"
|
||||
).send(ctx.sendParam(author));
|
||||
async function getFeeGlobalState(ctx: NFTContext, feeAddress: string, baseToken, quoteToken, stakeToken) {
|
||||
let feeInstance = contracts.getContractWithAddress(contracts.NFT_FEE, feeAddress);
|
||||
let baseReserve = await feeInstance.methods._BASE_RESERVE_().call();
|
||||
let quoteReserve = await feeInstance.methods._QUOTE_RESERVE_().call();
|
||||
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) {
|
||||
var tx = await ctx.NFTTokenFacotry.methods.createERC721(
|
||||
"https://app.dodoex.io"
|
||||
).send(ctx.sendParam(author));
|
||||
return tx.events['NewERC721']['returnValues']['erc721'];
|
||||
async function getFeeUserState(ctx: NFTContext, feeAddress: string, userAddress: string) {
|
||||
let feeInstance = contracts.getContractWithAddress(contracts.NFT_FEE, feeAddress);
|
||||
let userShares = await feeInstance.methods._SHARES_(userAddress).call();
|
||||
let [baseRewards, quoteRewards] = await feeInstance.methods.getPendingReward(userAddress).call();
|
||||
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", () => {
|
||||
let snapshotId: string;
|
||||
@@ -74,41 +120,43 @@ describe("DODONFT", () => {
|
||||
});
|
||||
|
||||
it("createTokenAndTransferToVault", async () => {
|
||||
var erc721Address = await createERC721(ctx);
|
||||
var vaultAddress = await createNFTVault(ctx);
|
||||
var erc721Address = await ctx.createERC721(ctx, author);
|
||||
var vaultAddress = await ctx.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));
|
||||
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();
|
||||
assert(nftInfo.amount, '1')
|
||||
assert(nftInfo.tokenId, '0')
|
||||
});
|
||||
|
||||
it.only("createFragment", async () => {
|
||||
var erc721Address = await createERC721(ctx);
|
||||
var vaultAddress = await createNFTVault(ctx);
|
||||
it("createFragment", async () => {
|
||||
var erc721Address = await ctx.createERC721(ctx, author);
|
||||
var vaultAddress = await ctx.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));
|
||||
|
||||
var quoteToken = "0x156595bAF85D5C29E91d959889B022d952190A64";
|
||||
var vaultPreOwner = "0xaac153c1344cA14497A5dd22b1F70C28793625aa";
|
||||
var stakeToken = "0x854b0f89BAa9101e49Bfb357A38071C9db5d0DFa";
|
||||
// var quoteToken = ctx.USDT.options.address;
|
||||
// var vaultPreOwner = author;
|
||||
// var stakeToken = "0x0000000000000000000000000000000000000000";
|
||||
// var quoteToken = "0x156595bAF85D5C29E91d959889B022d952190A64";
|
||||
// var vaultPreOwner = "0xaac153c1344cA14497A5dd22b1F70C28793625aa";
|
||||
// var stakeToken = "0x854b0f89BAa9101e49Bfb357A38071C9db5d0DFa";
|
||||
var quoteToken = ctx.USDT.options.address;
|
||||
var vaultPreOwner = author;
|
||||
var stakeToken = "0x0000000000000000000000000000000000000000";
|
||||
|
||||
var dvmParams = [
|
||||
"0",
|
||||
"10000000000000000",
|
||||
"1000000",
|
||||
"1000000000000000000"
|
||||
"0", //lpFeeRate
|
||||
decimalStr("0.01"), //mtFeeRate
|
||||
mweiStr("1"), // I
|
||||
decimalStr("1") // K
|
||||
];
|
||||
var fragParams = [
|
||||
"100000000000000000000000000",
|
||||
"200000000000000000",
|
||||
"1617976800"
|
||||
decimalStr("100000000"), //totalSupply
|
||||
decimalStr("0.2"), //ownerRatio
|
||||
Math.floor(new Date().getTime() / 1000 + 60 * 60) //buyoutTimeStamp 1h later
|
||||
]
|
||||
|
||||
var isOpenTwap = false
|
||||
var callData = ctx.NFTProxy.methods.createFragment(
|
||||
quoteToken,
|
||||
@@ -118,35 +166,96 @@ describe("DODONFT", () => {
|
||||
fragParams,
|
||||
isOpenTwap
|
||||
).encodeABI();
|
||||
console.log("data:",callData);
|
||||
console.log("data:", callData);
|
||||
|
||||
// var tx = await logGas(await nftVaultInstance.methods.createFragment(
|
||||
// ctx.NFTProxy.options.address,
|
||||
// callData
|
||||
// ), ctx.sendParam(author), "createFragment");
|
||||
await logGas(await nftVaultInstance.methods.createFragment(
|
||||
ctx.NFTProxy.options.address,
|
||||
callData
|
||||
), 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("redeem", async () => {
|
||||
|
||||
@@ -24,7 +24,7 @@ export class NFTContext {
|
||||
EVM: EVM;
|
||||
Web3: Web3;
|
||||
NFTTokenFacotry: Contract;
|
||||
|
||||
|
||||
NFTRegister: Contract;
|
||||
CollatteralVault: Contract;
|
||||
Fragment: Contract;
|
||||
@@ -33,10 +33,11 @@ export class NFTContext {
|
||||
NFTProxy: Contract;
|
||||
DODOApprove: Contract;
|
||||
DODOApproveProxy: Contract;
|
||||
|
||||
|
||||
//token
|
||||
USDT: Contract;
|
||||
WETH: Contract;
|
||||
DODO: Contract;
|
||||
|
||||
Deployer: string;
|
||||
Maintainer: string;
|
||||
@@ -59,6 +60,11 @@ export class NFTContext {
|
||||
["USDT Token", "USDT", 6]
|
||||
);
|
||||
|
||||
this.DODO = await contracts.newContract(
|
||||
contracts.MINTABLE_ERC20_CONTRACT_NAME,
|
||||
["DODO Token", "DODO", 6]
|
||||
);
|
||||
|
||||
var cloneFactory = await contracts.newContract(
|
||||
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.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.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));
|
||||
}
|
||||
|
||||
async approveProxy(account: string) {
|
||||
await this.USDT.methods
|
||||
.approve(this.DODOApprove.options.address, MAX_UINT256)
|
||||
.send(this.sendParam(account));
|
||||
await this.WETH.methods
|
||||
async approveProxy(token, account: string) {
|
||||
await token.methods
|
||||
.approve(this.DODOApprove.options.address, MAX_UINT256)
|
||||
.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> {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#!/bin/bash
|
||||
# truffle compile --all
|
||||
truffle compile --all
|
||||
|
||||
if [ "$1"x = "proxy-dpp"x ]
|
||||
then
|
||||
|
||||
Reference in New Issue
Block a user