diff --git a/cpp/contracts/adapter.cpp b/cpp/contracts/adapter.cpp index 1416a1c..1be14bd 100644 --- a/cpp/contracts/adapter.cpp +++ b/cpp/contracts/adapter.cpp @@ -153,6 +153,15 @@ void adapter::freeuserdata(const name& account) { } } +void adapter::setchainid(bytes chain_id) { + require_auth(get_self()); + pam::chain_id _chain_id(get_self(), get_self().value); + + _chain_id.set(pam::local_chain_id{ + .chain_id = chain_id + }, get_self()); +} + void adapter::settee(public_key pub_key, bytes attestation) { require_auth(get_self()); pam::tee_pubkey _tee_pubkey(get_self(), get_self().value); diff --git a/cpp/contracts/adapter.hpp b/cpp/contracts/adapter.hpp index f063de5..c3c4db2 100644 --- a/cpp/contracts/adapter.hpp +++ b/cpp/contracts/adapter.hpp @@ -51,6 +51,8 @@ namespace eosio { ACTION setorigin(bytes chain_id, bytes emitter, bytes topic_zero); + ACTION setchainid(bytes chain_id); + ACTION swap(const bytes& event_bytes); ACTION settle(const name& caller, const operation& operation, const metadata& metadata); @@ -96,6 +98,7 @@ namespace eosio { // Define alias for ABI inclusion using mappings_table = pam::mappings_table; using tee_pubkey = pam::tee_pubkey; + using chain_id = pam::chain_id; global_storage_table empty_storage = { .nonce = 0, diff --git a/cpp/contracts/pam.hpp b/cpp/contracts/pam.hpp index 5f42ba6..8b9b70a 100644 --- a/cpp/contracts/pam.hpp +++ b/cpp/contracts/pam.hpp @@ -10,13 +10,6 @@ namespace eosio { using bytes = std::vector<uint8_t>; namespace pam { - // aca376f206b8fc25a6ed44dbdc66547c36c6c33e3a119ffbeaef943642f0e906 - const bytes CHAIN_ID = { - 0xac, 0xa3, 0x76, 0xf2, 0x06, 0xb8, 0xfc, 0x25, - 0xa6, 0xed, 0x44, 0xdb, 0xdc, 0x66, 0x54, 0x7c, - 0x36, 0xc6, 0xc3, 0x3e, 0x3a, 0x11, 0x9f, 0xfb, - 0xea, 0xef, 0x94, 0x36, 0x42, 0xf0, 0xe9, 0x06 - }; TABLE mappings { bytes chain_id; @@ -36,6 +29,10 @@ namespace eosio { } }; + TABLE local_chain_id { + bytes chain_id; + }; + TABLE tee { public_key key; public_key updating_key; @@ -44,6 +41,7 @@ namespace eosio { uint64_t change_grace_threshold = 0; }; + using chain_id = singleton<"chainid"_n, local_chain_id>; using tee_pubkey = singleton<"tee"_n, tee>; typedef eosio::multi_index<"mappings"_n, mappings> mappings_table; @@ -77,7 +75,12 @@ namespace eosio { // +----------- context ---------+------------- event ---------------+ check(context_checks(operation, metadata), "unexpected context"); + chain_id _chain_id(adapter, adapter.value); + check(_chain_id.exists(), "local chain id singleton not set"); + bytes local_chain_id = _chain_id.get().chain_id; + tee_pubkey _tee_pubkey(adapter, adapter.value); + check(_tee_pubkey.exists(), "tee singleton not set"); public_key tee_key = _tee_pubkey.get().key; uint128_t offset = 2; @@ -148,7 +151,7 @@ namespace eosio { bytes dest_chain_id = extract_32bytes(event_data, offset); check(operation.destinationChainId == dest_chain_id, "destination chain id does not match with the expected one"); - check(CHAIN_ID == dest_chain_id, "destination chain id does not match with the current chain"); + check(local_chain_id == dest_chain_id, "destination chain id does not match with the current chain"); offset += 32; bytes amount = extract_32bytes(event_data, offset); diff --git a/cpp/test/adapter-local.test.js b/cpp/test/adapter-local.test.js index 8f73d2f..f60ffba 100644 --- a/cpp/test/adapter-local.test.js +++ b/cpp/test/adapter-local.test.js @@ -48,6 +48,8 @@ describe('Adapter Testing - Local deployment', () => { '000000000000000000000000bcf063a9eb18bc3c6eb005791c61801b7cb16fe4' const evmTopicZero = '66756e6473206172652073616675207361667520736166752073616675202e2e' + const EOSChainId = + 'aca376f206b8fc25a6ed44dbdc66547c36c6c33e3a119ffbeaef943642f0e906' const token = { symbol: symbol, @@ -198,6 +200,12 @@ describe('Adapter Testing - Local deployment', () => { .send(active(adapter.account)) }) + it('Should set the local chain id successfully', async () => { + await adapter.contract.actions + .setchainid([EOSChainId]) + .send(active(adapter.account)) + }) + it('Should add the tee public key successfully', async () => { const teePubKey = fromEthersPublicKey( evmEA.signingKey.compressedPublicKey, diff --git a/cpp/test/adapter-non-local.test.js b/cpp/test/adapter-non-local.test.js index cc5c6ba..3f1a825 100644 --- a/cpp/test/adapter-non-local.test.js +++ b/cpp/test/adapter-non-local.test.js @@ -50,6 +50,8 @@ describe('Adapter Testing - Non Local Deployment', () => { '000000000000000000000000bcf063a9eb18bc3c6eb005791c61801b7cb16fe4' const evmTopicZero = '66756e6473206172652073616675207361667520736166752073616675202e2e' + const EOSChainId = + 'aca376f206b8fc25a6ed44dbdc66547c36c6c33e3a119ffbeaef943642f0e906' const token = { symbol, @@ -181,6 +183,12 @@ describe('Adapter Testing - Non Local Deployment', () => { .send(active(adapter.account)) }) + it('Should set the local chain id successfully', async () => { + await adapter.contract.actions + .setchainid([EOSChainId]) + .send(active(adapter.account)) + }) + it('Should add the tee public key successfully', async () => { const teePubKey = fromEthersPublicKey( evmEA.signingKey.compressedPublicKey, diff --git a/cpp/test/adapter.test.js b/cpp/test/adapter.test.js index 8a35bae..6dc3644 100644 --- a/cpp/test/adapter.test.js +++ b/cpp/test/adapter.test.js @@ -25,6 +25,7 @@ const { TimePointSec } = require('@wharfkit/antelope') const TEE_ADDRESS_CHANGE_GRACE_PERIOD_MS = 172800 * 1000 const TABLE_STORAGE = 'storage' const TABLE_TEE = 'tee' +const TABLE_LOCAL_CHAIN_ID = 'chainid' describe('Adapter tests', () => { const symbol = 'TST' @@ -48,6 +49,8 @@ describe('Adapter tests', () => { '000000000000000000000000bcf063a9eb18bc3c6eb005791c61801b7cb16fe4' const evmTopicZero = '66756e6473206172652073616675207361667520736166752073616675202e2e' + const EOSChainId = + 'aca376f206b8fc25a6ed44dbdc66547c36c6c33e3a119ffbeaef943642f0e906' const token = { symbol, @@ -367,6 +370,38 @@ describe('Adapter tests', () => { }) }) + describe('adapter::setchainid', () => { + it('Should throw if called by not authorized account', async () => { + const action = adapter.contract.actions + .setchainid([EOSChainId]) + .send(active(evil)) + + await expectToThrow(action, errors.AUTH_MISSING(adapter.account)) + }) + + it('Should set the local chain id correctly', async () => { + const chain_id = 'ababba' + await adapter.contract.actions + .setchainid([chain_id]) + .send(active(adapter.account)) + + const local_chain_id = getSingletonInstance( + adapter.contract, + TABLE_LOCAL_CHAIN_ID, + ) + expect(local_chain_id.chain_id).to.be.equal(chain_id) + }) + + it('Should update the local chain id correctly', async () => { + await adapter.contract.actions + .setchainid([EOSChainId]) + .send(active(adapter.account)) + + const local_chain_id = getSingletonInstance(adapter.contract, 'chainid') + expect(local_chain_id.chain_id).to.be.equal(EOSChainId) + }) + }) + describe('adapter::settee', () => { it('Should throw if called by not authorized account', async () => { const action = adapter.contract.actions diff --git a/cpp/test/pam.test.js b/cpp/test/pam.test.js index 1fb6b0c..21f5859 100644 --- a/cpp/test/pam.test.js +++ b/cpp/test/pam.test.js @@ -47,6 +47,8 @@ describe('PAM testing', () => { const evmEmitter = '0x5623D0aF4bfb6F7B18d6618C166d518E4357ceE2' const evmTopic0 = '0x66756e6473206172652073616675207361667520736166752073616675202e2e' + const EOSChainId = + 'aca376f206b8fc25a6ed44dbdc66547c36c6c33e3a119ffbeaef943642f0e906' const recipient = 'recipient' @@ -104,12 +106,24 @@ describe('PAM testing', () => { ) }) + it('Should reject when the local chain id is not set', async () => { + const action = pam.contract.actions + .isauthorized([operation, metadata]) + .send(active(user)) + + await expectToThrow(action, errors.LOCAL_CHAIN_NOT_SET) + }) + it('Should reject when the public key is not set', async () => { + await adapter.contract.actions + .setchainid([EOSChainId]) + .send(active(adapter.account)) + const action = pam.contract.actions .isauthorized([operation, metadata]) .send(active(user)) - await expectToThrow(action, errors.SINGLETON_NOT_EXISTING) + await expectToThrow(action, errors.TEE_NOT_SET) }) it('Should reject when the origin_chain_id is not set', async () => { diff --git a/cpp/test/utils/errors.js b/cpp/test/utils/errors.js index ee2a23f..5d9c7ee 100644 --- a/cpp/test/utils/errors.js +++ b/cpp/test/utils/errors.js @@ -27,7 +27,9 @@ const INVALID_MINFEE_SYMBOL = eosio_assert('invalid minimum fee symbol') const NOT_INITIALIZED = eosio_assert('adapter contract not initialized') -const SINGLETON_NOT_EXISTING = eosio_assert('singleton does not exist') +const TEE_NOT_SET = eosio_assert('tee singleton not set') + +const LOCAL_CHAIN_NOT_SET = eosio_assert('local chain id singleton not set') const ORIGIN_CHAINID_NOT_REGISTERED = eosio_assert( 'origin chain_id not registered', @@ -93,7 +95,8 @@ module.exports = { INVALID_MINFEE_SYMBOL, NOT_INITIALIZED, SYMBOL_NOT_FOUND, - SINGLETON_NOT_EXISTING, + TEE_NOT_SET, + LOCAL_CHAIN_NOT_SET, ORIGIN_CHAINID_NOT_REGISTERED, INVALID_SIGNATURE, UNEXPECTED_EMITTER,