// File: contracts/IMultisigControl.sol
//SPDX-License-Identifier: MIT
pragma solidity 0.8.8;
/// @title MultisigControl Interface
/// @author Vega Protocol
/// @notice Implementations of this interface are used by the Vega network to control smart contracts without the need for Vega to have any Ethereum of its own.
/// @notice To do this, the Vega validators sign a MultisigControl order to construct a signature bundle. Any interested party can then take that signature bundle and pay the gas to run the command on Ethereum
abstract contract IMultisigControl {
/***************************EVENTS****************************/
event SignerAdded(address new_signer, uint256 nonce);
event SignerRemoved(address old_signer, uint256 nonce);
event ThresholdSet(uint16 new_threshold, uint256 nonce);
/**************************FUNCTIONS*********************/
/// @notice Sets threshold of signatures that must be met before function is executed.
/// @param new_threshold New threshold value
/// @param nonce Vega-assigned single-use number that provides replay attack protection
/// @param signatures Vega-supplied signature bundle of a validator-signed order
/// @notice See MultisigControl for more about signatures
/// @notice Ethereum has no decimals, threshold is % * 10 so 50% == 500 100% == 1000
/// @notice signatures are OK if they are >= threshold count of total valid signers
/// @dev MUST emit ThresholdSet event
function set_threshold(uint16 new_threshold, uint nonce, bytes calldata signatures) public virtual;
/// @notice Adds new valid signer and adjusts signer count.
/// @param new_signer New signer address
/// @param nonce Vega-assigned single-use number that provides replay attack protection
/// @param signatures Vega-supplied signature bundle of a validator-signed order
/// @notice See MultisigControl for more about signatures
/// @dev MUST emit 'SignerAdded' event
function add_signer(address new_signer, uint nonce, bytes calldata signatures) public virtual;
/// @notice Removes currently valid signer and adjusts signer count.
/// @param old_signer Address of signer to be removed.
/// @param nonce Vega-assigned single-use number that provides replay attack protection
/// @param signatures Vega-supplied signature bundle of a validator-signed order
/// @notice See MultisigControl for more about signatures
/// @dev MUST emit 'SignerRemoved' event
function remove_signer(address old_signer, uint nonce, bytes calldata signatures) public virtual;
/// @notice Verifies a signature bundle and returns true only if the threshold of valid signers is met,
/// @notice this is a function that any function controlled by Vega MUST call to be securely controlled by the Vega network
/// @notice message to hash to sign follows this pattern:
/// @notice abi.encode( abi.encode(param1, param2, param3, ... , nonce, function_name_string), validating_contract_or_submitter_address);
/// @notice Note that validating_contract_or_submitter_address is the the submitting party. If on MultisigControl contract itself, it's the submitting ETH address
/// @notice if function on bridge that then calls Multisig, then it's the address of that contract
/// @notice Note also the embedded encoding, this is required to verify what function/contract the function call goes to
/// @return MUST return true if valid signatures are over the threshold
function verify_signatures(bytes calldata signatures, bytes memory message, uint nonce) public virtual returns(bool);
/**********************VIEWS*********************/
/// @return Number of valid signers
function get_valid_signer_count() public virtual view returns(uint8);
/// @return Current threshold
function get_current_threshold() public virtual view returns(uint16);
/// @param signer_address target potential signer address
/// @return true if address provided is valid signer
function is_valid_signer(address signer_address) public virtual view returns(bool);
/// @param nonce Nonce to lookup
/// @return true if nonce has been used
function is_nonce_used(uint nonce) public virtual view returns(bool);
}
/**
MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
MMMMWEMMMMMMMMMMMMMMMMMMMMMMMMMM...............MMMMMMMMMMMMM
MMMMMMLOVEMMMMMMMMMMMMMMMMMMMMMM...............MMMMMMMMMMMMM
MMMMMMMMMMHIXELMMMMMMMMMMMM....................MMMMMNNMMMMMM
MMMMMMMMMMMMMMMMMMMMMMMMMMM....................MMMMMMMMMMMMM
MMMMMMMMMMMMMMMMMMMMMM88=........................+MMMMMMMMMM
MMMMMMMMMMMMMMMMM....................MMMMM...MMMMMMMMMMMMMMM
MMMMMMMMMMMMMMMMM....................MMMMM...MMMMMMMMMMMMMMM
MMMMMMMMMMMM.........................MM+..MMM....+MMMMMMMMMM
MMMMMMMMMNMM...................... ..MM?..MMM.. .+MMMMMMMMMM
MMMMNDDMM+........................+MM........MM..+MMMMMMMMMM
MMMMZ.............................+MM....................MMM
MMMMZ.............................+MM....................MMM
MMMMZ.............................+MM....................DDD
MMMMZ.............................+MM..ZMMMMMMMMMMMMMMMMMMMM
MMMMZ.............................+MM..ZMMMMMMMMMMMMMMMMMMMM
MM..............................MMZ....ZMMMMMMMMMMMMMMMMMMMM
MM............................MM.......ZMMMMMMMMMMMMMMMMMMMM
MM............................MM.......ZMMMMMMMMMMMMMMMMMMMM
MM......................ZMMMMM.......MMMMMMMMMMMMMMMMMMMMMMM
MM............... ......ZMMMMM.... ..MMMMMMMMMMMMMMMMMMMMMMM
MM...............MMMMM88~.........+MM..ZMMMMMMMMMMMMMMMMMMMM
MM.......$DDDDDDD.......$DDDDD..DDNMM..ZMMMMMMMMMMMMMMMMMMMM
MM.......$DDDDDDD.......$DDDDD..DDNMM..ZMMMMMMMMMMMMMMMMMMMM
MM.......ZMMMMMMM.......ZMMMMM..MMMMM..ZMMMMMMMMMMMMMMMMMMMM
MMMMMMMMM+.......MMMMM88NMMMMM..MMMMMMMMMMMMMMMMMMMMMMMMMMMM
MMMMMMMMM+.......MMMMM88NMMMMM..MMMMMMMMMMMMMMMMMMMMMMMMMMMM
MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM*/
// File: contracts/IERC20_Bridge_Logic.sol
/// @title ERC20 Bridge Logic Interface
/// @author Vega Protocol
/// @notice Implementations of this interface are used by Vega network users to deposit and withdraw ERC20 tokens to/from Vega.
// @notice All funds deposited/withdrawn are to/from the ERC20_Asset_Pool
abstract contract IERC20_Bridge_Logic {
/***************************EVENTS****************************/
event Asset_Withdrawn(address indexed user_address, address indexed asset_source, uint256 amount, uint256 nonce);
event Asset_Deposited(address indexed user_address, address indexed asset_source, uint256 amount, bytes32 vega_public_key);
event Asset_Deposit_Minimum_Set(address indexed asset_source, uint256 new_minimum, uint256 nonce);
event Asset_Deposit_Maximum_Set(address indexed asset_source, uint256 new_maximum, uint256 nonce);
event Asset_Listed(address indexed asset_source, bytes32 indexed vega_asset_id, uint256 nonce);
event Asset_Removed(address indexed asset_source, uint256 nonce);
/***************************FUNCTIONS*************************/
/// @notice This function lists the given ERC20 token contract as valid for deposit to this bridge
/// @param asset_source Contract address for given ERC20 token
/// @param vega_asset_id Vega-generated asset ID for internal use in Vega Core
/// @param nonce Vega-assigned single-use number that provides replay attack protection
/// @param signatures Vega-supplied signature bundle of a validator-signed order
/// @notice See MultisigControl for more about signatures
/// @dev MUST emit Asset_Listed if successful
function list_asset(address asset_source, bytes32 vega_asset_id, uint256 nonce, bytes memory signatures) public virtual;
/// @notice This function removes from listing the given ERC20 token contract. This marks the token as invalid for deposit to this bridge
/// @param asset_source Contract address for given ERC20 token
/// @param nonce Vega-assigned single-use number that provides replay attack protection
/// @param signatures Vega-supplied signature bundle of a validator-signed order
/// @notice See MultisigControl for more about signatures
/// @dev MUST emit Asset_Removed if successful
function remove_asset(address asset_source, uint256 nonce, bytes memory signatures) public virtual;
/// @notice This function sets the minimum allowable deposit for the given ERC20 token
/// @param asset_source Contract address for given ERC20 token
/// @param minimum_amount Minimum deposit amount
/// @param nonce Vega-assigned single-use number that provides replay attack protection
/// @param signatures Vega-supplied signature bundle of a validator-signed order
/// @notice See MultisigControl for more about signatures
/// @dev MUST emit Asset_Deposit_Minimum_Set if successful
function set_deposit_minimum(address asset_source, uint256 minimum_amount, uint256 nonce, bytes memory signatures) public virtual;
/// @notice This function sets the maximum allowable deposit for the given ERC20 token
/// @param asset_source Contract address for given ERC20 token
/// @param maximum_amount Maximum deposit amount
/// @param nonce Vega-assigned single-use number that provides replay attack protection
/// @param signatures Vega-supplied signature bundle of a validator-signed order
/// @notice See MultisigControl for more about signatures
/// @dev MUST emit Asset_Deposit_Maximum_Set if successful
function set_deposit_maximum(address asset_source, uint256 maximum_amount, uint256 nonce, bytes memory signatures) public virtual;
/// @notice This function withdrawals assets to the target Ethereum address
/// @param asset_source Contract address for given ERC20 token
/// @param amount Amount of ERC20 tokens to withdraw
/// @param target Target Ethereum address to receive withdrawn ERC20 tokens
/// @param nonce Vega-assigned single-use number that provides replay attack protection
/// @param signatures Vega-supplied signature bundle of a validator-signed order
/// @notice See MultisigControl for more about signatures
/// @dev MUST emit Asset_Withdrawn if successful
function withdraw_asset(address asset_source, uint256 amount, address target, uint256 nonce, bytes memory signatures) public virtual;
/// @notice This function allows a user to deposit given ERC20 tokens into Vega
/// @param asset_source Contract address for given ERC20 token
/// @param amount Amount of tokens to be deposited into Vega
/// @param vega_public_key Target Vega public key to be credited with this deposit
/// @dev MUST emit Asset_Deposited if successful
/// @dev ERC20 approve function should be run before running this
/// @notice ERC20 approve function should be run before running this
function deposit_asset(address asset_source, uint256 amount, bytes32 vega_public_key) public virtual;
/***************************VIEWS*****************************/
/// @notice This view returns true if the given ERC20 token contract has been listed valid for deposit
/// @param asset_source Contract address for given ERC20 token
/// @return True if asset is listed
function is_asset_listed(address asset_source) public virtual view returns(bool);
/// @notice This view returns minimum valid deposit
/// @param asset_source Contract address for given ERC20 token
/// @return Minimum valid deposit of given ERC20 token
function get_deposit_minimum(address asset_source) public virtual view returns(uint256);
/// @notice This view returns maximum valid deposit
/// @param asset_source Contract address for given ERC20 token
/// @return Maximum valid deposit of given ERC20 token
function get_deposit_maximum(address asset_source) public virtual view returns(uint256);
/// @return current multisig_control_address
function get_multisig_control_address() public virtual view returns(address);
/// @param asset_source Contract address for given ERC20 token
/// @return The assigned Vega Asset ID for given ERC20 token
function get_vega_asset_id(address asset_source) public virtual view returns(bytes32);
/// @param vega_asset_id Vega-assigned asset ID for which you want the ERC20 token address
/// @return The ERC20 token contract address for a given Vega Asset ID
function get_asset_source(bytes32 vega_asset_id) public virtual view returns(address);
}
/**
MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
MMMMWEMMMMMMMMMMMMMMMMMMMMMMMMMM...............MMMMMMMMMMMMM
MMMMMMLOVEMMMMMMMMMMMMMMMMMMMMMM...............MMMMMMMMMMMMM
MMMMMMMMMMHIXELMMMMMMMMMMMM....................MMMMMNNMMMMMM
MMMMMMMMMMMMMMMMMMMMMMMMMMM....................MMMMMMMMMMMMM
MMMMMMMMMMMMMMMMMMMMMM88=........................+MMMMMMMMMM
MMMMMMMMMMMMMMMMM....................MMMMM...MMMMMMMMMMMMMMM
MMMMMMMMMMMMMMMMM....................MMMMM...MMMMMMMMMMMMMMM
MMMMMMMMMMMM.........................MM+..MMM....+MMMMMMMMMM
MMMMMMMMMNMM...................... ..MM?..MMM.. .+MMMMMMMMMM
MMMMNDDMM+........................+MM........MM..+MMMMMMMMMM
MMMMZ.............................+MM....................MMM
MMMMZ.............................+MM....................MMM
MMMMZ.............................+MM....................DDD
MMMMZ.............................+MM..ZMMMMMMMMMMMMMMMMMMMM
MMMMZ.............................+MM..ZMMMMMMMMMMMMMMMMMMMM
MM..............................MMZ....ZMMMMMMMMMMMMMMMMMMMM
MM............................MM.......ZMMMMMMMMMMMMMMMMMMMM
MM............................MM.......ZMMMMMMMMMMMMMMMMMMMM
MM......................ZMMMMM.......MMMMMMMMMMMMMMMMMMMMMMM
MM............... ......ZMMMMM.... ..MMMMMMMMMMMMMMMMMMMMMMM
MM...............MMMMM88~.........+MM..ZMMMMMMMMMMMMMMMMMMMM
MM.......$DDDDDDD.......$DDDDD..DDNMM..ZMMMMMMMMMMMMMMMMMMMM
MM.......$DDDDDDD.......$DDDDD..DDNMM..ZMMMMMMMMMMMMMMMMMMMM
MM.......ZMMMMMMM.......ZMMMMM..MMMMM..ZMMMMMMMMMMMMMMMMMMMM
MMMMMMMMM+.......MMMMM88NMMMMM..MMMMMMMMMMMMMMMMMMMMMMMMMMMM
MMMMMMMMM+.......MMMMM88NMMMMM..MMMMMMMMMMMMMMMMMMMMMMMMMMMM
MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM*/
// File: contracts/IERC20.sol
/**
* @dev Interface of the ERC20 standard as defined in the EIP. Does not include
* the optional functions; to access them see {ERC20Detailed}.
*/
interface IERC20 {
/**
* @dev Returns the amount of tokens in existence.
*/
function totalSupply() external view returns (uint256);
/**
* @dev Returns the amount of tokens owned by `account`.
*/
function balanceOf(address account) external view returns (uint256);
/**
* @dev Moves `amount` tokens from the caller's account to `recipient`.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transfer(address recipient, uint256 amount) external returns (bool);
/**
* @dev Returns the remaining number of tokens that `spender` will be
* allowed to spend on behalf of `owner` through {transferFrom}. This is
* zero by default.
*
* This value changes when {approve} or {transferFrom} are called.
*/
function allowance(address owner, address spender) external view returns (uint256);
/**
* @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* IMPORTANT: Beware that changing an allowance with this method brings the risk
* that someone may use both the old and the new allowance by unfortunate
* transaction ordering. One possible solution to mitigate this race
* condition is to first reduce the spender's allowance to 0 and set the
* desired value afterwards:
* https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
*
* Emits an {Approval} event.
*/
function approve(address spender, uint256 amount) external returns (bool);
/**
* @dev Moves `amount` tokens from `sender` to `recipient` using the
* allowance mechanism. `amount` is then deducted from the caller's
* allowance.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);
/**
* @dev Emitted when `value` tokens are moved from one account (`from`) to
* another (`to`).
*
* Note that `value` may be zero.
*/
event Transfer(address indexed from, address indexed to, uint256 value);
/**
* @dev Emitted when the allowance of a `spender` for an `owner` is set by
* a call to {approve}. `value` is the new allowance.
*/
event Approval(address indexed owner, address indexed spender, uint256 value);
}
// File: contracts/ERC20_Asset_Pool.sol
/// @title ERC20 Asset Pool
/// @author Vega Protocol
/// @notice This contract is the target for all deposits to the ERC20 Bridge via ERC20_Bridge_Logic
contract ERC20_Asset_Pool {
event Multisig_Control_Set(address indexed new_address);
event Bridge_Address_Set(address indexed new_address);
/// @return Current MultisigControl contract address
address public multisig_control_address;
/// @return Current ERC20_Bridge_Logic contract address
address public erc20_bridge_address;
/// @param multisig_control The initial MultisigControl contract address
/// @notice Emits Multisig_Control_Set event
constructor(address multisig_control) {
multisig_control_address = multisig_control;
emit Multisig_Control_Set(multisig_control);
}
/// @notice this contract is not intended to accept ether directly
receive() external payable {
revert("this contract does not accept ETH");
}
/// @param new_address The new MultisigControl contract address.
/// @param nonce Vega-assigned single-use number that provides replay attack protection
/// @param signatures Vega-supplied signature bundle of a validator-signed set_multisig_control order
/// @notice See MultisigControl for more about signatures
/// @notice Emits Multisig_Control_Set event
function set_multisig_control(address new_address, uint256 nonce, bytes memory signatures) public {
require(new_address != address(0));
bytes memory message = abi.encode(new_address, nonce, 'set_multisig_control');
require(IMultisigControl(multisig_control_address).verify_signatures(signatures, message, nonce), "bad signatures");
multisig_control_address = new_address;
emit Multisig_Control_Set(new_address);
}
/// @param new_address The new ERC20_Bridge_Logic contract address.
/// @param nonce Vega-assigned single-use number that provides replay attack protection
/// @param signatures Vega-supplied signature bundle of a validator-signed set_bridge_address order
/// @notice See MultisigControl for more about signatures
/// @notice Emits Bridge_Address_Set event
function set_bridge_address(address new_address, uint256 nonce, bytes memory signatures) public {
bytes memory message = abi.encode(new_address, nonce, 'set_bridge_address');
require(IMultisigControl(multisig_control_address).verify_signatures(signatures, message, nonce), "bad signatures");
erc20_bridge_address = new_address;
emit Bridge_Address_Set(new_address);
}
/// @notice This function can only be run by the current "multisig_control_address" and, if available, will send the target tokens to the target
/// @param token_address Contract address of the ERC20 token to be withdrawn
/// @param target Target Ethereum address that the ERC20 tokens will be sent to
/// @param amount Amount of ERC20 tokens to withdraw
/// @dev amount is in whatever the lowest decimal value the ERC20 token has. For instance, an 18 decimal ERC20 token, 1 "amount" == 0.000000000000000001
/// @return true if transfer was successful.
function withdraw(address token_address, address target, uint256 amount) public returns(bool) {
require(msg.sender == erc20_bridge_address, "msg.sender not authorized bridge");
IERC20(token_address).transfer(target, amount);
/// @dev the following is a test for non-standard ERC20 tokens IE ones without a return value
bool result;
assembly {
switch returndatasize()
case 0 { // no return value but didn't revert
result := true
}
case 32 { // standard ERC20, has return value
returndatacopy(0, 0, 32)
result := mload(0) // result is result of transfer call
}
default {}
}
require(result, "token transfer failed"); // revert() if result is false
return true;
}
}
/**
MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
MMMMWEMMMMMMMMMMMMMMMMMMMMMMMMMM...............MMMMMMMMMMMMM
MMMMMMLOVEMMMMMMMMMMMMMMMMMMMMMM...............MMMMMMMMMMMMM
MMMMMMMMMMHIXELMMMMMMMMMMMM....................MMMMMNNMMMMMM
MMMMMMMMMMMMMMMMMMMMMMMMMMM....................MMMMMMMMMMMMM
MMMMMMMMMMMMMMMMMMMMMM88=........................+MMMMMMMMMM
MMMMMMMMMMMMMMMMM....................MMMMM...MMMMMMMMMMMMMMM
MMMMMMMMMMMMMMMMM....................MMMMM...MMMMMMMMMMMMMMM
MMMMMMMMMMMM.........................MM+..MMM....+MMMMMMMMMM
MMMMMMMMMNMM...................... ..MM?..MMM.. .+MMMMMMMMMM
MMMMNDDMM+........................+MM........MM..+MMMMMMMMMM
MMMMZ.............................+MM....................MMM
MMMMZ.............................+MM....................MMM
MMMMZ.............................+MM....................DDD
MMMMZ.............................+MM..ZMMMMMMMMMMMMMMMMMMMM
MMMMZ.............................+MM..ZMMMMMMMMMMMMMMMMMMMM
MM..............................MMZ....ZMMMMMMMMMMMMMMMMMMMM
MM............................MM.......ZMMMMMMMMMMMMMMMMMMMM
MM............................MM.......ZMMMMMMMMMMMMMMMMMMMM
MM......................ZMMMMM.......MMMMMMMMMMMMMMMMMMMMMMM
MM............... ......ZMMMMM.... ..MMMMMMMMMMMMMMMMMMMMMMM
MM...............MMMMM88~.........+MM..ZMMMMMMMMMMMMMMMMMMMM
MM.......$DDDDDDD.......$DDDDD..DDNMM..ZMMMMMMMMMMMMMMMMMMMM
MM.......$DDDDDDD.......$DDDDD..DDNMM..ZMMMMMMMMMMMMMMMMMMMM
MM.......ZMMMMMMM.......ZMMMMM..MMMMM..ZMMMMMMMMMMMMMMMMMMMM
MMMMMMMMM+.......MMMMM88NMMMMM..MMMMMMMMMMMMMMMMMMMMMMMMMMMM
MMMMMMMMM+.......MMMMM88NMMMMM..MMMMMMMMMMMMMMMMMMMMMMMMMMMM
MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM*/
// File: contracts/ERC20_Bridge_Logic.sol
/// @title ERC20 Bridge Logic
/// @author Vega Protocol
/// @notice This contract is used by Vega network users to deposit and withdraw ERC20 tokens to/from Vega.
// @notice All funds deposited/withdrawn are to/from the assigned ERC20_Asset_Pool
contract ERC20_Bridge_Logic is IERC20_Bridge_Logic {
address multisig_control_address;
address payable erc20_asset_pool_address;
// asset address => is listed
mapping(address => bool) listed_tokens;
// asset address => minimum deposit amt
mapping(address => uint256) minimum_deposits;
// asset address => maximum deposit amt
mapping(address => uint256) maximum_deposits;
// Vega asset ID => asset_source
mapping(bytes32 => address) vega_asset_ids_to_source;
// asset_source => Vega asset ID
mapping(address => bytes32) asset_source_to_vega_asset_id;
/// @param erc20_asset_pool Initial Asset Pool contract address
/// @param multisig_control Initial MultisigControl contract address
constructor(address payable erc20_asset_pool, address multisig_control) {
erc20_asset_pool_address = erc20_asset_pool;
multisig_control_address = multisig_control;
}
/***************************FUNCTIONS*************************/
/// @notice This function lists the given ERC20 token contract as valid for deposit to this bridge
/// @param asset_source Contract address for given ERC20 token
/// @param vega_asset_id Vega-generated asset ID for internal use in Vega Core
/// @param nonce Vega-assigned single-use number that provides replay attack protection
/// @param signatures Vega-supplied signature bundle of a validator-signed order
/// @notice See MultisigControl for more about signatures
/// @dev Emits Asset_Listed if successful
function list_asset(address asset_source, bytes32 vega_asset_id, uint256 nonce, bytes memory signatures) public override {
require(!listed_tokens[asset_source], "asset already listed");
bytes memory message = abi.encode(asset_source, vega_asset_id, nonce, 'list_asset');
require(IMultisigControl(multisig_control_address).verify_signatures(signatures, message, nonce), "bad signatures");
listed_tokens[asset_source] = true;
vega_asset_ids_to_source[vega_asset_id] = asset_source;
asset_source_to_vega_asset_id[asset_source] = vega_asset_id;
emit Asset_Listed(asset_source, vega_asset_id, nonce);
}
/// @notice This function removes from listing the given ERC20 token contract. This marks the token as invalid for deposit to this bridge
/// @param asset_source Contract address for given ERC20 token
/// @param nonce Vega-assigned single-use number that provides replay attack protection
/// @param signatures Vega-supplied signature bundle of a validator-signed order
/// @notice See MultisigControl for more about signatures
/// @dev Emits Asset_Removed if successful
function remove_asset(address asset_source, uint256 nonce, bytes memory signatures) public override {
require(listed_tokens[asset_source], "asset not listed");
bytes memory message = abi.encode(asset_source, nonce, 'remove_asset');
require(IMultisigControl(multisig_control_address).verify_signatures(signatures, message, nonce), "bad signatures");
listed_tokens[asset_source] = false;
emit Asset_Removed(asset_source, nonce);
}
/// @notice This function sets the minimum allowable deposit for the given ERC20 token
/// @param asset_source Contract address for given ERC20 token
/// @param minimum_amount Minimum deposit amount
/// @param nonce Vega-assigned single-use number that provides replay attack protection
/// @param signatures Vega-supplied signature bundle of a validator-signed order
/// @notice See MultisigControl for more about signatures
/// @dev Emits Asset_Deposit_Minimum_Set if successful
function set_deposit_minimum(address asset_source, uint256 minimum_amount, uint256 nonce, bytes memory signatures) public override{
require(listed_tokens[asset_source], "asset not listed");
bytes memory message = abi.encode(asset_source, minimum_amount, nonce, 'set_deposit_minimum');
require(IMultisigControl(multisig_control_address).verify_signatures(signatures, message, nonce), "bad signatures");
minimum_deposits[asset_source] = minimum_amount;
emit Asset_Deposit_Minimum_Set(asset_source, minimum_amount, nonce);
}
/// @notice This function sets the maximum allowable deposit for the given ERC20 token
/// @param asset_source Contract address for given ERC20 token
/// @param maximum_amount Maximum deposit amount
/// @param nonce Vega-assigned single-use number that provides replay attack protection
/// @param signatures Vega-supplied signature bundle of a validator-signed order
/// @notice See MultisigControl for more about signatures
/// @dev Emits Asset_Deposit_Maximum_Set if successful
function set_deposit_maximum(address asset_source, uint256 maximum_amount, uint256 nonce, bytes memory signatures) public override {
require(listed_tokens[asset_source], "asset not listed");
bytes memory message = abi.encode(asset_source, maximum_amount, nonce, 'set_deposit_maximum');
require(IMultisigControl(multisig_control_address).verify_signatures(signatures, message, nonce), "bad signatures");
maximum_deposits[asset_source] = maximum_amount;
emit Asset_Deposit_Maximum_Set(asset_source, maximum_amount, nonce);
}
/// @notice This function withdrawals assets to the target Ethereum address
/// @param asset_source Contract address for given ERC20 token
/// @param amount Amount of ERC20 tokens to withdraw
/// @param target Target Ethereum address to receive withdrawn ERC20 tokens
/// @param nonce Vega-assigned single-use number that provides replay attack protection
/// @param signatures Vega-supplied signature bundle of a validator-signed order
/// @notice See MultisigControl for more about signatures
/// @dev Emits Asset_Withdrawn if successful
function withdraw_asset(address asset_source, uint256 amount, address target, uint256 nonce, bytes memory signatures) public override{
bytes memory message = abi.encode(asset_source, amount, target, nonce, 'withdraw_asset');
require(IMultisigControl(multisig_control_address).verify_signatures(signatures, message, nonce), "bad signatures");
require(ERC20_Asset_Pool(erc20_asset_pool_address).withdraw(asset_source, target, amount), "token didn't transfer, rejected by asset pool.");
emit Asset_Withdrawn(target, asset_source, amount, nonce);
}
/// @notice This function allows a user to deposit given ERC20 tokens into Vega
/// @param asset_source Contract address for given ERC20 token
/// @param amount Amount of tokens to be deposited into Vega
/// @param vega_public_key Target Vega public key to be credited with this deposit
/// @dev MUST emit Asset_Deposited if successful
/// @dev ERC20 approve function should be run before running this
/// @notice ERC20 approve function should be run before running this
function deposit_asset(address asset_source, uint256 amount, bytes32 vega_public_key) public override {
require(listed_tokens[asset_source], "asset not listed");
//User must run approve before deposit
require(maximum_deposits[asset_source] == 0 || amount <= maximum_deposits[asset_source], "deposit above maximum");
require(amount >= minimum_deposits[asset_source], "deposit below minimum");
require(IERC20(asset_source).transferFrom(msg.sender, erc20_asset_pool_address, amount), "transfer failed in deposit");
emit Asset_Deposited(msg.sender, asset_source, amount, vega_public_key);
}
/***************************VIEWS*****************************/
/// @notice This view returns true if the given ERC20 token contract has been listed valid for deposit
/// @param asset_source Contract address for given ERC20 token
/// @return True if asset is listed
function is_asset_listed(address asset_source) public override view returns(bool){
return listed_tokens[asset_source];
}
/// @notice This view returns minimum valid deposit
/// @param asset_source Contract address for given ERC20 token
/// @return Minimum valid deposit of given ERC20 token
function get_deposit_minimum(address asset_source) public override view returns(uint256){
return minimum_deposits[asset_source];
}
/// @notice This view returns maximum valid deposit
/// @param asset_source Contract address for given ERC20 token
/// @return Maximum valid deposit of given ERC20 token
function get_deposit_maximum(address asset_source) public override view returns(uint256){
return maximum_deposits[asset_source];
}
/// @return current multisig_control_address
function get_multisig_control_address() public override view returns(address) {
return multisig_control_address;
}
/// @param asset_source Contract address for given ERC20 token
/// @return The assigned Vega Asset Id for given ERC20 token
function get_vega_asset_id(address asset_source) public override view returns(bytes32){
return asset_source_to_vega_asset_id[asset_source];
}
/// @param vega_asset_id Vega-assigned asset ID for which you want the ERC20 token address
/// @return The ERC20 token contract address for a given Vega Asset Id
function get_asset_source(bytes32 vega_asset_id) public override view returns(address){
return vega_asset_ids_to_source[vega_asset_id];
}
}
/**
MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
MMMMWEMMMMMMMMMMMMMMMMMMMMMMMMMM...............MMMMMMMMMMMMM
MMMMMMLOVEMMMMMMMMMMMMMMMMMMMMMM...............MMMMMMMMMMMMM
MMMMMMMMMMHIXELMMMMMMMMMMMM....................MMMMMNNMMMMMM
MMMMMMMMMMMMMMMMMMMMMMMMMMM....................MMMMMMMMMMMMM
MMMMMMMMMMMMMMMMMMMMMM88=........................+MMMMMMMMMM
MMMMMMMMMMMMMMMMM....................MMMMM...MMMMMMMMMMMMMMM
MMMMMMMMMMMMMMMMM....................MMMMM...MMMMMMMMMMMMMMM
MMMMMMMMMMMM.........................MM+..MMM....+MMMMMMMMMM
MMMMMMMMMNMM...................... ..MM?..MMM.. .+MMMMMMMMMM
MMMMNDDMM+........................+MM........MM..+MMMMMMMMMM
MMMMZ.............................+MM....................MMM
MMMMZ.............................+MM....................MMM
MMMMZ.............................+MM....................DDD
MMMMZ.............................+MM..ZMMMMMMMMMMMMMMMMMMMM
MMMMZ.............................+MM..ZMMMMMMMMMMMMMMMMMMMM
MM..............................MMZ....ZMMMMMMMMMMMMMMMMMMMM
MM............................MM.......ZMMMMMMMMMMMMMMMMMMMM
MM............................MM.......ZMMMMMMMMMMMMMMMMMMMM
MM......................ZMMMMM.......MMMMMMMMMMMMMMMMMMMMMMM
MM............... ......ZMMMMM.... ..MMMMMMMMMMMMMMMMMMMMMMM
MM...............MMMMM88~.........+MM..ZMMMMMMMMMMMMMMMMMMMM
MM.......$DDDDDDD.......$DDDDD..DDNMM..ZMMMMMMMMMMMMMMMMMMMM
MM.......$DDDDDDD.......$DDDDD..DDNMM..ZMMMMMMMMMMMMMMMMMMMM
MM.......ZMMMMMMM.......ZMMMMM..MMMMM..ZMMMMMMMMMMMMMMMMMMMM
MMMMMMMMM+.......MMMMM88NMMMMM..MMMMMMMMMMMMMMMMMMMMMMMMMMMM
MMMMMMMMM+.......MMMMM88NMMMMM..MMMMMMMMMMMMMMMMMMMMMMMMMMMM
MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM*/
{
"compilationTarget": {
"ERC20_Bridge_Logic.sol": "ERC20_Bridge_Logic"
},
"evmVersion": "london",
"libraries": {},
"metadata": {
"bytecodeHash": "ipfs"
},
"optimizer": {
"enabled": false,
"runs": 200
},
"remappings": []
}
[{"inputs":[{"internalType":"address payable","name":"erc20_asset_pool","type":"address"},{"internalType":"address","name":"multisig_control","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"asset_source","type":"address"},{"indexed":false,"internalType":"uint256","name":"new_maximum","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"nonce","type":"uint256"}],"name":"Asset_Deposit_Maximum_Set","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"asset_source","type":"address"},{"indexed":false,"internalType":"uint256","name":"new_minimum","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"nonce","type":"uint256"}],"name":"Asset_Deposit_Minimum_Set","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user_address","type":"address"},{"indexed":true,"internalType":"address","name":"asset_source","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"bytes32","name":"vega_public_key","type":"bytes32"}],"name":"Asset_Deposited","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"asset_source","type":"address"},{"indexed":true,"internalType":"bytes32","name":"vega_asset_id","type":"bytes32"},{"indexed":false,"internalType":"uint256","name":"nonce","type":"uint256"}],"name":"Asset_Listed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"asset_source","type":"address"},{"indexed":false,"internalType":"uint256","name":"nonce","type":"uint256"}],"name":"Asset_Removed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user_address","type":"address"},{"indexed":true,"internalType":"address","name":"asset_source","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"nonce","type":"uint256"}],"name":"Asset_Withdrawn","type":"event"},{"inputs":[{"internalType":"address","name":"asset_source","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"bytes32","name":"vega_public_key","type":"bytes32"}],"name":"deposit_asset","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"vega_asset_id","type":"bytes32"}],"name":"get_asset_source","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"asset_source","type":"address"}],"name":"get_deposit_maximum","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"asset_source","type":"address"}],"name":"get_deposit_minimum","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"get_multisig_control_address","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"asset_source","type":"address"}],"name":"get_vega_asset_id","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"asset_source","type":"address"}],"name":"is_asset_listed","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"asset_source","type":"address"},{"internalType":"bytes32","name":"vega_asset_id","type":"bytes32"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"bytes","name":"signatures","type":"bytes"}],"name":"list_asset","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"asset_source","type":"address"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"bytes","name":"signatures","type":"bytes"}],"name":"remove_asset","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"asset_source","type":"address"},{"internalType":"uint256","name":"maximum_amount","type":"uint256"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"bytes","name":"signatures","type":"bytes"}],"name":"set_deposit_maximum","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"asset_source","type":"address"},{"internalType":"uint256","name":"minimum_amount","type":"uint256"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"bytes","name":"signatures","type":"bytes"}],"name":"set_deposit_minimum","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"asset_source","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"address","name":"target","type":"address"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"bytes","name":"signatures","type":"bytes"}],"name":"withdraw_asset","outputs":[],"stateMutability":"nonpayable","type":"function"}]