Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Mint wrapped NAM on the Vault address #61

Closed
wants to merge 12 commits into from
66 changes: 7 additions & 59 deletions contracts/contract/Bridge.sol
Original file line number Diff line number Diff line change
Expand Up @@ -6,32 +6,19 @@ import "../interface/IProxy.sol";
import "../interface/IVault.sol";

import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import "@openzeppelin/contracts/utils/cryptography/ECDSA.sol";
import "@openzeppelin/contracts/security/ReentrancyGuard.sol";
import "@openzeppelin/contracts/utils/cryptography/MerkleProof.sol";

library TokenCaps {
struct Token {
bool exists;
bool isWhitelisted;
uint256 cap;
}
}

contract Bridge is IBridge, ReentrancyGuard {
uint8 private immutable version;
uint256 private immutable thresholdVotingPower;

bytes32 public currentValidatorSetHash;
bytes32 public nextValidatorSetHash;

uint256 private transferToErc20Nonce = 0;
uint256 private transferToNamadaNonce = 0;

uint256 private constant MAX_NONCE_INCREMENT = 10000;

mapping(address => TokenCaps.Token) private tokenWhiteList;
uint256 public transferToErc20Nonce = 0;
uint256 public transferToNamadaNonce = 0;

IProxy private proxy;

Expand All @@ -41,14 +28,11 @@ contract Bridge is IBridge, ReentrancyGuard {
uint256[] memory _currentPowers,
address[] memory _nextValidators,
uint256[] memory _nextPowers,
address[] memory _tokenList,
uint256[] memory _tokenCap,
uint256 _thresholdVotingPower,
IProxy _proxy
) {
require(_currentValidators.length == _currentPowers.length, "Mismatch array length.");
require(_nextValidators.length == _nextPowers.length, "Mismatch array length.");
require(_tokenList.length == _tokenCap.length, "Invalid token whitelist.");
require(_isEnoughVotingPower(_currentPowers, _thresholdVotingPower), "Invalid voting power threshold.");
require(_isEnoughVotingPower(_nextPowers, _thresholdVotingPower), "Invalid voting power threshold.");

Expand All @@ -57,12 +41,6 @@ contract Bridge is IBridge, ReentrancyGuard {
currentValidatorSetHash = _computeValidatorSetHash(_currentValidators, _currentPowers, 0);
nextValidatorSetHash = _computeValidatorSetHash(_nextValidators, _nextPowers, 0);

for (uint256 i = 0; i < _tokenList.length; ++i) {
address tokenAddress = _tokenList[i];
uint256 tokenCap = _tokenCap[i];
tokenWhiteList[tokenAddress] = TokenCaps.Token(true, true, tokenCap);
}

proxy = IProxy(_proxy);
}

Expand Down Expand Up @@ -100,11 +78,10 @@ contract Bridge is IBridge, ReentrancyGuard {
);

bytes32[] memory leaves = new bytes32[](relayProof.transfers.length);
bool[] memory validTransferableToken = new bool[](relayProof.transfers.length);

for (uint256 i = 0; i < relayProof.transfers.length; i++) {
bytes32 transferHash = _computeTransferHash(relayProof.transfers[i]);
leaves[i] = transferHash;
validTransferableToken[i] = tokenWhiteList[relayProof.transfers[i].from].exists;
}

bytes32 root = MerkleProof.processMultiProof(relayProof.proof, relayProof.proofFlags, leaves);
Expand All @@ -116,12 +93,7 @@ contract Bridge is IBridge, ReentrancyGuard {
address vaultAddress = proxy.getContract("vault");
IVault vault = IVault(vaultAddress);

bool[] memory completedTransfers = vault.batchTransferToErc20(relayProof.transfers, validTransferableToken);
for (uint256 i = 0; i < relayProof.transfers.length; i++) {
if (completedTransfers[i]) {
tokenWhiteList[relayProof.transfers[i].from].cap += relayProof.transfers[i].amount;
}
}
bool[] memory completedTransfers = vault.batchTransferToErc20(relayProof.transfers);

emit TransferToErc(relayProof.batchNonce, relayProof.transfers, completedTransfers, relayProof.relayerAddress);
}
Expand All @@ -133,43 +105,24 @@ contract Bridge is IBridge, ReentrancyGuard {
bool[] memory validMap = new bool[](_transfers.length);

for (uint256 i = 0; i < _transfers.length; ++i) {
if (
!tokenWhiteList[_transfers[i].from].isWhitelisted ||
_transfers[i].amount >= tokenWhiteList[_transfers[i].from].cap
) {
validMap[i] = false;
continue;
}

tokenWhiteList[_transfers[i].from].cap -= _transfers[i].amount;

try IERC20(_transfers[i].from).transferFrom(msg.sender, vaultAddress, _transfers[i].amount) {
validMap[i] = true;
} catch {
validMap[i] = false;
continue;
}
}

uint256 currentNonce = transferToNamadaNonce;
transferToNamadaNonce = transferToNamadaNonce + 1;
emit TransferToNamada(transferToNamadaNonce, _transfers, validMap, confirmations);

emit TransferToNamada(currentNonce, _transfers, validMap, confirmations);
}

function updateValidatorSetHash(bytes32 _validatorSetHash) external onlyLatestGovernanceContract {
currentValidatorSetHash = nextValidatorSetHash;
nextValidatorSetHash = _validatorSetHash;
}

function updateTokenWhitelist(
address[] calldata _tokens,
uint256[] calldata _tokensCap
) external onlyLatestGovernanceContract {
require(_tokens.length == _tokensCap.length, "Invalid inputs.");
for (uint256 i = 0; i < _tokens.length; i++) {
tokenWhiteList[_tokens[i]] = TokenCaps.Token(true, true, _tokensCap[i]);
}
}

function checkValidatorSetVotingPowerAndSignature(
ValidatorSetArgs calldata validatorSet,
Signature[] calldata _signatures,
Expand All @@ -190,11 +143,6 @@ contract Bridge is IBridge, ReentrancyGuard {
return powerAccumulator >= thresholdVotingPower;
}

function getWhitelistAmountFor(address tokenAddress) external view returns (uint256) {
require(tokenWhiteList[tokenAddress].isWhitelisted, "Not whitelisted.");
return tokenWhiteList[tokenAddress].cap;
}

function isValidSignature(
address _signer,
bytes32 _messageHash,
Expand Down
55 changes: 16 additions & 39 deletions contracts/contract/Governance.sol
Original file line number Diff line number Diff line change
Expand Up @@ -13,28 +13,31 @@ contract Governance is IGovernance, ReentrancyGuard {
uint8 private immutable version;
uint256 private immutable thresholdVotingPower;

bytes32 public validatorSetHash;
bytes32 public currentValidatorSetHash;
bytes32 public nextValidatorSetHash;
uint256 public validatorSetNonce = 0;

uint256 public whitelistNonce = 0;

uint256 private constant MAX_NONCE_INCREMENT = 10000;

IProxy private proxy;

constructor(
uint8 _version,
address[] memory _validators,
uint256[] memory _powers,
address[] memory _currentValidators,
uint256[] memory _currentPowers,
address[] memory _nextValidators,
uint256[] memory _nextPowers,
uint256 _thresholdVotingPower,
IProxy _proxy
) {
require(_validators.length == _powers.length, "Mismatch array length.");
require(_isEnoughVotingPower(_powers, _thresholdVotingPower), "Invalid voting power threshold.");
require(_currentValidators.length == _currentPowers.length, "Mismatch array length.");
require(_nextValidators.length == _nextPowers.length, "Mismatch array length.");
require(_isEnoughVotingPower(_currentPowers, _thresholdVotingPower), "Invalid voting power threshold.");
require(_isEnoughVotingPower(_nextPowers, _thresholdVotingPower), "Invalid voting power threshold.");

version = _version;
validatorSetHash = _computeValidatorSetHash(_validators, _powers, 0);
thresholdVotingPower = _thresholdVotingPower;
currentValidatorSetHash = _computeValidatorSetHash(_currentValidators, _currentPowers, 0);
nextValidatorSetHash = _computeValidatorSetHash(_nextValidators, _nextPowers, 0);

proxy = IProxy(_proxy);
}

Expand Down Expand Up @@ -108,46 +111,20 @@ contract Governance is IGovernance, ReentrancyGuard {

require(bridge.authorize(_currentValidatorSetArgs, _signatures, messageHash), "Unauthorized.");

validatorSetHash = _governanceValidatorSetHash;
currentValidatorSetHash = nextValidatorSetHash;
nextValidatorSetHash = _governanceValidatorSetHash;
bridge.updateValidatorSetHash(_bridgeValidatorSetHash);

emit ValidatorSetUpdate(validatorSetNonce, _governanceValidatorSetHash, _bridgeValidatorSetHash);
}

function updateBridgeWhitelist(
ValidatorSetArgs calldata _currentValidatorSetArgs,
address[] calldata _tokens,
uint256[] calldata _tokensCap,
Signature[] calldata _signatures
) external {
require(
_currentValidatorSetArgs.validators.length == _currentValidatorSetArgs.powers.length &&
_currentValidatorSetArgs.validators.length == _signatures.length,
"Malformed input."
);

address bridgeAddress = proxy.getContract("bridge");
IBridge bridge = IBridge(bridgeAddress);

bytes32 messageHash = keccak256(
abi.encode(version, "updateBridgeWhitelist", _tokens, _tokensCap, whitelistNonce)
);

require(bridge.authorize(_currentValidatorSetArgs, _signatures, messageHash), "Unauthorized.");

whitelistNonce = whitelistNonce + 1;
bridge.updateTokenWhitelist(_tokens, _tokensCap);

emit UpdateBridgeWhitelist(whitelistNonce - 1, _tokens, _tokensCap);
}

function authorize(
ValidatorSetArgs calldata _validators,
Signature[] calldata _signatures,
bytes32 _messageHash
) private view returns (bool) {
require(_validators.validators.length == _validators.powers.length, "Malformed input.");
require(_computeValidatorSetHash(_validators) == validatorSetHash, "Invalid validatorSetHash.");
require(_computeValidatorSetHash(_validators) == currentValidatorSetHash, "Invalid currentValidatorSetHash.");

uint256 powerAccumulator = 0;
for (uint256 i = 0; i < _validators.powers.length; i++) {
Expand Down
13 changes: 3 additions & 10 deletions contracts/contract/Token.sol
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,9 @@ pragma solidity ^0.8.19;
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";

contract Token is ERC20 {
constructor(
string memory name,
string memory symbol,
uint256[] memory initialSupplies,
address[] memory addresses
) ERC20(name, symbol) {
require(initialSupplies.length == addresses.length, "Invalid parameters.");
uint256 private constant MAX_UINT = 2 ** 256 - 1;

for (uint256 i = 0; i < addresses.length; ++i) {
_mint(addresses[i], initialSupplies[i]);
}
constructor(address _vaultAddress, string memory _name, string memory _symbol) ERC20(_name, _symbol) {
_mint(_vaultAddress, MAX_UINT);
}
}
8 changes: 1 addition & 7 deletions contracts/contract/Vault.sol
Original file line number Diff line number Diff line change
Expand Up @@ -14,17 +14,11 @@ contract Vault is IVault {
}

function batchTransferToErc20(
Erc20Transfer[] calldata _transfers,
bool[] calldata _validTransfers
Erc20Transfer[] calldata _transfers
) external onlyLatestBridgeContract returns (bool[] memory) {
bool[] memory transfersStatus = new bool[](_transfers.length);

for (uint256 i = 0; i < _transfers.length; ++i) {
if (!_validTransfers[i]) {
transfersStatus[i] = false;
continue;
}

try IERC20(_transfers[i].from).transfer(_transfers[i].to, _transfers[i].amount) {
transfersStatus[i] = true;
} catch {
Expand Down
2 changes: 0 additions & 2 deletions contracts/interface/IBridge.sol
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,5 @@ interface IBridge is ICommon {

function transferToErc(RelayProof calldata relayProof) external;

function updateTokenWhitelist(address[] calldata tokens, uint256[] calldata tokensCap) external;

function updateValidatorSetHash(bytes32 _validatorSetHash) external;
}
6 changes: 6 additions & 0 deletions contracts/interface/ICommon.sol
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,13 @@ interface ICommon {
string to;
}

enum Erc20TransferKind {
ERC20,
NUT
}

struct Erc20Transfer {
Erc20TransferKind kind;
address from;
address to;
uint256 amount;
Expand Down
8 changes: 0 additions & 8 deletions contracts/interface/IGovernance.sol
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ interface IGovernance is ICommon {
);
event NewContract(string indexed name, address addr);
event UpgradedContract(string indexed name, address addr);
event UpdateBridgeWhitelist(uint256 indexed nonce, address[] tokens, uint256[] tokenCap);

function upgradeContract(
ValidatorSetArgs calldata validators,
Expand Down Expand Up @@ -41,11 +40,4 @@ interface IGovernance is ICommon {
Signature[] calldata signatures,
uint256 nonce
) external;

function updateBridgeWhitelist(
ValidatorSetArgs calldata currentValidatorSetArgs,
address[] calldata tokens,
uint256[] calldata tokensCap,
Signature[] calldata signatures
) external;
}
7 changes: 1 addition & 6 deletions contracts/interface/IVault.sol
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,5 @@ pragma solidity ^0.8.19;
import "./ICommon.sol";

interface IVault is ICommon {
event InvalidTransfer(Erc20Transfer transfer);

function batchTransferToErc20(
Erc20Transfer[] calldata tranfers,
bool[] calldata validTransfers
) external returns (bool[] memory);
function batchTransferToErc20(Erc20Transfer[] calldata tranfers) external returns (bool[] memory);
}
Loading
Loading