Skip to content

Commit

Permalink
Merge pull request #50 from sygmaprotocol/nmlinaric/colors-example
Browse files Browse the repository at this point in the history
Add colors example for using generic handler v1
  • Loading branch information
nmlinaric authored Oct 6, 2022
2 parents 36d4c5e + aa01f7c commit 643525d
Show file tree
Hide file tree
Showing 8 changed files with 335 additions and 7 deletions.
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 {
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

0 comments on commit 643525d

Please sign in to comment.