Skip to content
This repository has been archived by the owner on Nov 10, 2023. It is now read-only.

Commit

Permalink
Merge pull request #223 from gnosis/bug/218-non-18-decimals-tokens-tr…
Browse files Browse the repository at this point in the history
…ansfer

BUG: Hotfix #218 Non-18 decimals tokens transfer
  • Loading branch information
mmv08 authored Oct 14, 2019
2 parents 7929ff5 + 2b6f33c commit c3f4732
Show file tree
Hide file tree
Showing 7 changed files with 105 additions and 16 deletions.
1 change: 1 addition & 0 deletions contracts/DevDependencies.sol
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,6 @@ pragma solidity ^0.5.2;

import "../src/test/contracts/TokenOMG.sol";
import "../src/test/contracts/TokenRDN.sol";
import "../src/test/contracts/Token6Decimals.sol";

contract DevDependenciesGetter {}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
// @flow
import React from 'react'
import { BigNumber } from 'bignumber.js'
import OpenInNew from '@material-ui/icons/OpenInNew'
import { withStyles } from '@material-ui/core/styles'
import Close from '@material-ui/icons/Close'
Expand All @@ -17,7 +18,7 @@ import { copyToClipboard } from '~/utils/clipboard'
import Hairline from '~/components/layout/Hairline'
import SafeInfo from '~/routes/safe/components/Balances/SendModal/SafeInfo'
import { setImageToPlaceholder } from '~/routes/safe/components/Balances/utils'
import { getStandardTokenContract } from '~/logic/tokens/store/actions/fetchTokens'
import { getHumanFriendlyToken } from '~/logic/tokens/store/actions/fetchTokens'
import { EMPTY_DATA } from '~/logic/wallets/ethTransactions'
import { getWeb3 } from '~/logic/wallets/getWeb3'
import { TX_NOTIFICATION_TYPES } from '~/logic/safe/transactions'
Expand Down Expand Up @@ -66,8 +67,10 @@ const ReviewTx = ({
let txAmount = web3.utils.toWei(tx.amount, 'ether')

if (!isSendingETH) {
const StandardToken = await getStandardTokenContract()
const tokenInstance = await StandardToken.at(tx.token.address)
const HumanFriendlyToken = await getHumanFriendlyToken()
const tokenInstance = await HumanFriendlyToken.at(tx.token.address)
const decimals = await tokenInstance.decimals()
txAmount = new BigNumber(tx.amount).times(10 ** decimals.toNumber()).toString()

txData = tokenInstance.contract.methods.transfer(tx.recipientAddress, txAmount).encodeABI()
// txAmount should be 0 if we send tokens
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ type CustomDescProps = {
value: string,
recipient: string,
data: String,
classes: Obeject,
classes: Object,
}

const TransferDescription = ({ value = '', symbol, recipient }: TransferDescProps) => (
Expand Down
17 changes: 17 additions & 0 deletions src/test/contracts/Token6Decimals.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
pragma solidity ^0.5.2;

import "@gnosis.pm/util-contracts/contracts/GnosisStandardToken.sol";

contract Token6Decimals is GnosisStandardToken {
string public constant symbol = "6DEC";
string public constant name = "6 Decimals";
uint8 public constant decimals = 6;

constructor(
uint amount
)
public
{
balances[msg.sender] = amount;
}
}
59 changes: 55 additions & 4 deletions src/test/safe.dom.funds.threshold=1.test.js
Original file line number Diff line number Diff line change
@@ -1,17 +1,19 @@
// @flow
import { fireEvent } from '@testing-library/react'
import { Map, Set } from 'immutable'
import { Map, Set, List } from 'immutable'
import { aNewStore } from '~/store'
import { aMinedSafe } from '~/test/builder/safe.redux.builder'
import { sendTokenTo, sendEtherTo } from '~/test/utils/tokenMovements'
import { sendTokenTo, sendEtherTo, get6DecimalsTokenContract } from '~/test/utils/tokenMovements'
import { renderSafeView } from '~/test/builder/safe.dom.utils'
import { getWeb3, getBalanceInEtherOf } from '~/logic/wallets/getWeb3'
import { dispatchAddTokenToList } from '~/test/utils/transactions/moveTokens.helper'
import { sleep } from '~/utils/timer'
import saveTokens from '~/logic/tokens/store/actions/saveTokens'
import { calculateBalanceOf } from '~/routes/safe/store/actions/fetchTokenBalances'
import updateActiveTokens from '~/routes/safe/store/actions/updateActiveTokens'
import '@testing-library/jest-dom/extend-expect'
import updateSafe from '~/routes/safe/store/actions/updateSafe'
import { makeToken } from '~/logic/tokens/store/model/token'
import { checkRegisteredTxSend, fillAndSubmitSendFundsForm } from './utils/transactions'
import { BALANCE_ROW_TEST_ID } from '~/routes/safe/components/Balances'

Expand All @@ -21,7 +23,6 @@ describe('DOM > Feature > Sending Funds', () => {
let accounts
beforeEach(async () => {
store = aNewStore()
// using 4th account because other accounts were used in other tests and paid gas
safeAddress = await aMinedSafe(store)
accounts = await getWeb3().eth.getAccounts()
})
Expand Down Expand Up @@ -62,7 +63,7 @@ describe('DOM > Feature > Sending Funds', () => {
await checkRegisteredTxSend(SafeDom, ethAmount, 'ETH', accounts[9])
})

it('Sends Tokens with threshold = 1', async () => {
it('Sends Tokens with 18 decimals with threshold = 1', async () => {
// GIVEN
const tokensAmount = '100'
const tokenReceiver = accounts[1]
Expand Down Expand Up @@ -102,4 +103,54 @@ describe('DOM > Feature > Sending Funds', () => {
// Check that the transaction was registered
await checkRegisteredTxSend(SafeDom, tokensAmount, 'OMG', tokenReceiver)
})

it('Sends Tokens with decimals other than 18 with threshold = 1', async () => {
// GIVEN
const tokensAmount = '1000000'
const tokenReceiver = accounts[1]
const web3 = await getWeb3()
const SixDecimalsToken = await get6DecimalsTokenContract(web3, accounts[0])
const tokenList = List([
makeToken({
address: SixDecimalsToken.address,
name: '6 Decimals',
symbol: '6DEC',
decimals: 6,
logoUri: 'https://upload.wikimedia.org/wikipedia/commons/c/c0/Earth_simple_icon.png',
}),
])
await store.dispatch(saveTokens(tokenList))

await SixDecimalsToken.contract.methods.transfer(safeAddress, tokensAmount).send({ from: accounts[0] })

// WHEN
const SafeDom = await renderSafeView(store, safeAddress)
await sleep(1300)

// Activate token
const safeTokenBalance = await calculateBalanceOf(SixDecimalsToken.address, safeAddress, 6)
expect(safeTokenBalance).toBe('1')

const balances = Map({
[SixDecimalsToken.address]: safeTokenBalance,
})

store.dispatch(updateActiveTokens(safeAddress, Set([SixDecimalsToken.address])))
store.dispatch(updateSafe({ address: safeAddress, balances }))
await sleep(1000)

// Open send funds modal
const balanceRows = SafeDom.getAllByTestId(BALANCE_ROW_TEST_ID)
expect(balanceRows.length).toBe(2)
const sendButtons = SafeDom.getAllByTestId('balance-send-btn')
expect(sendButtons.length).toBe(2)

await fillAndSubmitSendFundsForm(SafeDom, sendButtons[1], '1', tokenReceiver)

// THEN
const safeFunds = await calculateBalanceOf(SixDecimalsToken.address, safeAddress, 6)
expect(Number(safeFunds)).toBe(0)
const receiverFunds = await calculateBalanceOf(SixDecimalsToken.address, tokenReceiver, 6)
expect(receiverFunds).toBe('1')
})
})
13 changes: 13 additions & 0 deletions src/test/utils/tokenMovements.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { ensureOnce } from '~/utils/singleton'
import { toNative } from '~/logic/wallets/tokens'
import TokenOMG from '../../../build/contracts/TokenOMG'
import TokenRDN from '../../../build/contracts/TokenRDN'
import Token6Decimals from '../../../build/contracts/Token6Decimals.json'

export const sendEtherTo = async (address: string, eth: string, fromAccountIndex: number = 0) => {
const web3 = getWeb3()
Expand Down Expand Up @@ -41,8 +42,20 @@ const createTokenRDNContract = async (web3: any, creator: string) => {
return token.new(amount, { from: creator })
}

const create6DecimalsTokenContract = async (web3: any, creator: string) => {
const token = contract(Token6Decimals)
const { toBN } = web3.utils
const amount = toBN(50000)
.mul(toBN(10).pow(toBN(6)))
.toString()
token.setProvider(web3.currentProvider)

return token.new(amount, { from: creator })
}

export const getFirstTokenContract = ensureOnce(createTokenOMGContract)
export const getSecondTokenContract = ensureOnce(createTokenRDNContract)
export const get6DecimalsTokenContract = ensureOnce(create6DecimalsTokenContract)

export const sendTokenTo = async (safe: string, value: string, tokenContract?: any) => {
const web3 = getWeb3()
Expand Down
20 changes: 12 additions & 8 deletions src/test/utils/transactions/moveFunds.helper.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// @flow
import * as React from 'react'
import { fireEvent, waitForElement } from '@testing-library/react'
import { fireEvent, waitForElement, act } from '@testing-library/react'
import { sleep } from '~/utils/timer'

export const fillAndSubmitSendFundsForm = async (
Expand All @@ -9,22 +9,26 @@ export const fillAndSubmitSendFundsForm = async (
value: string,
recipient: string,
) => {
// load add multisig form component
fireEvent.click(sendButton)
await act(async () => {
fireEvent.click(sendButton)
})
// give time to re-render it
await sleep(400)

// Fill first send funds screen
const recipientInput = SafeDom.getByPlaceholderText('Recipient*')
const amountInput = SafeDom.getByPlaceholderText('Amount*')
const reviewBtn = SafeDom.getByTestId('review-tx-btn')
fireEvent.change(recipientInput, { target: { value: recipient } })
fireEvent.change(amountInput, { target: { value } })
await sleep(200)
fireEvent.click(reviewBtn)
await act(async () => {
fireEvent.change(recipientInput, { target: { value: recipient } })
fireEvent.change(amountInput, { target: { value } })
fireEvent.click(reviewBtn)
})

// Submit the tx (Review Tx screen)
const submitBtn = await waitForElement(() => SafeDom.getByTestId('submit-tx-btn'))
fireEvent.click(submitBtn)
await act(async () => {
fireEvent.click(submitBtn)
})
await sleep(1000)
}

0 comments on commit c3f4732

Please sign in to comment.