Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,15 @@ class [[eosio::contract]] evmutil : public contract {

[[eosio::action]] void initgasfund();

/**
* @brief Set extra lock manager
*
* @auth self
*
* @param proxy_address Target contract address
* @param manager_address New manager address
*/
[[eosio::action]] void setlockmngr(std::string proxy_address, std::string manager_address);


// Public Helpers
Expand Down
40 changes: 40 additions & 0 deletions antelope_contracts/contracts/evmutil/src/evmutil.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -749,6 +749,46 @@ void evmutil::setlocktime(std::string proxy_address, uint64_t locktime) {
call_act.send(receiver_account(), *address_bytes, value_zero, call_data, config.evm_gaslimit);
}

void evmutil::setlockmngr(std::string proxy_address, std::string manager_address) {
require_auth(get_self());

config_t config = get_config();


auto address_bytes = from_hex(proxy_address);
eosio::check(!!address_bytes, "token address must be valid 0x EVM address");
eosio::check(address_bytes->size() == kAddressLength, "invalid length of token address");

helpers_t helpers = get_helpers();

if (!((helpers.btc_deposit_address && helpers.btc_deposit_address.value() == *address_bytes) ||
(helpers.xsat_deposit_address && helpers.xsat_deposit_address.value() == *address_bytes))) {
checksum256 addr_key = make_key(*address_bytes);
token_table_t token_table(_self, _self.value);
auto index = token_table.get_index<"by.address"_n>();
auto token_table_iter = index.find(addr_key);

check(token_table_iter != index.end() && token_table_iter->address == address_bytes, "ERC-20 token not registerred");
}

auto manager_address_bytes = from_hex(manager_address);
eosio::check(!!manager_address_bytes, "address must be valid 0x EVM address");
eosio::check(manager_address_bytes->size() == kAddressLength, "invalid length of address");

bytes call_data;
// sha(setLockManager(address)) == 0xdeedfdbd
uint8_t func_[4] = {0xde,0xed,0xfd,0xbd};
call_data.insert(call_data.end(), func_, func_ + sizeof(func_));
call_data.insert(call_data.end(), 32 - kAddressLength, 0); // padding for address
call_data.insert(call_data.end(), manager_address_bytes->begin(), manager_address_bytes->end());

bytes value_zero;
value_zero.resize(32, 0);

evm_runtime::call_action call_act(config.evm_account, {{receiver_account(), "active"_n}});
call_act.send(receiver_account(), *address_bytes, value_zero, call_data, config.evm_gaslimit);
}

void evmutil::upstakeimpl(std::string proxy_address) {
require_auth(get_self());

Expand Down
154 changes: 154 additions & 0 deletions antelope_contracts/tests/evmutil/integrated_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -327,6 +327,32 @@ struct it_tester : evmutil_tester {
}
}

void setExtraLock(evm_eoa& from, name validator, evm_eoa& user, bool value) {
auto target = evmc::from_hex<evmc::address>(stake_address);

auto txn = generate_tx(*target, 0, 500'000);
// setExtraLock(address,address,bool) = 05773015
txn.data = evmc::from_hex("0x05773015").value();
auto reserved_addr = silkworm::make_reserved_address(validator.to_uint64_t());

auto to = evmc::from_hex<evmc::address>(user.address_0x());

txn.data += evmc::from_hex(address_str32(reserved_addr)).value(); // param1 (to: address)
txn.data += evmc::from_hex(address_str32(*to)).value(); // param1 (to: address)
txn.data += evmc::from_hex(uint256_str32(value?1:0)).value(); // param2 (value: bool)

auto old_nonce = from.next_nonce;
from.sign(txn);

try {
auto r = pushtx(txn);
// dlog("action trace: ${a}", ("a", r));
} catch (...) {
from.next_nonce = old_nonce;
throw;
}
}

void stake(evm_eoa& from, name validator, intx::uint256 amount, intx::uint256 fee) {
auto target = evmc::from_hex<evmc::address>(stake_address);

Expand Down Expand Up @@ -1954,4 +1980,132 @@ try {
}
FC_LOG_AND_RETHROW()

BOOST_FIXTURE_TEST_CASE(it_extra_lock, it_tester)
try {
// Change target for this test
//stake_address = xsat_deposit_address;

auto proxy = evmc::from_hex<evmc::address>(stake_address);
push_action(endrmng_account,
"reset"_n,
endrmng_account,
mvo()("proxy",make_key(proxy->bytes, 20))("staker",make_key(evm1.address.bytes, 20))("validator","alice"_n)("test_xsat",false));
produce_block();


// Give evm1 some EOS
transfer_token(eos_token_account, "alice"_n, evm_account, make_asset(100'00000000, eos_token_symbol), evm1.address_0x().c_str());

produce_block();
push_action(evmutil_account, "setlocktime"_n, evmutil_account, mvo()("proxy_address",stake_address)("locktime",0));
produce_block();
auto token_addr = *evmc::from_hex<evmc::address>(xbtc_address);

auto tx = generate_tx(token_addr, intx::exp(10_u256, intx::uint256(18))*2 ,10'0000);
evm1.sign(tx);
pushtx(tx);

produce_block();

auto bal = balanceOf(evm1.address_0x().c_str());
BOOST_REQUIRE_MESSAGE(bal == intx::exp(10_u256, intx::uint256(18))*2, std::string("balance: ") + intx::to_string(bal));


approve(evm1, intx::exp(10_u256, intx::uint256(18)));
produce_block();


push_action(evmutil_account, "setlockmngr"_n, evmutil_account, mvo()("proxy_address",stake_address)("manager_address",evm1.address_0x()));
produce_block();

setExtraLock(evm1, "alice"_n, evm1, true);

produce_block();

auto fee = depFee();
produce_block();

assertstake(0,evm1);

stake(evm1, "alice"_n, intx::exp(10_u256, intx::uint256(18)), fee);
produce_block();

// Shall fail
assertstake(0,evm1);

setExtraLock(evm1, "alice"_n, evm1, false);

produce_block();

stake(evm1, "alice"_n, intx::exp(10_u256, intx::uint256(18)), fee);
produce_block();

assertstake(1'00000000,evm1);

bal = balanceOf(evm1.address_0x().c_str());
BOOST_REQUIRE_MESSAGE(bal == intx::exp(10_u256, intx::uint256(18)), std::string("balance: ") + intx::to_string(bal));

produce_block();

BOOST_REQUIRE_EXCEPTION(
claim(evm1, "bob"_n),
eosio_assert_message_exception,
eosio_assert_message_is("validator not found"));

setExtraLock(evm1, "alice"_n, evm1, true);

produce_block();

restake(evm1, "alice"_n, "bob"_n, intx::exp(10_u256, intx::uint256(18)));
produce_block();

// restake should fail
assertval("alice"_n);
BOOST_REQUIRE_EXCEPTION(
assertval("bob"_n),
eosio_assert_message_exception,
eosio_assert_message_is("validator not correct"));


claim(evm1, "alice"_n);
produce_block();

withdraw(evm1,"alice"_n, intx::exp(10_u256, intx::uint256(18)));
produce_block();

// Shall fail
assertstake(1'00000000,evm1);


setExtraLock(evm1, "alice"_n, evm1, false);

produce_block();

restake(evm1, "alice"_n, "bob"_n, intx::exp(10_u256, intx::uint256(18)));
produce_block();

assertval("bob"_n);

BOOST_REQUIRE_EXCEPTION(
assertval("alice"_n),
eosio_assert_message_exception,
eosio_assert_message_is("validator not correct"));

withdraw(evm1,"bob"_n, intx::exp(10_u256, intx::uint256(18)));
produce_block();

bal = balanceOf(evm1.address_0x().c_str());
BOOST_REQUIRE_MESSAGE(bal == intx::exp(10_u256, intx::uint256(18)), std::string("balance: ") + intx::to_string(bal));

produce_block();

claimPendingFunds(evm1, "bob"_n);
produce_block();

bal = balanceOf(evm1.address_0x().c_str());
BOOST_REQUIRE_MESSAGE(bal == intx::exp(10_u256, intx::uint256(18))*2, std::string("balance: ") + intx::to_string(bal));

}
FC_LOG_AND_RETHROW()

BOOST_AUTO_TEST_SUITE_END()
24 changes: 24 additions & 0 deletions solidity_contracts/evmutil/stake_helper.sol
Original file line number Diff line number Diff line change
Expand Up @@ -1387,6 +1387,9 @@ contract StakeHelper is Initializable, UUPSUpgradeable {
bool notBTC; // default to false
bool isValidatorDeposits; // default to false

address lockManager;
mapping(address => mapping(address => bool)) public extraLock;

function initialize(address _linkedEOSAddress, address _evmAddress, IERC20 _linkedERC20, uint256 _depositFee, bool _notBTC, bool _isValidatorDeposits) initializer public {
__UUPSUpgradeable_init();

Expand Down Expand Up @@ -1528,8 +1531,19 @@ contract StakeHelper is Initializable, UUPSUpgradeable {
lockTime = _lockTime;
}

function setLockManager(address _manager) public {
require(msg.sender == linkedEOSAddress, "Bridge: only linked EOS address can set lock manager");
lockManager = _manager;
}

function setExtraLock(address _target, address _user, bool _value) public {
require(msg.sender == lockManager, "Bridge: only lock manager can set extra lock");
extraLock[_target][_user] = _value;
}

function deposit(address _target, uint256 _amount) public payable {
StakeInfo storage stake = stakeInfo[_target][msg.sender];
require(extraLock[_target][msg.sender] == false, "Deposit: extra lock is imposed");
require(msg.value == depositFee, "Deposit: must pay exact amount of deposit fee");
if (_amount > 0) {
linkedERC20.safeTransferFrom(address(msg.sender), address(this), _amount);
Expand All @@ -1550,6 +1564,9 @@ contract StakeHelper is Initializable, UUPSUpgradeable {
require(!isValidatorDeposits, "Forbidden");
StakeInfo storage stakeFrom = stakeInfo[_from][msg.sender];

require(extraLock[_from][msg.sender] == false, "Restake: extra lock is imposed on from");
require(extraLock[_to][msg.sender] == false, "Withdraw: extra lock is imposed on to");

require(_amount <= stakeFrom.amount, "Restake: cannot restake more than deposited amound");

StakeInfo storage stakeTo = stakeInfo[_to][msg.sender];
Expand Down Expand Up @@ -1590,6 +1607,8 @@ contract StakeHelper is Initializable, UUPSUpgradeable {
function withdraw(address _target, uint256 _amount) external {
StakeInfo storage stake = stakeInfo[_target][msg.sender];

require(extraLock[_target][msg.sender] == false, "Withdraw: extra lock is imposed");

require(_amount <= stake.amount, "Withdraw: cannot withdraw more than deposited amound");

if (_amount > 0) {
Expand Down Expand Up @@ -1839,6 +1858,7 @@ contract StakeHelper is Initializable, UUPSUpgradeable {
function depositWithBTC(address _target) external payable {
require(!notBTC, "Linked Token is not XBTC.");
require(msg.value > depositFee, "Deposit: amount must be greater than amount of deposit fee");
require(extraLock[_target][msg.sender] == false, "deposit: extra lock is imposed");
uint256 amount = msg.value - depositFee;
// Record the initial ERC20 balance
uint256 initialBalance = linkedERC20.balanceOf(address(this));
Expand Down Expand Up @@ -1872,6 +1892,7 @@ contract StakeHelper is Initializable, UUPSUpgradeable {
function reDelegatePendingFunds(address _newTarget) external {
require(!isValidatorDeposits, "Forbidden");
require(_newTarget != address(0), "Invalid target address");
require(extraLock[_newTarget][msg.sender] == false, "deposit: extra lock is imposed");

address _user = msg.sender;
uint256 reDelegateAmount = 0;
Expand Down Expand Up @@ -1928,6 +1949,7 @@ contract StakeHelper is Initializable, UUPSUpgradeable {
function authorizeTransfer(address _operator, address _fromValidator, uint256 _amount) external {
require(!isValidatorDeposits, "Forbidden");
require(_amount > 0, "Approve: amount must be greater than zero");
require(extraLock[_fromValidator][msg.sender] == false, "transfer: extra lock is imposed");
StakeInfo storage stake = stakeInfo[_fromValidator][msg.sender];
require(_amount <= stake.amount, "Approve: insufficient stake");

Expand All @@ -1939,6 +1961,8 @@ contract StakeHelper is Initializable, UUPSUpgradeable {

function performTransfer(address _user, address _fromValidator, address _toValidator, uint256 _amount) external {
require(!isValidatorDeposits, "Forbidden");
require(extraLock[_fromValidator][_user] == false, "transfer: extra lock is imposed");
require(extraLock[_toValidator][msg.sender] == false, "transfer: extra lock is imposed");
TransferAuthorization storage auth = transferAuthorizations[_user][msg.sender];
require(auth.exists, "Permit: no authorization found");
require(auth.amount == _amount, "Permit: amount mismatch");
Expand Down
Loading