Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add colors example for using generic handler v1 #50

Merged
merged 5 commits into from
Oct 6, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
66 changes: 66 additions & 0 deletions contracts/example/Colors.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity 0.8.11;

contract Colors {
bytes32[] public colorsArray;

uint256 public colorCounter = 0;

event setColorEvent(bytes32 color);
event metadataDepositorEvent(address depositorAddress);

function setColorOnDeploy(bytes32 color) public {
colorsArray.push(color);
}

function setColor(bytes32 metadataDepositor, bytes32 color) public {
nmlinaric marked this conversation as resolved.
Show resolved Hide resolved
colorsArray.push(color);
colorCounter++;

address depositorAddress = address(uint160(uint256(metadataDepositor)));

emit setColorEvent(color);
emit metadataDepositorEvent(depositorAddress);
}

function popColor() public {
colorsArray.pop();
}

function getColorsArrayLenght() public view returns (uint256 l) {
return colorsArray.length;
}

function getCurrentColors(uint256 index)
public
view
returns (bytes32 colorReturned)
{
colorReturned = colorsArray[index];
return colorReturned;
}

function insertColorToColorsArray(bytes32 newColor) public {
colorsArray.push(newColor);
emit setColorEvent(newColor);
}

function findColor(bytes32 color)
public
view
returns (bytes32 colorFound)
{
for (uint i = 0; i < colorsArray.length; i++) {
bytes32 c = colorsArray[i];

if (
keccak256(abi.encodePacked((color))) ==
keccak256(abi.encodePacked((c)))
) {
colorFound = c;
break;
}
}
return colorFound;
}
}
4 changes: 2 additions & 2 deletions contracts/handlers/GenericHandlerV1.sol
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ contract GenericHandlerV1 is IGenericHandler {
maxFee: uint256 bytes 96 - 128
metaData:
metadataDepositor: address padded to 32 bytes bytes 128 - 160
executionData: bytes bytes 128 - len(metaData)
executionData: bytes bytes 160 - (128 + len(metaData))
*/
function deposit(bytes32 resourceID, address depositor, bytes calldata data) external returns (bytes memory) {
require(data.length > 160, "Incorrect data length");
Expand Down Expand Up @@ -88,7 +88,7 @@ contract GenericHandlerV1 is IGenericHandler {
maxFee: uint256 bytes 96 - 128
metadata:
metadataDepositor: address padded to 32 bytes bytes 128 - 160
executionData: bytes bytes 128 - len(metaData)
executionData: bytes bytes 160 - (128 + len(metaData))
*/
function executeProposal(bytes32 resourceID, bytes calldata data) external {
uint256 lenMetadata;
Expand Down
3 changes: 1 addition & 2 deletions migrations/3_deploy_genericHandlerV1.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ module.exports = async function(deployer, network) {

// fetch deployed contracts addresses
const bridgeInstance = await BridgeContract.deployed();
const TestStoreInstance = await TestStoreContract.deployed();
const feeRouterInstance = await FeeRouterContract.deployed();
const basicFeeHandlerInstance = await BasicFeeHandlerContract.deployed();

Expand All @@ -33,7 +32,7 @@ module.exports = async function(deployer, network) {
console.log("Generic handler v1 resourceID:", "\t", currentNetworkConfig.genericV1ResourceID);

// setup generic handler v1
await bridgeInstance.adminSetGenericResource(genericHandlerV1Instance.address, currentNetworkConfig.genericV1ResourceID, TestStoreInstance.address, Helpers.blankFunctionSig, Helpers.blankFunctionDepositorOffset, Helpers.getFunctionSignature(TestStoreInstance, 'storeWithDepositor'));
await bridgeInstance.adminSetGenericResource(genericHandlerV1Instance.address, currentNetworkConfig.genericV1ResourceID, bridgeInstance.address, Helpers.blankFunctionSig, Helpers.blankFunctionDepositorOffset, Helpers.blankFunctionSig);

// set resourceID for every network except current from networks config
delete networksConfig[currentNetworkName]
Expand Down
14 changes: 14 additions & 0 deletions migrations/4_deploy_colors_example.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
/**
* Copyright 2020 ChainSafe Systems
* SPDX-License-Identifier: LGPL-3.0-only
*/

const ColorsContract = artifacts.require("Colors");

module.exports = async function(deployer, network) {
// deploy colors example contract
await deployer.deploy(ColorsContract);
const colorsInstance = await ColorsContract.deployed();

console.log("Colors contract address:", "\t", colorsInstance.address);
}
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@buildwithsygma/sygma-contracts",
"version": "1.1.0",
"version": "1.1.1",
"description": "",
"main": "dist/index.js",
"repository": "https://github.com/sygmaprotocol/sygma-solidity.git",
Expand Down
126 changes: 126 additions & 0 deletions test/handlers/generic/colors_example/deposit.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
/**
* Copyright 2020 ChainSafe Systems
* SPDX-License-Identifier: LGPL-3.0-only
*/

const TruffleAssert = require('truffle-assertions');
const Ethers = require('ethers');
const Helpers = require('../../../helpers');

const ColorsContract = artifacts.require("Colors");
const GenericHandlerContract = artifacts.require("GenericHandlerV1");
const WithDepositorContract = artifacts.require("WithDepositor");
const ReturnDataContract = artifacts.require("ReturnData");

contract('GenericHandlerV1 colors example - [deposit]', async (accounts) => {
const originDomainID = 1;
const destinationDomainID = 2;
const expectedDepositNonce = 1;

const depositorAddress = accounts[1];

const feeData = '0x';
const destinationMaxFee = 2000000;
const hexRedColor = Helpers.toHex("0xD2042D", 32);

let BridgeInstance;
let ColorsInstance;

let resourceID;
let depositFunctionSignature;
let GenericHandlerInstance;
let depositData;

beforeEach(async () => {
await Promise.all([
BridgeInstance = await Helpers.deployBridge(originDomainID, accounts[0]),
ColorsContract.new().then(instance => ColorsInstance = instance),
WithDepositorContract.new().then(instance => WithDepositorInstance = instance),
ReturnDataContract.new().then(instance => ReturnDataInstance = instance),
]);

resourceID = Helpers.createResourceID(ColorsInstance.address, originDomainID)

GenericHandlerInstance = await GenericHandlerContract.new(
BridgeInstance.address);

await BridgeInstance.adminSetGenericResource(GenericHandlerInstance.address, resourceID, ColorsInstance.address, Helpers.blankFunctionSig, Helpers.blankFunctionDepositorOffset, Helpers.blankFunctionSig);

depositFunctionSignature = Helpers.getFunctionSignature(ColorsInstance, 'setColor');


depositData = Helpers.createGenericDepositDataV1(
depositFunctionSignature,
ColorsInstance.address,
destinationMaxFee,
depositorAddress,
hexRedColor,
false // don't append depositor for destination chain check
);

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

it('deposit can be made successfully', async () => {
await TruffleAssert.passes(BridgeInstance.deposit(
destinationDomainID,
resourceID,
depositData,
feeData,
{ from: depositorAddress }
));
});

it('depositEvent is emitted with expected values', async () => {
const depositTx = await BridgeInstance.deposit(
destinationDomainID,
resourceID,
depositData,
feeData,
{ from: depositorAddress }
);

TruffleAssert.eventEmitted(depositTx, 'Deposit', (event) => {
return event.destinationDomainID.toNumber() === destinationDomainID &&
event.resourceID === resourceID.toLowerCase() &&
event.depositNonce.toNumber() === expectedDepositNonce &&
event.user === depositorAddress &&
event.data === depositData &&
event.handlerResponse === null
});
});

it('deposit data should be of required length', async () => {
const invalidDepositData = "0x" + "02a3d".repeat(31);

await TruffleAssert.reverts(BridgeInstance.deposit(
destinationDomainID,
resourceID,
invalidDepositData,
feeData,
{ from: depositorAddress }
), "Incorrect data length");
});

it('should revert if metadata encoded depositor does not match deposit depositor', async () => {
const invalidDepositorAddress = accounts[2];

const invalidDepositData = Helpers.createGenericDepositDataV1(
depositFunctionSignature,
ColorsInstance.address,
destinationMaxFee,
invalidDepositorAddress,
hexRedColor,
false // don't append depositor for destination chain check
);

await TruffleAssert.reverts(BridgeInstance.deposit(
destinationDomainID,
resourceID,
invalidDepositData,
feeData,
{ from: depositorAddress }
), "incorrect depositor in deposit data");
});
});
117 changes: 117 additions & 0 deletions test/handlers/generic/colors_example/executeProposal.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
/**
* Copyright 2020 ChainSafe Systems
* SPDX-License-Identifier: LGPL-3.0-only
*/

const TruffleAssert = require('truffle-assertions');
const Ethers = require('ethers');
const Helpers = require('../../../helpers');

const ColorsContract = artifacts.require("Colors");
const GenericHandlerContract = artifacts.require("GenericHandlerV1");

contract('GenericHandlerV1 colors example - [Execute Proposal]', async (accounts) => {
const originDomainID = 1;
const destinationDomainID = 2;
const expectedDepositNonce = 1;

const depositorAddress = accounts[1];
const relayer1Address = accounts[2];
const relayer2Address = accounts[3];

const feeData = '0x';
const destinationMaxFee = 2000000;
const hexRedColor = Helpers.toHex("0xD2042D", 32);

let BridgeInstance;
let ColorsInstance;

let resourceID;
let depositFunctionSignature;
let GenericHandlerInstance;
let depositData;
let proposal;

beforeEach(async () => {
await Promise.all([
BridgeInstance = await Helpers.deployBridge(destinationDomainID, accounts[0]),
ColorsContract.new().then(instance => ColorsInstance = instance)
]);

resourceID = Helpers.createResourceID(ColorsInstance.address, originDomainID);

GenericHandlerInstance = await GenericHandlerContract.new(
BridgeInstance.address);

await BridgeInstance.adminSetGenericResource(GenericHandlerInstance.address, resourceID, ColorsInstance.address, Helpers.blankFunctionSig, Helpers.blankFunctionDepositorOffset, Helpers.blankFunctionSig);

depositFunctionSignature = Helpers.getFunctionSignature(ColorsInstance, 'setColor');

depositData =
Helpers.createGenericDepositDataV1(
depositFunctionSignature,
ColorsInstance.address,
destinationMaxFee,
depositorAddress,
hexRedColor,
false // don't append depositor for destination chain check
);

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

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

it('deposit can be executed successfully', async () => {
const proposalSignedData = await Helpers.signTypedProposal(BridgeInstance.address, [proposal]);
await TruffleAssert.passes(BridgeInstance.deposit(
originDomainID,
resourceID,
depositData,
feeData,
{ from: depositorAddress }
));

// relayer1 executes the proposal
await TruffleAssert.passes(BridgeInstance.executeProposal(
proposal,
proposalSignedData,
{ from: relayer1Address }
));

// Verifying color was stored in ColorsInstance contract
const storedColor = await ColorsInstance.findColor(hexRedColor);
assert.equal(storedColor, hexRedColor);
});

it('setColor event should be emitted', async () => {
const proposalSignedData = await Helpers.signTypedProposal(BridgeInstance.address, [proposal]);


await TruffleAssert.passes(BridgeInstance.deposit(
originDomainID,
resourceID,
depositData,
feeData,
{ from: depositorAddress }
));

// relayer1 executes the proposal
const executeTx = await BridgeInstance.executeProposal(
proposal,
proposalSignedData,
{ from: relayer2Address }
);

const internalTx = await TruffleAssert.createTransactionResult(ColorsInstance, executeTx.tx);
TruffleAssert.eventEmitted(internalTx, 'setColorEvent', event => {
return event.color === hexRedColor;
});
});
});
10 changes: 8 additions & 2 deletions test/helpers.js
Original file line number Diff line number Diff line change
Expand Up @@ -92,8 +92,14 @@ const createGenericDepositData = (hexMetaData) => {
hexMetaData.substr(2)
};

const createGenericDepositDataV1 = (executeFunctionSignature, executeContractAddress, maxFee, depositor, executionData) => {
const metaData = toHex(depositor, 32).substr(2) + executionData.substr(2) + toHex(depositor, 32).substr(2); // append depositor address for destination chain check
const createGenericDepositDataV1 = (executeFunctionSignature, executeContractAddress, maxFee, depositor, executionData, depositorCheck = true) => {
let metaData = toHex(depositor, 32).substr(2) + executionData.substr(2);

if(depositorCheck) {
// if "depositorCheck" is true -> append depositor address for destination chain check
metaData = metaData.concat(toHex(depositor, 32).substr(2));
}

const metaDataLength = metaData.length / 2;

return '0x' +
Expand Down