Commit c1da9d02 authored by hezhengjun's avatar hezhengjun

add draft sol code for bridgevmxgo

parent c81872d0
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
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
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
);
}
}
This diff is collapsed.
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
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;
}
}
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
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment