Skip to content

Commit

Permalink
Merge pull request #30 from pnetwork-association/feat/dandelion-forwa…
Browse files Browse the repository at this point in the history
…rders

feat(forwarders): add dandelion voting forwarders
  • Loading branch information
oliviera9 authored Feb 23, 2024
2 parents 050ef3c + 4f1cbc9 commit 1610ba8
Show file tree
Hide file tree
Showing 14 changed files with 3,056 additions and 1,596 deletions.
70 changes: 70 additions & 0 deletions contracts/forwarder/CrossExecutor.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.17;

import {Context} from "@openzeppelin/contracts/utils/Context.sol";
import {IERC777Recipient} from "@openzeppelin/contracts/token/ERC777/IERC777Recipient.sol";
import {IERC1820Registry} from "@openzeppelin/contracts/interfaces/IERC1820Registry.sol";
import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol";

error CallFailed(address target, bytes data);
error InvalidCallParams(address[] targets, bytes[] data, address caller);
error InvalidOriginAddress(address originAddress);
error InvalidCaller(address caller, address expected);

contract CrossExecutor is IERC777Recipient, Context, Ownable {
address public immutable token;
address public immutable sender;
mapping(address => bool) private _whitelistedOriginAddresses;

constructor(address _token, address _sender) {
IERC1820Registry(0x1820a4B7618BdE71Dce8cdc73aAB6C95905faD24).setInterfaceImplementer(
address(this),
keccak256("ERC777TokensRecipient"),
address(this)
);

token = _token;
sender = _sender; // set it to 0 on an host chain, vault address on a native chain
}

function tokensReceived(
address /*_operator*/,
address _from,
address /*_to,*/,
uint256 /*_amount*/,
bytes calldata _metaData,
bytes calldata /*_operatorData*/
) external override {
if (_msgSender() == token && _from == sender) {
(, bytes memory callsAndTargets, , address originAddress, , , , ) = abi.decode(
_metaData,
(bytes1, bytes, bytes4, address, bytes4, address, bytes, bytes)
);

if (!_whitelistedOriginAddresses[originAddress]) {
revert InvalidOriginAddress(originAddress);
}

(address[] memory targets, bytes[] memory data) = abi.decode(callsAndTargets, (address[], bytes[]));

if (targets.length != data.length) {
revert InvalidCallParams(targets, data, originAddress);
}

for (uint256 i = 0; i < targets.length; ) {
(bool success, ) = targets[i].call(data[i]);
if (!success) {
revert CallFailed(targets[i], data[i]);
}
unchecked {
++i;
}
}
}
}

function whitelistOriginAddress(address originAddress) external onlyOwner {
_whitelistedOriginAddresses[originAddress] = true;
}
}
17 changes: 17 additions & 0 deletions contracts/interfaces/external/IErc20Vault.sol
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,28 @@
pragma solidity ^0.8.17;

interface IErc20Vault {
event PegIn(
address _tokenAddress,
address _tokenSender,
uint256 _tokenAmount,
string _destinationAddress,
bytes _userData,
bytes4 _originChainId,
bytes4 _destinationChainId
);

function pegIn(
uint256 tokenAmount,
address tokenAddress,
string memory destinationAddress,
bytes memory userData,
bytes4 destinationChainId
) external returns (bool);

function pegOut(
address payable _tokenRecipient,
address _tokenAddress,
uint256 _tokenAmount,
bytes calldata _userData
) external returns (bool success);
}
58 changes: 58 additions & 0 deletions lib/metadata.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
// Refs: https://github.com/pnetwork-association/ptokens-core/blob/master/common/metadata/src/metadata_encoders.rs#L24-L49
const METADATA_TYPES = [
'bytes1', // version
'bytes', // userData
'bytes4', // sourceNetworkId
'address', // senderAddress
'bytes4', // destinationNetworkId
'address', // receiverAddress
'bytes', // protocolOptions
'bytes' // protocolReceipt
]

module.exports.decodeMetadata = (_ethers, _metadata) => {
const [
version,
userData,
sourceNetworkId,
senderAddress,
destinationNetworkId,
receiverAddress,
protocolOptions,
protocolReceipt
] = _ethers.AbiCoder.defaultAbiCoder().decode(METADATA_TYPES, _metadata)
return {
version,
userData,
sourceNetworkId,
senderAddress,
destinationNetworkId,
receiverAddress,
protocolOptions,
protocolReceipt
}
}

module.exports.encodeMetadata = (
_ethers,
{
version = '0x02',
userData,
sourceNetworkId,
senderAddress,
destinationNetworkId,
receiverAddress,
protocolOptions = '0x',
protocolReceipt = '0x'
}
) =>
_ethers.AbiCoder.defaultAbiCoder().encode(METADATA_TYPES, [
version,
userData,
sourceNetworkId,
senderAddress,
destinationNetworkId,
receiverAddress,
protocolOptions,
protocolReceipt
])
Loading

0 comments on commit 1610ba8

Please sign in to comment.