From 867e3a6d4accae95e3afe56c62818717f49e42a9 Mon Sep 17 00:00:00 2001 From: todd <81545601+todd-woko@users.noreply.github.com> Date: Sat, 12 Oct 2024 15:28:57 +0800 Subject: [PATCH] fix(734): update parameter names and references --- contract/IBridgeFeeQuote.go | 318 ++++++++++++++++++ contract/compile.sh | 2 +- solidity/contracts/bridge/BridgeFeeOracle.sol | 51 +-- solidity/contracts/bridge/BridgeFeeQuote.sol | 41 ++- solidity/test/bridge_fee_quote.ts | 11 +- 5 files changed, 383 insertions(+), 40 deletions(-) create mode 100644 contract/IBridgeFeeQuote.go diff --git a/contract/IBridgeFeeQuote.go b/contract/IBridgeFeeQuote.go new file mode 100644 index 00000000..ee874e12 --- /dev/null +++ b/contract/IBridgeFeeQuote.go @@ -0,0 +1,318 @@ +// Code generated - DO NOT EDIT. +// This file is a generated binding and any manual changes will be lost. + +package contract + +import ( + "errors" + "math/big" + "strings" + + ethereum "github.com/ethereum/go-ethereum" + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/event" +) + +// Reference imports to suppress errors if they are not otherwise used. +var ( + _ = errors.New + _ = big.NewInt + _ = strings.NewReader + _ = ethereum.NotFound + _ = bind.Bind + _ = common.Big1 + _ = types.BloomLookup + _ = event.NewSubscription + _ = abi.ConvertType +) + +// IBridgeFeeQuoteQuoteInfo is an auto generated low-level Go binding around an user-defined struct. +type IBridgeFeeQuoteQuoteInfo struct { + Id *big.Int + ChainName string + Token common.Address + Oracle common.Address + Fee *big.Int + GasLimit *big.Int + Expiry *big.Int +} + +// IBridgeFeeQuoteQuoteInput is an auto generated low-level Go binding around an user-defined struct. +type IBridgeFeeQuoteQuoteInput struct { + ChainName string + Token common.Address + Oracle common.Address + Fee *big.Int + GasLimit *big.Int + Expiry *big.Int + Signature []byte +} + +// IBridgeFeeQuoteMetaData contains all meta data concerning the IBridgeFeeQuote contract. +var IBridgeFeeQuoteMetaData = &bind.MetaData{ + ABI: "[{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_id\",\"type\":\"uint256\"}],\"name\":\"getQuoteById\",\"outputs\":[{\"components\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"internalType\":\"string\",\"name\":\"chainName\",\"type\":\"string\"},{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"oracle\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"fee\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"gasLimit\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"expiry\",\"type\":\"uint256\"}],\"internalType\":\"structIBridgeFeeQuote.QuoteInfo\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"_chainName\",\"type\":\"string\"},{\"internalType\":\"address\",\"name\":\"_token\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"}],\"name\":\"getQuoteByToken\",\"outputs\":[{\"components\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"internalType\":\"string\",\"name\":\"chainName\",\"type\":\"string\"},{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"oracle\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"fee\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"gasLimit\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"expiry\",\"type\":\"uint256\"}],\"internalType\":\"structIBridgeFeeQuote.QuoteInfo\",\"name\":\"\",\"type\":\"tuple\"},{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"_chainName\",\"type\":\"string\"}],\"name\":\"getQuoteList\",\"outputs\":[{\"components\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"internalType\":\"string\",\"name\":\"chainName\",\"type\":\"string\"},{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"oracle\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"fee\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"gasLimit\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"expiry\",\"type\":\"uint256\"}],\"internalType\":\"structIBridgeFeeQuote.QuoteInfo[]\",\"name\":\"\",\"type\":\"tuple[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"string\",\"name\":\"chainName\",\"type\":\"string\"},{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"oracle\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"fee\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"gasLimit\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"expiry\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"signature\",\"type\":\"bytes\"}],\"internalType\":\"structIBridgeFeeQuote.QuoteInput[]\",\"name\":\"_inputs\",\"type\":\"tuple[]\"}],\"name\":\"quote\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", +} + +// IBridgeFeeQuoteABI is the input ABI used to generate the binding from. +// Deprecated: Use IBridgeFeeQuoteMetaData.ABI instead. +var IBridgeFeeQuoteABI = IBridgeFeeQuoteMetaData.ABI + +// IBridgeFeeQuote is an auto generated Go binding around an Ethereum contract. +type IBridgeFeeQuote struct { + IBridgeFeeQuoteCaller // Read-only binding to the contract + IBridgeFeeQuoteTransactor // Write-only binding to the contract + IBridgeFeeQuoteFilterer // Log filterer for contract events +} + +// IBridgeFeeQuoteCaller is an auto generated read-only Go binding around an Ethereum contract. +type IBridgeFeeQuoteCaller struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// IBridgeFeeQuoteTransactor is an auto generated write-only Go binding around an Ethereum contract. +type IBridgeFeeQuoteTransactor struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// IBridgeFeeQuoteFilterer is an auto generated log filtering Go binding around an Ethereum contract events. +type IBridgeFeeQuoteFilterer struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// IBridgeFeeQuoteSession is an auto generated Go binding around an Ethereum contract, +// with pre-set call and transact options. +type IBridgeFeeQuoteSession struct { + Contract *IBridgeFeeQuote // Generic contract binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// IBridgeFeeQuoteCallerSession is an auto generated read-only Go binding around an Ethereum contract, +// with pre-set call options. +type IBridgeFeeQuoteCallerSession struct { + Contract *IBridgeFeeQuoteCaller // Generic contract caller binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session +} + +// IBridgeFeeQuoteTransactorSession is an auto generated write-only Go binding around an Ethereum contract, +// with pre-set transact options. +type IBridgeFeeQuoteTransactorSession struct { + Contract *IBridgeFeeQuoteTransactor // Generic contract transactor binding to set the session for + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// IBridgeFeeQuoteRaw is an auto generated low-level Go binding around an Ethereum contract. +type IBridgeFeeQuoteRaw struct { + Contract *IBridgeFeeQuote // Generic contract binding to access the raw methods on +} + +// IBridgeFeeQuoteCallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract. +type IBridgeFeeQuoteCallerRaw struct { + Contract *IBridgeFeeQuoteCaller // Generic read-only contract binding to access the raw methods on +} + +// IBridgeFeeQuoteTransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract. +type IBridgeFeeQuoteTransactorRaw struct { + Contract *IBridgeFeeQuoteTransactor // Generic write-only contract binding to access the raw methods on +} + +// NewIBridgeFeeQuote creates a new instance of IBridgeFeeQuote, bound to a specific deployed contract. +func NewIBridgeFeeQuote(address common.Address, backend bind.ContractBackend) (*IBridgeFeeQuote, error) { + contract, err := bindIBridgeFeeQuote(address, backend, backend, backend) + if err != nil { + return nil, err + } + return &IBridgeFeeQuote{IBridgeFeeQuoteCaller: IBridgeFeeQuoteCaller{contract: contract}, IBridgeFeeQuoteTransactor: IBridgeFeeQuoteTransactor{contract: contract}, IBridgeFeeQuoteFilterer: IBridgeFeeQuoteFilterer{contract: contract}}, nil +} + +// NewIBridgeFeeQuoteCaller creates a new read-only instance of IBridgeFeeQuote, bound to a specific deployed contract. +func NewIBridgeFeeQuoteCaller(address common.Address, caller bind.ContractCaller) (*IBridgeFeeQuoteCaller, error) { + contract, err := bindIBridgeFeeQuote(address, caller, nil, nil) + if err != nil { + return nil, err + } + return &IBridgeFeeQuoteCaller{contract: contract}, nil +} + +// NewIBridgeFeeQuoteTransactor creates a new write-only instance of IBridgeFeeQuote, bound to a specific deployed contract. +func NewIBridgeFeeQuoteTransactor(address common.Address, transactor bind.ContractTransactor) (*IBridgeFeeQuoteTransactor, error) { + contract, err := bindIBridgeFeeQuote(address, nil, transactor, nil) + if err != nil { + return nil, err + } + return &IBridgeFeeQuoteTransactor{contract: contract}, nil +} + +// NewIBridgeFeeQuoteFilterer creates a new log filterer instance of IBridgeFeeQuote, bound to a specific deployed contract. +func NewIBridgeFeeQuoteFilterer(address common.Address, filterer bind.ContractFilterer) (*IBridgeFeeQuoteFilterer, error) { + contract, err := bindIBridgeFeeQuote(address, nil, nil, filterer) + if err != nil { + return nil, err + } + return &IBridgeFeeQuoteFilterer{contract: contract}, nil +} + +// bindIBridgeFeeQuote binds a generic wrapper to an already deployed contract. +func bindIBridgeFeeQuote(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) { + parsed, err := IBridgeFeeQuoteMetaData.GetAbi() + if err != nil { + return nil, err + } + return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil +} + +// Call invokes the (constant) contract method with params as input values and +// sets the output to result. The result type might be a single field for simple +// returns, a slice of interfaces for anonymous returns and a struct for named +// returns. +func (_IBridgeFeeQuote *IBridgeFeeQuoteRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _IBridgeFeeQuote.Contract.IBridgeFeeQuoteCaller.contract.Call(opts, result, method, params...) +} + +// Transfer initiates a plain transaction to move funds to the contract, calling +// its default method if one is available. +func (_IBridgeFeeQuote *IBridgeFeeQuoteRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _IBridgeFeeQuote.Contract.IBridgeFeeQuoteTransactor.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_IBridgeFeeQuote *IBridgeFeeQuoteRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _IBridgeFeeQuote.Contract.IBridgeFeeQuoteTransactor.contract.Transact(opts, method, params...) +} + +// Call invokes the (constant) contract method with params as input values and +// sets the output to result. The result type might be a single field for simple +// returns, a slice of interfaces for anonymous returns and a struct for named +// returns. +func (_IBridgeFeeQuote *IBridgeFeeQuoteCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _IBridgeFeeQuote.Contract.contract.Call(opts, result, method, params...) +} + +// Transfer initiates a plain transaction to move funds to the contract, calling +// its default method if one is available. +func (_IBridgeFeeQuote *IBridgeFeeQuoteTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _IBridgeFeeQuote.Contract.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_IBridgeFeeQuote *IBridgeFeeQuoteTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _IBridgeFeeQuote.Contract.contract.Transact(opts, method, params...) +} + +// GetQuoteById is a free data retrieval call binding the contract method 0xa8541c17. +// +// Solidity: function getQuoteById(uint256 _id) view returns((uint256,string,address,address,uint256,uint256,uint256)) +func (_IBridgeFeeQuote *IBridgeFeeQuoteCaller) GetQuoteById(opts *bind.CallOpts, _id *big.Int) (IBridgeFeeQuoteQuoteInfo, error) { + var out []interface{} + err := _IBridgeFeeQuote.contract.Call(opts, &out, "getQuoteById", _id) + + if err != nil { + return *new(IBridgeFeeQuoteQuoteInfo), err + } + + out0 := *abi.ConvertType(out[0], new(IBridgeFeeQuoteQuoteInfo)).(*IBridgeFeeQuoteQuoteInfo) + + return out0, err + +} + +// GetQuoteById is a free data retrieval call binding the contract method 0xa8541c17. +// +// Solidity: function getQuoteById(uint256 _id) view returns((uint256,string,address,address,uint256,uint256,uint256)) +func (_IBridgeFeeQuote *IBridgeFeeQuoteSession) GetQuoteById(_id *big.Int) (IBridgeFeeQuoteQuoteInfo, error) { + return _IBridgeFeeQuote.Contract.GetQuoteById(&_IBridgeFeeQuote.CallOpts, _id) +} + +// GetQuoteById is a free data retrieval call binding the contract method 0xa8541c17. +// +// Solidity: function getQuoteById(uint256 _id) view returns((uint256,string,address,address,uint256,uint256,uint256)) +func (_IBridgeFeeQuote *IBridgeFeeQuoteCallerSession) GetQuoteById(_id *big.Int) (IBridgeFeeQuoteQuoteInfo, error) { + return _IBridgeFeeQuote.Contract.GetQuoteById(&_IBridgeFeeQuote.CallOpts, _id) +} + +// GetQuoteByToken is a free data retrieval call binding the contract method 0xadcdd23a. +// +// Solidity: function getQuoteByToken(string _chainName, address _token, uint256 _amount) view returns((uint256,string,address,address,uint256,uint256,uint256), bool) +func (_IBridgeFeeQuote *IBridgeFeeQuoteCaller) GetQuoteByToken(opts *bind.CallOpts, _chainName string, _token common.Address, _amount *big.Int) (IBridgeFeeQuoteQuoteInfo, bool, error) { + var out []interface{} + err := _IBridgeFeeQuote.contract.Call(opts, &out, "getQuoteByToken", _chainName, _token, _amount) + + if err != nil { + return *new(IBridgeFeeQuoteQuoteInfo), *new(bool), err + } + + out0 := *abi.ConvertType(out[0], new(IBridgeFeeQuoteQuoteInfo)).(*IBridgeFeeQuoteQuoteInfo) + out1 := *abi.ConvertType(out[1], new(bool)).(*bool) + + return out0, out1, err + +} + +// GetQuoteByToken is a free data retrieval call binding the contract method 0xadcdd23a. +// +// Solidity: function getQuoteByToken(string _chainName, address _token, uint256 _amount) view returns((uint256,string,address,address,uint256,uint256,uint256), bool) +func (_IBridgeFeeQuote *IBridgeFeeQuoteSession) GetQuoteByToken(_chainName string, _token common.Address, _amount *big.Int) (IBridgeFeeQuoteQuoteInfo, bool, error) { + return _IBridgeFeeQuote.Contract.GetQuoteByToken(&_IBridgeFeeQuote.CallOpts, _chainName, _token, _amount) +} + +// GetQuoteByToken is a free data retrieval call binding the contract method 0xadcdd23a. +// +// Solidity: function getQuoteByToken(string _chainName, address _token, uint256 _amount) view returns((uint256,string,address,address,uint256,uint256,uint256), bool) +func (_IBridgeFeeQuote *IBridgeFeeQuoteCallerSession) GetQuoteByToken(_chainName string, _token common.Address, _amount *big.Int) (IBridgeFeeQuoteQuoteInfo, bool, error) { + return _IBridgeFeeQuote.Contract.GetQuoteByToken(&_IBridgeFeeQuote.CallOpts, _chainName, _token, _amount) +} + +// GetQuoteList is a free data retrieval call binding the contract method 0x398a0e6b. +// +// Solidity: function getQuoteList(string _chainName) view returns((uint256,string,address,address,uint256,uint256,uint256)[]) +func (_IBridgeFeeQuote *IBridgeFeeQuoteCaller) GetQuoteList(opts *bind.CallOpts, _chainName string) ([]IBridgeFeeQuoteQuoteInfo, error) { + var out []interface{} + err := _IBridgeFeeQuote.contract.Call(opts, &out, "getQuoteList", _chainName) + + if err != nil { + return *new([]IBridgeFeeQuoteQuoteInfo), err + } + + out0 := *abi.ConvertType(out[0], new([]IBridgeFeeQuoteQuoteInfo)).(*[]IBridgeFeeQuoteQuoteInfo) + + return out0, err + +} + +// GetQuoteList is a free data retrieval call binding the contract method 0x398a0e6b. +// +// Solidity: function getQuoteList(string _chainName) view returns((uint256,string,address,address,uint256,uint256,uint256)[]) +func (_IBridgeFeeQuote *IBridgeFeeQuoteSession) GetQuoteList(_chainName string) ([]IBridgeFeeQuoteQuoteInfo, error) { + return _IBridgeFeeQuote.Contract.GetQuoteList(&_IBridgeFeeQuote.CallOpts, _chainName) +} + +// GetQuoteList is a free data retrieval call binding the contract method 0x398a0e6b. +// +// Solidity: function getQuoteList(string _chainName) view returns((uint256,string,address,address,uint256,uint256,uint256)[]) +func (_IBridgeFeeQuote *IBridgeFeeQuoteCallerSession) GetQuoteList(_chainName string) ([]IBridgeFeeQuoteQuoteInfo, error) { + return _IBridgeFeeQuote.Contract.GetQuoteList(&_IBridgeFeeQuote.CallOpts, _chainName) +} + +// Quote is a paid mutator transaction binding the contract method 0x9533ae43. +// +// Solidity: function quote((string,address,address,uint256,uint256,uint256,bytes)[] _inputs) returns(bool) +func (_IBridgeFeeQuote *IBridgeFeeQuoteTransactor) Quote(opts *bind.TransactOpts, _inputs []IBridgeFeeQuoteQuoteInput) (*types.Transaction, error) { + return _IBridgeFeeQuote.contract.Transact(opts, "quote", _inputs) +} + +// Quote is a paid mutator transaction binding the contract method 0x9533ae43. +// +// Solidity: function quote((string,address,address,uint256,uint256,uint256,bytes)[] _inputs) returns(bool) +func (_IBridgeFeeQuote *IBridgeFeeQuoteSession) Quote(_inputs []IBridgeFeeQuoteQuoteInput) (*types.Transaction, error) { + return _IBridgeFeeQuote.Contract.Quote(&_IBridgeFeeQuote.TransactOpts, _inputs) +} + +// Quote is a paid mutator transaction binding the contract method 0x9533ae43. +// +// Solidity: function quote((string,address,address,uint256,uint256,uint256,bytes)[] _inputs) returns(bool) +func (_IBridgeFeeQuote *IBridgeFeeQuoteTransactorSession) Quote(_inputs []IBridgeFeeQuoteQuoteInput) (*types.Transaction, error) { + return _IBridgeFeeQuote.Contract.Quote(&_IBridgeFeeQuote.TransactOpts, _inputs) +} diff --git a/contract/compile.sh b/contract/compile.sh index 17cfd70c..a2814f59 100755 --- a/contract/compile.sh +++ b/contract/compile.sh @@ -31,7 +31,7 @@ echo "===> Compiling contracts" [[ ! -d "$project_dir/contract/artifacts" ]] && mkdir -p "$project_dir/contract/artifacts" # add core contracts -contracts=(WFXUpgradable FIP20Upgradable ICrossChain IStaking IFxBridgeLogic IBridgeCallback IError) +contracts=(WFXUpgradable FIP20Upgradable ICrossChain IStaking IFxBridgeLogic IBridgeCallback IError IBridgeFeeQuote) contracts_test=(CrossChainTest StakingTest) # add 3rd party contracts contracts+=(ERC1967Proxy) diff --git a/solidity/contracts/bridge/BridgeFeeOracle.sol b/solidity/contracts/bridge/BridgeFeeOracle.sol index f745b58d..10fc696d 100644 --- a/solidity/contracts/bridge/BridgeFeeOracle.sol +++ b/solidity/contracts/bridge/BridgeFeeOracle.sol @@ -5,6 +5,7 @@ import {AccessControlUpgradeable} from "@openzeppelin/contracts-upgradeable/acce import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; import {UUPSUpgradeable} from "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol"; import {ReentrancyGuardUpgradeable} from "@openzeppelin/contracts-upgradeable/security/ReentrancyGuardUpgradeable.sol"; +import {EnumerableSetUpgradeable} from "@openzeppelin/contracts-upgradeable/utils/structs/EnumerableSetUpgradeable.sol"; import {IBridgeFeeOracle} from "./IBridgeFee.sol"; import {ICrossChain} from "./ICrossChain.sol"; @@ -15,35 +16,43 @@ contract BridgeFeeOracle is AccessControlUpgradeable, ReentrancyGuardUpgradeable { + using EnumerableSetUpgradeable for EnumerableSetUpgradeable.AddressSet; + bytes32 public constant QUOTE_ROLE = keccak256("QUOTE_ROLE"); address public crossChainContract; address public defaultOracle; struct State { - bool isBlackListed; + bool isBlacklisted; bool isActive; } - address[] public oracles; + EnumerableSetUpgradeable.AddressSet private oracles; mapping(address => State) public oracleStatus; function initialize(address _crossChain) public initializer { - crossChainContract = _crossChain; - - _grantRole(DEFAULT_ADMIN_ROLE, msg.sender); - __AccessControl_init(); __UUPSUpgradeable_init(); __ReentrancyGuard_init(); + + crossChainContract = _crossChain; + + _grantRole(DEFAULT_ADMIN_ROLE, msg.sender); } + /** + * @notice Checks if an oracle is online for a given chain. + * @param _chainName The name of the chain. + * @param _oracle The address of the oracle. + * @return bool indicating if the oracle is online. + */ function isOnline( string memory _chainName, address _oracle - ) external onlyRole(QUOTE_ROLE) returns (bool) { + ) external onlyRole(QUOTE_ROLE) nonReentrant returns (bool) { if (oracleStatus[_oracle].isActive) return true; - if (oracleStatus[_oracle].isBlackListed) return false; + if (oracleStatus[_oracle].isBlacklisted) return false; if (!ICrossChain(crossChainContract).hasOracle(_chainName, _oracle)) { return false; } @@ -53,39 +62,33 @@ contract BridgeFeeOracle is return false; } oracleStatus[_oracle] = State(false, true); - oracles.push(_oracle); + oracles.add(_oracle); return true; } function blackOracle( address _oracle - ) external onlyRole(DEFAULT_ADMIN_ROLE) { - if (oracleStatus[_oracle].isBlackListed) return; + ) external onlyRole(DEFAULT_ADMIN_ROLE) nonReentrant { + if (oracleStatus[_oracle].isBlacklisted) return; if (oracleStatus[_oracle].isActive) { oracleStatus[_oracle].isActive = false; - removeOracle(_oracle); - } - oracleStatus[_oracle].isBlackListed = true; - } - - function removeOracle(address _oracle) internal { - for (uint256 i = 0; i < oracles.length; i++) { - if (oracles[i] == _oracle) { - oracles[i] = oracles[oracles.length - 1]; - oracles.pop(); - break; - } + oracles.remove(_oracle); } + oracleStatus[_oracle].isBlacklisted = true; } function setDefaultOracle( address _defaultOracle ) external onlyRole(DEFAULT_ADMIN_ROLE) { + if (!oracles.contains(_defaultOracle)) { + oracleStatus[_defaultOracle] = State(false, true); + oracles.add(_defaultOracle); + } defaultOracle = _defaultOracle; } function getOracleList() external view returns (address[] memory) { - return oracles; + return oracles.values(); } function _authorizeUpgrade( diff --git a/solidity/contracts/bridge/BridgeFeeQuote.sol b/solidity/contracts/bridge/BridgeFeeQuote.sol index 357758b2..12dee172 100644 --- a/solidity/contracts/bridge/BridgeFeeQuote.sol +++ b/solidity/contracts/bridge/BridgeFeeQuote.sol @@ -30,7 +30,7 @@ contract BridgeFeeQuote is using SafeERC20Upgradeable for IERC20MetadataUpgradeable; using ECDSAUpgradeable for bytes32; - struct Assert { + struct Asset { bool isActive; address[] tokens; } @@ -49,7 +49,7 @@ contract BridgeFeeQuote is string[] public chainNames; // chainName -> Assert - mapping(string => Assert) public assets; + mapping(string => Asset) public assets; // Only one quote is allowed per chainName + token + oracle mapping(bytes => Quote) internal quotes; // key: chainName + token + oracle @@ -74,6 +74,11 @@ contract BridgeFeeQuote is uint256 expiry ); + /** + * @notice Quote the bridge fee for a given chainName, token and oracle. + * @param _inputs QuoteInput[] The quote inputs. + * @return bool Whether the quote is successful. + */ function quote( QuoteInput[] memory _inputs ) external nonReentrant returns (bool) { @@ -111,7 +116,11 @@ contract BridgeFeeQuote is return true; } - // get quote list by chainName + /** + * @notice Get the quote list for a given chainName. + * @param _chainName The name of the chain. + * @return QuoteInfo[] The quote list. + */ function getQuoteList( string memory _chainName ) external view returns (QuoteInfo[] memory) { @@ -150,6 +159,11 @@ contract BridgeFeeQuote is return quotesList; } + /** + * @notice Get the quote by id. + * @param _id The id of the quote. + * @return q QuoteInfo The quote. + */ function getQuoteById( uint256 _id ) external view returns (QuoteInfo memory q) { @@ -171,10 +185,18 @@ contract BridgeFeeQuote is }); } + /** + * @notice Get the quote by token. + * @param _chainName The name of the chain. + * @param _token The address of the token. + * @param _amount The bridge fee amount of the token. + * @return QuoteInfo The quote. + * @return bool Whether the quote is expired. + */ function getQuoteByToken( string memory _chainName, address _token, - uint256 + uint256 _amount ) external view returns (QuoteInfo memory, bool) { if (!assets[_chainName].isActive) { revert ChainNameInvalid(); @@ -192,7 +214,8 @@ contract BridgeFeeQuote is gasLimit: quotes[asset].gasLimit, expiry: quotes[asset].expiry }), - quotes[asset].expiry > block.timestamp + quotes[asset].expiry > block.timestamp && + _amount >= quotes[asset].fee ); } @@ -261,9 +284,7 @@ contract BridgeFeeQuote is uint256 _expiry ) public pure returns (bytes32) { return - keccak256( - abi.encodePacked(_chainName, _token, _fee, _gasLimit, _expiry) - ); + keccak256(abi.encode(_chainName, _token, _fee, _gasLimit, _expiry)); } function packAsset( @@ -291,7 +312,7 @@ contract BridgeFeeQuote is string memory _chainName, address _token ) public view returns (bool) { - Assert memory asset = assets[_chainName]; + Asset memory asset = assets[_chainName]; for (uint256 i = 0; i < asset.tokens.length; i++) { if (asset.tokens[i] == _token) { return asset.isActive; @@ -329,7 +350,7 @@ contract BridgeFeeQuote is if (assets[_chainName].isActive) { revert ChainNameAlreadyExists(); } - assets[_chainName] = Assert({isActive: true, tokens: _tokens}); + assets[_chainName] = Asset({isActive: true, tokens: _tokens}); chainNames.push(_chainName); return true; } diff --git a/solidity/test/bridge_fee_quote.ts b/solidity/test/bridge_fee_quote.ts index 327cc027..2f912577 100644 --- a/solidity/test/bridge_fee_quote.ts +++ b/solidity/test/bridge_fee_quote.ts @@ -63,7 +63,7 @@ describe("BridgeFeeQuoteUpgradeable", function () { it("should block an oracle correctly", async function () { await bridgeFeeOracle.blackOracle(oracle.address); const oracleStatus = await bridgeFeeOracle.oracleStatus(oracle.address); - expect(oracleStatus.isBlackListed).to.be.true; + expect(oracleStatus.isBlacklisted).to.be.true; }); }); @@ -99,7 +99,7 @@ describe("BridgeFeeQuoteUpgradeable", function () { }); it("should revert when trying to get quotes for an inactive chain", async function () { - const chainName = ethers.encodeBytes32String("InactiveChain"); + const chainName = "InactiveChain"; await expect( bridgeFeeQuote.getQuoteList(chainName) ).to.be.revertedWithCustomError(bridgeFeeQuote, "ChainNameInvalid"); @@ -220,7 +220,7 @@ describe("BridgeFeeQuoteUpgradeable", function () { const [quote, expire] = await bridgeFeeQuote.getQuoteByToken( chainName, token1.address, - 0 + 2 ); expect(expire).to.be.true; expect(quote.fee).to.be.equal(fee); @@ -237,11 +237,12 @@ async function generateSignature( expiry: number, wallet: HDNodeWallet ): Promise { - const hash = ethers.solidityPackedKeccak256( + const abiCoder = new ethers.AbiCoder(); + const coderHash = abiCoder.encode( ["string", "address", "uint256", "uint256", "uint256"], [chainName, token, fee, gasLimit, expiry] ); - + const hash = ethers.keccak256(coderHash); const messageHash = ethers.solidityPackedKeccak256( ["string", "bytes32"], [messagePrefix, hash]