Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
P
plugin
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
JIRA
JIRA
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
link33
plugin
Commits
c1da9d02
Commit
c1da9d02
authored
Sep 30, 2021
by
hezhengjun
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
add draft sol code for bridgevmxgo
parent
c81872d0
Show whitespace changes
Inline
Side-by-side
Showing
8 changed files
with
2124 additions
and
0 deletions
+2124
-0
BridgeBank.sol
plugin/dapp/bridgevmxgo/contracts/BridgeBank/BridgeBank.sol
+337
-0
BridgeToken.sol
plugin/dapp/bridgevmxgo/contracts/BridgeBank/BridgeToken.sol
+27
-0
EvmAssetBank.sol
...in/dapp/bridgevmxgo/contracts/BridgeBank/EvmAssetBank.sol
+273
-0
GoAssetBank.sol
plugin/dapp/bridgevmxgo/contracts/BridgeBank/GoAssetBank.sol
+385
-0
BridgeRegistry.sol
plugin/dapp/bridgevmxgo/contracts/BridgeRegistry.sol
+40
-0
GoAssetBridge.sol
plugin/dapp/bridgevmxgo/contracts/GoAssetBridge.sol
+368
-0
Oracle.sol
plugin/dapp/bridgevmxgo/contracts/Oracle.sol
+278
-0
Valset.sol
plugin/dapp/bridgevmxgo/contracts/Valset.sol
+416
-0
No files found.
plugin/dapp/bridgevmxgo/contracts/BridgeBank/BridgeBank.sol
0 → 100644
View file @
c1da9d02
pragma solidity ^0.5.0;
import "./GoAssetBank.sol";
import "./EvmAssetBank.sol";
import "../Oracle.sol";
import "../GoAssetBridge.sol";
/**
* @title BridgeBank
* @dev Bank contract which coordinates asset-related functionality.
* GoAssetBank manages the minting and burning of tokens which
* represent go contract issued assets, while EvmAssetBank manages
* the locking and unlocking of Chain33 and ERC20 token assets
* based on Chain33.
**/
contract BridgeBank is GoAssetBank, EvmAssetBank {
using SafeMath for uint256;
address public operator;
Oracle public oracle;
GoAssetBridge public goAssetBridge;
/*
* @dev: Constructor, sets operator
*/
constructor (
address _operatorAddress,
address _oracleAddress,
address _goAssetBridgeAddress
)
public
{
operator = _operatorAddress;
oracle = Oracle(_oracleAddress);
goAssetBridge = GoAssetBridge(_goAssetBridgeAddress);
}
/*
* @dev: Modifier to restrict access to operator
*/
modifier onlyOperator() {
require(
msg.sender == operator,
'Must be BridgeBank operator.'
);
_;
}
/*
* @dev: Modifier to restrict access to Offline
*/
modifier onlyOffline() {
require(
msg.sender == offlineSave,
'Must be onlyOffline.'
);
_;
}
/*
* @dev: Modifier to restrict access to the oracle
*/
modifier onlyOracle()
{
require(
msg.sender == address(oracle),
"Access restricted to the oracle"
);
_;
}
/*
* @dev: Modifier to restrict access to the goAsset bridge
*/
modifier onlyGoAssetBridge()
{
require(
msg.sender == address(goAssetBridge),
"Access restricted to the goAsset bridge"
);
_;
}
/*
* @dev: Fallback function allows operator to send funds to the bank directly
* This feature is used for testing and is available at the operator's own risk.
*/
function() external payable onlyOffline {}
/*
* @dev: Creates a new BridgeToken
*
* @param _symbol: The new BridgeToken's symbol
* @return: The new BridgeToken contract's address
*/
function createNewBridgeToken(
string memory _symbol
)
public
onlyOperator
returns(address)
{
return deployNewBridgeToken(_symbol);
}
/*
* @dev: Mints new BankTokens
*
* @param _goAssetSender: The goAsset sender's address.
* @param _chain33Recipient: The intended recipient's Chain33 address.
* @param _bridgeTokenAddress: The bridge token address
* @param _symbol: goAsset token symbol
* @param _amount: number of goAsset tokens to be minted
*/
function mintBridgeTokens(
address _goAssetSender,
address payable _intendedRecipient,
address _bridgeTokenAddress,
string memory _symbol,
uint256 _amount
)
public
onlyGoAssetBridge
{
return mintNewBridgeTokens(
_goAssetSender,
_intendedRecipient,
_bridgeTokenAddress,
_symbol,
_amount
);
}
/*
* @dev: Burns bank tokens
*
* @param _goAssetReceiver: The _goAsset receiver address in bytes.
* @param _goAssetTokenAddress: The currency type
* @param _amount: number of goAsset tokens to be burned
*/
function burnBridgeTokens(
address _goAssetReceiver,
address _goAssetTokenAddress,
uint256 _amount
)
public
{
return burnGoAssetTokens(
msg.sender,
_goAssetReceiver,
_goAssetTokenAddress,
_amount
);
}
/*
* @dev: addToken2LockList used to add token with the specified address to be
* allowed locked from GoAsset
*
* @param _token: token contract address
* @param _symbol: token symbol
*/
function addToken2LockList(
address _token,
string memory _symbol
)
public
onlyOperator
{
addToken2AllowLock(_token, _symbol);
}
/*
* @dev: configTokenOfflineSave used to config threshold to trigger tranfer token to offline account
* when the balance of locked token reaches
*
* @param _token: token contract address
* @param _symbol:token symbol,just used for double check that token address and symbol is consistent
* @param _threshold: _threshold to trigger transfer
* @param _percents: amount to transfer per percents of threshold
*/
function configLockedTokenOfflineSave(
address _token,
string memory _symbol,
uint256 _threshold,
uint8 _percents
)
public
onlyOperator
{
if (address(0) != _token) {
require(keccak256(bytes(BridgeToken(_token).symbol())) == keccak256(bytes(_symbol)), "token address and symbol is not consistent");
} else {
require(keccak256(bytes("BTY")) == keccak256(bytes(_symbol)), "token address and symbol is not consistent");
}
configOfflineSave4Lock(_token, _symbol, _threshold, _percents);
}
/*
* @dev: configOfflineSaveAccount used to config offline account to receive token
* when the balance of locked token reaches threshold
*
* @param _offlineSave: receiver address
*/
function configOfflineSaveAccount(address payable _offlineSave) public onlyOperator
{
offlineSave = _offlineSave;
}
/*
* @dev: Locks received Chain33 funds.
*
* @param _recipient: bytes representation of destination address.
* @param _token: token address in origin chain (0x0 if chain33)
* @param _amount: value of deposit
*/
function lock(
bytes memory _recipient,
address _token,
uint256 _amount
)
public
availableNonce()
payable
{
string memory symbol;
// Chain33 deposit
if (msg.value > 0) {
require(
_token == address(0),
"BTY deposits require the 'token' address to be the null address"
);
require(
msg.value == _amount,
"The transactions value must be equal the specified amount(BTY decimal is 8)"
);
// Set the the symbol to BTY
symbol = "BTY";
// ERC20 deposit
} else {
require(
BridgeToken(_token).transferFrom(msg.sender, address(this), _amount),
"Contract token allowances insufficient to complete this lock request"
);
// Set symbol to the ERC20 token's symbol
symbol = BridgeToken(_token).symbol();
require(
tokenAllow2Lock[keccak256(abi.encodePacked(symbol))] == _token,
'The token is not allowed to be locked from Chain33.'
);
}
lockFunds(
msg.sender,
_recipient,
_token,
symbol,
_amount
);
}
/*
* @dev: Unlocks Chain33 and ERC20 tokens held on the contract.
*
* @param _recipient: recipient's Chain33 address
* @param _token: token contract address
* @param _symbol: token symbol
* @param _amount: wei amount or ERC20 token count
\ */
function unlock(
address payable _recipient,
address _token,
string memory _symbol,
uint256 _amount
)
public
onlyGoAssetBridge
hasLockedFunds(
_token,
_amount
)
canDeliver(
_token,
_amount
)
{
unlockFunds(
_recipient,
_token,
_symbol,
_amount
);
}
/*
* @dev: Exposes an item's current status.
*
* @param _id: The item in question.
* @return: Boolean indicating the lock status.
*/
function getGoAssetDepositStatus(
bytes32 _id
)
public
view
returns(bool)
{
return isLockedGoAssetDeposit(_id);
}
/*
* @dev: Allows access to a GoAsset deposit's information via its unique identifier.
*
* @param _id: The deposit to be viewed.
* @return: Original sender's Chain33 address.
* @return: Intended GoAsset recipient's address in bytes.
* @return: The lock deposit's currency, denoted by a token address.
* @return: The amount locked in the deposit.
* @return: The deposit's unique nonce.
*/
function viewGoAssetDeposit(
bytes32 _id
)
public
view
returns(bytes memory, address payable, address, uint256)
{
return getGoAssetDeposit(_id);
}
}
\ No newline at end of file
plugin/dapp/bridgevmxgo/contracts/BridgeBank/BridgeToken.sol
0 → 100644
View file @
c1da9d02
pragma solidity ^0.5.0;
import "../../openzeppelin-solidity/contracts/token/ERC20/ERC20Mintable.sol";
import "../../openzeppelin-solidity/contracts/token/ERC20/ERC20Burnable.sol";
import "../../openzeppelin-solidity/contracts/token/ERC20/ERC20Detailed.sol";
/**
* @title BridgeToken
* @dev Mintable, ERC20 compatible BankToken for use by BridgeBank
**/
contract BridgeToken is ERC20Mintable, ERC20Burnable, ERC20Detailed {
constructor(
string memory _symbol
)
public
ERC20Detailed(
_symbol,
_symbol,
8
)
{
// Intentionally left blank
}
}
\ No newline at end of file
plugin/dapp/bridgevmxgo/contracts/BridgeBank/EvmAssetBank.sol
0 → 100644
View file @
c1da9d02
pragma solidity ^0.5.0;
import "../../openzeppelin-solidity/contracts/math/SafeMath.sol";
import "./BridgeToken.sol";
/*
* @title: EvmAssetBank
* @dev: EvmAsset bank which locks Chain33/ERC20 token deposits, and unlocks
* Chain33/ERC20 tokens once the prophecy has been successfully processed.
* @dev:当emv资产转移到go合约时,用于锁定资产;
* 当emv资产从go合约进行提币时,用于解锁资产;
*/
contract EvmAssetBank {
using SafeMath for uint256;
address payable public offlineSave;
uint256 public lockNonce;
mapping(address => uint256) public lockedFunds;
mapping(bytes32 => address) public tokenAllow2Lock;
mapping(address => OfflineSaveCfg) public offlineSaveCfgs;
uint8 public lowThreshold = 5;
uint8 public highThreshold = 80;
struct OfflineSaveCfg {
address token;
string symbol;
uint256 _threshold;
uint8 _percents;
}
/*
* @dev: Event declarations
*/
event LogLock(
address _from,
bytes _to,
address _token,
string _symbol,
uint256 _value,
uint256 _nonce
);
event LogUnlock(
address _to,
address _token,
string _symbol,
uint256 _value
);
/*
* @dev: Modifier declarations
*/
modifier hasLockedFunds(
address _token,
uint256 _amount
) {
require(
lockedFunds[_token] >= _amount,
"The Bank does not hold enough locked tokens to fulfill this request."
);
_;
}
modifier canDeliver(
address _token,
uint256 _amount
)
{
if(_token == address(0)) {
require(
address(this).balance >= _amount,
'Insufficient Chain33 balance for delivery.'
);
} else {
require(
BridgeToken(_token).balanceOf(address(this)) >= _amount,
'Insufficient ERC20 token balance for delivery.'
);
}
_;
}
modifier availableNonce() {
require(
lockNonce + 1 > lockNonce,
'No available nonces.'
);
_;
}
/*
* @dev: Constructor which sets the lock nonce
*/
constructor()
public
{
lockNonce = 0;
}
/*
* @dev: addToken2AllowLock used to add token with the specified address to be
* allowed locked from GoAsset
*
* @param _token: token contract address
* @param _symbol: token symbol
*/
function addToken2AllowLock(
address _token,
string memory _symbol
)
internal
{
bytes32 symHash = keccak256(abi.encodePacked(_symbol));
address tokenQuery = tokenAllow2Lock[symHash];
require(tokenQuery == address(0), 'The token with the same symbol has been added to lock allow list already.');
tokenAllow2Lock[symHash] = _token;
}
/*
* @dev: addToken2AllowLock used to add token with the specified address to be
* allowed locked from GoAsset
*
* @param _symbol: token symbol
*/
function getLockedTokenAddress(string memory _symbol) public view returns(address)
{
bytes32 symHash = keccak256(abi.encodePacked(_symbol));
return tokenAllow2Lock[symHash];
}
/*
* @dev: configOfflineSave4Lock used to config threshold to trigger tranfer token to offline account
* when the balance of locked token reaches
*
* @param _token: token contract address
* @param _symbol:token symbol,just used for double check that token address and symbol is consistent
* @param _threshold: _threshold to trigger transfer
* @param _percents: amount to transfer per percents of threshold
*/
function configOfflineSave4Lock(
address _token,
string memory _symbol,
uint256 _threshold,
uint8 _percents
)
internal
{
require(
_percents >= lowThreshold && _percents <= highThreshold,
"The percents to trigger should within range [5, 80]"
);
OfflineSaveCfg memory offlineSaveCfg = OfflineSaveCfg(
_token,
_symbol,
_threshold,
_percents
);
offlineSaveCfgs[_token] = offlineSaveCfg;
}
/*
* @dev: getofflineSaveCfg used to get token's offline save configuration
*
* @param _token: token contract address
*/
function getofflineSaveCfg(address _token) public view returns(uint256, uint8)
{
OfflineSaveCfg memory offlineSaveCfg = offlineSaveCfgs[_token];
return (offlineSaveCfg._threshold, offlineSaveCfg._percents);
}
/*
* @dev: Creates a new Chain33 deposit with a unique id.
*
* @param _sender: The sender's Chain33 address.
* @param _recipient: The intended recipient's Chain33 address.
* @param _token: The currency type, either erc20 or Chain33.
* @param _amount: The amount of erc20 tokens/ Chain33 (in wei) to be itemized.
*/
function lockFunds(
address payable _sender,
bytes memory _recipient,
address _token,
string memory _symbol,
uint256 _amount
)
internal
{
// Incerment the lock nonce
lockNonce = lockNonce.add(1);
// Increment locked funds by the amount of tokens to be locked
lockedFunds[_token] = lockedFunds[_token].add(_amount);
emit LogLock(
_sender,
_recipient,
_token,
_symbol,
_amount,
lockNonce
);
if (address(0) == offlineSave) {
return;
}
uint256 balance;
if (address(0) == _token) {
balance = address(this).balance;
} else {
balance = BridgeToken(_token).balanceOf(address(this));
}
OfflineSaveCfg memory offlineSaveCfg = offlineSaveCfgs[_token];
//check not zero,so configured already
if (offlineSaveCfg._percents < lowThreshold) {
return;
}
if (balance < offlineSaveCfg._threshold ) {
return;
}
uint256 amount = offlineSaveCfg._percents * balance / 100;
if (address(0) == _token) {
offlineSave.transfer(amount);
} else {
require(BridgeToken(_token).transfer(offlineSave, amount), "Erc20 Token Transfer to offline Save account failed");
}
}
/*
* @dev: Unlocks funds held on contract and sends them to the
* intended recipient
*
* @param _recipient: recipient's Chain33 address
* @param _token: token contract address
* @param _symbol: token symbol
* @param _amount: wei amount or ERC20 token count
*/
function unlockFunds(
address payable _recipient,
address _token,
string memory _symbol,
uint256 _amount
)
internal
{
// Decrement locked funds mapping by the amount of tokens to be unlocked
lockedFunds[_token] = lockedFunds[_token].sub(_amount);
// Transfer funds to intended recipient
if (_token == address(0)) {
_recipient.transfer(_amount);
} else {
require(
BridgeToken(_token).transfer(_recipient, _amount),
"Token transfer failed"
);
}
emit LogUnlock(
_recipient,
_token,
_symbol,
_amount
);
}
}
plugin/dapp/bridgevmxgo/contracts/BridgeBank/GoAssetBank.sol
0 → 100644
View file @
c1da9d02
pragma solidity ^0.5.0;
import "../../openzeppelin-solidity/contracts/math/SafeMath.sol";
import "./BridgeToken.sol";
/**
* @title GoAssetBank
* @dev Manages the deployment and minting of ERC20 compatible BridgeTokens
* which represent assets issued by Go contracts.
* @dev 为chain33上的go合约发行的资产进行BridgeTokens合约部署,铸币和销毁
**/
contract GoAssetBank {
using SafeMath for uint256;
uint256 public bridgeTokenCount;
mapping(address => bool) public bridgeTokenWhitelist;
mapping(bytes32 => bool) public bridgeTokenCreated;
mapping(bytes32 => GoAssetDeposit) goAssetDeposits;
mapping(bytes32 => GoAssetBurn) goAssetBurns;
mapping(address => DepositBurnCount) depositBurnCounts;
mapping(bytes32 => address) public token2address;
struct GoAssetDeposit {
address goAssetSender;
address payable chain33Recipient;
address bridgeTokenAddress;
uint256 amount;
bool exist;
uint256 nonce;
}
struct DepositBurnCount {
uint256 depositCount;
uint256 burnCount;
}
struct GoAssetBurn {
address goAssetSender;
address payable chain33Owner;
address bridgeTokenAddress;
uint256 amount;
uint256 nonce;
}
/*
* @dev: Event declarations
*/
event LogNewBridgeToken(
address _token,
string _symbol
);
event LogBridgeTokenMint(
address _token,
string _symbol,
uint256 _amount,
address _beneficiary
);
event LogGoAssetTokenBurn(
address _token,
string _symbol,
uint256 _amount,
address _ownerFrom,
address _goAssetReceiver,
uint256 _nonce
);
/*
* @dev: Modifier to make sure this symbol not created now
*/
modifier notCreated(string memory _symbol)
{
require(
!hasBridgeTokenCreated(_symbol),
"The symbol has been created already"
);
_;
}
/*
* @dev: Modifier to make sure this symbol not created now
*/
modifier created(string memory _symbol)
{
require(
hasBridgeTokenCreated(_symbol),
"The symbol has not been created yet"
);
_;
}
/*
* @dev: Constructor, sets bridgeTokenCount
*/
constructor () public {
bridgeTokenCount = 0;
}
/*
* @dev: check whether this symbol has been created yet or not
*
* @param _symbol: token symbol
* @return: true or false
*/
function hasBridgeTokenCreated(string memory _symbol) public view returns(bool) {
bytes32 symHash = keccak256(abi.encodePacked(_symbol));
return bridgeTokenCreated[symHash];
}
/*
* @dev: Creates a new GoAssetDeposit with a unique ID
*
* @param _goAssetSender: The _goAssetSender sender's address.
* @param _chain33Recipient: The intended recipient's Chain33 address.
* @param _token: The currency type
* @param _amount: The amount in the deposit.
* @return: The newly created GoAssetSenderDeposit's unique id.
*/
function newGoAssetDeposit(
address memory _goAssetSender,
address payable _chain33Recipient,
address _token,
uint256 _amount
)
internal
returns(bytes32)
{
DepositBurnCount memory depositBurnCount = depositBurnCounts[_token];
depositBurnCount.depositCount = depositBurnCount.depositCount.add(1);
depositBurnCounts[_token] = depositBurnCount;
bytes32 depositID = keccak256(
abi.encodePacked(
_goAssetSender,
_chain33Recipient,
_token,
_amount,
depositBurnCount.depositCount
)
);
goAssetDeposits[depositID] = GoAssetDeposit(
_goAssetSender,
_chain33Recipient,
_token,
_amount,
true,
depositBurnCount.depositCount
);
return depositID;
}
/*
* @dev: Creates a new GoAssetBurn with a unique ID
*
* @param _goAssetSender: The go Asset Sender address
* @param _chain33Owner: The owner's Chain33 address.
* @param _token: The token Address
* @param _amount: The amount to be burned.
* @param _nonce: The nonce indicates the burn count for this token
* @return: The newly created GoAssetBurn's unique id.
*/
function newGoAssetBurn(
address _goAssetSender,
address payable _chain33Owner,
address _token,
uint256 _amount,
uint256 nonce
)
internal
returns(bytes32)
{
bytes32 burnID = keccak256(
abi.encodePacked(
_goAssetSender,
_chain33Owner,
_token,
_amount,
nonce
)
);
goAssetBurns[burnID] = GoAssetBurn(
_goAssetSender,
_chain33Owner,
_token,
_amount,
nonce
);
return burnID;
}
/*
* @dev: Deploys a new BridgeToken contract
*
* @param _symbol: The BridgeToken's symbol
*/
function deployNewBridgeToken(
string memory _symbol
)
internal
notCreated(_symbol)
returns(address)
{
bridgeTokenCount = bridgeTokenCount.add(1);
// Deploy new bridge token contract
BridgeToken newBridgeToken = (new BridgeToken)(_symbol);
// Set address in tokens mapping
address newBridgeTokenAddress = address(newBridgeToken);
bridgeTokenWhitelist[newBridgeTokenAddress] = true;
bytes32 symHash = keccak256(abi.encodePacked(_symbol));
bridgeTokenCreated[symHash] = true;
depositBurnCounts[newBridgeTokenAddress] = DepositBurnCount(
uint256(0),
uint256(0));
token2address[symHash] = newBridgeTokenAddress;
emit LogNewBridgeToken(
newBridgeTokenAddress,
_symbol
);
return newBridgeTokenAddress;
}
/*
* @dev: Mints new goAsset tokens
*
* @param _goAssetSender: The _goAssetSender sender's address.
* @param _chain33Recipient: The intended recipient's Chain33 address.
* @param _goAssetTokenAddress: The currency type
* @param _symbol: goAsset token symbol
* @param _amount: number of goAsset tokens to be minted
*/
function mintNewBridgeTokens(
address _goAssetSender,
address payable _intendedRecipient,
address _bridgeTokenAddress,
string memory _symbol,
uint256 _amount
)
internal
{
// Must be whitelisted bridge token
require(
bridgeTokenWhitelist[_bridgeTokenAddress],
"Token must be a whitelisted bridge token"
);
// Mint bridge tokens
require(
BridgeToken(_bridgeTokenAddress).mint(
_intendedRecipient,
_amount
),
"Attempted mint of bridge tokens failed"
);
newGoAssetDeposit(
_goAssetSender,
_intendedRecipient,
_bridgeTokenAddress,
_amount
);
emit LogBridgeTokenMint(
_bridgeTokenAddress,
_symbol,
_amount,
_intendedRecipient
);
}
/*
* @dev: Burn goAsset tokens
*
* @param _from: The address to be burned from
* @param _goAssetReceiver: The receiver's GoAsset address in bytes.
* @param _goAssetTokenAddress: The token address of goAsset asset issued on chain33
* @param _amount: number of goAsset tokens to be minted
*/
function burnGoAssetTokens(
address payable _from,
address _goAssetReceiver,
address _goAssetTokenAddress,
uint256 _amount
)
internal
{
// Must be whitelisted bridge token
require(
bridgeTokenWhitelist[_goAssetTokenAddress],
"Token must be a whitelisted bridge token"
);
// burn bridge tokens
BridgeToken bridgeTokenInstance = BridgeToken(_goAssetTokenAddress);
bridgeTokenInstance.burnFrom(_from, _amount);
DepositBurnCount memory depositBurnCount = depositBurnCounts[_goAssetTokenAddress];
require(
depositBurnCount.burnCount + 1 > depositBurnCount.burnCount,
"burn nonce is not available"
);
depositBurnCount.burnCount = depositBurnCount.burnCount.add(1);
depositBurnCounts[_goAssetTokenAddress] = depositBurnCount;
newGoAssetBurn(
_goAssetReceiver,
_from,
_goAssetTokenAddress,
_amount,
depositBurnCount.burnCount
);
emit LogGoAssetTokenBurn(
_goAssetTokenAddress,
bridgeTokenInstance.symbol(),
_amount,
_from,
_goAssetReceiver,
depositBurnCount.burnCount
);
}
/*
* @dev: Checks if an individual GoAssetDeposit exists.
*
* @param _id: The unique GoAssetDeposit's id.
* @return: Boolean indicating if the GoAssetDeposit exists in memory.
*/
function isLockedGoAssetDeposit(
bytes32 _id
)
internal
view
returns(bool)
{
return(goAssetDeposits[_id].exist);
}
/*
* @dev: Gets an item's information
*
* @param _Id: The item containing the desired information.
* @return: Sender's address.
* @return: Recipient's address in bytes.
* @return: Token address.
* @return: Amount of chain33/erc20 in the item.
* @return: Unique nonce of the item.
*/
function getGoAssetDeposit(
bytes32 _id
)
internal
view
returns(bytes memory, address payable, address, uint256)
{
GoAssetDeposit memory deposit = goAssetDeposits[_id];
return(
deposit.goAssetSender,
deposit.chain33Recipient,
deposit.bridgeTokenAddress,
deposit.amount
);
}
function getToken2address(string memory _symbol)
created(_symbol)
public view returns(address)
{
bytes32 symHash = keccak256(abi.encodePacked(_symbol));
return token2address[symHash];
}
}
\ No newline at end of file
plugin/dapp/bridgevmxgo/contracts/BridgeRegistry.sol
0 → 100644
View file @
c1da9d02
pragma solidity ^0.5.0;
contract BridgeRegistry {
address public goAssetBridge;
address public bridgeBank;
address public oracle;
address public valset;
uint256 public deployHeight;
event LogContractsRegistered(
address _goAssetBridge,
address _bridgeBank,
address _oracle,
address _valset
);
constructor(
address _goAssetBridge,
address _bridgeBank,
address _oracle,
address _valset
)
public
{
goAssetBridge = _goAssetBridge;
bridgeBank = _bridgeBank;
oracle = _oracle;
valset = _valset;
deployHeight = block.number;
emit LogContractsRegistered(
goAssetBridge,
bridgeBank,
oracle,
valset
);
}
}
\ No newline at end of file
plugin/dapp/bridgevmxgo/contracts/GoAssetBridge.sol
0 → 100644
View file @
c1da9d02
pragma solidity ^0.5.0;
import "../openzeppelin-solidity/contracts/math/SafeMath.sol";
import "./Valset.sol";
import "./BridgeBank/BridgeBank.sol";
contract GoAssetBridge {
using SafeMath for uint256;
/*
* @dev: Public variable declarations
*/
address public operator;
Valset public valset;
address public oracle;
bool public hasOracle;
BridgeBank public bridgeBank;
bool public hasBridgeBank;
uint256 public prophecyClaimCount;
mapping(bytes32 => ProphecyClaim) public prophecyClaims;
enum Status {
Null,
Pending,
Success,
Failed
}
enum ClaimType {
Unsupported,
Burn,
Lock
}
struct ProphecyClaim {
ClaimType claimType;
address goAssetSender;
address payable chain33Receiver;
address originalValidator;
address tokenAddress;
string symbol;
uint256 amount;
Status status;
}
/*
* @dev: Event declarations
*/
event LogOracleSet(
address _oracle
);
event LogBridgeBankSet(
address _bridgeBank
);
event LogNewProphecyClaim(
uint256 _prophecyID,
ClaimType _claimType,
address _goAssetSender,
address payable _chain33Receiver,
address _validatorAddress,
address _tokenAddress,
string _symbol,
uint256 _amount
);
event LogProphecyCompleted(
bytes32 _claimID,
ClaimType _claimType
);
/*
* @dev: Modifier which only allows access to currently pending prophecies
*/
modifier isPending(
bytes32 _claimID
)
{
require(
isProphecyClaimActive(_claimID),
"Prophecy claim is not active"
);
_;
}
/*
* @dev: Modifier to restrict access to the operator.
*/
modifier onlyOperator()
{
require(
msg.sender == operator,
'Must be the operator.'
);
_;
}
/*
* @dev: Modifier to restrict access to the oracle.
*/
modifier onlyOracle()
{
require(
msg.sender == oracle,
'Must be the oracle.'
);
_;
}
/*
* @dev: The bridge is not active until oracle and bridge bank are set
*/
modifier isActive()
{
require(
hasOracle == true && hasBridgeBank == true,
"The Operator must set the oracle and bridge bank for bridge activation"
);
_;
}
/*
* @dev: Modifier to make sure the claim type is valid
*/
modifier validClaimType(
ClaimType _claimType
)
{
require(
_claimType == ClaimType.Burn || _claimType == ClaimType.Lock,
"The claim type must be ClaimType.Burn or ClaimType.Lock"
);
_;
}
/*
* @dev: Constructor
*/
constructor(
address _operator,
address _valset
)
public
{
prophecyClaimCount = 0;
operator = _operator;
valset = Valset(_valset);
hasOracle = false;
hasBridgeBank = false;
}
/*
* @dev: setOracle
*/
function setOracle(
address _oracle
)
public
onlyOperator
{
require(
!hasOracle,
"The Oracle cannot be updated once it has been set"
);
hasOracle = true;
oracle = _oracle;
emit LogOracleSet(
oracle
);
}
/*
* @dev: setBridgeBank
*/
function setBridgeBank(
address payable _bridgeBank
)
public
onlyOperator
{
require(
!hasBridgeBank,
"The Bridge Bank cannot be updated once it has been set"
);
hasBridgeBank = true;
bridgeBank = BridgeBank(_bridgeBank);
emit LogBridgeBankSet(
address(bridgeBank)
);
}
/*
* @dev: setNewProphecyClaim
* Sets a new burn or lock prophecy claim, adding it to the prophecyClaims mapping.
* Lock claims can only be created for BridgeTokens on BridgeBank's whitelist. The operator
* is responsible for adding them, and lock claims will fail until the operator has done so.
*/
function setNewProphecyClaim(
bytes32 _claimID,
uint8 _claimType,
address _goAssetSender,
address payable _chain33Receiver,
address _originalValidator,
address _tokenAddress,
string memory _symbol,
uint256 _amount
)
public
isActive
onlyOracle
{
// Increment the prophecy claim count
prophecyClaimCount = prophecyClaimCount.add(1);
ClaimType claimType = ClaimType(_claimType);
//overwrite the token address in case of lock
if (claimType == ClaimType.Lock) {
_tokenAddress = bridgeBank.getToken2address(_symbol);
}
// Create the new ProphecyClaim
ProphecyClaim memory prophecyClaim = ProphecyClaim(
claimType,
_goAssetSender,
_chain33Receiver,
_originalValidator,
_tokenAddress,
_symbol,
_amount,
Status.Pending
);
// Add the new ProphecyClaim to the mapping
prophecyClaims[_claimID] = prophecyClaim;
emit LogNewProphecyClaim(
prophecyClaimCount,
claimType,
_goAssetSender,
_chain33Receiver,
_originalValidator,
_tokenAddress,
_symbol,
_amount
);
}
/*
* @dev: completeClaim
* Allows for the completion of ProphecyClaims once processed by the Oracle.
* Burn claims unlock tokens stored by BridgeBank.
* Lock claims mint BridgeTokens on BridgeBank's token whitelist.
*/
function completeClaim(
bytes32 _claimID
)
public
isPending(_claimID)
{
require(
msg.sender == oracle,
"Only the Oracle may complete prophecies"
);
prophecyClaims[_claimID].status = Status.Success;
ClaimType claimType = prophecyClaims[_claimID].claimType;
if(claimType == ClaimType.Burn) {
unlockTokens(_claimID);
} else {
issueBridgeTokens(_claimID);
}
emit LogProphecyCompleted(
_claimID,
claimType
);
}
/*
* @dev: issueBridgeTokens
* Issues a request for the BridgeBank to mint new BridgeTokens
*/
function issueBridgeTokens(
bytes32 _claimID
)
internal
{
ProphecyClaim memory prophecyClaim = prophecyClaims[_claimID];
bridgeBank.mintBridgeTokens(
prophecyClaim.goAssetSender,
prophecyClaim.chain33Receiver,
prophecyClaim.tokenAddress,
prophecyClaim.symbol,
prophecyClaim.amount
);
}
/*
* @dev: unlockTokens
* Issues a request for the BridgeBank to unlock funds held on contract
*/
function unlockTokens(
bytes32 _claimID
)
internal
{
ProphecyClaim memory prophecyClaim = prophecyClaims[_claimID];
bridgeBank.unlock(
prophecyClaim.chain33Receiver,
prophecyClaim.tokenAddress,
prophecyClaim.symbol,
prophecyClaim.amount
);
}
/*
* @dev: isProphecyClaimActive
* Returns boolean indicating if the ProphecyClaim is active
*/
function isProphecyClaimActive(
bytes32 _claimID
)
public
view
returns(bool)
{
return prophecyClaims[_claimID].status == Status.Pending;
}
/*
* @dev: isProphecyValidatorActive
* Returns boolean indicating if the validator that originally
* submitted the ProphecyClaim is still an active validator
*/
function isProphecyClaimValidatorActive(
bytes32 _claimID
)
public
view
returns(bool)
{
return valset.isActiveValidator(
prophecyClaims[_claimID].originalValidator
);
}
/*
* @dev: Modifier to make sure the claim type is valid
*/
function isValidClaimType(uint8 _claimType) public pure returns(bool)
{
ClaimType claimType = ClaimType(_claimType);
if (claimType == ClaimType.Burn || claimType == ClaimType.Lock) {
return true;
}
return false;
}
}
plugin/dapp/bridgevmxgo/contracts/Oracle.sol
0 → 100644
View file @
c1da9d02
pragma solidity ^0.5.0;
import "../openzeppelin-solidity/contracts/math/SafeMath.sol";
import "./Valset.sol";
import "./GoAssetBridge.sol";
contract Oracle {
using SafeMath for uint256;
/*
* @dev: Public variable declarations
*/
GoAssetBridge public GoAssetBridge;
Valset public valset;
address public operator;
// Tracks the number of OracleClaims made on an individual BridgeClaim
mapping(bytes32 => address[]) public oracleClaimValidators;
mapping(bytes32 => mapping(address => bool)) public hasMadeClaim;
enum ClaimType {
Unsupported,
Burn,
Lock
}
/*
* @dev: Event declarations
*/
event LogNewOracleClaim(
bytes32 _claimID,
address _validatorAddress,
bytes _signature
);
event LogProphecyProcessed(
bytes32 _claimID,
uint256 _weightedSignedPower,
uint256 _weightedTotalPower,
address _submitter
);
/*
* @dev: Modifier to restrict access to the operator.
*/
modifier onlyOperator()
{
require(
msg.sender == operator,
'Must be the operator.'
);
_;
}
/*
* @dev: Modifier to restrict access to current ValSet validators
*/
modifier onlyValidator()
{
require(
valset.isActiveValidator(msg.sender),
"Must be an active validator"
);
_;
}
/*
* @dev: Modifier to restrict access to current ValSet validators
*/
modifier isPending(
bytes32 _claimID
)
{
require(
goAssetBridge.isProphecyClaimActive(
_claimID
) == true,
"The prophecy must be pending for this operation"
);
_;
}
/*
* @dev: Modifier to restrict the claim type must be burn or lock
*/
modifier isValidClaimType(
ClaimType _claimType
)
{
require(
goAssetBridge.isValidClaimType(
uint8(_claimType)
) == true,
"The claim type must be burn or lock"
);
_;
}
/*
* @dev: Constructor
*/
constructor(
address _operator,
address _valset,
address _goAssetBridge
)
public
{
operator = _operator;
goAssetBridge = GoAssetBridge(_goAssetBridge);
valset = Valset(_valset);
}
/*
* @dev: newOracleClaim
* Allows validators to make new OracleClaims on goAsset lock/burn prophecy,
* if the required vote power reached,just make it processed
* @param _claimType: burn or lock,
* @param _goAssetSender: goAsset sender,
* @param _chain33Receiver: receiver on chain33
* @param _tokenAddress: token address
* @param _symbol: token symbol
* @param _amount: amount
* @param _claimID: claim id
* @param _message: message for verifying
* @param _signature: need to recover sender
*/
function newOracleClaim(
ClaimType _claimType,
address _goAssetSender,
address payable _chain33Receiver,
address _tokenAddress,
string memory _symbol,
uint256 _amount,
bytes32 _claimID,
bytes memory _signature
)
public
onlyValidator
isValidClaimType(_claimType)
{
address validatorAddress = msg.sender;
// Validate the msg.sender's signature
require(
validatorAddress == valset.recover(
_claimID,
_signature
),
"Invalid _claimID signature."
);
// Confirm that this address has not already made an oracle claim on this _ClaimID
require(
!hasMadeClaim[_claimID][validatorAddress],
"Cannot make duplicate oracle claims from the same address."
);
if (oracleClaimValidators[_claimID].length == 0) {
goAssetBridge.setNewProphecyClaim(
_claimID,
uint8(_claimType),
_goAssetSender,
_chain33Receiver,
validatorAddress,
_tokenAddress,
_symbol,
_amount);
}
hasMadeClaim[_claimID][validatorAddress] = true;
oracleClaimValidators[_claimID].push(validatorAddress);
emit LogNewOracleClaim(
_claimID,
validatorAddress,
_signature
);
(bool valid, uint256 weightedSignedPower, uint256 weightedTotalPower ) = getClaimThreshold(_claimID);
if (true == valid) {
//if processed already,just emit an event
if (goAssetBridge.isProphecyClaimActive(_claimID) == true) {
completeClaim(_claimID);
}
emit LogProphecyProcessed(
_claimID,
weightedSignedPower,
weightedTotalPower,
msg.sender
);
}
}
/*
* @dev: checkBridgeProphecy
* Operator accessor method which checks if a prophecy has passed
* the validity threshold, without actually completing the prophecy.
*/
function checkBridgeProphecy(
bytes32 _claimID
)
public
view
onlyOperator
isPending(_claimID)
returns(bool, uint256, uint256)
{
require(
goAssetBridge.isProphecyClaimActive(
_claimID
) == true,
"Can only check active prophecies"
);
return getClaimThreshold(
_claimID
);
}
/*
* @dev: getClaimThreshold
* Calculates the status of a claim. The claim is considered valid if the
* combined active signatory validator powers pass the validation threshold.
* The hardcoded threshold is (Combined signed power * 2) >= (Total power * 3).
*/
function getClaimThreshold(
bytes32 _claimID
)
internal
view
returns(bool, uint256, uint256)
{
uint256 signedPower = 0;
uint256 totalPower = valset.totalPower();
// Iterate over the signatory addresses
for (uint256 i = 0; i < oracleClaimValidators[_claimID].length; i = i.add(1)) {
address signer = oracleClaimValidators[_claimID][i];
// Only add the power of active validators
if(valset.isActiveValidator(signer)) {
signedPower = signedPower.add(
valset.getValidatorPower(
signer
)
);
}
}
// Calculate if weighted signed power has reached threshold of weighted total power
uint256 weightedSignedPower = signedPower.mul(3);
uint256 weightedTotalPower = totalPower.mul(2);
bool hasReachedThreshold = weightedSignedPower >= weightedTotalPower;
return(
hasReachedThreshold,
weightedSignedPower,
weightedTotalPower
);
}
/*
* @dev: completeClaim
* Completes a claim by completing the corresponding BridgeClaim
* on the GoAssetBridge.
*/
function completeClaim(
bytes32 _claimID
)
internal
{
goAssetBridge.completeClaim(
_claimID
);
}
}
\ No newline at end of file
plugin/dapp/bridgevmxgo/contracts/Valset.sol
0 → 100644
View file @
c1da9d02
pragma solidity ^0.5.0;
import "../openzeppelin-solidity/contracts/math/SafeMath.sol";
import "../openzeppelin-solidity/contracts/cryptography/ECDSA.sol";
contract Valset {
using SafeMath for uint256;
using ECDSA for bytes32;
/*
* @dev: Variable declarations
*/
address public operator;
uint256 public totalPower;
uint256 public currentValsetVersion;
uint256 public validatorCount;
mapping (bytes32 => bool) public validators;
mapping(bytes32 => uint256) public powers;
/*
* @dev: Event declarations
*/
event LogValidatorAdded(
address _validator,
uint256 _power,
uint256 _currentValsetVersion,
uint256 _validatorCount,
uint256 _totalPower
);
event LogValidatorPowerUpdated(
address _validator,
uint256 _power,
uint256 _currentValsetVersion,
uint256 _validatorCount,
uint256 _totalPower
);
event LogValidatorRemoved(
address _validator,
uint256 _power,
uint256 _currentValsetVersion,
uint256 _validatorCount,
uint256 _totalPower
);
event LogValsetReset(
uint256 _newValsetVersion,
uint256 _validatorCount,
uint256 _totalPower
);
event LogValsetUpdated(
uint256 _newValsetVersion,
uint256 _validatorCount,
uint256 _totalPower
);
/*
* @dev: Modifier which restricts access to the operator.
*/
modifier onlyOperator()
{
require(
msg.sender == operator,
'Must be the operator.'
);
_;
}
/*
* @dev: Constructor
*/
constructor(
address _operator,
address[] memory _initValidators,
uint256[] memory _initPowers
)
public
{
operator = _operator;
currentValsetVersion = 0;
updateValset(
_initValidators,
_initPowers
);
}
function recover(
bytes32 _message,
bytes memory _signature
)
public
pure
returns (address)
{
bytes32 message = ethMessageHash(_message);
return verify(message, _signature);
}
/*
* @dev: addValidator
*/
function addValidator(
address _validatorAddress,
uint256 _validatorPower
)
public
onlyOperator
{
addValidatorInternal(
_validatorAddress,
_validatorPower
);
}
/*
* @dev: updateValidatorPower
*/
function updateValidatorPower(
address _validatorAddress,
uint256 _newValidatorPower
)
public
onlyOperator
{
// Create a unique key which for this validator's position in the current version of the mapping
bytes32 key = keccak256(
abi.encodePacked(
currentValsetVersion,
_validatorAddress
)
);
require(
validators[key],
"Can only update the power of active valdiators"
);
// Adjust total power by new validator power
uint256 priorPower = powers[key];
totalPower = totalPower.sub(priorPower);
totalPower = totalPower.add(_newValidatorPower);
// Set validator's new power
powers[key] = _newValidatorPower;
emit LogValidatorPowerUpdated(
_validatorAddress,
_newValidatorPower,
currentValsetVersion,
validatorCount,
totalPower
);
}
/*
* @dev: removeValidator
*/
function removeValidator(
address _validatorAddress
)
public
onlyOperator
{
// Create a unique key which for this validator's position in the current version of the mapping
bytes32 key = keccak256(
abi.encodePacked(
currentValsetVersion,
_validatorAddress
)
);
require(
validators[key],
"Can only remove active valdiators"
);
// Update validator count and total power
validatorCount = validatorCount.sub(1);
totalPower = totalPower.sub(powers[key]);
// Delete validator and power
delete validators[key];
delete powers[key];
emit LogValidatorRemoved(
_validatorAddress,
0,
currentValsetVersion,
validatorCount,
totalPower
);
}
/*
* @dev: updateValset
*/
function updateValset(
address[] memory _validators,
uint256[] memory _powers
)
public
onlyOperator
{
require(
_validators.length == _powers.length,
"Every validator must have a corresponding power"
);
resetValset();
for(uint256 i = 0; i < _validators.length; i = i.add(1)) {
addValidatorInternal(_validators[i], _powers[i]);
}
emit LogValsetUpdated(
currentValsetVersion,
validatorCount,
totalPower
);
}
/*
* @dev: isActiveValidator
*/
function isActiveValidator(
address _validatorAddress
)
public
view
returns(bool)
{
// Recreate the unique key for this address given the current mapping version
bytes32 key = keccak256(
abi.encodePacked(
currentValsetVersion,
_validatorAddress
)
);
// Return bool indicating if this address is an active validator
return validators[key];
}
/*
* @dev: getValidatorPower
*/
function getValidatorPower(
address _validatorAddress
)
external
view
returns(uint256)
{
// Recreate the unique key for this address given the current mapping version
bytes32 key = keccak256(
abi.encodePacked(
currentValsetVersion,
_validatorAddress
)
);
return powers[key];
}
/*
* @dev: recoverGas
*/
function recoverGas(
uint256 _valsetVersion,
address _validatorAddress
)
external
onlyOperator
{
require(
_valsetVersion < currentValsetVersion,
"Gas recovery only allowed for previous validator sets"
);
// Recreate the unique key used to identify this validator in the given version
bytes32 key = keccak256(
abi.encodePacked(
_valsetVersion,
_validatorAddress
)
);
// Delete from mappings and recover gas
delete(validators[key]);
delete(powers[key]);
}
/*
* @dev: addValidatorInternal
*/
function addValidatorInternal(
address _validatorAddress,
uint256 _validatorPower
)
internal
{
// Create a unique key which for this validator's position in the current version of the mapping
bytes32 key = keccak256(
abi.encodePacked(
currentValsetVersion,
_validatorAddress
)
);
validatorCount = validatorCount.add(1);
totalPower = totalPower.add(_validatorPower);
// Set validator as active and set their power
validators[key] = true;
powers[key] = _validatorPower;
emit LogValidatorAdded(
_validatorAddress,
_validatorPower,
currentValsetVersion,
validatorCount,
totalPower
);
}
/*
* @dev: resetValset
*/
function resetValset()
internal
{
currentValsetVersion = currentValsetVersion.add(1);
validatorCount = 0;
totalPower = 0;
emit LogValsetReset(
currentValsetVersion,
validatorCount,
totalPower
);
}
/*
* @dev: Verify
*
*/
function verify(
bytes32 h,
bytes memory signature
)
internal
pure
returns (address)
{
bytes32 r;
bytes32 s;
uint8 v;
// Check the signature length
if (signature.length != 65) {
return (address(0));
}
// Divide the signature in r, s and v variables
// ecrecover takes the signature parameters, and the only way to get them
// currently is to use assembly.
// solium-disable-next-line security/no-inline-assembly
assembly {
r := mload(add(signature, 32))
s := mload(add(signature, 64))
v := byte(0, mload(add(signature, 96)))
}
// Version of signature should be 27 or 28, but 0 and 1 are also possible versions
if (v < 27) {
v += 27;
}
// If the version is correct return the signer address
if (v != 27 && v != 28) {
return (address(0));
} else {
// solium-disable-next-line arg-overflow
return ecrecover(h, v, r, s);
}
}
/**
* @dev prefix a bytes32 value with "\x19Ethereum Signed Message:" and hash the result
*/
function ethMessageHash(bytes32 hash) internal pure returns (bytes32) {
return keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", hash));
}
/**
* @dev debug for pack
*/
function Debug_Packed(bytes32 hash) public pure returns (bytes memory) {
bytes memory info;
info = abi.encodePacked("\x19Ethereum Signed Message:\n32", hash);
return info;
}
/**
* @dev debug for hash
*/
function Debug_ethMessageHash(bytes32 hash) public pure returns (bytes32) {
return keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", hash));
}
}
\ No newline at end of file
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment