From 14741f9656c7f3addaba0bd396fb4d853a438f59 Mon Sep 17 00:00:00 2001 From: envin Date: Thu, 7 Nov 2024 23:28:44 +0100 Subject: [PATCH 01/11] feat(adapter): update registry table description --- cpp/contracts/tables/adapter_registry.table.hpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/cpp/contracts/tables/adapter_registry.table.hpp b/cpp/contracts/tables/adapter_registry.table.hpp index 7612f260..2549c03c 100644 --- a/cpp/contracts/tables/adapter_registry.table.hpp +++ b/cpp/contracts/tables/adapter_registry.table.hpp @@ -11,10 +11,10 @@ namespace eosio { // native token is somewhere else (i.e. wETH on Ethereum) // // Example: - // wram.token => local chain is EOS, then adapter's registry is + // wram.token, '6,WRAM' => local chain is EOS, then adapter's registry is // - // |_____token_____|_______token_bytes_____________|_____xerc20_____| - // | 'wram.token' | bytes32(WRAM.symbol.code.raw) | 'xwram.token' | + // |_____token____|___token_symbol___|_______token_bytes_____________|_____xerc20_____| + // | 'wram.token' | '6,WRAM' | bytes32(WRAM.symbol.code.raw) | 'xwram.token' | // // NOTE: on destination chains we will set each adapter's registry // with bytes32(WRAM.symbol.code.raw) for WRAM @@ -22,9 +22,9 @@ namespace eosio { // Example: // WETH ERC20 => local chain is Ethereum, then adapter's registry is // - // |_____token_____|______token_bytes_______|_____xerc20_____| - // | '' | bytes32(address(WETH)) | 'xweth.token' | - // + // |_____token____|___token_symbol___|______token_bytes_______|_____xerc20_____| + // | '' | '0,XXX' | bytes32(address(WETH)) | 'xweth.token' | + // NOTE: for not local token_symbol = '0,XXX' TABLE adapter_registry_table { name token; symbol token_symbol; From 9bb3704785881bd8bc00aec4ecba738cd95de429 Mon Sep 17 00:00:00 2001 From: envin Date: Thu, 7 Nov 2024 23:29:46 +0100 Subject: [PATCH 02/11] feat(adapter): support only one token per adapter contract --- cpp/contracts/adapter.cpp | 87 +++++++++---------- cpp/contracts/adapter.hpp | 7 +- .../tables/adapter_registry.table.hpp | 26 +----- 3 files changed, 42 insertions(+), 78 deletions(-) diff --git a/cpp/contracts/adapter.cpp b/cpp/contracts/adapter.cpp index e6de1ce1..3f0c46f7 100644 --- a/cpp/contracts/adapter.cpp +++ b/cpp/contracts/adapter.cpp @@ -4,27 +4,23 @@ namespace eosio { asset adapter::calculate_fees(const asset& quantity) { registry_adapter _registry(get_self(), get_self().value); - auto idx = _registry.get_index(); - auto search_token = _registry.find(quantity.symbol.code().raw()); - auto search_xerc20 = idx.find(quantity.symbol.code().raw()); - - asset min_fee; - if (search_token != _registry.end()) { - min_fee = search_token->min_fee; - } else if (search_xerc20 != idx.end()) { - min_fee = search_xerc20->min_fee; - } else { - check(false, "invalid quantity given for calculating the fees"); - } + check(_registry.exists(), "contract not inizialized"); + adapter_registry_table registry_data = _registry.get(); + + check( + quantity.symbol == registry_data.token_symbol || + quantity.symbol == registry_data.xerc20_symbol, + "invalid quantity given for calculating the fees" + ); // Fees are expressed in the wrapped token (xerc20), hence why // the min_fee.symbol - auto ref_symbol = min_fee.symbol; + auto ref_symbol = registry_data.min_fee.symbol; uint128_t fee_amount = (FEE_BASIS_POINTS * quantity.amount) / FEE_BASIS_POINTS_DIVISOR; asset fee = asset(fee_amount, ref_symbol); - return fee < min_fee ? min_fee : fee; + return fee < registry_data.min_fee ? registry_data.min_fee : fee; } void adapter::check_symbol_is_valid(const name& account, const symbol& sym) { @@ -42,34 +38,32 @@ void adapter::create( const asset& min_fee ) { require_auth(get_self()); + registry_adapter _registry(get_self(), get_self().value); + check(!_registry.exists(), "adapter already registered"); auto _token_bytes = token_bytes.extract_as_byte_array(); check(is_account(xerc20), "xERC20 account does not exist"); check(min_fee.symbol == xerc20_symbol, "invalid minimum fee symbol"); - - registry_adapter _registry(get_self(), get_self().value); - auto itr = _registry.find(token_symbol.code().raw()); - check(itr == _registry.end(), "token already registered"); check_symbol_is_valid(xerc20, xerc20_symbol); if (token != name(0)) { - // Check token symbol if toekn is local to a EOS like chain + // checks done only for local token check_symbol_is_valid(token, token_symbol); - // Difference in precision allowed if token is not local check(token_symbol.precision() == xerc20_symbol.precision(), "invalid xerc20 precision"); - // Do not check token validity if token is not local check(is_account(token), "token account does not exist"); } - checksum256 c; - _registry.emplace( get_self(), [&]( auto& r ) { - r.xerc20 = xerc20; - r.xerc20_symbol = xerc20_symbol; - r.token = token; - r.token_symbol = token_symbol; - r.token_bytes = token_bytes; - r.min_fee = min_fee; - }); + symbol non_local_token_symbol = symbol(symbol_code("XXX"), 0); + + adapter_registry_table registry_data { + .token = token, + .token_symbol = token == name(0) ? non_local_token_symbol : token_symbol, + .token_bytes = token_bytes, + .xerc20 = xerc20, + .xerc20_symbol = xerc20_symbol, + .min_fee = min_fee + }; + _registry.set(registry_data, get_self()); storage _storage(get_self(), get_self().value); _storage.get_or_create(get_self(), adapter::empty_storage); @@ -191,10 +185,10 @@ void adapter::settle(const name& caller, const operation& operation, const metad require_auth(caller); registry_adapter _registry(get_self(), get_self().value); - auto idx_registry = _registry.get_index(); - auto search_token_bytes = idx_registry.find(operation.token); - check(search_token_bytes != idx_registry.end(), "underlying token does not match with adapter registry"); - check(search_token_bytes->xerc20_symbol == operation.amount.symbol, "registered xerc20 symbols differs from the operation one"); // TODO: test me + check(_registry.exists(), "contract not inizialized"); + adapter_registry_table registry_data = _registry.get(); + check (registry_data.token_bytes == operation.token, "underlying token does not match with adapter registry"); + check(registry_data.xerc20_symbol == operation.amount.symbol, "registered xerc20 symbols differs from the operation one"); // TODO: test me checksum256 event_id; // output pam::check_authorization(get_self(), operation, metadata, event_id); @@ -216,13 +210,13 @@ void adapter::settle(const name& caller, const operation& operation, const metad storage.nonce++; _storage.set(storage, get_self()); - name xerc20 = search_token_bytes->xerc20; + name xerc20 = registry_data.xerc20; check(is_account(xerc20), "Not valid xerc20 name"); if (operation.amount.amount > 0) { - asset quantity(operation.amount.amount, search_token_bytes->xerc20_symbol); + asset quantity(operation.amount.amount, registry_data.xerc20_symbol); lockbox_singleton _lockbox(xerc20, xerc20.value); - action_mint _mint(search_token_bytes->xerc20, {get_self(), "active"_n}); + action_mint _mint(registry_data.xerc20, {get_self(), "active"_n}); if (_lockbox.exists()) { // If the lockbox exists, we release the collateral auto lockbox = _lockbox.get(); @@ -342,19 +336,18 @@ void adapter::ontransfer(const name& from, const name& to, const asset& quantity check(quantity.amount > 0, "invalid amount"); registry_adapter _registry(get_self(), get_self().value); - auto search_token = _registry.find(quantity.symbol.code().raw()); - auto idx = _registry.get_index(); - auto search_xerc20 = idx.find(quantity.symbol.code().raw()); + check(_registry.exists(), "contract not inizialized"); + adapter_registry_table registry_data = _registry.get(); - bool is_token_transfer = search_token != _registry.end(); - bool is_xerc20_transfer = search_xerc20 != idx.end(); + bool is_token_transfer = registry_data.token_symbol == quantity.symbol; + bool is_xerc20_transfer = registry_data.xerc20_symbol == quantity.symbol; - check(is_token_transfer || is_xerc20_transfer, "token not registered"); + check(is_token_transfer || is_xerc20_transfer, "token not supported by this adapter"); - auto xerc20 = is_token_transfer ? search_token->xerc20 : search_xerc20->xerc20; - auto xerc20_symbol = is_token_transfer ? search_token->xerc20_symbol : search_xerc20->xerc20_symbol; - auto token = is_token_transfer ? search_token->token : search_xerc20->token; - auto token_symbol = is_token_transfer ? search_token->token_symbol : search_xerc20->token_symbol; + auto xerc20 = is_token_transfer ? registry_data.xerc20 : registry_data.xerc20; + auto xerc20_symbol = is_token_transfer ? registry_data.xerc20_symbol : registry_data.xerc20_symbol; + auto token = is_token_transfer ? registry_data.token : registry_data.token; + auto token_symbol = is_token_transfer ? registry_data.token_symbol : registry_data.token_symbol; if (is_token_transfer) check(quantity.symbol == token_symbol, "invalid token quantity symbol"); if (is_xerc20_transfer) check(quantity.symbol == xerc20_symbol, "invalid xerc20 quantity symbol"); diff --git a/cpp/contracts/adapter.hpp b/cpp/contracts/adapter.hpp index 59373ff5..cc27547f 100644 --- a/cpp/contracts/adapter.hpp +++ b/cpp/contracts/adapter.hpp @@ -86,13 +86,8 @@ namespace eosio { typedef eosio::multi_index<"userdata"_n, user_data_table> user_data; typedef eosio::multi_index<"pastevents"_n, adapter_past_events_table, adapter_past_events_byeventid> past_events; typedef eosio::multi_index<"reglockbox"_n, lockbox_registry_table, lockbox_registry_byxtoken> registry_lockbox; - typedef eosio::multi_index< - "regadapter"_n, - adapter_registry_table, - adapter_registry_byxtoken, - adapter_registry_bytokenbytes - > registry_adapter; + using registry_adapter = singleton<"regadapter"_n, adapter_registry_table>; using lockbox_singleton = singleton<"lockbox"_n, name>; using storage = singleton<"storage"_n, global_storage_table>; diff --git a/cpp/contracts/tables/adapter_registry.table.hpp b/cpp/contracts/tables/adapter_registry.table.hpp index 2549c03c..45d02048 100644 --- a/cpp/contracts/tables/adapter_registry.table.hpp +++ b/cpp/contracts/tables/adapter_registry.table.hpp @@ -25,6 +25,7 @@ namespace eosio { // |_____token____|___token_symbol___|______token_bytes_______|_____xerc20_____| // | '' | '0,XXX' | bytes32(address(WETH)) | 'xweth.token' | // NOTE: for not local token_symbol = '0,XXX' + TABLE adapter_registry_table { name token; symbol token_symbol; @@ -32,30 +33,5 @@ namespace eosio { name xerc20; symbol xerc20_symbol; asset min_fee; - - uint64_t primary_key() const { return token_symbol.code().raw(); } - uint64_t secondary_key() const { return xerc20_symbol.code().raw(); } - const checksum256& ternary_key() const { return token_bytes; } }; - - constexpr name adapter_registry_idx_xtoken = "byxtoken1"_n; - constexpr name adapter_registry_idx_token_bytes = "bytokenbytes"_n; - - typedef indexed_by< - adapter_registry_idx_xtoken, - const_mem_fun< - adapter_registry_table, - uint64_t, - &adapter_registry_table::secondary_key - > - > adapter_registry_byxtoken; - - typedef indexed_by< - adapter_registry_idx_token_bytes, - const_mem_fun< - adapter_registry_table, - const checksum256&, - &adapter_registry_table::ternary_key - > - > adapter_registry_bytokenbytes; } \ No newline at end of file From eb0b68e39d35a86c0b3bf05e5044504e7b181c5d Mon Sep 17 00:00:00 2001 From: envin Date: Thu, 7 Nov 2024 23:30:06 +0100 Subject: [PATCH 03/11] test(adapter): update tests --- cpp/test/adapter-local.test.js | 4 +--- cpp/test/adapter-non-local.test.js | 23 +++++++---------------- 2 files changed, 8 insertions(+), 19 deletions(-) diff --git a/cpp/test/adapter-local.test.js b/cpp/test/adapter-local.test.js index d00de274..6e98fabd 100644 --- a/cpp/test/adapter-local.test.js +++ b/cpp/test/adapter-local.test.js @@ -170,9 +170,7 @@ describe('Adapter EOS -> ETH testing', () => { .setfeemanagr([feemanager]) .send(active(adapter.account)) - const row = adapter.contract.tables - .regadapter(getAccountCodeRaw(adapter.account)) - .getTableRow(getSymbolCodeRaw(token.maxSupply)) + const row = getSingletonInstance(adapter.contract, 'regadapter') const storage = getSingletonInstance(adapter.contract, TABLE_STORAGE) diff --git a/cpp/test/adapter-non-local.test.js b/cpp/test/adapter-non-local.test.js index 8e4ffc76..8b99b3f4 100644 --- a/cpp/test/adapter-non-local.test.js +++ b/cpp/test/adapter-non-local.test.js @@ -18,7 +18,6 @@ const errors = require('./utils/errors') const ethers = require('ethers') const { evmOperationSamples, - amounts, evmTopicZero, evmAdapter, } = require('./samples/evm-operations') @@ -26,7 +25,6 @@ const { evmMetadataSamples, teePubKey } = require('./samples/evm-metadata') const { adjustPrecision } = require('./utils/precision-utils') const attestation = 'deadbeef' -const NULL_KEY = 'PUB_K1_11111111111111111111111111111111149Mr2R' // null initialization of public_key() CDT function describe('Adapter EVM -> EOS testing', () => { const evmTokenSymbol = 'TST' @@ -35,8 +33,6 @@ describe('Adapter EVM -> EOS testing', () => { const evmXERC20Precision = 8 const TABLE_STORAGE = 'storage' - const FEE_BASIS_POINTS = 1750 - const FEE_BASIS_POINTS_DIVISOR = 1000000 // infos of the underlying token const evmUnderlyingToken = { @@ -313,9 +309,7 @@ describe('Adapter EVM -> EOS testing', () => { ]) .send(active(adapter.account)) - const row = adapter.contract.tables - .regadapter(getAccountCodeRaw(adapter.account)) - .getTableRow(getSymbolCodeRaw(evmUnderlyingToken.maxSupply)) + const row = getSingletonInstance(adapter.contract, 'regadapter') const storage = getSingletonInstance(adapter.contract, TABLE_STORAGE) const tee = getSingletonInstance(adapter.contract, 'tee') const mappingsRow = adapter.contract.tables @@ -324,10 +318,7 @@ describe('Adapter EVM -> EOS testing', () => { expect(row).to.be.deep.equal({ token: '', - token_symbol: precision( - evmUnderlyingToken.precision, - evmUnderlyingToken.symbol, - ), + token_symbol: precision(0, 'XXX'), token_bytes: evmUnderlyingToken.bytes, xerc20: evmXERC20.account, xerc20_symbol: precision(evmXERC20.precision, evmXERC20.symbol), @@ -344,16 +335,16 @@ describe('Adapter EVM -> EOS testing', () => { it('Should throw if already created', async () => { const action = adapter.contract.actions .create([ - evmXERC20.account, - precision(evmXERC20.precision, evmXERC20.symbol), - evmUnderlyingToken.account, - precision(evmUnderlyingToken.precision, evmUnderlyingToken.symbol), + 'xerc20.2', + precision(6, 'XERC'), + 'local', + precision(6, 'XXX'), evmUnderlyingToken.bytes, evmXERC20.minFee, ]) .send(active(adapter.account)) - await expectToThrow(action, 'eosio_assert: token already registered') + await expectToThrow(action, 'eosio_assert: adapter already registered') }) }) From 7c1e2093e83ce68f1ec48cf66c71d0a2d13598b2 Mon Sep 17 00:00:00 2001 From: envin Date: Fri, 8 Nov 2024 02:50:38 +0100 Subject: [PATCH 04/11] fix(adapter): fix settle with not matching precision --- cpp/contracts/adapter.cpp | 12 ++++++++---- cpp/contracts/utils.hpp | 16 ++++++++++++++++ 2 files changed, 24 insertions(+), 4 deletions(-) diff --git a/cpp/contracts/adapter.cpp b/cpp/contracts/adapter.cpp index 3f0c46f7..a6e45e31 100644 --- a/cpp/contracts/adapter.cpp +++ b/cpp/contracts/adapter.cpp @@ -187,8 +187,10 @@ void adapter::settle(const name& caller, const operation& operation, const metad registry_adapter _registry(get_self(), get_self().value); check(_registry.exists(), "contract not inizialized"); adapter_registry_table registry_data = _registry.get(); - check (registry_data.token_bytes == operation.token, "underlying token does not match with adapter registry"); - check(registry_data.xerc20_symbol == operation.amount.symbol, "registered xerc20 symbols differs from the operation one"); // TODO: test me + check(registry_data.token_bytes == operation.token, "underlying token does not match with adapter registry"); + // symbol check if underlying is EOS type + if (registry_data.token != name(0)) // TODO add test + check(registry_data.xerc20_symbol == operation.amount.symbol, "registered xerc20 symbols differs from the operation one"); checksum256 event_id; // output pam::check_authorization(get_self(), operation, metadata, event_id); @@ -213,8 +215,10 @@ void adapter::settle(const name& caller, const operation& operation, const metad name xerc20 = registry_data.xerc20; check(is_account(xerc20), "Not valid xerc20 name"); if (operation.amount.amount > 0) { - asset quantity(operation.amount.amount, registry_data.xerc20_symbol); - + asset adj_operation_amount = (registry_data.token == name(0) && registry_data.token_symbol == symbol(symbol_code("XXX"), 0)) ? + adjust_precision(operation.amount, registry_data.xerc20_symbol) : + operation.amount; + asset quantity(adj_operation_amount.amount, registry_data.xerc20_symbol); lockbox_singleton _lockbox(xerc20, xerc20.value); action_mint _mint(registry_data.xerc20, {get_self(), "active"_n}); if (_lockbox.exists()) { diff --git a/cpp/contracts/utils.hpp b/cpp/contracts/utils.hpp index 1330ff94..05a359c9 100644 --- a/cpp/contracts/utils.hpp +++ b/cpp/contracts/utils.hpp @@ -131,6 +131,22 @@ namespace eosio { return asset(amount / powint(10, exp), sym); } + asset adjust_precision(const asset& from_asset, const symbol& to_sym) { + int16_t exp = from_asset.symbol.precision() - to_sym.precision(); + uint128_t factor; + uint128_t adjusted_amount; + if (exp < 0) { + exp = -exp; + factor = powint(10, exp); + adjusted_amount = from_asset.amount * factor; + } else { + print("WARNING: Operation precision exceeds destination symbol; amount will be floored to destination symbol precision."); + factor = powint(10, exp); + adjusted_amount = from_asset.amount / factor; + } + return asset(adjusted_amount, to_sym); + } + bytes extract_32bytes(const bytes& data, uint128_t offset) { bytes _data(data.begin() + offset, data.begin() + offset + 32); return _data; From 67326010f010df658c3439c00ffb5e8f9587cb8c Mon Sep 17 00:00:00 2001 From: envin Date: Fri, 8 Nov 2024 02:51:19 +0100 Subject: [PATCH 05/11] test(adapter): update tests --- cpp/test/adapter-non-local.test.js | 32 ++++++++++++++++++++++++++++++ cpp/test/samples/evm-metadata.js | 6 ++++++ cpp/test/samples/evm-operations.js | 14 +++++++++++++ 3 files changed, 52 insertions(+) diff --git a/cpp/test/adapter-non-local.test.js b/cpp/test/adapter-non-local.test.js index 8b99b3f4..45105381 100644 --- a/cpp/test/adapter-non-local.test.js +++ b/cpp/test/adapter-non-local.test.js @@ -584,5 +584,37 @@ describe('Adapter EVM -> EOS testing', () => { `0.0000 ${evmXERC20.symbol}`, ) }) + + it('Should truncate the passed amount to the set precision', async () => { + const operation = evmOperationSamples.peginLargePrecision + const metadata = evmMetadataSamples.peginLargePrecision + + const before = getAccountsBalances( + [user, recipient, adapter.account], + [evmXERC20], + ) + const beforeAsset = Asset.from(before[recipient][evmXERC20.symbol]) + + await adapter.contract.actions + .settle([user, operation, metadata]) + .send(active(user)) + + console.log(adapter.contract.bc.console) + + const after = getAccountsBalances( + [user, recipient, adapter.account], + [evmXERC20], + ) + + const adjAmount = adjustPrecision(operation.amount, evmXERC20Precision) + const adjOperationAmount = Asset.from(`${adjAmount} ${evmXERC20.symbol}`) + expect(after[recipient][evmXERC20.symbol]).to.equal( + sum(adjOperationAmount, beforeAsset).toString(), + ) + + expect(after[adapter.account][evmXERC20.symbol]).to.be.equal( + `0.0000 ${evmXERC20.symbol}`, + ) + }) }) }) diff --git a/cpp/test/samples/evm-metadata.js b/cpp/test/samples/evm-metadata.js index 70d2ae18..9955fdab 100644 --- a/cpp/test/samples/evm-metadata.js +++ b/cpp/test/samples/evm-metadata.js @@ -18,6 +18,12 @@ const evmMetadataSamples = { signature: '1b5d941f9856d83e6776500344e4e62bfe66deb509c509228bb2ab88d32b8a2dee290c160bf5c575034c88dd39d4b598f5fa7080a97be90398437cb3ccb9049051', }, + peginLargePrecision: { + preimage: + '010100000000000000000000000000000000000000000000000000000000000000019c6d1358f426fe23fc7cf0e67aa422ff27c4e5ec7899297a10f036e6cf6643da96d4d6885f072cb3f734d1b4add1d78d46487692cf9d912a6a91cfc6c65bc7d6000000000000000000000000bcf063a9eb18bc3c6eb005791c61801b7cb16fe466756e6473206172652073616675207361667520736166752073616675202e2e0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000810090f35dfa6b18b5eb59d298e2a2443a2811e2aca376f206b8fc25a6ed44dbdc66547c36c6c33e3a119ffbeaef943642f0e9060000000000000000000000000000000000000000000000001080f0f245c7e965000000000000000000000000f39fd6e51aad88f6f4ce6ab8827279cfffb92266000000000000000000000000000000000000000000000000000000000000000c656f73726563697069656e74', + signature: + '1c788142219de023a33e6916e3f396084003401be5551e5f972d9e628cf9685ab740a4619cd30e2adfd21527f50835f3b993ef19d398592c55bd362eec6ddb7cd9', + }, peginWithWrongSignature: { preimage: '010100000000000000000000000000000000000000000000000000000000000000017e21ba208ea2a072bad2d011dbc3a9f870c574a66203d84bde926fcf85756d782e3704b180feda25af9dfe50793e292fd99d644aa505c3d170fa69407091dbd3000000000000000000000000bcf063a9eb18bc3c6eb005791c61801b7cb16fe466756e6473206172652073616675207361667520736166752073616675202e2e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000810090f35dfa6b18b5eb59d298e2a2443a2811e2aca376f206b8fc25a6ed44dbdc66547c36c6c33e3a119ffbeaef943642f0e906000000000000000000000000000000000000000000000000517d3388612e7c00000000000000000000000000f39fd6e51aad88f6f4ce6ab8827279cfffb92266000000000000000000000000000000000000000000000000000000000000000c656f73726563697069656e74', diff --git a/cpp/test/samples/evm-operations.js b/cpp/test/samples/evm-operations.js index 84d4c4e1..5b3c6bb3 100644 --- a/cpp/test/samples/evm-operations.js +++ b/cpp/test/samples/evm-operations.js @@ -35,6 +35,20 @@ const evmOperationSamples = { recipient: 'eosrecipient', data: '12345abcdefc0de1337f', }, + peginLargePrecision: { + blockId: '9c6d1358f426fe23fc7cf0e67aa422ff27c4e5ec7899297a10f036e6cf6643da', + txId: '96d4d6885f072cb3f734d1b4add1d78d46487692cf9d912a6a91cfc6c65bc7d6', + nonce: 0, + token: '000000000000000000000000810090f35dfa6b18b5eb59d298e2a2443a2811e2', + originChainId: + '0000000000000000000000000000000000000000000000000000000000000001', // ETH chain id + destinationChainId: + 'aca376f206b8fc25a6ed44dbdc66547c36c6c33e3a119ffbeaef943642f0e906', // EOS chain id + amount: '1.189215224969292133 XTST', + sender: '000000000000000000000000f39fd6e51aad88f6f4ce6ab8827279cfffb92266', + recipient: 'eosrecipient', + data: '', + }, } module.exports = { From fe7f9cd9c75a99d297a3dcf39e50ae8651a97625 Mon Sep 17 00:00:00 2001 From: envin Date: Fri, 8 Nov 2024 18:52:03 +0100 Subject: [PATCH 06/11] feat(adapter_registry_table): retain precision for non local token --- cpp/contracts/adapter.cpp | 2 +- cpp/contracts/tables/adapter_registry.table.hpp | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/cpp/contracts/adapter.cpp b/cpp/contracts/adapter.cpp index a6e45e31..e3168b91 100644 --- a/cpp/contracts/adapter.cpp +++ b/cpp/contracts/adapter.cpp @@ -53,7 +53,7 @@ void adapter::create( check(is_account(token), "token account does not exist"); } - symbol non_local_token_symbol = symbol(symbol_code("XXX"), 0); + symbol non_local_token_symbol = symbol(symbol_code("XXX"), token_symbol.precision()); adapter_registry_table registry_data { .token = token, diff --git a/cpp/contracts/tables/adapter_registry.table.hpp b/cpp/contracts/tables/adapter_registry.table.hpp index 45d02048..df1cb5aa 100644 --- a/cpp/contracts/tables/adapter_registry.table.hpp +++ b/cpp/contracts/tables/adapter_registry.table.hpp @@ -23,8 +23,9 @@ namespace eosio { // WETH ERC20 => local chain is Ethereum, then adapter's registry is // // |_____token____|___token_symbol___|______token_bytes_______|_____xerc20_____| - // | '' | '0,XXX' | bytes32(address(WETH)) | 'xweth.token' | - // NOTE: for not local token_symbol = '0,XXX' + // | '' | '18,XXX' | bytes32(address(WETH)) | 'xweth.token' | + // + // NOTE: for not local token_symbol = ',XXX' TABLE adapter_registry_table { name token; From 8c266dbc6b41bddab9e55abd70c69a97898c125d Mon Sep 17 00:00:00 2001 From: envin Date: Fri, 8 Nov 2024 18:52:36 +0100 Subject: [PATCH 07/11] feat(operation): use uint_128 amount --- cpp/contracts/adapter.cpp | 10 ++-------- cpp/contracts/operation.hpp | 2 +- cpp/contracts/pam.hpp | 2 +- cpp/contracts/tables/adapter_registry.table.hpp | 2 +- cpp/contracts/utils.hpp | 10 +++++----- 5 files changed, 10 insertions(+), 16 deletions(-) diff --git a/cpp/contracts/adapter.cpp b/cpp/contracts/adapter.cpp index e3168b91..52cd9b7e 100644 --- a/cpp/contracts/adapter.cpp +++ b/cpp/contracts/adapter.cpp @@ -188,10 +188,6 @@ void adapter::settle(const name& caller, const operation& operation, const metad check(_registry.exists(), "contract not inizialized"); adapter_registry_table registry_data = _registry.get(); check(registry_data.token_bytes == operation.token, "underlying token does not match with adapter registry"); - // symbol check if underlying is EOS type - if (registry_data.token != name(0)) // TODO add test - check(registry_data.xerc20_symbol == operation.amount.symbol, "registered xerc20 symbols differs from the operation one"); - checksum256 event_id; // output pam::check_authorization(get_self(), operation, metadata, event_id); @@ -214,10 +210,8 @@ void adapter::settle(const name& caller, const operation& operation, const metad name xerc20 = registry_data.xerc20; check(is_account(xerc20), "Not valid xerc20 name"); - if (operation.amount.amount > 0) { - asset adj_operation_amount = (registry_data.token == name(0) && registry_data.token_symbol == symbol(symbol_code("XXX"), 0)) ? - adjust_precision(operation.amount, registry_data.xerc20_symbol) : - operation.amount; + if (operation.amount > 0) { + asset adj_operation_amount = adjust_precision(operation.amount, registry_data.token_symbol, registry_data.xerc20_symbol); asset quantity(adj_operation_amount.amount, registry_data.xerc20_symbol); lockbox_singleton _lockbox(xerc20, xerc20.value); action_mint _mint(registry_data.xerc20, {get_self(), "active"_n}); diff --git a/cpp/contracts/operation.hpp b/cpp/contracts/operation.hpp index 0b256433..cbe8bb26 100644 --- a/cpp/contracts/operation.hpp +++ b/cpp/contracts/operation.hpp @@ -14,7 +14,7 @@ namespace eosio { checksum256 token; // erc20 on EVM bytes originChainId; bytes destinationChainId; - asset amount; + uint128_t amount; bytes sender; name recipient; bytes data; diff --git a/cpp/contracts/pam.hpp b/cpp/contracts/pam.hpp index 156d1820..67f202dc 100644 --- a/cpp/contracts/pam.hpp +++ b/cpp/contracts/pam.hpp @@ -148,7 +148,7 @@ namespace eosio { bytes amount = extract_32bytes(event_data, offset); uint128_t amount_num = bytes32_to_uint128(amount); - check(to_wei(operation.amount) == amount_num, "amount do not match"); + check(operation.amount == amount_num, "amount do not match"); offset += 32; bytes sender = extract_32bytes(event_data, offset); diff --git a/cpp/contracts/tables/adapter_registry.table.hpp b/cpp/contracts/tables/adapter_registry.table.hpp index df1cb5aa..394b8675 100644 --- a/cpp/contracts/tables/adapter_registry.table.hpp +++ b/cpp/contracts/tables/adapter_registry.table.hpp @@ -25,7 +25,7 @@ namespace eosio { // |_____token____|___token_symbol___|______token_bytes_______|_____xerc20_____| // | '' | '18,XXX' | bytes32(address(WETH)) | 'xweth.token' | // - // NOTE: for not local token_symbol = ',XXX' + // NOTE: for not local token_symbol = ',XXX' TABLE adapter_registry_table { name token; diff --git a/cpp/contracts/utils.hpp b/cpp/contracts/utils.hpp index 05a359c9..872d7bf2 100644 --- a/cpp/contracts/utils.hpp +++ b/cpp/contracts/utils.hpp @@ -131,20 +131,20 @@ namespace eosio { return asset(amount / powint(10, exp), sym); } - asset adjust_precision(const asset& from_asset, const symbol& to_sym) { - int16_t exp = from_asset.symbol.precision() - to_sym.precision(); + asset adjust_precision(uint128_t amount, const symbol& from_symbol, const symbol& to_symbol) { + int16_t exp = from_symbol.precision() - to_symbol.precision(); uint128_t factor; uint128_t adjusted_amount; if (exp < 0) { exp = -exp; factor = powint(10, exp); - adjusted_amount = from_asset.amount * factor; + adjusted_amount = amount * factor; } else { print("WARNING: Operation precision exceeds destination symbol; amount will be floored to destination symbol precision."); factor = powint(10, exp); - adjusted_amount = from_asset.amount / factor; + adjusted_amount = amount / factor; } - return asset(adjusted_amount, to_sym); + return asset(adjusted_amount, to_symbol); } bytes extract_32bytes(const bytes& data, uint128_t offset) { From fecc26c25d26e73aed2df5b5bf14ad901f994436 Mon Sep 17 00:00:00 2001 From: envin Date: Fri, 8 Nov 2024 18:52:53 +0100 Subject: [PATCH 08/11] test: update tests --- cpp/test/adapter-non-local.test.js | 24 +++++++++++++++++++----- cpp/test/pam.test.js | 4 ++-- cpp/test/samples/evm-operations.js | 6 +++--- cpp/test/utils/get-operation-sample.js | 2 +- 4 files changed, 25 insertions(+), 11 deletions(-) diff --git a/cpp/test/adapter-non-local.test.js b/cpp/test/adapter-non-local.test.js index 45105381..23daaea0 100644 --- a/cpp/test/adapter-non-local.test.js +++ b/cpp/test/adapter-non-local.test.js @@ -22,7 +22,7 @@ const { evmAdapter, } = require('./samples/evm-operations') const { evmMetadataSamples, teePubKey } = require('./samples/evm-metadata') -const { adjustPrecision } = require('./utils/precision-utils') +const { adjustPrecision, fromWei } = require('./utils/precision-utils') const attestation = 'deadbeef' @@ -318,7 +318,7 @@ describe('Adapter EVM -> EOS testing', () => { expect(row).to.be.deep.equal({ token: '', - token_symbol: precision(0, 'XXX'), + token_symbol: precision(18, 'XXX'), token_bytes: evmUnderlyingToken.bytes, xerc20: evmXERC20.account, xerc20_symbol: precision(evmXERC20.precision, evmXERC20.symbol), @@ -517,6 +517,12 @@ describe('Adapter EVM -> EOS testing', () => { }) describe('adapter::settle', () => { + const createOperationAsset = amount => + Asset.from( + amount / 10 ** evmPrecision, + precision(evmXERC20.precision, evmXERC20.symbol), + ) + it('Should reject if adapter and token do not match', async () => { const operation = evmOperationSamples.pegin const metadata = evmMetadataSamples.pegin @@ -546,7 +552,10 @@ describe('Adapter EVM -> EOS testing', () => { [evmXERC20], ) - expect(after[recipient][evmXERC20.symbol]).to.be.equal(operation.amount) + const operationAsset = createOperationAsset(operation.amount) + expect(after[recipient][evmXERC20.symbol]).to.be.equal( + operationAsset.toString(), + ) expect(after[adapter.account][evmXERC20.symbol]).to.be.equal( `0.0000 ${evmXERC20.symbol}`, @@ -576,8 +585,9 @@ describe('Adapter EVM -> EOS testing', () => { [evmXERC20], ) + const operationAsset = createOperationAsset(operation.amount) expect(after[recipient][evmXERC20.symbol]).to.equal( - sum(operation.amount, beforeAsset).toString(), + sum(operationAsset, beforeAsset).toString(), ) expect(after[adapter.account][evmXERC20.symbol]).to.be.equal( @@ -606,7 +616,11 @@ describe('Adapter EVM -> EOS testing', () => { [evmXERC20], ) - const adjAmount = adjustPrecision(operation.amount, evmXERC20Precision) + const operationAsset = createOperationAsset(operation.amount) + const adjAmount = adjustPrecision( + operationAsset.toString(), + evmXERC20Precision, + ) const adjOperationAmount = Asset.from(`${adjAmount} ${evmXERC20.symbol}`) expect(after[recipient][evmXERC20.symbol]).to.equal( sum(adjOperationAmount, beforeAsset).toString(), diff --git a/cpp/test/pam.test.js b/cpp/test/pam.test.js index 0c315163..bedfc9e7 100644 --- a/cpp/test/pam.test.js +++ b/cpp/test/pam.test.js @@ -59,7 +59,7 @@ describe('PAM testing', () => { const eosChainId = 'aca376f206b8fc25a6ed44dbdc66547c36c6c33e3a119ffbeaef943642f0e906' const operation = getOperationSample({ - amount: '1337.0000 TKN', + amount: '1337000000000000000000', sender: '0000000000000000000000002b5ad5c4795c026514f8317c7a215e218dccd6cf', token: '000000000000000000000000f2e246bb76df876cef8b38ae84130f4f55de395b', chainId: eosChainId, @@ -327,7 +327,7 @@ describe('PAM testing', () => { '0000000000000000000000000000000000000000000000746b6e2e746f6b656e' const originChainId = no0x(Chains(Protocols.Eos).Jungle) const destinationChainId = eosChainId - const amount = '9.9825 TKN' + const amount = '9982500000000000000' const sender = '0000000000000000000000000000000000000000000000000000000075736572' const recipient = 'recipient' diff --git a/cpp/test/samples/evm-operations.js b/cpp/test/samples/evm-operations.js index 5b3c6bb3..99036cd7 100644 --- a/cpp/test/samples/evm-operations.js +++ b/cpp/test/samples/evm-operations.js @@ -16,7 +16,7 @@ const evmOperationSamples = { '0000000000000000000000000000000000000000000000000000000000000001', // EVM mainnet chain id destinationChainId: 'aca376f206b8fc25a6ed44dbdc66547c36c6c33e3a119ffbeaef943642f0e906', // EOS chain id - amount: '5.87190615 XTST', + amount: '5871906150000000000', sender: '000000000000000000000000f39fd6e51aad88f6f4ce6ab8827279cfffb92266', recipient: 'eosrecipient', data: '', @@ -30,7 +30,7 @@ const evmOperationSamples = { '0000000000000000000000000000000000000000000000000000000000000001', // ETH chain id destinationChainId: 'aca376f206b8fc25a6ed44dbdc66547c36c6c33e3a119ffbeaef943642f0e906', // EOS chain id - amount: '0.99749956 XTST', + amount: '997499560000000000', sender: '000000000000000000000000f39fd6e51aad88f6f4ce6ab8827279cfffb92266', recipient: 'eosrecipient', data: '12345abcdefc0de1337f', @@ -44,7 +44,7 @@ const evmOperationSamples = { '0000000000000000000000000000000000000000000000000000000000000001', // ETH chain id destinationChainId: 'aca376f206b8fc25a6ed44dbdc66547c36c6c33e3a119ffbeaef943642f0e906', // EOS chain id - amount: '1.189215224969292133 XTST', + amount: '1189215224969292133', sender: '000000000000000000000000f39fd6e51aad88f6f4ce6ab8827279cfffb92266', recipient: 'eosrecipient', data: '', diff --git a/cpp/test/utils/get-operation-sample.js b/cpp/test/utils/get-operation-sample.js index a135ce59..05fc0f5e 100644 --- a/cpp/test/utils/get-operation-sample.js +++ b/cpp/test/utils/get-operation-sample.js @@ -13,7 +13,7 @@ const getOperationSample = _injectedOperation => '0000000000000000000000000000000000000000000000000000000000000001', // ETH chain id destinationChainId: 'aca376f206b8fc25a6ed44dbdc66547c36c6c33e3a119ffbeaef943642f0e906', // EOS chain id - amount: '5.889675 XTKN', + amount: '5889675000000000000', sender: '0x000000000000000000000000f39fd6e51aad88f6f4ce6ab8827279cfffb92266', recipient: 'destinatieos', From 27c83dfb247c4eeb6a423cfa3c1b042dc4908d50 Mon Sep 17 00:00:00 2001 From: envin Date: Fri, 8 Nov 2024 22:57:06 +0100 Subject: [PATCH 09/11] chore: fix prettier path config --- cpp/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cpp/package.json b/cpp/package.json index 1e5a84e2..12f844bd 100644 --- a/cpp/package.json +++ b/cpp/package.json @@ -12,7 +12,7 @@ "test": "yarn build && mocha", "lint": "./lint scripts/*.sh && npx prettier --check test/", "prettier:fix": "npx prettier --check --write test/", - "prettier": "npx prettier --cache --check --ignore-path ../.prettierignore --config ../.prettierrc ./src ./test" + "prettier": "npx prettier --cache --check --ignore-path ../.prettierignore --config ../.prettierrc ./contracts ./test" }, "devDependencies": { "@eosnetwork/vert": "^1.0.0", From 03eb9f24e5a4ad7fe1083f422f058d0bfbaddd77 Mon Sep 17 00:00:00 2001 From: envin Date: Fri, 8 Nov 2024 23:10:45 +0100 Subject: [PATCH 10/11] style(adapter): update comments and variables definitions --- cpp/contracts/adapter.cpp | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/cpp/contracts/adapter.cpp b/cpp/contracts/adapter.cpp index 52cd9b7e..15f16e80 100644 --- a/cpp/contracts/adapter.cpp +++ b/cpp/contracts/adapter.cpp @@ -5,7 +5,7 @@ namespace eosio { asset adapter::calculate_fees(const asset& quantity) { registry_adapter _registry(get_self(), get_self().value); check(_registry.exists(), "contract not inizialized"); - adapter_registry_table registry_data = _registry.get(); + auto registry_data = _registry.get(); check( quantity.symbol == registry_data.token_symbol || @@ -39,20 +39,21 @@ void adapter::create( ) { require_auth(get_self()); registry_adapter _registry(get_self(), get_self().value); - check(!_registry.exists(), "adapter already registered"); + check(!_registry.exists(), "adapter already initialized"); auto _token_bytes = token_bytes.extract_as_byte_array(); check(is_account(xerc20), "xERC20 account does not exist"); check(min_fee.symbol == xerc20_symbol, "invalid minimum fee symbol"); check_symbol_is_valid(xerc20, xerc20_symbol); + // Checks done only for the local token if (token != name(0)) { - // checks done only for local token check_symbol_is_valid(token, token_symbol); check(token_symbol.precision() == xerc20_symbol.precision(), "invalid xerc20 precision"); check(is_account(token), "token account does not exist"); } + // Default value for the token symbol on non-local deployments symbol non_local_token_symbol = symbol(symbol_code("XXX"), token_symbol.precision()); adapter_registry_table registry_data { @@ -186,7 +187,7 @@ void adapter::settle(const name& caller, const operation& operation, const metad registry_adapter _registry(get_self(), get_self().value); check(_registry.exists(), "contract not inizialized"); - adapter_registry_table registry_data = _registry.get(); + auto registry_data = _registry.get(); check(registry_data.token_bytes == operation.token, "underlying token does not match with adapter registry"); checksum256 event_id; // output pam::check_authorization(get_self(), operation, metadata, event_id); @@ -335,7 +336,7 @@ void adapter::ontransfer(const name& from, const name& to, const asset& quantity registry_adapter _registry(get_self(), get_self().value); check(_registry.exists(), "contract not inizialized"); - adapter_registry_table registry_data = _registry.get(); + auto registry_data = _registry.get(); bool is_token_transfer = registry_data.token_symbol == quantity.symbol; bool is_xerc20_transfer = registry_data.xerc20_symbol == quantity.symbol; From 5ca48a2d23686752ea9d75a26b5a3178ff1ba6f1 Mon Sep 17 00:00:00 2001 From: envin Date: Fri, 8 Nov 2024 23:11:26 +0100 Subject: [PATCH 11/11] test(adapter): fix error message after style update --- cpp/test/adapter-non-local.test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cpp/test/adapter-non-local.test.js b/cpp/test/adapter-non-local.test.js index 23daaea0..f0eb96ce 100644 --- a/cpp/test/adapter-non-local.test.js +++ b/cpp/test/adapter-non-local.test.js @@ -344,7 +344,7 @@ describe('Adapter EVM -> EOS testing', () => { ]) .send(active(adapter.account)) - await expectToThrow(action, 'eosio_assert: adapter already registered') + await expectToThrow(action, 'eosio_assert: adapter already initialized') }) })