import BigNumber from 'bignumber.js'
import EthereumTx from "ethereumjs-tx";
import {
Env,
getABIConfig
} from './env'
import ClientFetch from '../utils/clientFetch'
import bancorABI from './env/abi/ethereum/abi-bancor'
import actionABI from './env/abi/ethereum/abi-auction'
import ringABI from './env/abi/ethereum/abi-ring'
import withdrawABI from './env/abi/ethereum/abi-withdraw'
import bankABI from './env/abi/ethereum/abi-bank'
import ktonABI from './env/abi/ethereum/abi-kton'
import landABI from './env/abi/ethereum/abi-land'
import lotteryABI from './env/abi/ethereum/abi-lottery'
import rolesUpdaterABI from './env/abi/ethereum/abi-rolesUpdater'
import landResourceABI from './env/abi/ethereum/abi-landResource'
import apostleAuctionABI from './env/abi/ethereum/abi-apostleAuction'
import apostleTakeBackABI from './env/abi/ethereum/abi-takeBack'
import apostleSiringABI from './env/abi/ethereum/abi-apostleSiring'
import apostleBaseABI from './env/abi/ethereum/abi-apostleBase'
import tokenUseABI from './env/abi/ethereum/abi-tokenUse'
import petBaseABI from './env/abi/ethereum/abi-petbase'
import uniswapExchangeABI from './env/abi/ethereum/abi-uniswapExchangeV2'
import swapBridgeABI from './env/abi/ethereum/abi-swapBridge'
import luckyBoxABI from './env/abi/ethereum/abi-luckyBag'
import itemTreasureABI from './env/abi/ethereum/abi-itemTreasure'
import itemTakeBackABI from './env/abi/ethereum/abi-itemTakeBack'
import furnaceItemBaseABI from './env/abi/ethereum/abi-furnaceItemBase'
import Utils from '../utils/index'
import UniswapUtils from '../utils/uniswap'
import { Currency, ChainId, Token, TokenAmount, Pair, WETH, Fetcher, Percent, Route, TradeType, Trade, JSBI, CurrencyAmount } from '@uniswap/sdk'
const loop = function () { }
/**
* @class
* Evolution Land for Ethereum
*/
class EthereumEvolutionLand {
/**
* constructor function.
* @param {object} web3js - web3js instance
* @param {string} network
*/
constructor(web3js, network, option = {}) {
this.version = '1.0.0'
this._web3js = web3js
this.env = Env(network)
this.ABIs = getABIConfig(network)
this.ABIClientFetch = new ClientFetch({
baseUrl: this.env.ABI_DOMAIN,
chainId: 60
})
this.ClientFetch = new ClientFetch({
baseUrl: this.env.DOMAIN,
chainId: 60
})
this.option = {
sign: true,
address: null,
...option
}
}
setCustomAccount(account) {
this.option.address = account
}
/**
* get web3js Current address.
* @returns {Promise<any>}
*/
getCurrentAccount() {
return new Promise((resolve, reject) => {
if (this.option.address) {
resolve(this.option.address)
}
this._web3js.eth.getAccounts((error, accounts) => {
if (error) {
reject(error)
} else {
resolve(accounts[0])
}
})
})
}
/**
* Interact with a contract.
* @param {string} methodName - contract method name
* @param {string} abiKey - If the contract exists in the configuration file, you can use the key in the configuration to get it directly.
* @param {json} abiString - ethereum ABI json
* @param contractParams - contract function with arguments
* @param sendParams - web3js send() arguments
* @param beforeFetch
* @param transactionHashCallback
* @param confirmationCallback
* @param receiptCallback
* @param errorCallback
* @returns {Promise<PromiEvent<any>>}
*/
async triggerContract({
methodName,
abiKey,
abiString,
contractParams = [],
sendParams = {}
}, {
beforeFetch = loop,
transactionHashCallback = loop,
confirmationCallback = loop,
receiptCallback = loop,
errorCallback = loop,
receiptFinal = loop,
unSignedTx = loop,
payload = {}
} = {}) {
try {
beforeFetch && beforeFetch();
let _contract = null;
let contractAddress = await this.getContractAddress(abiKey);
_contract = new this._web3js.eth.Contract(abiString, contractAddress);
const extendPayload = { ...payload, _contractAddress: contractAddress };
const _method = _contract.methods[methodName].apply(this, contractParams)
const from = await this.getCurrentAccount()
const gasRes = await this.ClientFetch.apiGasPrice({ wallet: this.option.address || from })
let estimateGas = 300000;
try {
let hexSendParams = { value: 0 }
Object.keys(sendParams).forEach((item) => {
hexSendParams[item] = Utils.toHex(sendParams[item])
})
estimateGas = await this.estimateGas(_method, this.option.address || from, gasRes.data.gas_price.standard, hexSendParams.value) || 300000;
} catch (e) {
console.log('estimateGas', e)
}
if (!this.option.sign) {
if (!this.option.address) {
throw Error('from account is empty!')
}
let hexSendParams = {}
Object.keys(sendParams).forEach((item) => {
hexSendParams[item] = Utils.toHex(sendParams[item])
})
const tx = new EthereumTx({
to: contractAddress,
value: 0,
nonce: gasRes.data.nonce,
gasPrice: gasRes.data.gas_price.standard,
gasLimit: Utils.toHex(estimateGas + 30000),
chainId: parseInt(await this.getNetworkId()),
data: _method ? _method.encodeABI() : '',
...hexSendParams
})
const serializedTx = tx.serialize().toString("hex")
unSignedTx && unSignedTx(serializedTx, extendPayload)
return serializedTx;
}
return _method.send({
from: await this.getCurrentAccount(),
value: 0,
gasLimit: Utils.toHex(estimateGas + 30000),
...sendParams
})
.once('transactionHash', (hash) => {
transactionHashCallback && transactionHashCallback(hash, extendPayload)
})
.once('confirmation', (confirmationNumber, receipt) => {
confirmationCallback && confirmationCallback(confirmationNumber, receipt, extendPayload)
})
.once('receipt', (receipt) => {
receiptCallback && receiptCallback(receipt, extendPayload)
})
.once('error', (error) => {
errorCallback && errorCallback(error, extendPayload)
})
// .then((receipt) =>{
// receiptFinal && receiptFinal(receipt, extendPayload);
// })
} catch (e) {
console.error('triggerContract', e)
const extendPayload = { ...payload, _contractAddress: contractAddress };
errorCallback && errorCallback(e, extendPayload)
}
// return _method.send.bind(this,{
// from: await this.getCurrentAccount(),
// value: 0,
// ...sendParams
// })
}
/**
* Interact with a contract.
* @param {string} methodName - contract method name
* @param {string} abiKey - If the contract exists in the configuration file, you can use the key in the configuration to get it directly.
* @param {json} abiString - ethereum ABI json
* @param contractParams - contract function with arguments
* @param sendParams - web3js send() arguments
* @param beforeFetch
* @param transactionHashCallback
* @param confirmationCallback
* @param receiptCallback
* @param errorCallback
* @returns {Promise<PromiEvent<any>>}
*/
async callContract({
methodName,
abiKey,
abiString,
contractParams = [],
}, {
beforeFetch = loop,
errorCallback = loop
} = {}) {
try {
beforeFetch && beforeFetch()
let _contract = null
let contractAddress = await this.getContractAddress(abiKey);
_contract = new this._web3js.eth.Contract(abiString, contractAddress);
const _method = _contract.methods[methodName].apply(this, contractParams)
return _method.call({
from: await this.getCurrentAccount(),
})
} catch (e) {
console.error('triggerContract', e)
errorCallback && errorCallback(e)
}
}
/**
* Get the contract address of evolution land by key.
* @param {*} tokenKey ring | kton | gold ...
*/
async getContractAddress(tokenKey) {
let token = (this.ABIs[tokenKey] && this.ABIs[tokenKey].address) || tokenKey;
// if(Array.isArray(tokenKey) && tokenKey.length === 2) {
// const pair = await this.getDerivedPairInfo(...tokenKey)
// token = pair.liquidityToken.address
// }
return token;
}
/**
* Query if an address is an authorized operator for another address
* @param {*} owner The address that owns the NFTs
* @param {*} operator The address that acts on behalf of the owner
* @param {*} contractAddress ERC721 contract address
*/
erc721IsApprovedForAll(owner, operator, contractAddress, callback={}) {
return this.callContract({
methodName: 'isApprovedForAll',
abiKey: contractAddress,
abiString: this.ABIs['erc721'].abi,
contractParams: [owner, operator],
}, callback)
}
/**
* Returns whether `spender` is allowed to manage `tokenId`.
* @param {*} spender The address that acts on behalf of the owner
* @param {*} contractAddress The factory of tokenId.
* @param {*} tokenId ERC721 token Id;
*/
async erc721IsApprovedOrOwner(spender, contractAddress, tokenId) {
const owner = await this.callContract({
methodName: 'ownerOf',
abiKey: contractAddress,
abiString: this.ABIs['erc721'].abi,
contractParams: [tokenId],
});
const approvedAddress = await this.callContract({
methodName: 'getApproved',
abiKey: contractAddress,
abiString: this.ABIs['erc721'].abi,
contractParams: [tokenId],
});
const isApprovedForAll = await this.erc721IsApprovedForAll(owner, spender, contractAddress);
return (owner.toLowerCase() === spender.toLowerCase() || approvedAddress.toLowerCase() === spender.toLowerCase() || isApprovedForAll);
}
/**
*
* @param {*} owner
* @param {*} operator
* @param {*} contractAddress
* @param {*} callback
*/
erc721IsApprovedForAll(owner, operator, contractAddress, callback={}) {
return this.callContract({
methodName: 'isApprovedForAll',
abiKey: contractAddress,
abiString: this.ABIs['erc721'].abi,
contractParams: [owner, operator],
}, callback)
}
/**
* Change or reaffirm the approved address for an NFT
* @param {*} to The new approved NFT controller
* @param {*} tokenId The NFT to approve
*/
async erc721Approve(to, tokenId, contractAddress, callback={}) {
return this.triggerContract({
methodName: 'approve',
abiKey: contractAddress,
abiString: this.ABIs['erc721'].abi,
contractParams: [to, tokenId],
}, callback)
}
/**
* Enable or disable approval for a third party ("operator") to manage
* @param {*} to Address to add to the set of authorized operators
* @param {*} approved True if the operator is approved, false to revoke approval
* @param {*} contractAddress ERC721 contract address
* @param {*} callback
*/
async erc721SetApprovalForAll(to, approved, contractAddress, callback={}) {
return this.triggerContract({
methodName: 'setApprovalForAll',
abiKey: contractAddress,
abiString: this.ABIs['erc721'].abi,
contractParams: [to, approved],
}, callback)
}
/**
* Atlantis swap fee
* @param {string} value amount of rings to be swaped
* @param {*} callback
*/
async fetchAtlantisSwapFee(value, callback = {}) {
return this.callContract({
methodName: 'querySwapFee',
abiKey: 'swapBridge',
abiString: swapBridgeABI,
contractParams: [value],
}, callback)
}
getSimpleBridgeStatus(callback = {}) {
return this.callContract({
methodName: 'paused',
abiKey: 'swapBridge',
abiString: swapBridgeABI,
contractParams: [],
}, callback)
}
/**
* Atlantis ring transfer to Byzantium
* @param {string} value amount of rings to be swaped
* @param {string} value tron address (bs58)
* @param {*} callback
*/
async AtlantisSwapBridge(value, targetAddress, symbol = 'ring', callback = {}) {
if (!targetAddress) {
throw Error('empty targetAddress')
}
const fee = await this.fetchAtlantisSwapFee(value)
const hexTargetAddress = Utils.decodeBase58Address(targetAddress);
const extraData = `${Utils.toHexAndPadLeft(value)}${Utils.toHexAndPadLeft(2).slice(2)}${Utils.padLeft(hexTargetAddress.substring(2), 64, '0')}`
return this.triggerContract({
methodName: 'approveAndCall',
abiKey: symbol.toLowerCase(),
abiString: ringABI,
contractParams: [this.ABIs['swapBridge'].address, new BigNumber(fee).plus(1).plus(new BigNumber(value)).toFixed(0), extraData],
}, callback)
}
/**
* Swap Ether to Ring token - Powered by uniswap.
* @param {string} value - amount for Ring, unit of measurement(wei)
* @returns {Promise<PromiEvent<any>>}
*/
async buyRingUniswap(value, callback = {}) {
const RING = new Token(parseInt(this.env.CONTRACT.NETWORK), this.env.CONTRACT.TOKEN_RING, 18, "RING", "Darwinia Network Native Token")
const pair = await Fetcher.fetchPairData(WETH[RING.chainId], RING)
const route = new Route([pair], WETH[RING.chainId])
const amountIn = value
const trade = new Trade(route, new TokenAmount(RING, amountIn), TradeType.EXACT_OUTPUT)
const slippageTolerance = new Percent('0', '10000') // 30 bips, or 0.30%
const amountInMax = trade.maximumAmountIn(slippageTolerance).raw // needs to be converted to e.g. hex
const path = [WETH[RING.chainId].address, RING.address]
const to = await this.getCurrentAccount() // should be a checksummed recipient address
const deadline = Math.floor(Date.now() / 1000) + 60 * 20 // 20 minutes from the current Unix time
const outputAmount = trade.outputAmount.raw // // needs to be converted to e.g. hex
return this.triggerContract({
methodName: 'swapETHForExactTokens',
abiKey: 'uniswapExchange',
abiString: uniswapExchangeABI,
contractParams: [
outputAmount.toString(10),
path,
to,
deadline
],
sendParams: {
value: amountInMax.toString(10)
}
}, callback)
}
/**
* Swap Ring token to Ether - Powered by uniswap.
* @param {string} value - amount for Ring, unit of measurement(wei)
* @returns {Promise<PromiEvent<any>>}
*/
async sellRingUniswap(value, callback = {}) {
const RING = new Token(parseInt(this.env.CONTRACT.NETWORK), this.env.CONTRACT.TOKEN_RING, 18, "RING", "Darwinia Network Native Token")
const pair = await Fetcher.fetchPairData(RING, WETH[RING.chainId])
const route = new Route([pair], RING)
const amountIn = value
const trade = new Trade(route, new TokenAmount(RING, amountIn), TradeType.EXACT_INPUT)
const slippageTolerance = new Percent('0', '10000') // 30 bips, or 0.30%
const amountOutMin = trade.minimumAmountOut(slippageTolerance).raw // needs to be converted to e.g. hex
const path = [RING.address, WETH[RING.chainId].address]
const to = await this.getCurrentAccount() // should be a checksummed recipient address
const deadline = Math.floor(Date.now() / 1000) + 60 * 20 // 20 minutes from the current Unix time
const inputAmount = trade.inputAmount.raw // // needs to be converted to e.g. hex
return this.triggerContract({
methodName: 'swapExactTokensForETH',
abiKey: 'uniswapExchange',
abiString: uniswapExchangeABI,
contractParams: [
inputAmount.toString(10),
amountOutMin.toString(10),
path,
to,
deadline
],
sendParams: {
value: 0
}
}, callback)
}
/**
* Transfers value amount of tokens to address to
* @param {string} value - amount of tokens
* @param {string} to - receiving address
* @param {string} symbol - symbol of token [ring, kton, gold, wood, water, fire, soil]
* @param {*} callback
*/
async tokenTransfer(value, to, symbol, callback = {}) {
if (!to || to === "0x0000000000000000000000000000000000000000") return;
let abiString = ''
if (symbol === 'kton') {
abiString = ktonABI
} else {
abiString = ringABI
}
return this.triggerContract({
methodName: 'transfer',
abiKey: symbol,
abiString: abiString,
contractParams: [to, value],
}, callback)
}
/**
* Ethereum Function, Approve Ring to Uniswap Exchange
* @param {*} callback
*/
async approveRingToUniswap(callback = {}, value="20000000000000000000000000") {
return this.triggerContract({
methodName: 'approve',
abiKey: 'ring',
abiString: ringABI,
contractParams: [this.ABIs['uniswapExchange'].address, value],
}, callback)
}
/**
* Allows Uniswap to withdraw from your account multiple times, up to the value amount.
* @param {*} addressOrType ERC20 token contract address.
* @param {*} value
* @param {*} callback
*/
approveTokenToUniswap(addressOrType, value="0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", callback = {}) {
if(!addressOrType) {
throw 'ethereum::approveTokenToUniswap: missing addressOrType param'
}
return this.triggerContract({
methodName: 'approve',
abiKey: addressOrType,
abiString: ringABI,
contractParams: [this.ABIs['uniswapExchange'].address, value],
}, callback)
}
/**
* Approve liquidity to uniswap
* @param {*} tokenAType Token 0 contract address
* @param {*} tokenBType Token 1 contract address
* @param {*} value Approved value
* @param {*} callback
*/
async approveLiquidityTokenToUniswap(tokenAType, tokenBType, value="0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", callback = {}) {
if(!tokenAType || !tokenBType) {
throw 'ethereum::approveLiquidityTokenToUniswap: missing addressOrType param'
}
const pair = await this.getDerivedPairInfo(tokenAType, tokenBType);
return this.approveTokenToUniswap(pair.liquidityToken.address, value, callback);
}
/**
* Allows spender to withdraw from your account multiple times, up to the value amount. If this function is called again it overwrites the current allowance with value.
* @param {*} tokenContractOrType Erc20 token contract address
* @param {*} spender
* @param {*} value
* @param {*} callback
*/
async approveToken(tokenContractOrType, spender, value="0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", callback = {}) {
if(!spender) {
return;
}
return this.triggerContract({
methodName: 'approve',
abiKey: tokenContractOrType,
abiString: ringABI,
contractParams: [spender, value],
}, callback)
}
/**
* Approve uniswap liquidity token to spender.
* @param {*} tokenAType
* @param {*} tokenBType
* @param {*} value
* @param {*} callback
*/
async approveUniswapLiquidityToken(tokenAType, tokenBType, spender, value="0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", callback = {}) {
if(!tokenAType || !tokenBType) {
throw 'ethereum::approveUniswapLiquidityToken: missing addressOrType param'
}
const pair = await this.getDerivedPairInfo(tokenAType, tokenBType);
return this.triggerContract({
methodName: 'approve',
abiKey: pair.liquidityToken.address,
abiString: ringABI,
contractParams: [spender, value],
}, callback)
}
/**
* Check if uniswap has sufficient transfer authority
* @param {*} amount
* @param {*} tokenAddressOrType
* @param {*} account
*/
async checkUniswapAllowance(amount, tokenAddressOrType = 'ring', account) {
const from = account || await this.getCurrentAccount();
const token = await this.getContractAddress(tokenAddressOrType);
const erc20Contract = new this._web3js.eth.Contract(ringABI, token)
const allowanceAmount = await erc20Contract.methods.allowance(from, this.ABIs['uniswapExchange'].address).call()
return !Utils.toBN(allowanceAmount).lt(Utils.toBN(amount || '1000000000000000000000000'))
}
/**
* Check if spender has sufficient transfer authority
* @param {*} amount
* @param {*} tokenAddressOrType,
* @param {*} account
* @param {*} spender
*/
async checkTokenAllowance(amount, tokenAddressOrType, account, spender) {
if(!amount || !tokenAddressOrType || !spender) {
throw 'ethereum::checkTokenAllowance: missing param'
}
const from = account || await this.getCurrentAccount();
const token = await this.getContractAddress(tokenAddressOrType);
const erc20Contract = new this._web3js.eth.Contract(ringABI, token)
const allowanceAmount = await erc20Contract.methods.allowance(from, spender).call()
return !Utils.toBN(allowanceAmount).lt(Utils.toBN(amount || '1000000000000000000000000'))
}
/**
* get amount of ether in uniswap exchange
*/
async getUniswapEthBalance() {
const RING = new Token(parseInt(this.env.CONTRACT.NETWORK), this.env.CONTRACT.TOKEN_RING, 18, "RING", "Darwinia Network Native Token")
const pair = await Fetcher.fetchPairData(WETH[RING.chainId], RING)
return pair.tokenAmounts[1].raw.toString(10)
}
/**
* get amount of ring in uniswap exchange
*/
async getUniswapTokenBalance() {
const RING = new Token(parseInt(this.env.CONTRACT.NETWORK), this.env.CONTRACT.TOKEN_RING, 18, "RING", "Darwinia Network Native Token")
const pair = await Fetcher.fetchPairData(WETH[RING.chainId], RING)
return pair.tokenAmounts[0].raw.toString(10)
}
/**
* Eth will be cost to swap 1 Ring
* @param {*} tokens_bought
*/
async getEthToTokenOutputPrice(tokens_bought = '1000000000000000000') {
const RING = new Token(parseInt(this.env.CONTRACT.NETWORK), this.env.CONTRACT.TOKEN_RING, 18, "RING", "Darwinia Network Native Token")
const pair = await Fetcher.fetchPairData(WETH[RING.chainId], RING)
const route = new Route([pair], WETH[RING.chainId])
const amountIn = tokens_bought
const trade = new Trade(route, new TokenAmount(RING, amountIn), TradeType.EXACT_OUTPUT)
const slippageTolerance = new Percent('0', '10000')
const amountInMax = trade.maximumAmountIn(slippageTolerance).raw
return [new BigNumber(amountInMax.toString(10)).times('1000000000000000000').div(tokens_bought).toFixed(0), amountInMax.toString(10)];
}
/**
* Eth will be got to swap 1 Ring
* @param {*} tokens_bought
*/
async getTokenToEthInputPrice(tokens_bought = '1000000000000000000') {
const RING = new Token(parseInt(this.env.CONTRACT.NETWORK), this.env.CONTRACT.TOKEN_RING, 18, "RING", "Darwinia Network Native Token")
const pair = await Fetcher.fetchPairData(RING, WETH[RING.chainId])
const route = new Route([pair], RING)
const amountIn = tokens_bought // 1 WETH
const trade = new Trade(route, new TokenAmount(RING, amountIn), TradeType.EXACT_INPUT)
const slippageTolerance = new Percent('0', '10000') // 50 bips, or 0.50%
const amountOutMin = trade.minimumAmountOut(slippageTolerance).raw // needs to be converted to e.g. hex
return [new BigNumber(amountOutMin.toString(10)).times('1000000000000000000').div(tokens_bought).toFixed(0), amountOutMin.toString(10)];
}
/**
* Buy ring token with Ether.
* @param {string} value - amount for Ether, unit of measurement(wei)
* @returns {Promise<PromiEvent<any>>}
*/
buyRing(value, callback = {}) {
return this.triggerContract({
methodName: 'buyRING',
abiKey: 'bancor',
abiString: bancorABI,
contractParams: [1],
sendParams: {
value: value
}
}, callback)
}
/**
* Claim land asset
* @param tokenId - Land tokenId
* @returns {Promise<PromiEvent<any>>}
*/
claimLandAsset(tokenId, callback = {}) {
return this.triggerContract({
methodName: 'claimLandAsset',
abiKey: 'auction',
abiString: actionABI,
contractParams: ['0x' + tokenId],
}, callback)
}
/**
* Bid Land Assets with Ring token.
* @param amount - bid price with ring token
* @param tokenId - tokenid of land
* @param referrer - Referrer address
* @returns {Promise<PromiEvent<any>>}
*/
buyLandContract(amount, tokenId, referrer, callback = {}) {
const finalReferrer = referrer
const data =
finalReferrer && Utils.isAddress(finalReferrer) ?
`0x${tokenId}${Utils.padLeft(finalReferrer.substring(2), 64, '0')}` :
`0x${tokenId}`
return this.triggerContract({
methodName: 'transfer',
abiKey: 'ring',
abiString: ringABI,
contractParams: [this.ABIs['auction'].address, amount, data],
}, callback)
}
/**
* Sell land asset
* @param tokenId - Land tokenId
* @param start - start price
* @param end - end price
* @param duration - bid duration time in second
* @returns {Promise<PromiEvent<any>>}
*/
async setLandPrice(tokenId, start, end, duration, callback = {}) {
const from = await this.getCurrentAccount()
const _from = Utils.padLeft(from.slice(2), 64, '0')
const _start = Utils.toHexAndPadLeft(start).slice(2)
const _end = Utils.toHexAndPadLeft(end).slice(2)
const _duration = Utils.toHexAndPadLeft(duration).slice(2)
const data = `0x${_start}${_end}${_duration}${_from}`
return this.triggerContract({
methodName: 'approveAndCall',
abiKey: 'land',
abiString: landABI,
contractParams: [this.ABIs['auction'].address, '0x' + tokenId, data],
}, callback)
}
/**
* Bid Land Assets with Ether.
* @param tokenId - tokenid of land
* @param referer - Referrer address
* @param value - bid price with ether
* @returns {Promise<PromiEvent<any>>}
*/
buyLandWithETHContract(tokenId, referer, value, callback = {}) {
return this.triggerContract({
methodName: "bidWithETH",
abiString: actionABI,
contractParams: ['0x' + tokenId, referer],
abiKey: "auction",
sendParams: {
value: value
}
}, callback)
}
/**
* Withdraw ring from the channel
* @param nonce
* @param value
* @param hash
* @param v
* @param r
* @param s
* @returns {Promise<PromiEvent<any>>}
*/
withdrawRing({
nonce,
value,
hash,
v,
r,
s
}, callback = {}) {
return this.triggerContract({
methodName: "takeBack",
abiString: withdrawABI,
contractParams: [nonce, value, hash, v, r, s],
abiKey: "withdraw",
}, callback);
}
/**
* Withdraw kton from the channel
* @param nonce
* @param value
* @param hash
* @param v
* @param r
* @param s
* @returns {Promise<PromiEvent<any>>}
*/
withdrawKton({
nonce,
value,
hash,
v,
r,
s
}, callback = {}) {
return this.triggerContract({
methodName: "takeBack",
abiString: withdrawABI,
contractParams: [nonce, value, hash, v, r, s],
abiKey: "withdrawKton",
}, callback);
}
/**
* Cancel the Land being auctioned.
* @param {string} tokenId - tokenid of land
* @returns {Promise<PromiEvent<any>>}
*/
cancelAuction(tokenId, callback = {}) {
return this.triggerContract({
methodName: "cancelAuction",
abiString: actionABI,
contractParams: ['0x' + tokenId],
abiKey: "auction",
}, callback);
}
/**
* Convert Ring token to Ether via bancor exchange
* @param amount - ring token amount
* @returns {Promise<PromiEvent<any>>}
*/
sellRing(amount, callback = {}) {
return this.triggerContract({
methodName: 'transfer',
abiKey: 'ring',
abiString: ringABI,
contractParams: [this.ABIs['bancor'].address, amount, '0x0000000000000000000000000000000000000000000000000000000000000001'],
}, callback)
}
/**
* Lock ring token to get Kton token
* @param amount - ring amount
* @param month - Locking time(unit: month)
* @returns {Promise<PromiEvent<any>>}
*/
saveRing(amount, month, callback = {}) {
return this.triggerContract({
methodName: 'transfer',
abiKey: 'ring',
abiString: ringABI,
contractParams: [this.ABIs['bank'].address, amount, Utils.toTwosComplement(month)],
}, callback)
}
/**
* Redemption of unexpired ring.
* @param amount - penalty Kton amount
* @param id - deposit ID
* @returns {Promise<PromiEvent<any>>}
*/
redeemRing(amount, id, callback = {}) {
return this.triggerContract({
methodName: 'transfer',
abiKey: 'kton',
abiString: ktonABI,
contractParams: [this.ABIs['bank'].address, amount, Utils.toTwosComplement(id)],
}, callback)
}
/**
* Redemption ring without penalty kton
* @param id - deposit ID
* @returns {Promise<PromiEvent<any>>}
*/
withdrawBankRing(id, callback = {}) {
return this.triggerContract({
methodName: 'claimDeposit',
abiKey: 'bank',
abiString: bankABI,
contractParams: [Utils.toTwosComplement(id)],
}, callback)
}
/**
* Play a ticket game
* @param type - ['small':playWithSmallTicket , 'large': playWithLargeTicket]
* @returns {Promise<PromiEvent<any>>}
*/
lotteryFromPoint(type = "small", callback = {}) {
return this.triggerContract({
methodName: type === "small" ? "playWithSmallTicket" : "playWithLargeTicket",
abiKey: 'lottery',
abiString: lotteryABI,
contractParams: [],
}, callback)
}
/**
* Binding tester code
* @param _nonce
* @param _testerCodeHash
* @param _hashmessage
* @param _v
* @param _r
* @param _s
* @returns {Promise<PromiEvent<any>>}
*/
updateTesterRole(_nonce, _testerCodeHash, _hashmessage, _v, _r, _s, callback = {}) {
return this.triggerContract({
methodName: 'updateTesterRole',
abiKey: 'rolesUpdater',
abiString: rolesUpdaterABI,
contractParams: [_nonce, _testerCodeHash, _hashmessage, _v, _r, _s],
}, callback)
}
/**
* create a red package
* @param amount - amount of red package
* @param number - number of received
* @param packetId - packet ID
* @returns {Promise<PromiEvent<any>>}
*/
createRedPackageContract(amount, number, packetId, callback = {}) {
const model = 0;
const _data = `0x${Utils.toHexAndPadLeft(number).slice(2)}${Utils.toHexAndPadLeft(model).slice(2)}${Utils.toHexAndPadLeft(packetId).slice(2)}`
return this.triggerContract({
methodName: 'transfer',
abiKey: 'ring',
abiString: ringABI,
contractParams: [this.ABIs['redPackage'].address, amount, _data],
}, callback)
}
/**
* tansfer the Land
* @param {address} from - sender address
* @param {address} to - receiver
* @param {string} tokenId - Land token ID
* @returns {*}
*/
async transferFromLand(to, tokenId, callback = {}) {
if (!to) {
return null
}
const from = await this.getCurrentAccount()
return this.triggerContract({
methodName: 'transferFrom',
abiKey: 'land',
abiString: landABI,
contractParams: [from, to, '0x' + tokenId],
}, callback)
}
/**
* claim resource on the Land
* @param tokenId Land token Id.
* @returns {Promise<PromiEvent<any>>}
*/
claimLandResource(tokenId, callback = {}) {
return this.triggerContract({
methodName: 'claimLandResource',
abiKey: 'apostleLandResource',
abiString: landResourceABI,
contractParams: ['0x' + tokenId],
}, callback)
}
/**
* Bid apostle by RING token
* @param amount - RING amount
* @param tokenId - Apostle token ID
* @param referrer - refer address
* @returns {Promise<PromiEvent<any>>}
*/
apostleBid(amount, tokenId, referrer, callback = {}) {
const finalReferrer = referrer
const data =
finalReferrer && Utils.isAddress(finalReferrer) ?
`0x${tokenId}${Utils.padLeft(finalReferrer.substring(2), 64, '0')}` :
`0x${tokenId}`
return this.triggerContract({
methodName: 'transfer',
abiKey: 'ring',
abiString: ringABI,
contractParams: [this.ABIs['apostleAuction'].address, amount, data],
}, callback)
}
/**
* Receive apostle
* @param tokenId - Apostle Token ID
* @returns {Promise<PromiEvent<any>>}
*/
apostleClaim(tokenId, callback = {}) {
return this.triggerContract({
methodName: 'claimApostleAsset',
abiKey: 'apostleAuction',
abiString: apostleAuctionABI,
contractParams: ['0x' + tokenId],
}, callback)
}
/**
* Sell apostle
* @param tokenId - Apostle Token ID
* @param start - auction start price
* @param end - auction end price
* @param duration - duration time
* @returns {Promise<PromiEvent<any>>}
*/
async apostleSell(tokenId, start, end, duration, callback = {}) {
const from = await this.getCurrentAccount()
const _from = Utils.padLeft(from.slice(2), 64, '0')
const _start = Utils.toHexAndPadLeft(start).slice(2)
const _end = Utils.toHexAndPadLeft(end).slice(2)
const _duration = Utils.toHexAndPadLeft(duration).slice(2)
const data = `0x${_start}${_end}${_duration}${_from}`
return this.triggerContract({
methodName: 'approveAndCall',
abiKey: 'land',
abiString: landABI,
contractParams: [this.ABIs['apostleAuction'].address, '0x' + tokenId, data],
}, callback)
}
/**
* Cancel the auction by apostle token ID
* @param tokenId - apostle token ID
* @returns {Promise<PromiEvent<any>>}
*/
apostleCancelSell(tokenId, callback = {}) {
return this.triggerContract({
methodName: 'cancelAuction',
abiKey: 'apostleAuction',
abiString: apostleAuctionABI,
contractParams: ['0x' + tokenId],
}, callback)
}
/**
*
* @param tokenId
* @param nftData
* @returns {Promise<PromiEvent<any>>}
*/
apostleRewardClaim(tokenId, nftData, callback = {}) {
return this.triggerContract({
methodName: 'takeBackNFT',
abiKey: 'apostleTakeBack',
abiString: apostleTakeBackABI,
contractParams: [
nftData.nonce,
'0x' + tokenId,
this.ABIs['land'].address,
nftData.expireTime,
nftData.hash_text,
nftData.v,
nftData.r,
nftData.s
],
}, callback)
}
/**
* Apostle reproduction in own
* @param tokenId
* @param targetTokenId
* @param amount
* @returns {Promise<PromiEvent<any>>}
*/
apostleBreed(tokenId, targetTokenId, amount, callback = {}) {
return this.triggerContract({
methodName: 'transfer',
abiKey: 'ring',
abiString: ringABI,
contractParams: [
this.ABIs["apostleBase"].address,
amount,
`0x${tokenId}${targetTokenId}`
]
}, callback)
}
/**
* Apostle reproduction
* @param tokenId
* @param targetTokenId
* @param amount
*/
apostleBreedBid(tokenId, targetTokenId, amount, callback = {}) {
return this.triggerContract({
methodName: 'transfer',
abiKey: 'ring',
abiString: ringABI,
contractParams: [
this.ABIs["apostleSiringAuction"].address,
amount,
`0x${tokenId}${targetTokenId}`
]
}, callback)
}
/**
* Apostle Breed Auction
* @param tokenId - Apostle tokenId
* @param start - start price
* @param end - end price
* @param duration - auction duration time
* @returns {Promise<PromiEvent<any>>}
*/
async apostleBreedAuction(tokenId, start, end, duration, callback = {}) {
const from = await this.getCurrentAccount()
const _from = Utils.padLeft(from.slice(2), 64, '0')
const _start = Utils.toHexAndPadLeft(start).slice(2)
const _end = Utils.toHexAndPadLeft(end).slice(2)
const _duration = Utils.toHexAndPadLeft(duration).slice(2)
const data = `0x${_start}${_end}${_duration}${_from}`
return this.triggerContract({
methodName: 'approveAndCall',
abiKey: 'land',
abiString: landABI,
contractParams: [this.ABIs['apostleSiringAuction'].address, '0x' + tokenId, data],
}, callback)
}
/**
* Cancel apostle breed auction
* @param tokenId
* @returns {Promise<PromiEvent<any>>}
*/
apostleCancelBreedAuction(tokenId, callback = {}) {
return this.triggerContract({
methodName: 'cancelAuction',
abiKey: 'apostleSiringAuction',
abiString: apostleSiringABI,
contractParams: [
'0x' + tokenId
]
}, callback)
}
/**
* Transfer apostle
* @param toAddress
* @param tokenId
* @returns {Promise<PromiEvent<any>>}
*/
async apostleTransfer(toAddress, tokenId, callback = {}) {
const from = await this.getCurrentAccount()
return this.triggerContract({
methodName: 'transferFrom',
abiKey: 'land',
abiString: landABI,
contractParams: [
from, toAddress, '0x' + tokenId
]
}, callback)
}
/**
* Let apostle go to work
* @param tokenId - Apostle tokenId
* @param landTokenId - Land tokenId
* @param element - ['gold', 'wood', 'water', 'fire' ,'soil']
*/
apostleWork(tokenId, landTokenId, element, callback = {}) {
const elementAddress = this.ABIs[element.toLowerCase() || 'token'].address
return this.triggerContract({
methodName: 'startMining',
abiKey: 'apostleLandResource',
abiString: landResourceABI,
contractParams: [
'0x' + tokenId, '0x' + landTokenId, elementAddress
]
}, callback)
}
/**
* Stop apostle mining
* @param tokenId - Apostle tokenId
*/
apostleStopWorking(tokenId, callback = {}) {
return this.triggerContract({
methodName: 'stopMining',
abiKey: 'apostleLandResource',
abiString: landResourceABI,
contractParams: [
'0x' + tokenId
]
}, callback)
}
/**
* Claim an apostle that expires at work
* @param tokenId - Apostle TokenId
* @returns {Promise<PromiEvent<any>>}
*/
apostleHireClaim(tokenId, callback = {}) {
return this.triggerContract({
methodName: 'removeTokenUseAndActivity',
abiKey: 'apostleTokenUse',
abiString: tokenUseABI,
contractParams: [
'0x' + tokenId
]
}, callback)
}
/**
* Renting apostles to work
* @param tokenId - Apostle TokenId
* @param duration - Duration in second
* @param price - Hire Price
*/
apostleHire(tokenId, duration, price, callback = {}) {
const address = this.ABIs['apostleLandResource'].address
const _resourceAddress = Utils.padLeft(address.slice(2), 64, '0')
const _price = Utils.toHexAndPadLeft(price).slice(2)
const _duration = Utils.toHexAndPadLeft(duration).slice(2)
const data = `0x${_duration}${_price}${_resourceAddress}`
return this.triggerContract({
methodName: 'approveAndCall',
abiKey: 'land',
abiString: landABI,
contractParams: [
this.ABIs['apostleTokenUse'].address,
'0x' + tokenId,
data
]
}, callback)
}
/**
* Cancel an apostle on Renting
* @param tokenId - Apostle tokenId
*/
apostleCancelHire(tokenId, callback = {}) {
return this.triggerContract({
methodName: 'cancelTokenUseOffer',
abiKey: 'apostleTokenUse',
abiString: tokenUseABI,
contractParams: [
'0x' + tokenId
]
}, callback)
}
/**
* Bid apostle on Renting
* @param tokenId - Apostle tokenId
* @param price - bid price
*/
apostleHireBid(tokenId, price, callback = {}) {
return this.triggerContract({
methodName: 'transfer',
abiKey: 'ring',
abiString: ringABI,
contractParams: [
this.ABIs['apostleTokenUse'].address,
price,
`0x${tokenId}`
]
}, callback)
}
/**
* Apostle Born without element
* @param motherTokenId
*/
apostleBorn(motherTokenId, callback = {}) {
return this.triggerContract({
methodName: 'giveBirth',
abiKey: 'apostleBase',
abiString: apostleBaseABI,
contractParams: [
'0x' + motherTokenId,
Utils.padLeft(0, 40, '0'),
0
]
}, callback)
}
/**
* Apostle Born with element
* @param motherTokenId
* @param element
* @param level
* @param levelUnitPrice
*/
apostleBornAndEnhance(
motherTokenId,
element,
level,
levelUnitPrice,
callback = {}
) {
return this.triggerContract({
methodName: 'transfer',
abiKey: element.toLowerCase(),
abiString: ringABI,
contractParams: [
this.ABIs['apostleBase'].address,
new BigNumber(level).times(new BigNumber(levelUnitPrice)).toFixed(),
`0x${motherTokenId}${Utils.toHexAndPadLeft(level).slice(2)}`
]
}, callback)
}
/**
* Bind pet
* @param originNftAddress
* @param originTokenId
* @param apostleTokenId
* @returns {Promise<PromiEvent<any>>}
*/
bridgeInAndTie(originNftAddress, originTokenId, apostleTokenId, callback = {}) {
return this.triggerContract({
methodName: 'bridgeInAndTie',
abiKey: 'petBase',
abiString: petBaseABI,
contractParams: [originNftAddress, originTokenId, '0x' + apostleTokenId]
}, callback)
}
/**
* Unbind pet
* @param petTokenId
* @returns {Promise<PromiEvent<any>>}
*/
untiePetToken(petTokenId, callback = {}) {
return this.triggerContract({
methodName: 'untiePetToken',
abiKey: 'petBase',
abiString: petBaseABI,
contractParams: ['0x' + petTokenId]
}, callback)
}
/**
* buy lucky box
* @param {*} buyer - Receiver
* @param {*} goldBoxAmount - gold box amount
* @param {*} silverBoxAmount - silver box amount
*/
async buyLuckyBox(buyer, goldBoxAmount, silverBoxAmount, callback) {
const luckyBoxInfo = await this.getLuckyBoxInfo()
const cost = Utils.toBN(luckyBoxInfo[0]).muln(goldBoxAmount).add(Utils.toBN(luckyBoxInfo[1]).muln(silverBoxAmount))
return this.triggerContract({
methodName: 'buyBoxs',
abiKey: 'luckybag',
abiString: luckyBoxABI,
contractParams: [buyer, goldBoxAmount, silverBoxAmount],
sendParams: {
value: cost
}
}, callback)
}
/**
* lucky box information
* @returns {Array} - promise -> [goldBoxPrice, silverBoxPrice, goldBoxAmountForSale, silverBoxAmountForSale, goldSaleLimit, silverSaleLimit]
*/
getLuckyBoxInfo() {
const _contract = new this._web3js.eth.Contract(luckyBoxABI, this.ABIs['luckybag'].address)
return Promise.all([
_contract.methods.goldBoxPrice().call(),
_contract.methods.silverBoxPrice().call(),
_contract.methods.goldBoxAmountForSale().call(),
_contract.methods.silverBoxAmountForSale().call(),
_contract.methods.goldSaleLimit().call(),
_contract.methods.silverSaleLimit().call(),
])
}
/**
* Number of lucky box already purchased at this address
* @param {*} address - buyer
* @returns {Array} - promise -> [goldSalesRecord, silverSalesRecord]
*/
getLuckyBoxSalesRecord(address) {
const _contract = new this._web3js.eth.Contract(luckyBoxABI, this.ABIs['luckybag'].address)
return Promise.all([
_contract.methods.goldSalesRecord(address).call(),
_contract.methods.silverSalesRecord(address).call(),
])
}
/**
* get furnace treasure price
* @returns {} - promise -> {0: "1026000000000000000000", 1: "102000000000000000000", priceGoldBox: "1026000000000000000000", priceSilverBox: "102000000000000000000"}
*/
getFurnaceTreasurePrice() {
const _contract = new this._web3js.eth.Contract(itemTreasureABI, this.ABIs['itemTreasure'].address)
return _contract.methods.getPrice().call()
}
getFurnaceTakeBackNonce(address) {
const _contract = new this._web3js.eth.Contract(itemTakeBackABI, this.ABIs['itemTakeBack'].address)
return _contract.methods.userToNonce(address).call()
}
/**
* buy lucky box
* @param {*} goldBoxAmount - gold box amount
* @param {*} silverBoxAmount - silver box amount
*/
async buyFurnaceTreasure(goldBoxAmount = 0, silverBoxAmount = 0, callback) {
const treasurePrice = await this.getFurnaceTreasurePrice()
const cost = Utils.toBN(treasurePrice.priceGoldBox).muln(goldBoxAmount).add(Utils.toBN(treasurePrice.priceSilverBox).muln(silverBoxAmount))
// Function: transfer(address _to, uint256 _value, bytes _data) ***
// data
// 0000000000000000000000000000000000000000000000000000000000000001 gold box amount
// 0000000000000000000000000000000000000000000000000000000000000002 silver box amount
const data = Utils.toTwosComplement(goldBoxAmount) + Utils.toTwosComplement(silverBoxAmount).substring(2, 66)
return this.triggerContract({
methodName: 'transfer',
abiKey: 'ring',
abiString: ringABI,
contractParams: [this.ABIs['itemTreasure'].address, cost.toString(10), data],
sendParams: {
value: 0
}
}, callback)
}
/**
* open furnace treasure
* @returns {Promise<PromiEvent<any>>}
*/
openFurnaceTreasure({
boxIds,
amounts,
hashmessage,
v,
r,
s
}, callback = {}) {
// During the process of opening the treasure chest, there is the logic of randomly gifting rings,
// which leads to inaccurate gas estimation, so manually set it to avoid out of gas.
// https://etherscan.io/tx/0xe71f54aee8f7ab1dd15df955d09c79af5060f20e91c0c5ecfcf17f20c9bf02b3
// https://etherscan.io/tx/0x7b04df9b55f33b6edcc402a5733dbc753a6bbe2f78af7c7bef6f3f4d8dce7491
// no return ring - gas used - 229,289
// https://etherscan.io/tx/0x4e1fc1dcec64bb497405126e55ab743368f1cb1cede945936937e0cde1d254e7
// prize ring - gas used - 254,776
// https://etherscan.io/tx/0xd2b3f05b19e74627940edfe98daee31eeab84b67e88dcf0e77d595430b3b1afc
let gasLimit = new BigNumber(amounts[0]).lt('1000000000000000000000') ? new BigNumber(260000) : new BigNumber(300000);
if(amounts.length > 1) {
for (let index = 1; index < amounts.length; index++) {
const amount = amounts[index];
gasLimit = gasLimit.plus(new BigNumber(amount).lt('1000000000000000000000') ? new BigNumber(260000) : new BigNumber(260000));
}
}
return this.triggerContract({
methodName: "openBoxes",
abiString: itemTakeBackABI,
contractParams: [
boxIds,
amounts,
hashmessage,
v,
r,
s
],
sendParams: {
value: 0,
gasLimit: gasLimit.toFixed(0)
},
abiKey: "itemTakeBack",
}, callback);
}
checkFurnaceTreasureStatus(id) {
const _contract = new this._web3js.eth.Contract(itemTakeBackABI, this.ABIs['itemTakeBack'].address)
return _contract.methods.ids(id).call()
}
/**
* Returns the amount of RING owned by account
* @param {*} address
*/
getRingBalance(address) {
const _contract = new this._web3js.eth.Contract(ringABI, this.ABIs['ring'].address)
return _contract.methods.balanceOf(address).call()
}
/**
* Returns the amount of KTON owned by account
* @param {*} address
*/
getKtonBalance(address) {
const _contract = new this._web3js.eth.Contract(ktonABI, this.ABIs['kton'].address)
return _contract.methods.balanceOf(address).call()
}
/**
* Returns the amount of tokens owned by account
* @param {*} account
* @param {*} contractAddress
*/
getTokenBalance(account, contractAddress) {
const _contract = new this._web3js.eth.Contract(ringABI, contractAddress)
return _contract.methods.balanceOf(account).call()
}
/**
* Get total supply of erc20 token
* @param {*} contractAddress Erc20 contract address
*/
getTokenTotalSupply(contractAddress) {
const _contract = new this._web3js.eth.Contract(ringABI, contractAddress)
return _contract.methods.totalSupply().call()
}
/**
* transfer evo land 721 object
* @param {*} to recevier
* @param {*} tokenId 721 tokenid
* @param {*} callback
*/
async transferFromObjectOwnership(to, tokenId, callback = {}) {
if (!to) {
return null
}
const from = await this.getCurrentAccount()
return this.triggerContract({
methodName: 'transferFrom',
abiKey: 'land',
abiString: landABI,
contractParams: [from, to, '0x' + tokenId],
}, callback)
}
/**
* Get uniswap Token info by lowercase symbol
*
* Token - https://uniswap.org/docs/v2/SDK/token/
*
* @param {*} tokenType ring kton gold wood water fire soil
*/
getUniswapToken(tokenType) {
switch (tokenType.toLowerCase()) {
case 'ring':
return new Token(parseInt(this.env.CONTRACT.NETWORK), this.env.CONTRACT.TOKEN_RING, 18, "RING", "Darwinia Network Native Token");
case 'kton':
return new Token(parseInt(this.env.CONTRACT.NETWORK), this.env.CONTRACT.TOKEN_KTON, 18, "KTON", "KTON");
case 'gold':
return new Token(parseInt(this.env.CONTRACT.NETWORK), this.env.CONTRACT.TOKEN_ELEMENT_GOLD, 18, "GOLD", "GOLD");
case 'wood':
return new Token(parseInt(this.env.CONTRACT.NETWORK), this.env.CONTRACT.TOKEN_ELEMENT_WOOD, 18, "WOOD", "WOOD");
case 'water':
return new Token(parseInt(this.env.CONTRACT.NETWORK), this.env.CONTRACT.TOKEN_ELEMENT_WATER, 18, "WATER", "WATER");
case 'fire':
return new Token(parseInt(this.env.CONTRACT.NETWORK), this.env.CONTRACT.TOKEN_ELEMENT_FIRE, 18, "FIRE", "FIRE");
case 'soil':
return new Token(parseInt(this.env.CONTRACT.NETWORK), this.env.CONTRACT.TOKEN_ELEMENT_SOIL, 18, "SOIL", "SOIL");
default:
break;
}
}
/**
* Get uniswap pair info
* @param {*} tokenA token address or lowercase symbol (ring kton gold wood water fire soil)
* @param {*} tokenB token address or lowercase symbol (ring kton gold wood water fire soil)
* @returns { pair } pair - https://uniswap.org/docs/v2/SDK/pair/
*/
async getDerivedPairInfo(tokenA, tokenB) {
if(!tokenA || !tokenB) {
return;
}
const currencyA = this.getUniswapToken(tokenA);
const currencyB = this.getUniswapToken(tokenB);
const pair = await Fetcher.fetchPairData(currencyA, currencyB);
return pair;
}
/**
* Support for addUniswapLiquidity function, and the return router pair instances and elements are returned.
*
* Only one account needs to be provided, and the other quantity needs to be provided according to the current pool price
*
* tokenType - token address or lowercase symbol (ring kton gold wood water fire soil)
*
* amount - amount in WEI
*
* @param {*} param0 {token: tokenAType, amount: amountA}
* @param {*} param1 {token: tokenBType, amount: amountB}
* @returns {*} {pair, parsedAmounts} pair - https://uniswap.org/docs/v2/SDK/pair/ parsedAmounts - {token0address: amount, token1address: amount}
*/
async getDerivedMintInfo({token: tokenAType, amount: amountA}, {token: tokenBType, amount: amountB}) {
const pair = await this.getDerivedPairInfo(tokenAType, tokenBType);
const totalSupply = new TokenAmount(pair.liquidityToken, await this.getTokenTotalSupply(pair.liquidityToken.address));
const independentToken = amountA ?
{ token: this.getUniswapToken(tokenAType), amount: amountA} :
{ token: this.getUniswapToken(tokenBType), amount: amountB};
const parsedAmounts = {
[pair.liquidityToken.address]: totalSupply,
[pair.token0.address]: new TokenAmount(pair.token0, independentToken.token.equals(pair.token0) ? JSBI.BigInt(independentToken.amount) : pair.priceOf(independentToken.token).quote(new CurrencyAmount(independentToken.token, JSBI.BigInt(independentToken.amount))).raw),
[pair.token1.address]: new TokenAmount(pair.token1, independentToken.token.equals(pair.token1) ? JSBI.BigInt(independentToken.amount) : pair.priceOf(independentToken.token).quote(new CurrencyAmount(independentToken.token, JSBI.BigInt(independentToken.amount))).raw),
}
return { pair, parsedAmounts }
}
/**
* Support for removeUniswapLiquidity function, assuming removal percentage of liquidity and the return router pair instances and elements are returned.
*
* tokenType - token address or lowercase symbol (ring kton gold wood water fire soil)
*
* pair - https://uniswap.org/docs/v2/SDK/pair/
*
* TokenAmount - https://github.com/Uniswap/uniswap-sdk/blob/v2/src/entities/fractions/tokenAmount.ts
*
* parsedAmounts - {
*
* LIQUIDITY_PERCENT: percent,
*
* liquidityTokenAddress: TokenAmount,
*
* token0Address: TokenAmount,
*
* token1Address: TokenAmount
*
* }
*
* @param {*} tokenAType
* @param {*} tokenBType
* @param {*} liquidityValue The value of liquidity removed
* @param {*} to
* @returns {*} {pair, parsedAmounts}
*/
async getDerivedBurnInfo(tokenAType, tokenBType, liquidityValue, to) {
const pair = await this.getDerivedPairInfo(tokenAType, tokenBType);
if(!to) {
to = await this.getCurrentAccount();
}
const lpBalanceStr = await this.getTokenBalance(to, pair.liquidityToken.address);
const userLiquidity = new TokenAmount(pair.liquidityToken, JSBI.BigInt(lpBalanceStr));
const totalSupply = new TokenAmount(pair.liquidityToken, await this.getTokenTotalSupply(pair.liquidityToken.address));
const liquidityValueA = pair &&
totalSupply &&
userLiquidity &&
pair.token0 && new TokenAmount(pair.token0, pair.getLiquidityValue(pair.token0, totalSupply, userLiquidity, false).raw);
const liquidityValueB = pair &&
totalSupply &&
userLiquidity &&
pair.token1 && new TokenAmount(pair.token1, pair.getLiquidityValue(pair.token1, totalSupply, userLiquidity, false).raw);
const percentToRemove = new Percent(JSBI.BigInt(liquidityValue), userLiquidity.raw);
const parsedAmounts = {
LIQUIDITY_PERCENT: percentToRemove,
[pair.liquidityToken.address]: new TokenAmount(userLiquidity.token, percentToRemove.multiply(userLiquidity.raw).quotient),
[pair.token0.address]: new TokenAmount(pair.token0, percentToRemove.multiply(liquidityValueA.raw).quotient),
[pair.token1.address]: new TokenAmount(pair.token1, percentToRemove.multiply(liquidityValueB.raw).quotient),
}
return { pair, parsedAmounts }
}
/**
* Adds liquidity to an ERC-20⇄ERC-20 pool
*
* msg.sender should have already given the router an allowance of at least amount on tokenA/tokenB.
*
* Always adds assets at the ideal ratio, according to the price when the transaction is executed.
*
* @param {*} param0 {token: tokenAType, amount: amountA}
* @param {*} param1 {token: tokenBType, amount: amountB}
* @param {*} to Recipient of the liquidity tokens.
* @param {*} slippage The amount the price moves in a trading pair between when a transaction is submitted and when it is executed.
* @param {*} callback
*/
async addUniswapLiquidity({token: tokenAType, amount: amountA}, {token: tokenBType, amount: amountB}, to, slippage = 100, callback = {}) {
const { pair, parsedAmounts } = await this.getDerivedMintInfo({token: tokenAType, amount: amountA}, {token: tokenBType, amount: amountB});
if(!pair || !pair.token0.address || !pair.token1.address) {
return;
}
if(!to) {
to = await this.getCurrentAccount();
}
const amountsMin = {
[pair.token0.address]: UniswapUtils.calculateSlippageAmount(parsedAmounts[pair.token0.address].raw, slippage)[0],
[pair.token1.address]: UniswapUtils.calculateSlippageAmount(parsedAmounts[pair.token1.address].raw, slippage)[0]
}
const deadline = Math.floor(Date.now() / 1000) + 60 * 120 // 120 minutes from the current Unix time
// https://uniswap.org/docs/v2/smart-contracts/router02/#addliquidity
return this.triggerContract({
methodName: 'addLiquidity',
abiKey: 'uniswapExchange',
abiString: uniswapExchangeABI,
contractParams: [
pair.token0.address,
pair.token1.address,
parsedAmounts[pair.token0.address].raw.toString(),
parsedAmounts[pair.token1.address].raw.toString(),
amountsMin[pair.token0.address].toString(),
amountsMin[pair.token1.address].toString(),
to,
deadline
],
sendParams: {
value: 0
}
}, callback)
}
/**
* Removes liquidity from an ERC-20⇄ERC-20 pool.
*
* msg.sender should have already given the router an allowance of at least liquidity on the pool.
*
* @param {*} tokenAType A pool token.
* @param {*} tokenBType A pool token.
* @param {*} liquidityValue The value of liquidity tokens to remove.
* @param {*} to Recipient of the underlying assets.
* @param {*} slippage The amount the price moves in a trading pair between when a transaction is submitted and when it is executed.
* @param {*} callback
*/
async removeUniswapLiquidity(tokenAType, tokenBType, liquidityValue, to, slippage = 100, callback = {}) {
if(!to) {
to = await this.getCurrentAccount();
}
const { pair, parsedAmounts } = await this.getDerivedBurnInfo(tokenAType, tokenBType, liquidityValue, to);
if(!pair || !pair.token0.address || !pair.token1.address) {
return;
}
const amountsMin = {
[pair.token0.address]: UniswapUtils.calculateSlippageAmount(parsedAmounts[pair.token0.address].raw, slippage)[0],
[pair.token1.address]: UniswapUtils.calculateSlippageAmount(parsedAmounts[pair.token1.address].raw, slippage)[0]
}
const deadline = Math.floor(Date.now() / 1000) + 60 * 120 // 20 minutes from the current Unix time
// https://uniswap.org/docs/v2/smart-contracts/router02/#removeliquidity
return this.triggerContract({
methodName: 'removeLiquidity',
abiKey: 'uniswapExchange',
abiString: uniswapExchangeABI,
contractParams: [
pair.token0.address,
pair.token1.address,
parsedAmounts[pair.liquidityToken.address].raw.toString(),
amountsMin[pair.token0.address].toString(),
amountsMin[pair.token1.address].toString(),
to,
deadline
],
sendParams: {
value: 0
}
}, callback)
}
/**
* Use nft and elements or LP tokens in the furnace formula to the props.
* @param {*} formulaIndex Formula for props - https://github.com/evolutionlandorg/furnace/blob/dev/src/Formula.sol
* @param {*} majorTokenId ERC721 token Id
* @param {*} minorTokenAddress Elements or LP tokens contract address
* @param {*} callback callback
*/
enchantFurnanceProps( formulaIndex, majorTokenId, minorTokenAddress, callback = {}) {
return this.triggerContract({
methodName: 'enchant',
abiKey: 'furnaceItemBase',
abiString: furnaceItemBaseABI,
contractParams: [
formulaIndex,
majorTokenId,
minorTokenAddress
],
sendParams: {
value: 0
}
}, callback)
}
/**
* Disenchant furnace props, and will get elements or LP and nft
* @param {*} propsTokenId Token Id of the Props
* @param {*} depth Supports one-time decomposition of high-level props. If a prop is in the second level, it needs to be restored to its original state, and the depth needs to be passed in 2
* @param {*} callback
*/
disenchantFurnanceProps( propsTokenId, depth, callback = {}) {
return this.triggerContract({
methodName: 'disenchant',
abiKey: 'furnaceItemBase',
abiString: furnaceItemBaseABI,
contractParams: [
propsTokenId,
depth
],
sendParams: {
value: 0
}
}, callback)
}
/**
* Transfers the ownership of an NFT from one address to another address
* @param {*} from The current owner of the NFT
* @param {*} to The new owner
* @param {*} tokenId The NFT to transfer
* @param {*} callback
*/
safeTransferFromEvoErc721(from, to, tokenId, callback = {}) {
return this.triggerContract({
methodName: 'safeTransferFrom',
abiKey: 'objectOwnership',
abiString: this.ABIs['erc721'].abi,
contractParams: [
from,
to,
tokenId
]
}, callback)
}
/**
* Equip function, A NFT can equip to EVO Bar (LandBar or ApostleBar).
* @param {*} tokenId Land token Id which to be quiped.
* @param {*} resource Which resouce appply to.
* @param {*} index Index of the Bar.
* @param {*} token Props token address which to quip.
* @param {*} id Props token Id which to quip.
* @param {*} callabck
*/
async equipLandResource(tokenId, resource, index, token, id, callback = {}) {
const resourceAddress = await this.getContractAddress(resource);
return this.triggerContract({
methodName: 'equip',
abiKey: 'apostleLandResource',
abiString: this.ABIs['apostleLandResource'].abi,
contractParams: [
tokenId, resourceAddress, index, token, id
]
}, callback)
}
/**
* Divest the props on the index slot on the tokenid land
* @param {*} tokenId The tokenId of land
* @param {*} index The index slot
* @param {*} callback
*/
divestLandProps(tokenId, index, callback = {}) {
return this.triggerContract({
methodName: 'divest',
abiKey: 'apostleLandResource',
abiString: this.ABIs['apostleLandResource'].abi,
contractParams: [
tokenId, index
]
}, callback)
}
/**
* claim resource on the Land
* @param tokenAddress The nft of props contract address
* @param tokenId Land token Id
* @returns {Promise<PromiEvent<any>>}
*/
claimFurnaceItemResource(tokenAddress, tokenId, callback = {}) {
return this.triggerContract({
methodName: 'claimItemResource',
abiKey: 'apostleLandResource',
abiString: landResourceABI,
contractParams: [tokenAddress, Utils.pad0x(tokenId)],
}, callback)
}
estimateGas(method, address, gasPrice, value = 0) {
if (!this._web3js) return;
return (method || this._web3js.eth).estimateGas({ from: address, gasLimit: 0, gasPrice: gasPrice, value });
}
getNetworkId() {
return this._web3js.eth.net.getId()
}
/**
* check address info
* @param address - Ethereum address
*/
checkAddress(address) {
return this.ClientFetch.$get('/api/verified_wallet', {
wallet: address
})
}
challengeAddress(address) {
return this.ClientFetch.$get('/api/challenge', {
wallet: address
})
}
async _sign({
data,
name
}, from) {
let signature;
try {
signature = await this._web3js.eth.personal.sign(
name + " " + data,
from
);
} catch (e) {
}
return {
address: from,
signature
};
}
/**
* Login Evolution Land
* @param address - Ethereum address
* @returns {Promise<*>}
*/
async login(address) {
return new Promise((resolve, reject) => {
this.challengeAddress(address).then((res) => {
const {
code,
data,
name
} = res
if (code === 0) {
this._sign({
data,
name
}, address)
.then(info => {
if (info.signature) {
this.ClientFetch.$post('/api/login', {
wallet: address,
sign: info.signature
}).then((res) => {
resolve(res)
})
} else {
reject({
code,
data
})
}
})
.catch(err => reject(err))
}
})
})
}
}
export default EthereumEvolutionLand