Skip to content

Commit

Permalink
Add default message receiver tests
Browse files Browse the repository at this point in the history
  • Loading branch information
nmlinaric committed Sep 19, 2024
1 parent 4abddf4 commit de44494
Showing 1 changed file with 263 additions and 0 deletions.
263 changes: 263 additions & 0 deletions test/defaultMessageReceiver/executeProposal.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,263 @@
// The Licensed Work is (c) 2022 Sygma
// SPDX-License-Identifier: LGPL-3.0-only

const TruffleAssert = require("truffle-assertions");
const Ethers = require("ethers");

const Helpers = require("../helpers");

const DefaultMessageReceiverContract = artifacts.require("DefaultMessageReceiver");
const NativeTokenHandlerContract = artifacts.require("NativeTokenHandler");
const NativeTokenAdapterContract = artifacts.require("NativeTokenAdapter");
const BasicFeeHandlerContract = artifacts.require("BasicFeeHandler");
const FeeHandlerRouterContract = artifacts.require("FeeHandlerRouter");
const ERC20MintableContract = artifacts.require("ERC20PresetMinterPauser");

contract("Bridge - [execute proposal - native token]", async (accounts) => {
const originDomainID = 1;
const destinationDomainID = 2;
const adminAddress = accounts[0];
const depositorAddress = accounts[1];
const evmRecipientAddress = accounts[2];
const relayer1Address = accounts[3];

const expectedDepositNonce = 1;
const emptySetResourceData = "0x";
const resourceID = "0x0000000000000000000000000000000000000000000000000000000000000650";
const depositAmount = Ethers.utils.parseEther("1");
const fee = Ethers.utils.parseEther("0.1");
const transferredAmount = depositAmount.sub(fee);
const transactionId = "0x0000000000000000000000000000000000000000000000000000000000000001";
const executionGasAmount = 30000000;

let BridgeInstance;
let DefaultMessageReceiverInstance;
let NativeTokenHandlerInstance;
let BasicFeeHandlerInstance;
let FeeHandlerRouterInstance;
let NativeTokenAdapterInstance;
let ERC20MintableInstance;
let proposal;
let depositProposalData;
let message;

beforeEach(async () => {
await Promise.all([
(BridgeInstance = await Helpers.deployBridge(
destinationDomainID,
adminAddress
)),
]);


FeeHandlerRouterInstance = await FeeHandlerRouterContract.new(
BridgeInstance.address
);
BasicFeeHandlerInstance = await BasicFeeHandlerContract.new(
BridgeInstance.address,
FeeHandlerRouterInstance.address
);
NativeTokenAdapterInstance = await NativeTokenAdapterContract.new(
BridgeInstance.address,
resourceID
);
DefaultMessageReceiverInstance = await DefaultMessageReceiverContract.new([], 100000);
NativeTokenHandlerInstance = await NativeTokenHandlerContract.new(
BridgeInstance.address,
NativeTokenAdapterInstance.address,
DefaultMessageReceiverInstance.address,
);
await DefaultMessageReceiverInstance.grantRole(
await DefaultMessageReceiverInstance.SYGMA_HANDLER_ROLE(),
NativeTokenHandlerInstance.address
);
ERC20MintableInstance = await ERC20MintableContract.new(
"token",
"TOK"
);

await BridgeInstance.adminSetResource(
NativeTokenHandlerInstance.address,
resourceID,
Ethers.constants.AddressZero,
emptySetResourceData
);
await BasicFeeHandlerInstance.changeFee(destinationDomainID, resourceID, fee);
await BridgeInstance.adminChangeFeeHandler(FeeHandlerRouterInstance.address),
await FeeHandlerRouterInstance.adminSetResourceHandler(
originDomainID,
resourceID,
BasicFeeHandlerInstance.address
),

await ERC20MintableInstance.grantRole(
await ERC20MintableInstance.MINTER_ROLE(),
DefaultMessageReceiverInstance.address
);

const mintableERC20Iface = new Ethers.utils.Interface(["function mint(address to, uint256 amount)"]);
const actions = [{
nativeValue: 0,
callTo: ERC20MintableInstance.address,
approveTo: Ethers.constants.AddressZero,
tokenSend: Ethers.constants.AddressZero,
tokenReceive: Ethers.constants.AddressZero,
data: mintableERC20Iface.encodeFunctionData("mint", [evmRecipientAddress, "20"]),
}]
message = Helpers.createMessageCallData(
transactionId,
actions,
evmRecipientAddress
);

depositProposalData = Helpers.createOptionalContractCallDepositData(
transferredAmount,
Ethers.constants.AddressZero,
executionGasAmount,
message
);

proposal = {
originDomainID: originDomainID,
depositNonce: expectedDepositNonce,
resourceID: resourceID,
data: depositProposalData
};

// set MPC address to unpause the Bridge
await BridgeInstance.endKeygen(Helpers.mpcAddress);
});

it("should revert if handler does not have SYGMA_HANDLER_ROLE", async () => {
await DefaultMessageReceiverInstance.revokeRole(
await DefaultMessageReceiverInstance.SYGMA_HANDLER_ROLE(),
NativeTokenHandlerInstance.address
);
const proposalSignedData = await Helpers.signTypedProposal(
BridgeInstance.address,
[proposal]
);

// depositorAddress makes initial deposit of depositAmount
assert.isFalse(await BridgeInstance.paused());
await TruffleAssert.passes(
NativeTokenAdapterInstance.depositToEVMWithMessage(
originDomainID,
Ethers.constants.AddressZero,
executionGasAmount,
message,
{
from: depositorAddress,
value: depositAmount
})
);

const executeTx = await BridgeInstance.executeProposal(
proposal,
proposalSignedData,
{
from: relayer1Address,
gas: executionGasAmount
}
);

TruffleAssert.eventEmitted(executeTx, "FailedHandlerExecution", (event) => {
return (
event.originDomainID.toNumber() === originDomainID &&
event.depositNonce.toNumber() === expectedDepositNonce &&
event.lowLevelData === "0xdeda9030" // InsufficientPermission()
);
});
});

it("should revert if insufficient gas limit left for executing action", async () => {
const insufficientExecutionGasAmount = 100000;
const proposalSignedData = await Helpers.signTypedProposal(
BridgeInstance.address,
[proposal]
);

// depositorAddress makes initial deposit of depositAmount
assert.isFalse(await BridgeInstance.paused());
await TruffleAssert.passes(
NativeTokenAdapterInstance.depositToEVMWithMessage(
originDomainID,
Ethers.constants.AddressZero,
insufficientExecutionGasAmount,
message,
{
from: depositorAddress,
value: depositAmount
})
);

const executeTx = await BridgeInstance.executeProposal(
proposal,
proposalSignedData,
{
from: relayer1Address,
gas: insufficientExecutionGasAmount
}
);

TruffleAssert.eventEmitted(executeTx, "FailedHandlerExecution", (event) => {
return (
event.originDomainID.toNumber() === originDomainID &&
event.depositNonce.toNumber() === expectedDepositNonce &&
event.lowLevelData === "0x60ee1247" // InsufficientGasLimit()
);
});
});

it("should fail to transfer funds if invalid message is provided", async () => {
const mintableERC20Iface = new Ethers.utils.Interface(["function mint(address to, uint256 amount)"]);
const actions = [{
nativeValue: 0,
callTo: Ethers.constants.AddressZero,
approveTo: Ethers.constants.AddressZero,
tokenSend: Ethers.constants.AddressZero,
tokenReceive: Ethers.constants.AddressZero,
data: mintableERC20Iface.encodeFunctionData("mint", [evmRecipientAddress, "20"]),
}]
const message = Helpers.createMessageCallData(
transactionId,
actions,
evmRecipientAddress
);

const depositProposalData = Helpers.createOptionalContractCallDepositData(
transferredAmount,
Ethers.constants.AddressZero,
executionGasAmount,
message
);

const proposal = {
originDomainID: originDomainID,
depositNonce: expectedDepositNonce,
resourceID: resourceID,
data: depositProposalData
};
const proposalSignedData = await Helpers.signTypedProposal(
BridgeInstance.address,
[proposal]
);

const executeTx = await BridgeInstance.executeProposal(
proposal,
proposalSignedData,
{
from: relayer1Address,
gas: executionGasAmount
}
);

TruffleAssert.eventEmitted(executeTx, "FailedHandlerExecution", (event) => {
return (
event.originDomainID.toNumber() === originDomainID &&
event.depositNonce.toNumber() === expectedDepositNonce &&
event.lowLevelData === "0x2ed7fc0e" // FailedFundsTransfer()
);
});
});
});

0 comments on commit de44494

Please sign in to comment.