mirror of
https://github.com/tornadocash/tornado-nova
synced 2024-02-02 14:53:56 +01:00
more tests
This commit is contained in:
parent
3fea84a759
commit
e14f7ba88f
@ -1,5 +1,6 @@
|
|||||||
// SPDX-License-Identifier: MIT
|
// SPDX-License-Identifier: MIT
|
||||||
pragma solidity ^0.7.0;
|
pragma solidity ^0.7.0;
|
||||||
|
pragma abicoder v2;
|
||||||
|
|
||||||
import { IAMB } from "../interfaces/IBridge.sol";
|
import { IAMB } from "../interfaces/IBridge.sol";
|
||||||
|
|
||||||
@ -7,6 +8,11 @@ contract MockAMB is IAMB {
|
|||||||
address public xDomainMessageSender;
|
address public xDomainMessageSender;
|
||||||
bytes32 public xDomainMessageChainId;
|
bytes32 public xDomainMessageChainId;
|
||||||
|
|
||||||
|
struct Call {
|
||||||
|
address who;
|
||||||
|
bytes callData;
|
||||||
|
}
|
||||||
|
|
||||||
constructor(address _xDomainMessageSender, uint256 _xDomainMessageChainId) {
|
constructor(address _xDomainMessageSender, uint256 _xDomainMessageChainId) {
|
||||||
xDomainMessageSender = _xDomainMessageSender;
|
xDomainMessageSender = _xDomainMessageSender;
|
||||||
xDomainMessageChainId = bytes32(uint256(_xDomainMessageChainId));
|
xDomainMessageChainId = bytes32(uint256(_xDomainMessageChainId));
|
||||||
@ -24,8 +30,10 @@ contract MockAMB is IAMB {
|
|||||||
return xDomainMessageChainId;
|
return xDomainMessageChainId;
|
||||||
}
|
}
|
||||||
|
|
||||||
function execute(address _who, bytes calldata _calldata) external returns (bool success, bytes memory result) {
|
function execute(Call[] calldata _calls) external returns (bool success, bytes memory result) {
|
||||||
(success, result) = _who.call(_calldata);
|
for (uint256 i = 0; i < _calls.length; i++) {
|
||||||
require(success, string(result));
|
(success, result) = _calls[i].who.call(_calls[i].callData);
|
||||||
|
require(success, string(result));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,11 +1,17 @@
|
|||||||
// SPDX-License-Identifier: MIT
|
// SPDX-License-Identifier: MIT
|
||||||
pragma solidity ^0.7.0;
|
pragma solidity ^0.7.0;
|
||||||
|
pragma abicoder v2;
|
||||||
|
|
||||||
import { IAMB, IOmniBridge } from "../interfaces/IBridge.sol";
|
import { IAMB, IOmniBridge } from "../interfaces/IBridge.sol";
|
||||||
|
|
||||||
contract MockOmniBridge is IOmniBridge {
|
contract MockOmniBridge is IOmniBridge {
|
||||||
IAMB public AMB;
|
IAMB public AMB;
|
||||||
|
|
||||||
|
struct Call {
|
||||||
|
address who;
|
||||||
|
bytes callData;
|
||||||
|
}
|
||||||
|
|
||||||
constructor(IAMB _AMB) {
|
constructor(IAMB _AMB) {
|
||||||
AMB = _AMB;
|
AMB = _AMB;
|
||||||
}
|
}
|
||||||
@ -14,9 +20,10 @@ contract MockOmniBridge is IOmniBridge {
|
|||||||
return AMB;
|
return AMB;
|
||||||
}
|
}
|
||||||
|
|
||||||
function execute(address _who, bytes calldata _calldata) external returns (bool success, bytes memory result) {
|
function execute(Call[] calldata _calls) external returns (bool success, bytes memory result) {
|
||||||
(success, result) = _who.call(_calldata);
|
for (uint256 i = 0; i < _calls.length; i++) {
|
||||||
require(success, string(result));
|
(success, result) = _calls[i].who.call(_calls[i].callData);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
event OnTokenTransfer(address contr, address from, address receiver, uint256 value, bytes data);
|
event OnTokenTransfer(address contr, address from, address receiver, uint256 value, bytes data);
|
||||||
|
@ -155,12 +155,15 @@ contract TornadoPool is MerkleTreeWithHistory, IERC20Receiver, ReentrancyGuard,
|
|||||||
require(token.balanceOf(address(this)) >= uint256(_extData.extAmount) + lastBalance, "bridge did not send enough tokens");
|
require(token.balanceOf(address(this)) >= uint256(_extData.extAmount) + lastBalance, "bridge did not send enough tokens");
|
||||||
require(uint256(_extData.extAmount) <= maximumDepositAmount, "amount is larger than maximumDepositAmount");
|
require(uint256(_extData.extAmount) <= maximumDepositAmount, "amount is larger than maximumDepositAmount");
|
||||||
uint256 sentAmount = token.balanceOf(address(this)) - lastBalance;
|
uint256 sentAmount = token.balanceOf(address(this)) - lastBalance;
|
||||||
try TornadoPool(address(this)).bridgeTransact(_args, _extData) {} catch (bytes memory) {
|
try TornadoPool(address(this)).onTransact(_args, _extData) {} catch (bytes memory) {
|
||||||
token.transfer(multisig, sentAmount);
|
token.transfer(multisig, sentAmount);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function bridgeTransact(Proof memory _args, ExtData memory _extData) external {
|
/**
|
||||||
|
* @dev Wrapper for the internal func _transact to call it using try-catch from onTokenBridged
|
||||||
|
*/
|
||||||
|
function onTransact(Proof memory _args, ExtData memory _extData) external {
|
||||||
require(msg.sender == address(this), "can be called only from onTokenBridged");
|
require(msg.sender == address(this), "can be called only from onTokenBridged");
|
||||||
_transact(_args, _extData);
|
_transact(_args, _extData);
|
||||||
}
|
}
|
||||||
|
@ -68,14 +68,14 @@ describe('TornadoPool', function () {
|
|||||||
|
|
||||||
await token.approve(tornadoPool.address, utils.parseEther('10000'))
|
await token.approve(tornadoPool.address, utils.parseEther('10000'))
|
||||||
|
|
||||||
return { tornadoPool, token, proxy, omniBridge, amb, gov }
|
return { tornadoPool, token, proxy, omniBridge, amb, gov, multisig }
|
||||||
}
|
}
|
||||||
|
|
||||||
describe('Upgradeability tests', () => {
|
describe('Upgradeability tests', () => {
|
||||||
it('admin should be gov', async () => {
|
it('admin should be gov', async () => {
|
||||||
const { proxy, amb, gov } = await loadFixture(fixture)
|
const { proxy, amb, gov } = await loadFixture(fixture)
|
||||||
const { data } = await proxy.populateTransaction.admin()
|
const { data } = await proxy.populateTransaction.admin()
|
||||||
const { result } = await amb.callStatic.execute(proxy.address, data)
|
const { result } = await amb.callStatic.execute([{ who: proxy.address, callData: data }])
|
||||||
expect('0x' + result.slice(26)).to.be.equal(gov.address.toLowerCase())
|
expect('0x' + result.slice(26)).to.be.equal(gov.address.toLowerCase())
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -96,7 +96,7 @@ describe('TornadoPool', function () {
|
|||||||
newDepositLimit,
|
newDepositLimit,
|
||||||
)
|
)
|
||||||
|
|
||||||
await amb.execute(tornadoPool.address, data)
|
await amb.execute([{ who: tornadoPool.address, callData: data }])
|
||||||
|
|
||||||
expect(await tornadoPool.maximumDepositAmount()).to.be.equal(newDepositLimit)
|
expect(await tornadoPool.maximumDepositAmount()).to.be.equal(newDepositLimit)
|
||||||
expect(await tornadoPool.minimalWithdrawalAmount()).to.be.equal(newWithdrawalLimit)
|
expect(await tornadoPool.minimalWithdrawalAmount()).to.be.equal(newWithdrawalLimit)
|
||||||
@ -240,9 +240,14 @@ describe('TornadoPool', function () {
|
|||||||
aliceDepositUtxo.amount,
|
aliceDepositUtxo.amount,
|
||||||
onTokenBridgedData,
|
onTokenBridgedData,
|
||||||
)
|
)
|
||||||
// emulating bridge. first it sends tokens and then calls onTokenBridged method
|
// emulating bridge. first it sends tokens to omnibridge mock then it sends to the pool
|
||||||
await token.transfer(tornadoPool.address, aliceDepositAmount)
|
await token.transfer(omniBridge.address, aliceDepositAmount)
|
||||||
await omniBridge.execute(tornadoPool.address, onTokenBridgedTx.data)
|
const transferTx = await token.populateTransaction.transfer(tornadoPool.address, aliceDepositAmount)
|
||||||
|
|
||||||
|
await omniBridge.execute([
|
||||||
|
{ who: token.address, callData: transferTx.data }, // send tokens to pool
|
||||||
|
{ who: tornadoPool.address, callData: onTokenBridgedTx.data }, // call onTokenBridgedTx
|
||||||
|
])
|
||||||
|
|
||||||
// withdraws a part of his funds from the shielded pool
|
// withdraws a part of his funds from the shielded pool
|
||||||
const aliceWithdrawAmount = utils.parseEther('0.06')
|
const aliceWithdrawAmount = utils.parseEther('0.06')
|
||||||
@ -265,6 +270,62 @@ describe('TornadoPool', function () {
|
|||||||
expect(omniBridgeBalance).to.be.equal(aliceWithdrawAmount)
|
expect(omniBridgeBalance).to.be.equal(aliceWithdrawAmount)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it('should transfer funds to multisig in case of L1 deposit fail', async function () {
|
||||||
|
const { tornadoPool, token, omniBridge, multisig } = await loadFixture(fixture)
|
||||||
|
const aliceKeypair = new Keypair() // contains private and public keys
|
||||||
|
|
||||||
|
// Alice deposits into tornado pool
|
||||||
|
const aliceDepositAmount = utils.parseEther('0.07')
|
||||||
|
const aliceDepositUtxo = new Utxo({ amount: aliceDepositAmount, keypair: aliceKeypair })
|
||||||
|
const { args, extData } = await prepareTransaction({
|
||||||
|
tornadoPool,
|
||||||
|
outputs: [aliceDepositUtxo],
|
||||||
|
})
|
||||||
|
|
||||||
|
args.proof = args.proof.slice(0, -2)
|
||||||
|
|
||||||
|
const onTokenBridgedData = encodeDataForBridge({
|
||||||
|
proof: args,
|
||||||
|
extData,
|
||||||
|
})
|
||||||
|
|
||||||
|
const onTokenBridgedTx = await tornadoPool.populateTransaction.onTokenBridged(
|
||||||
|
token.address,
|
||||||
|
aliceDepositUtxo.amount,
|
||||||
|
onTokenBridgedData,
|
||||||
|
)
|
||||||
|
// emulating bridge. first it sends tokens to omnibridge mock then it sends to the pool
|
||||||
|
await token.transfer(omniBridge.address, aliceDepositAmount)
|
||||||
|
const transferTx = await token.populateTransaction.transfer(tornadoPool.address, aliceDepositAmount)
|
||||||
|
|
||||||
|
const lastRoot = await tornadoPool.getLastRoot()
|
||||||
|
await omniBridge.execute([
|
||||||
|
{ who: token.address, callData: transferTx.data }, // send tokens to pool
|
||||||
|
{ who: tornadoPool.address, callData: onTokenBridgedTx.data }, // call onTokenBridgedTx
|
||||||
|
])
|
||||||
|
|
||||||
|
const multisigBalance = await token.balanceOf(multisig.address)
|
||||||
|
expect(multisigBalance).to.be.equal(aliceDepositAmount)
|
||||||
|
expect(await tornadoPool.getLastRoot()).to.be.equal(lastRoot)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should revert if onTransact called directly', async () => {
|
||||||
|
const { tornadoPool } = await loadFixture(fixture)
|
||||||
|
const aliceKeypair = new Keypair() // contains private and public keys
|
||||||
|
|
||||||
|
// Alice deposits into tornado pool
|
||||||
|
const aliceDepositAmount = utils.parseEther('0.07')
|
||||||
|
const aliceDepositUtxo = new Utxo({ amount: aliceDepositAmount, keypair: aliceKeypair })
|
||||||
|
const { args, extData } = await prepareTransaction({
|
||||||
|
tornadoPool,
|
||||||
|
outputs: [aliceDepositUtxo],
|
||||||
|
})
|
||||||
|
|
||||||
|
await expect(tornadoPool.onTransact(args, extData)).to.be.revertedWith(
|
||||||
|
'can be called only from onTokenBridged',
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
it('should work with 16 inputs', async function () {
|
it('should work with 16 inputs', async function () {
|
||||||
const { tornadoPool } = await loadFixture(fixture)
|
const { tornadoPool } = await loadFixture(fixture)
|
||||||
const aliceDepositAmount = utils.parseEther('0.07')
|
const aliceDepositAmount = utils.parseEther('0.07')
|
||||||
|
Loading…
Reference in New Issue
Block a user