mirror of
https://github.com/tornadocash/tornado-core.git
synced 2024-11-24 19:01:11 +01:00
return refund to a relayer in case of failure
This commit is contained in:
parent
a6519fb280
commit
ce550eea58
@ -38,8 +38,13 @@ contract ERC20Mixer is Mixer {
|
||||
if (_fee > 0) {
|
||||
_safeErc20Transfer(_relayer, _fee);
|
||||
}
|
||||
|
||||
if (_refund > 0) {
|
||||
_recipient.call.value(_refund)("");
|
||||
(bool success, ) = _recipient.call.value(_refund)("");
|
||||
if (!success) {
|
||||
// let's return _refund back to the relayer
|
||||
_relayer.transfer(_refund);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
7
contracts/Mocks/BadRecipient.sol
Normal file
7
contracts/Mocks/BadRecipient.sol
Normal file
@ -0,0 +1,7 @@
|
||||
pragma solidity ^0.5.0;
|
||||
|
||||
contract BadRecipient {
|
||||
function() external {
|
||||
require(false, "this contract does not accept ETH");
|
||||
}
|
||||
}
|
@ -9,6 +9,7 @@ const { toBN, toHex } = require('web3-utils')
|
||||
const { takeSnapshot, revertSnapshot } = require('../lib/ganacheHelper')
|
||||
|
||||
const Mixer = artifacts.require('./ERC20Mixer.sol')
|
||||
const BadRecipient = artifacts.require('./BadRecipient.sol')
|
||||
const Token = artifacts.require('./ERC20Mock.sol')
|
||||
const USDTToken = artifacts.require('./IUSDT.sol')
|
||||
const { ETH_AMOUNT, TOKEN_AMOUNT, MERKLE_TREE_HEIGHT, ERC20_TOKEN } = process.env
|
||||
@ -54,6 +55,7 @@ contract('ERC20Mixer', accounts => {
|
||||
let mixer
|
||||
let token
|
||||
let usdtToken
|
||||
let badRecipient
|
||||
const sender = accounts[0]
|
||||
const operator = accounts[0]
|
||||
const levels = MERKLE_TREE_HEIGHT || 16
|
||||
@ -63,7 +65,7 @@ contract('ERC20Mixer', accounts => {
|
||||
let tree
|
||||
const fee = bigInt(ETH_AMOUNT).shr(1) || bigInt(1e17)
|
||||
const refund = ETH_AMOUNT || '1000000000000000000' // 1 ether
|
||||
const recipient = getRandomRecipient()
|
||||
let recipient = getRandomRecipient()
|
||||
const relayer = accounts[1]
|
||||
let groth16
|
||||
let circuit
|
||||
@ -83,6 +85,7 @@ contract('ERC20Mixer', accounts => {
|
||||
token = await Token.deployed()
|
||||
await token.mint(sender, tokenDenomination)
|
||||
}
|
||||
badRecipient = await BadRecipient.new()
|
||||
snapshotId = await takeSnapshot()
|
||||
groth16 = await buildGroth16()
|
||||
circuit = require('../build/circuits/withdraw.json')
|
||||
@ -201,6 +204,85 @@ contract('ERC20Mixer', accounts => {
|
||||
isSpent.should.be.equal(true)
|
||||
})
|
||||
|
||||
it('should return refund to the relayer is case of fail', async () => {
|
||||
const deposit = generateDeposit()
|
||||
const user = accounts[4]
|
||||
recipient = bigInt(badRecipient.address)
|
||||
await tree.insert(deposit.commitment)
|
||||
await token.mint(user, tokenDenomination)
|
||||
|
||||
const balanceUserBefore = await token.balanceOf(user)
|
||||
await token.approve(mixer.address, tokenDenomination, { from: user })
|
||||
await mixer.deposit(toFixedHex(deposit.commitment), { from: user, gasPrice: '0' })
|
||||
|
||||
const balanceUserAfter = await token.balanceOf(user)
|
||||
balanceUserAfter.should.be.eq.BN(toBN(balanceUserBefore).sub(toBN(tokenDenomination)))
|
||||
|
||||
const { root, path_elements, path_index } = await tree.path(0)
|
||||
// Circuit input
|
||||
const input = stringifyBigInts({
|
||||
// public
|
||||
root,
|
||||
nullifierHash: pedersenHash(deposit.nullifier.leInt2Buff(31)),
|
||||
relayer,
|
||||
recipient,
|
||||
fee,
|
||||
refund,
|
||||
|
||||
// private
|
||||
nullifier: deposit.nullifier,
|
||||
secret: deposit.secret,
|
||||
pathElements: path_elements,
|
||||
pathIndices: path_index,
|
||||
})
|
||||
|
||||
|
||||
const proofData = await websnarkUtils.genWitnessAndProve(groth16, input, circuit, proving_key)
|
||||
const { proof } = websnarkUtils.toSolidityInput(proofData)
|
||||
|
||||
const balanceMixerBefore = await token.balanceOf(mixer.address)
|
||||
const balanceRelayerBefore = await token.balanceOf(relayer)
|
||||
const balanceRecieverBefore = await token.balanceOf(toHex(recipient.toString()))
|
||||
|
||||
const ethBalanceOperatorBefore = await web3.eth.getBalance(operator)
|
||||
const ethBalanceRecieverBefore = await web3.eth.getBalance(toHex(recipient.toString()))
|
||||
const ethBalanceRelayerBefore = await web3.eth.getBalance(relayer)
|
||||
let isSpent = await mixer.isSpent(toFixedHex(input.nullifierHash))
|
||||
isSpent.should.be.equal(false)
|
||||
|
||||
const args = [
|
||||
toFixedHex(input.root),
|
||||
toFixedHex(input.nullifierHash),
|
||||
toFixedHex(input.recipient, 20),
|
||||
toFixedHex(input.relayer, 20),
|
||||
toFixedHex(input.fee),
|
||||
toFixedHex(input.refund)
|
||||
]
|
||||
const { logs } = await mixer.withdraw(proof, ...args, { value: refund, from: relayer, gasPrice: '0' })
|
||||
|
||||
const balanceMixerAfter = await token.balanceOf(mixer.address)
|
||||
const balanceRelayerAfter = await token.balanceOf(relayer)
|
||||
const ethBalanceOperatorAfter = await web3.eth.getBalance(operator)
|
||||
const balanceRecieverAfter = await token.balanceOf(toHex(recipient.toString()))
|
||||
const ethBalanceRecieverAfter = await web3.eth.getBalance(toHex(recipient.toString()))
|
||||
const ethBalanceRelayerAfter = await web3.eth.getBalance(relayer)
|
||||
const feeBN = toBN(fee.toString())
|
||||
balanceMixerAfter.should.be.eq.BN(toBN(balanceMixerBefore).sub(toBN(tokenDenomination)))
|
||||
balanceRelayerAfter.should.be.eq.BN(toBN(balanceRelayerBefore).add(feeBN))
|
||||
balanceRecieverAfter.should.be.eq.BN(toBN(balanceRecieverBefore).add(toBN(tokenDenomination).sub(feeBN)))
|
||||
|
||||
ethBalanceOperatorAfter.should.be.eq.BN(toBN(ethBalanceOperatorBefore))
|
||||
ethBalanceRecieverAfter.should.be.eq.BN(toBN(ethBalanceRecieverBefore))
|
||||
ethBalanceRelayerAfter.should.be.eq.BN(toBN(ethBalanceRelayerBefore))
|
||||
|
||||
logs[0].event.should.be.equal('Withdrawal')
|
||||
logs[0].args.nullifierHash.should.be.equal(toFixedHex(input.nullifierHash))
|
||||
logs[0].args.relayer.should.be.eq.BN(relayer)
|
||||
logs[0].args.fee.should.be.eq.BN(feeBN)
|
||||
isSpent = await mixer.isSpent(toFixedHex(input.nullifierHash))
|
||||
isSpent.should.be.equal(true)
|
||||
})
|
||||
|
||||
it('should reject with wrong refund value', async () => {
|
||||
const deposit = generateDeposit()
|
||||
const user = accounts[4]
|
||||
|
Loading…
Reference in New Issue
Block a user