feat: integration of erc-20 tokens
This commit is contained in:
parent
0b5da0b78f
commit
dfca785ed0
7 changed files with 127 additions and 29 deletions
32
lib/plugins/common/kraken.js
Normal file
32
lib/plugins/common/kraken.js
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
const PAIRS = {
|
||||
BTC: {
|
||||
USD: 'XXBTZUSD',
|
||||
EUR: 'XXBTZEUR'
|
||||
},
|
||||
ETH: {
|
||||
USD: 'XETHZUSD',
|
||||
EUR: 'XETHZEUR'
|
||||
},
|
||||
ZEC: {
|
||||
USD: 'XZECZUSD',
|
||||
EUR: 'XZECZEUR'
|
||||
},
|
||||
LTC: {
|
||||
USD: 'XLTCZUSD',
|
||||
EUR: 'XLTCZEUR'
|
||||
},
|
||||
DASH: {
|
||||
USD: 'DASHUSD',
|
||||
EUR: 'DASHEUR'
|
||||
},
|
||||
BCH: {
|
||||
USD: 'BCHUSD',
|
||||
EUR: 'BCHEUR'
|
||||
},
|
||||
USDT: {
|
||||
USD: 'USDTZUSD',
|
||||
EUR: 'USDTEUR'
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {PAIRS}
|
||||
File diff suppressed because one or more lines are too long
1
lib/plugins/erc20/abi/yeenus.json
Normal file
1
lib/plugins/erc20/abi/yeenus.json
Normal file
|
|
@ -0,0 +1 @@
|
|||
[{"constant":true,"inputs":[],"name":"name","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"spender","type":"address"},{"name":"tokens","type":"uint256"}],"name":"approve","outputs":[{"name":"success","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"totalSupply","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"from","type":"address"},{"name":"to","type":"address"},{"name":"tokens","type":"uint256"}],"name":"transferFrom","outputs":[{"name":"success","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"decimals","outputs":[{"name":"","type":"uint8"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"tokenOwner","type":"address"}],"name":"balanceOf","outputs":[{"name":"balance","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"acceptOwnership","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"owner","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"symbol","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"drip","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"to","type":"address"},{"name":"tokens","type":"uint256"}],"name":"transfer","outputs":[{"name":"success","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"spender","type":"address"},{"name":"tokens","type":"uint256"},{"name":"data","type":"bytes"}],"name":"approveAndCall","outputs":[{"name":"success","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"newOwner","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"tokenAddress","type":"address"},{"name":"tokens","type":"uint256"}],"name":"transferAnyERC20Token","outputs":[{"name":"success","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"tokenOwner","type":"address"},{"name":"spender","type":"address"}],"name":"allowance","outputs":[{"name":"remaining","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"inputs":[],"payable":false,"stateMutability":"nonpayable","type":"constructor"},{"payable":true,"stateMutability":"payable","type":"fallback"},{"anonymous":false,"inputs":[{"indexed":true,"name":"_from","type":"address"},{"indexed":true,"name":"_to","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"from","type":"address"},{"indexed":true,"name":"to","type":"address"},{"indexed":false,"name":"tokens","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"tokenOwner","type":"address"},{"indexed":true,"name":"spender","type":"address"},{"indexed":false,"name":"tokens","type":"uint256"}],"name":"Approval","type":"event"}]
|
||||
|
|
@ -1,3 +1,4 @@
|
|||
const usdt = require('./abi/usdt.json')
|
||||
const USDT = require('./abi/usdt.json')
|
||||
const YEENUS = require('./abi/yeenus.json')
|
||||
|
||||
module.exports = { usdt }
|
||||
module.exports = { USDT, YEENUS }
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ const paymentPrefixPath = "m/44'/60'/0'/0'"
|
|||
const defaultPrefixPath = "m/44'/60'/1'/0'"
|
||||
let lastUsedNonces = {}
|
||||
|
||||
const contract = web3.eth.contract(erc20ABIs.usdt, coins.utils.getErc20Token('USDT').contractAddress)
|
||||
// const contract = web3.eth.contract(erc20ABIs.usdt, coins.utils.getErc20Token('USDT').contractAddress)
|
||||
// console.log(contract)
|
||||
|
||||
module.exports = {
|
||||
|
|
@ -52,8 +52,8 @@ function isStrictAddress (cryptoCode, toAddress, settings, operatorId) {
|
|||
}
|
||||
|
||||
function sendCoins (account, tx, settings, operatorId) {
|
||||
const { toAddress, cryptoAtoms } = tx
|
||||
return generateTx(toAddress, defaultWallet(account), cryptoAtoms, false)
|
||||
const { toAddress, cryptoAtoms, cryptoCode } = tx
|
||||
return generateTx(toAddress, defaultWallet(account), cryptoAtoms, false, cryptoCode)
|
||||
.then(pify(web3.eth.sendRawTransaction))
|
||||
.then(txid => {
|
||||
return pify(web3.eth.getTransaction)(txid)
|
||||
|
|
@ -68,29 +68,89 @@ function sendCoins (account, tx, settings, operatorId) {
|
|||
}
|
||||
|
||||
function checkCryptoCode (cryptoCode) {
|
||||
console.log('estou a entrar no checkCryptoCode do ETH com o valor ' + cryptoCode)
|
||||
if (cryptoCode === 'ETH' || coins.utils.isErc20Token(cryptoCode)) return Promise.resolve()
|
||||
if (cryptoCode === 'ETH' || coins.utils.isErc20Token(cryptoCode)) {
|
||||
// console.log(cryptoCode)
|
||||
return Promise.resolve(cryptoCode)
|
||||
}
|
||||
return Promise.reject(new Error('cryptoCode must be ETH'))
|
||||
}
|
||||
|
||||
function balance (account, cryptoCode, settings, operatorId) {
|
||||
return checkCryptoCode(cryptoCode)
|
||||
.then(() => confirmedBalance(defaultAddress(account)))
|
||||
.then(code => confirmedBalance(defaultAddress(account), code))
|
||||
}
|
||||
|
||||
const pendingBalance = address => {
|
||||
const promises = [_balance(true, address), _balance(false, address)]
|
||||
const pendingBalance = (address, cryptoCode) => {
|
||||
const promises = [_balance(true, address, cryptoCode), _balance(false, address, cryptoCode)]
|
||||
return Promise.all(promises).then(([pending, confirmed]) => pending - confirmed)
|
||||
}
|
||||
const confirmedBalance = address => _balance(false, address)
|
||||
const confirmedBalance = (address, cryptoCode) => _balance(false, address, cryptoCode)
|
||||
|
||||
function _balance (includePending, address) {
|
||||
function _balance (includePending, address, cryptoCode) {
|
||||
if (coins.utils.getCryptoCurrency(cryptoCode).type === 'erc-20') {
|
||||
const contract = web3.eth.contract(erc20ABIs[cryptoCode]).at(coins.utils.getErc20Token(cryptoCode).contractAddress)
|
||||
return contract.balanceOf(address.toLowerCase())
|
||||
}
|
||||
const block = includePending ? 'pending' : undefined
|
||||
|
||||
return pify(web3.eth.getBalance)(address.toLowerCase(), block)
|
||||
}
|
||||
|
||||
function generateTx (_toAddress, wallet, amount, includesFee) {
|
||||
function generateTx (toAddress, wallet, amount, includesFee, cryptoCode) {
|
||||
return coins.utils.getCryptoCurrency(cryptoCode).type === 'erc-20'
|
||||
? generateContractTx(toAddress, wallet, amount, includesFee, cryptoCode)
|
||||
: generateCoinTx(toAddress, wallet, amount, includesFee)
|
||||
}
|
||||
|
||||
function generateContractTx (_toAddress, wallet, amount, includesFee, cryptoCode) {
|
||||
const contract = web3.eth.contract(erc20ABIs[cryptoCode]).at(coins.utils.getErc20Token(cryptoCode).contractAddress)
|
||||
|
||||
const fromAddress = '0x' + wallet.getAddress().toString('hex')
|
||||
const toAddress = _toAddress.toLowerCase()
|
||||
|
||||
const txTemplate = {
|
||||
from: fromAddress,
|
||||
to: coins.utils.getErc20Token(cryptoCode).contractAddress,
|
||||
value: amount
|
||||
}
|
||||
|
||||
const promises = [
|
||||
pify(web3.eth.estimateGas)(txTemplate),
|
||||
pify(web3.eth.getGasPrice)(),
|
||||
pify(web3.eth.getTransactionCount)(fromAddress)
|
||||
]
|
||||
|
||||
return Promise.all(promises)
|
||||
.then(arr => {
|
||||
const gas = arr[0]
|
||||
const gasPrice = arr[1]
|
||||
const txCount = arr[2] <= lastUsedNonces[fromAddress]
|
||||
? lastUsedNonces[fromAddress] + 1
|
||||
: arr[2]
|
||||
|
||||
const toSend = includesFee
|
||||
? amount.minus(gasPrice.times(gas))
|
||||
: amount
|
||||
|
||||
const rawTx = {
|
||||
nonce: txCount,
|
||||
gasPrice: hex(gasPrice),
|
||||
gasLimit: gas,
|
||||
to: coins.utils.getErc20Token(cryptoCode).contractAddress,
|
||||
from: fromAddress,
|
||||
value: hex(BN(0)),
|
||||
data: contract.transfer.getData(toAddress, hex(toSend))
|
||||
}
|
||||
|
||||
const tx = new Tx(rawTx)
|
||||
const privateKey = wallet.getPrivateKey()
|
||||
|
||||
tx.sign(privateKey)
|
||||
|
||||
return '0x' + tx.serialize().toString('hex')
|
||||
})
|
||||
}
|
||||
|
||||
function generateCoinTx (_toAddress, wallet, amount, includesFee) {
|
||||
const fromAddress = '0x' + wallet.getAddress().toString('hex')
|
||||
const toAddress = _toAddress.toLowerCase()
|
||||
|
||||
|
|
@ -150,11 +210,11 @@ function sweep (account, cryptoCode, hdIndex, settings, operatorId) {
|
|||
const wallet = paymentHdNode(account).deriveChild(hdIndex).getWallet()
|
||||
const fromAddress = wallet.getChecksumAddressString()
|
||||
|
||||
return confirmedBalance(fromAddress)
|
||||
return confirmedBalance(fromAddress, cryptoCode)
|
||||
.then(r => {
|
||||
if (r.eq(0)) return
|
||||
|
||||
return generateTx(defaultAddress(account), wallet, r, true)
|
||||
return generateTx(defaultAddress(account), wallet, r, true, cryptoCode)
|
||||
.then(signedTx => pify(web3.eth.sendRawTransaction)(signedTx))
|
||||
})
|
||||
}
|
||||
|
|
@ -167,11 +227,11 @@ function newAddress (account, info, tx, settings, operatorId) {
|
|||
function getStatus (account, tx, requested, settings, operatorId) {
|
||||
const { toAddress, cryptoCode } = tx
|
||||
return checkCryptoCode(cryptoCode)
|
||||
.then(() => confirmedBalance(toAddress))
|
||||
.then(confirmed => {
|
||||
.then(code => Promise.all([confirmedBalance(toAddress, code), code]))
|
||||
.then(([confirmed, code]) => {
|
||||
if (confirmed.gte(requested)) return { receivedCryptoAtoms: confirmed, status: 'confirmed' }
|
||||
|
||||
return pendingBalance(toAddress)
|
||||
return pendingBalance(toAddress, code)
|
||||
.then(pending => {
|
||||
if (pending.gte(requested)) return { receivedCryptoAtoms: pending, status: 'published' }
|
||||
if (pending.gt(0)) return { receivedCryptoAtoms: pending, status: 'insufficientFunds' }
|
||||
|
|
@ -196,12 +256,12 @@ function defaultHdNode (account) {
|
|||
|
||||
function newFunding (account, cryptoCode, settings, operatorId) {
|
||||
return checkCryptoCode(cryptoCode)
|
||||
.then(() => {
|
||||
.then(code => {
|
||||
const fundingAddress = defaultAddress(account)
|
||||
|
||||
const promises = [
|
||||
pendingBalance(fundingAddress),
|
||||
confirmedBalance(fundingAddress)
|
||||
pendingBalance(fundingAddress, code),
|
||||
confirmedBalance(fundingAddress, code)
|
||||
]
|
||||
|
||||
return Promise.all(promises)
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ import { useLazyQuery } from '@apollo/react-hooks'
|
|||
import { makeStyles } from '@material-ui/core'
|
||||
import BigNumber from 'bignumber.js'
|
||||
import gql from 'graphql-tag'
|
||||
import { utils } from 'lamassu-coins'
|
||||
import moment from 'moment'
|
||||
import * as R from 'ramda'
|
||||
import React, { useEffect, useState } from 'react'
|
||||
|
|
@ -11,7 +12,6 @@ import { mainStyles } from 'src/pages/Transactions/Transactions.styles'
|
|||
import { getStatus } from 'src/pages/Transactions/helper'
|
||||
import { ReactComponent as TxInIcon } from 'src/styling/icons/direction/cash-in.svg'
|
||||
import { ReactComponent as TxOutIcon } from 'src/styling/icons/direction/cash-out.svg'
|
||||
import { toUnit, formatCryptoAddress } from 'src/utils/coin'
|
||||
|
||||
import DataTable from './DataTable'
|
||||
const useStyles = makeStyles(mainStyles)
|
||||
|
|
@ -118,13 +118,13 @@ const Transactions = ({ id }) => {
|
|||
textAlign: 'right',
|
||||
size: 'sm',
|
||||
view: it =>
|
||||
`${toUnit(new BigNumber(it.cryptoAtoms), it.cryptoCode).toFormat(5)} ${
|
||||
it.cryptoCode
|
||||
}`
|
||||
`${utils
|
||||
.toUnit(new BigNumber(it.cryptoAtoms), it.cryptoCode)
|
||||
.toFormat(5)} ${it.cryptoCode}`
|
||||
},
|
||||
{
|
||||
header: 'Address',
|
||||
view: it => formatCryptoAddress(it.cryptoCode, it.toAddress),
|
||||
view: it => utils.formatCryptoAddress(it.cryptoCode, it.toAddress),
|
||||
className: classes.overflowTd,
|
||||
size: 'sm',
|
||||
textAlign: 'left',
|
||||
|
|
|
|||
|
|
@ -50,8 +50,12 @@ const getLogo = code => {
|
|||
return LitecoinLogo
|
||||
case 'ZEC':
|
||||
return ZCashLogo
|
||||
default:
|
||||
case 'USDT':
|
||||
return EthereumLogo
|
||||
case 'YEENUS':
|
||||
return EthereumLogo
|
||||
default:
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue