From a1c8210833cfdb7f6b5beadf53eeb28be67fb15c Mon Sep 17 00:00:00 2001 From: nuno Date: Thu, 5 Jan 2023 16:35:37 +0100 Subject: [PATCH 01/45] connectors: Test Domain encoding --- pallets/connectors/src/message.rs | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/pallets/connectors/src/message.rs b/pallets/connectors/src/message.rs index 65e32b34fa..7704ef5e85 100644 --- a/pallets/connectors/src/message.rs +++ b/pallets/connectors/src/message.rs @@ -207,6 +207,24 @@ mod tests { assert_eq!(msg.encode(), vec![0]); } + #[test] + fn encoding_domain_evm() { + let evm_domain = Domain::EVM(u64::MAX); + + let expected_hex = "00ffffffffffffffff"; + let expected = <[u8; 9]>::from_hex(expected_hex).expect("Decoding failed"); + assert_eq!(evm_domain.encode(), expected); + } + + #[test] + fn encoding_domain_parachain() { + let parachain_domain = Domain::Parachain(ParachainId::Moonbeam); + + let expected_hex = "0100"; + let expected = <[u8; 2]>::from_hex(expected_hex).expect("Decoding failed"); + assert_eq!(parachain_domain.encode(), expected); + } + #[test] fn add_pool_zero() { let msg = Message::::AddPool { pool_id: 0 }; From fc3ec9ecfaae6484098d48268b9fdedfe4459a2a Mon Sep 17 00:00:00 2001 From: nuno Date: Thu, 19 Jan 2023 08:36:26 +0100 Subject: [PATCH 02/45] dev: Bump spec_version --- runtime/development/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/runtime/development/src/lib.rs b/runtime/development/src/lib.rs index a4f488c62d..41b4a44ab5 100644 --- a/runtime/development/src/lib.rs +++ b/runtime/development/src/lib.rs @@ -123,7 +123,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { spec_name: create_runtime_str!("centrifuge-devel"), impl_name: create_runtime_str!("centrifuge-devel"), authoring_version: 1, - spec_version: 1007, + spec_version: 1008, impl_version: 1, #[cfg(not(feature = "disable-runtime-api"))] apis: RUNTIME_API_VERSIONS, From 65c252d3791167f9e98d7d15f5e925bb4ff17b96 Mon Sep 17 00:00:00 2001 From: nuno Date: Fri, 20 Jan 2023 10:05:27 +0100 Subject: [PATCH 03/45] tmp: Enable full CI for this branch --- .github/workflows/build-nix.yml | 2 +- .github/workflows/build.yml | 2 +- .github/workflows/docker-nix.yml | 2 +- .github/workflows/docker.yml | 2 +- .github/workflows/lints.yml | 2 +- .github/workflows/tests.yml | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/build-nix.yml b/.github/workflows/build-nix.yml index 8476901543..ba87335c8b 100644 --- a/.github/workflows/build-nix.yml +++ b/.github/workflows/build-nix.yml @@ -2,7 +2,7 @@ name: nix-build on: pull_request: push: - branches: [main, 'release-v**'] + branches: [main, 'release-v**', 'connectors-v0.1.0'] jobs: build: runs-on: ubuntu-latest diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 7d6936d629..01f3f6a3a7 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -1,6 +1,6 @@ on: push: - branches: [main, 'release-v**'] + branches: [main, 'release-v**', 'connectors-v0.1.0'] pull_request: name: Build jobs: diff --git a/.github/workflows/docker-nix.yml b/.github/workflows/docker-nix.yml index b695af4bfe..be3b65b405 100644 --- a/.github/workflows/docker-nix.yml +++ b/.github/workflows/docker-nix.yml @@ -1,7 +1,7 @@ name: docker on: push: - branches: [main, 'release-v**'] + branches: [main, 'release-v**', 'connectors-v0.1.0'] jobs: docker: strategy: diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index 63e5671f23..82d6ef79a7 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -1,7 +1,7 @@ name: docker on: push: - branches: [main, 'release-v**'] + branches: [main, 'release-v**', 'connectors-v0.1.0'] workflow_dispatch: inputs: docker_tag: diff --git a/.github/workflows/lints.yml b/.github/workflows/lints.yml index 6d94b7b983..8c7ca8ae3e 100644 --- a/.github/workflows/lints.yml +++ b/.github/workflows/lints.yml @@ -1,6 +1,6 @@ on: push: - branches: [main, 'release-v**'] + branches: [main, 'release-v**', 'connectors-v0.1.0'] pull_request: name: Lints jobs: diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index a516aca493..bb17ddfb76 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -1,6 +1,6 @@ on: push: - branches: [main, 'release-v**'] + branches: [main, 'release-v**', 'connectors-v0.1.0'] pull_request: name: Tests jobs: From d02bf35963e2d954e166f1dc8a48564969dd9b90 Mon Sep 17 00:00:00 2001 From: nuno Date: Tue, 24 Jan 2023 10:08:02 +0100 Subject: [PATCH 04/45] Test ethereum mainnet and avalanche domain encoding --- pallets/connectors/src/message.rs | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/pallets/connectors/src/message.rs b/pallets/connectors/src/message.rs index 7704ef5e85..2f9016c1a6 100644 --- a/pallets/connectors/src/message.rs +++ b/pallets/connectors/src/message.rs @@ -208,21 +208,30 @@ mod tests { } #[test] - fn encoding_domain_evm() { - let evm_domain = Domain::EVM(u64::MAX); + fn encoding_domain_evm_ethereum_mainnet() { + let domain = Domain::EVM(1); - let expected_hex = "00ffffffffffffffff"; + let expected_hex = "000100000000000000"; let expected = <[u8; 9]>::from_hex(expected_hex).expect("Decoding failed"); - assert_eq!(evm_domain.encode(), expected); + assert_eq!(domain.encode(), expected); + } + + #[test] + fn encoding_domain_evm_avalanche() { + let domain = Domain::EVM(43114); + + let expected_hex = "006aa8000000000000"; + let expected = <[u8; 9]>::from_hex(expected_hex).expect("Decoding failed"); + assert_eq!(domain.encode(), expected); } #[test] fn encoding_domain_parachain() { - let parachain_domain = Domain::Parachain(ParachainId::Moonbeam); + let domain = Domain::Parachain(ParachainId::Moonbeam); let expected_hex = "0100"; let expected = <[u8; 2]>::from_hex(expected_hex).expect("Decoding failed"); - assert_eq!(parachain_domain.encode(), expected); + assert_eq!(domain.encode(), expected); } #[test] From f126ceae852b726e33b8f8d15e8a62a6b4dd1014 Mon Sep 17 00:00:00 2001 From: nuno Date: Wed, 25 Jan 2023 16:04:17 +0100 Subject: [PATCH 05/45] Un-skip and fix transfer message encoding test --- pallets/connectors/src/lib.rs | 2 +- pallets/connectors/src/message.rs | 7 +++---- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/pallets/connectors/src/lib.rs b/pallets/connectors/src/lib.rs index ab4aca3049..de71c22c82 100644 --- a/pallets/connectors/src/lib.rs +++ b/pallets/connectors/src/lib.rs @@ -465,7 +465,7 @@ pub mod pallet { encoded.append( &mut xcm_primitives::EthereumXcmTransaction::V1( xcm_primitives::EthereumXcmTransactionV1 { - gas_limit: U256::from(80_000), + gas_limit: U256::from(500_000), fee_payment: xcm_primitives::EthereumXcmFee::Auto, action: pallet_ethereum::TransactionAction::Call( xcm_domain.contract_address, diff --git a/pallets/connectors/src/message.rs b/pallets/connectors/src/message.rs index 2f9016c1a6..4a26e76a0f 100644 --- a/pallets/connectors/src/message.rs +++ b/pallets/connectors/src/message.rs @@ -306,7 +306,6 @@ mod tests { } #[test] - #[ignore = "wip"] fn transfer() { let msg = Message::::Transfer { pool_id: 1, @@ -316,10 +315,10 @@ mod tests { amount: 100 * CURRENCY, }; let encoded = msg.encode(); - println!("{}", hex::encode(encoded.clone())); - let input = "0500000000000000010000000000000000000000000000000101010101010101010101010101010101010101010101010101010101010101016400000000000000"; - let expected = <[u8; 65]>::from_hex(input).expect("Decoding failed"); + let input = "0500000000000000010000000000000000000000000000000101000101010101010101010101010101010101010101010101010101010101010101000010632d5ec76b0500000000000000"; + + let expected = <[u8; 75]>::from_hex(input).expect("Decoding failed"); assert_eq!(encoded, expected); } } From 252efa68fa54d0c6b17fe63bac7fd765171c9c57 Mon Sep 17 00:00:00 2001 From: nuno Date: Wed, 25 Jan 2023 16:33:48 +0100 Subject: [PATCH 06/45] fix encoded_ethereum_xcm_add_pool --- .../integration-tests/src/xcm/development/tests/connectors.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/runtime/integration-tests/src/xcm/development/tests/connectors.rs b/runtime/integration-tests/src/xcm/development/tests/connectors.rs index f62f62fa61..a8c74e7333 100644 --- a/runtime/integration-tests/src/xcm/development/tests/connectors.rs +++ b/runtime/integration-tests/src/xcm/development/tests/connectors.rs @@ -261,7 +261,7 @@ fn test_vec_to_fixed_array() { fn encoded_ethereum_xcm_add_pool() { // Ethereum_xcm with Connectors::hande(Message::AddPool) as `input` - this was our first // successfully ethereum_xcm encoded call tested in Moonbase. - let expected_encoded_hex = "26000080380100000000000000000000000000000000000000000000000000000000000100ce0cb9bb900dfd0d378393a041f3abab6b18288200000000000000000000000000000000000000000000000000000000000000009101bf48bcb600000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000009010000000000bce1a4000000000000000000000000000000000000000000000000"; + let expected_encoded_hex = "26000020a10700000000000000000000000000000000000000000000000000000000000100ce0cb9bb900dfd0d378393a041f3abab6b18288200000000000000000000000000000000000000000000000000000000000000009101bf48bcb600000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000009010000000000bce1a4000000000000000000000000000000000000000000000000"; let _expected_encoded = hex::decode(expected_encoded_hex).expect("Decode failed"); let moonbase_location = MultiLocation { From 881412976417f830544448f8e0e4714dfb1450b8 Mon Sep 17 00:00:00 2001 From: nuno Date: Wed, 25 Jan 2023 17:01:31 +0100 Subject: [PATCH 07/45] Add `max_gas_limit` to XcmDomain --- pallets/connectors/src/lib.rs | 2 +- pallets/connectors/src/routers.rs | 2 ++ .../integration-tests/src/xcm/development/tests/connectors.rs | 4 +++- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/pallets/connectors/src/lib.rs b/pallets/connectors/src/lib.rs index de71c22c82..071ec23050 100644 --- a/pallets/connectors/src/lib.rs +++ b/pallets/connectors/src/lib.rs @@ -465,7 +465,7 @@ pub mod pallet { encoded.append( &mut xcm_primitives::EthereumXcmTransaction::V1( xcm_primitives::EthereumXcmTransactionV1 { - gas_limit: U256::from(500_000), + gas_limit: U256::from(xcm_domain.max_gas_limit), fee_payment: xcm_primitives::EthereumXcmFee::Auto, action: pallet_ethereum::TransactionAction::Call( xcm_domain.contract_address, diff --git a/pallets/connectors/src/routers.rs b/pallets/connectors/src/routers.rs index 13066d4c12..93bab7e744 100644 --- a/pallets/connectors/src/routers.rs +++ b/pallets/connectors/src/routers.rs @@ -28,6 +28,8 @@ pub struct XcmDomain { pub contract_address: H160, /// The currency in which execution fees will be paid on pub fee_currency: CurrencyId, + /// The max gas_limit we want to propose for a remote evm execution + pub max_gas_limit: u128, } // NOTE: Remove this custom implementation once the following underlying data implements MaxEncodedLen: diff --git a/runtime/integration-tests/src/xcm/development/tests/connectors.rs b/runtime/integration-tests/src/xcm/development/tests/connectors.rs index a8c74e7333..bd6215e2d8 100644 --- a/runtime/integration-tests/src/xcm/development/tests/connectors.rs +++ b/runtime/integration-tests/src/xcm/development/tests/connectors.rs @@ -261,7 +261,7 @@ fn test_vec_to_fixed_array() { fn encoded_ethereum_xcm_add_pool() { // Ethereum_xcm with Connectors::hande(Message::AddPool) as `input` - this was our first // successfully ethereum_xcm encoded call tested in Moonbase. - let expected_encoded_hex = "26000020a10700000000000000000000000000000000000000000000000000000000000100ce0cb9bb900dfd0d378393a041f3abab6b18288200000000000000000000000000000000000000000000000000000000000000009101bf48bcb600000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000009010000000000bce1a4000000000000000000000000000000000000000000000000"; + let expected_encoded_hex = "26000060ae0a00000000000000000000000000000000000000000000000000000000000100ce0cb9bb900dfd0d378393a041f3abab6b18288200000000000000000000000000000000000000000000000000000000000000009101bf48bcb600000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000009010000000000bce1a4000000000000000000000000000000000000000000000000"; let _expected_encoded = hex::decode(expected_encoded_hex).expect("Decode failed"); let moonbase_location = MultiLocation { @@ -278,6 +278,7 @@ fn encoded_ethereum_xcm_add_pool() { ethereum_xcm_transact_call_index, contract_address, fee_currency: ForeignAsset(1), + max_gas_limit: 700_000, }; let connectors_message = @@ -366,6 +367,7 @@ mod utils { .expect("Invalid address"), ), fee_currency: glmr_currency_id, + max_gas_limit: 700_000, }), )); From 001795fe29a2584f140cd57d54cf455ad999070d Mon Sep 17 00:00:00 2001 From: nuno Date: Wed, 25 Jan 2023 17:07:55 +0100 Subject: [PATCH 08/45] dev: Bump spec_version to 1009 --- runtime/development/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/runtime/development/src/lib.rs b/runtime/development/src/lib.rs index 41b4a44ab5..0ac63d78f8 100644 --- a/runtime/development/src/lib.rs +++ b/runtime/development/src/lib.rs @@ -123,7 +123,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { spec_name: create_runtime_str!("centrifuge-devel"), impl_name: create_runtime_str!("centrifuge-devel"), authoring_version: 1, - spec_version: 1008, + spec_version: 1009, impl_version: 1, #[cfg(not(feature = "disable-runtime-api"))] apis: RUNTIME_API_VERSIONS, From c82ed7fb430f12aa2e0272bce25a170e5a1e3203 Mon Sep 17 00:00:00 2001 From: nuno Date: Wed, 25 Jan 2023 18:56:59 +0100 Subject: [PATCH 09/45] Derive transact_required_weight_at_most from gas_limit --- pallets/connectors/src/lib.rs | 2 +- pallets/connectors/src/routers.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pallets/connectors/src/lib.rs b/pallets/connectors/src/lib.rs index 071ec23050..197b7410df 100644 --- a/pallets/connectors/src/lib.rs +++ b/pallets/connectors/src/lib.rs @@ -434,7 +434,7 @@ pub mod pallet { OriginKind::SovereignAccount, TransactWeights { // Specify a conservative max weight - transact_required_weight_at_most: 8_000_000_000, + transact_required_weight_at_most: xcm_domain.max_gas_limit * 25_000 + 100_000_000, overall_weight: None, }, )?; diff --git a/pallets/connectors/src/routers.rs b/pallets/connectors/src/routers.rs index 93bab7e744..fd229c8d2d 100644 --- a/pallets/connectors/src/routers.rs +++ b/pallets/connectors/src/routers.rs @@ -29,7 +29,7 @@ pub struct XcmDomain { /// The currency in which execution fees will be paid on pub fee_currency: CurrencyId, /// The max gas_limit we want to propose for a remote evm execution - pub max_gas_limit: u128, + pub max_gas_limit: u64, } // NOTE: Remove this custom implementation once the following underlying data implements MaxEncodedLen: From 3ad77ffb7fdd653bd4ec2f68a1cfc7b5d5020c51 Mon Sep 17 00:00:00 2001 From: nuno Date: Wed, 25 Jan 2023 18:57:31 +0100 Subject: [PATCH 10/45] fmt --- pallets/connectors/src/lib.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pallets/connectors/src/lib.rs b/pallets/connectors/src/lib.rs index 197b7410df..957aa283a0 100644 --- a/pallets/connectors/src/lib.rs +++ b/pallets/connectors/src/lib.rs @@ -434,7 +434,8 @@ pub mod pallet { OriginKind::SovereignAccount, TransactWeights { // Specify a conservative max weight - transact_required_weight_at_most: xcm_domain.max_gas_limit * 25_000 + 100_000_000, + transact_required_weight_at_most: xcm_domain.max_gas_limit * 25_000 + + 100_000_000, overall_weight: None, }, )?; From ad71b3b6424686c75bc45337a883dc3ddceeb95d Mon Sep 17 00:00:00 2001 From: nuno Date: Wed, 25 Jan 2023 19:14:08 +0100 Subject: [PATCH 11/45] dev: Bump spec_version to 1010 --- runtime/development/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/runtime/development/src/lib.rs b/runtime/development/src/lib.rs index 0ac63d78f8..9e3f85b474 100644 --- a/runtime/development/src/lib.rs +++ b/runtime/development/src/lib.rs @@ -123,7 +123,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { spec_name: create_runtime_str!("centrifuge-devel"), impl_name: create_runtime_str!("centrifuge-devel"), authoring_version: 1, - spec_version: 1009, + spec_version: 1010, impl_version: 1, #[cfg(not(feature = "disable-runtime-api"))] apis: RUNTIME_API_VERSIONS, From 79be0de8dbb486f0f0d4f98903ac1df85183ee24 Mon Sep 17 00:00:00 2001 From: nuno Date: Thu, 26 Jan 2023 19:37:22 +0100 Subject: [PATCH 12/45] Test update_member_that_failed --- pallets/connectors/src/message.rs | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/pallets/connectors/src/message.rs b/pallets/connectors/src/message.rs index 4a26e76a0f..44b232b850 100644 --- a/pallets/connectors/src/message.rs +++ b/pallets/connectors/src/message.rs @@ -305,6 +305,21 @@ mod tests { assert_eq!(encoded, expected); } + #[test] + fn update_member_that_failed() { + let msg = Message::::UpdateMember { + pool_id: 2, + tranche_id: <[u8; 16]>::from_hex("811acd5b3f17c06841c7e41e9e04cb1b").expect(""), + address: <[u8; 32]>::from_hex("1231231231231231231231231231231231231231231231231231231231231231").expect(""), + valid_until: 1706260138, + }; + let encoded = msg.encode(); + + let input = "040000000000000002811acd5b3f17c06841c7e41e9e04cb1b1231231231231231231231231231231231231231231231231231231231231231aa76b36500000000"; + let expected = <[u8; 65]>::from_hex(input).expect("Decoding failed"); + assert_eq!(hex::encode(encoded), hex::encode(expected)); + } + #[test] fn transfer() { let msg = Message::::Transfer { From fde1c8aa819fc2231629e0470b6668220028ebb0 Mon Sep 17 00:00:00 2001 From: nuno Date: Mon, 30 Jan 2023 11:52:26 +0100 Subject: [PATCH 13/45] fix: Align valid_until encoding to solidity counterpart --- pallets/connectors/src/message.rs | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/pallets/connectors/src/message.rs b/pallets/connectors/src/message.rs index 44b232b850..4426f43ea7 100644 --- a/pallets/connectors/src/message.rs +++ b/pallets/connectors/src/message.rs @@ -152,7 +152,10 @@ impl< message.append(&mut tranche_id.encode()); message.append(&mut address.encode()); - message.append(&mut valid_until.encode()); + + let mut encoded_valid_until = valid_until.encode(); + encoded_valid_until.reverse(); + message.append(&mut encoded_valid_until); message } @@ -300,7 +303,7 @@ mod tests { }; let encoded = msg.encode(); - let input = "0400000000000000010000000000000000000000000000000101010101010101010101010101010101010101010101010101010101010101016400000000000000"; + let input = "0400000000000000010000000000000000000000000000000101010101010101010101010101010101010101010101010101010101010101010000000000000064"; let expected = <[u8; 65]>::from_hex(input).expect("Decoding failed"); assert_eq!(encoded, expected); } @@ -315,7 +318,8 @@ mod tests { }; let encoded = msg.encode(); - let input = "040000000000000002811acd5b3f17c06841c7e41e9e04cb1b1231231231231231231231231231231231231231231231231231231231231231aa76b36500000000"; + // 65B376AA - AA 76 B3 65 + let input = "040000000000000002811acd5b3f17c06841c7e41e9e04cb1b12312312312312312312312312312312312312312312312312312312312312310000000065B376AA"; let expected = <[u8; 65]>::from_hex(input).expect("Decoding failed"); assert_eq!(hex::encode(encoded), hex::encode(expected)); } From c9549f797c63c98c16d483359b14faf59d233ea8 Mon Sep 17 00:00:00 2001 From: nuno Date: Mon, 30 Jan 2023 15:49:33 +0100 Subject: [PATCH 14/45] Add price to `AddTranche` --- pallets/connectors/src/lib.rs | 3 +++ pallets/connectors/src/message.rs | 6 +++++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/pallets/connectors/src/lib.rs b/pallets/connectors/src/lib.rs index 957aa283a0..f2fb7785ae 100644 --- a/pallets/connectors/src/lib.rs +++ b/pallets/connectors/src/lib.rs @@ -266,6 +266,8 @@ pub mod pallet { .ok_or(Error::::TrancheMetadataNotFound)?; let token_name = vec_to_fixed_array(metadata.name); let token_symbol = vec_to_fixed_array(metadata.symbol); + let latest_price = T::PoolInspect::get_tranche_token_price(pool_id, tranche_id) + .ok_or(Error::::MissingTranchePrice)?; // Send the message to the domain Self::do_send_message( @@ -275,6 +277,7 @@ pub mod pallet { tranche_id, token_name, token_symbol, + price: latest_price.price, }, domain, )?; diff --git a/pallets/connectors/src/message.rs b/pallets/connectors/src/message.rs index 4426f43ea7..4b8227c35b 100644 --- a/pallets/connectors/src/message.rs +++ b/pallets/connectors/src/message.rs @@ -33,6 +33,7 @@ where tranche_id: TrancheId, token_name: [u8; TOKEN_NAME_SIZE], token_symbol: [u8; TOKEN_SYMBOL_SIZE], + price: Rate, }, UpdateTokenPrice { pool_id: PoolId, @@ -106,6 +107,7 @@ impl< tranche_id, token_name, token_symbol, + price, } => { let mut message: Vec = vec![]; message.push(self.call_type()); @@ -117,6 +119,7 @@ impl< message.append(&mut tranche_id.encode()); message.append(&mut token_name.encode()); message.append(&mut token_symbol.encode()); + message.append(&mut price.encode()); message } @@ -265,12 +268,13 @@ mod tests { tranche_id: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1], token_name: [5; 128], token_symbol: [6; 32], + price: Rate::one(), }; let encoded_bytes = msg.encode(); // We encode the encoded bytes as hex to verify it's what we expect let encoded_hex = hex::encode(encoded_bytes.clone()); - let expected_hex = "020000000000bce1a40000000000000000000000000000000105050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050606060606060606060606060606060606060606060606060606060606060606"; + let expected_hex = "020000000000bce1a40000000000000000000000000000000105050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050606060606060606060606060606060606060606060606060606060606060606000000e83c80d09f3c2e3b0300000000"; assert_eq!(expected_hex, encoded_hex); // Now decode the bytes encoded as hex back to bytes and verify it's the same as From 1e0e8bb7e6e4387df40845915d77b06a5cf52c47 Mon Sep 17 00:00:00 2001 From: nuno Date: Mon, 30 Jan 2023 15:53:38 +0100 Subject: [PATCH 15/45] Encode AddTranche.price as little endian --- pallets/connectors/src/message.rs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/pallets/connectors/src/message.rs b/pallets/connectors/src/message.rs index 4b8227c35b..e522dc49d3 100644 --- a/pallets/connectors/src/message.rs +++ b/pallets/connectors/src/message.rs @@ -119,7 +119,10 @@ impl< message.append(&mut tranche_id.encode()); message.append(&mut token_name.encode()); message.append(&mut token_symbol.encode()); - message.append(&mut price.encode()); + + let mut encoded_price = price.encode(); + encoded_price.reverse(); + message.append(&mut encoded_price); message } @@ -274,7 +277,7 @@ mod tests { // We encode the encoded bytes as hex to verify it's what we expect let encoded_hex = hex::encode(encoded_bytes.clone()); - let expected_hex = "020000000000bce1a40000000000000000000000000000000105050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050606060606060606060606060606060606060606060606060606060606060606000000e83c80d09f3c2e3b0300000000"; + let expected_hex = "020000000000bce1a4000000000000000000000000000000010505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505060606060606060606060606060606060606060606060606060606060606060600000000033b2e3c9fd0803ce8000000"; assert_eq!(expected_hex, encoded_hex); // Now decode the bytes encoded as hex back to bytes and verify it's the same as From 1a3f64bfe2d111aa7da6a0659235dbc72d822319 Mon Sep 17 00:00:00 2001 From: nuno Date: Tue, 31 Jan 2023 14:28:18 +0100 Subject: [PATCH 16/45] Encode UpdateTokenPrice.price as le --- pallets/connectors/src/message.rs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/pallets/connectors/src/message.rs b/pallets/connectors/src/message.rs index e522dc49d3..14b26e562e 100644 --- a/pallets/connectors/src/message.rs +++ b/pallets/connectors/src/message.rs @@ -139,7 +139,10 @@ impl< message.append(&mut encoded_pool_id); message.append(&mut tranche_id.encode()); - message.append(&mut price.encode()); + + let mut encoded_price = price.encode(); + encoded_price.reverse(); + message.append(&mut encoded_price); message } @@ -290,12 +293,12 @@ mod tests { fn update_token_price() { let msg = Message::::UpdateTokenPrice { pool_id: 1, - tranche_id: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1], + tranche_id: <[u8; 16]>::from_hex("811acd5b3f17c06841c7e41e9e04cb1b").expect(""), price: Rate::one(), }; let encoded = msg.encode(); - let input = "03000000000000000100000000000000000000000000000001000000e83c80d09f3c2e3b0300000000"; + let input = "030000000000000001811acd5b3f17c06841c7e41e9e04cb1b00000000033b2e3c9fd0803ce8000000"; let expected = <[u8; 41]>::from_hex(input).expect("Decoding failed"); assert_eq!(encoded, expected); } From c0c32d40b3e6655286d99cad9788de04bd2e04ee Mon Sep 17 00:00:00 2001 From: nuno Date: Tue, 31 Jan 2023 19:37:03 +0100 Subject: [PATCH 17/45] Fix add_tranche test --- pallets/connectors/src/message.rs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/pallets/connectors/src/message.rs b/pallets/connectors/src/message.rs index 14b26e562e..9e9988730d 100644 --- a/pallets/connectors/src/message.rs +++ b/pallets/connectors/src/message.rs @@ -209,6 +209,7 @@ mod tests { const CURRENCY: Balance = 1_000_000_000_000_000_000; pub mod encode { + use cfg_utils::vec_to_fixed_array; use super::*; use crate::{Domain, ParachainId}; @@ -271,16 +272,16 @@ mod tests { fn add_tranche() { let msg = Message::::AddTranche { pool_id: 12378532, - tranche_id: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1], - token_name: [5; 128], - token_symbol: [6; 32], + tranche_id: <[u8; 16]>::from_hex("811acd5b3f17c06841c7e41e9e04cb1b").expect(""), + token_name: vec_to_fixed_array("Some Name".to_string().into_bytes()), + token_symbol: vec_to_fixed_array("SYMBOL".to_string().into_bytes()), price: Rate::one(), }; let encoded_bytes = msg.encode(); // We encode the encoded bytes as hex to verify it's what we expect let encoded_hex = hex::encode(encoded_bytes.clone()); - let expected_hex = "020000000000bce1a4000000000000000000000000000000010505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505060606060606060606060606060606060606060606060606060606060606060600000000033b2e3c9fd0803ce8000000"; + let expected_hex = "020000000000bce1a4811acd5b3f17c06841c7e41e9e04cb1b536f6d65204e616d65000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000053594d424f4c000000000000000000000000000000000000000000000000000000000000033b2e3c9fd0803ce8000000"; assert_eq!(expected_hex, encoded_hex); // Now decode the bytes encoded as hex back to bytes and verify it's the same as From 45550a76027c85ccc5a097b49fb82758c995f5ce Mon Sep 17 00:00:00 2001 From: nuno Date: Wed, 1 Feb 2023 08:55:04 +0100 Subject: [PATCH 18/45] Dry tranche_id_from_hex --- pallets/connectors/src/message.rs | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/pallets/connectors/src/message.rs b/pallets/connectors/src/message.rs index 9e9988730d..4802b8f37e 100644 --- a/pallets/connectors/src/message.rs +++ b/pallets/connectors/src/message.rs @@ -329,8 +329,7 @@ mod tests { }; let encoded = msg.encode(); - // 65B376AA - AA 76 B3 65 - let input = "040000000000000002811acd5b3f17c06841c7e41e9e04cb1b12312312312312312312312312312312312312312312312312312312312312310000000065B376AA"; + let input = "040000000000000002811acd5b3f17c06841c7e41e9e04cb1b12312312312312312312312312312312312312312312312312312312312312310000000065b376aa"; let expected = <[u8; 65]>::from_hex(input).expect("Decoding failed"); assert_eq!(hex::encode(encoded), hex::encode(expected)); } @@ -339,7 +338,7 @@ mod tests { fn transfer() { let msg = Message::::Transfer { pool_id: 1, - tranche_id: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1], + tranche_id: tranche_id_from_hex("811acd5b3f17c06841c7e41e9e04cb1b"), domain: Domain::Parachain(ParachainId::Moonbeam), destination: [1; 32], amount: 100 * CURRENCY, @@ -352,4 +351,10 @@ mod tests { assert_eq!(encoded, expected); } } + + fn tranche_id_from_hex(hex: &str) -> TrancheId { + <[u8; 16]>::from_hex(hex).expect("Should be valid tranche id") + } } + + From 06ed7a4fa7f32de9dde44954472c9b857d2d5f2d Mon Sep 17 00:00:00 2001 From: nuno Date: Wed, 1 Feb 2023 09:03:07 +0100 Subject: [PATCH 19/45] Test transfer to xcm and evm domains --- pallets/connectors/src/message.rs | 25 +++++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/pallets/connectors/src/message.rs b/pallets/connectors/src/message.rs index 4802b8f37e..4b022bad35 100644 --- a/pallets/connectors/src/message.rs +++ b/pallets/connectors/src/message.rs @@ -335,21 +335,38 @@ mod tests { } #[test] - fn transfer() { + fn transfer_xcm_domain() { let msg = Message::::Transfer { pool_id: 1, tranche_id: tranche_id_from_hex("811acd5b3f17c06841c7e41e9e04cb1b"), domain: Domain::Parachain(ParachainId::Moonbeam), - destination: [1; 32], - amount: 100 * CURRENCY, + destination: <[u8; 32]>::from_hex("1231231231231231231231231231231231231231231231231231231231231231").expect(""), + amount: 123 * CURRENCY, }; let encoded = msg.encode(); - let input = "0500000000000000010000000000000000000000000000000101000101010101010101010101010101010101010101010101010101010101010101000010632d5ec76b0500000000000000"; + let input = "050000000000000001811acd5b3f17c06841c7e41e9e04cb1b0100123123123123123123123123123123123123123123123123123123123123123100000c6d51c8f7aa0600000000000000"; let expected = <[u8; 75]>::from_hex(input).expect("Decoding failed"); assert_eq!(encoded, expected); } + + #[test] + fn transfer_evm_domain() { + let msg = Message::::Transfer { + pool_id: 1, + tranche_id: tranche_id_from_hex("811acd5b3f17c06841c7e41e9e04cb1b"), + domain: Domain::EVM(43114), + destination: <[u8; 32]>::from_hex("1231231231231231231231231231231231231231231231231231231231231231").expect(""), + amount: 123 * CURRENCY, + }; + let encoded = msg.encode(); + + let input = "050000000000000001811acd5b3f17c06841c7e41e9e04cb1b006aa8000000000000123123123123123123123123123123123123123123123123123123123123123100000c6d51c8f7aa0600000000000000"; + + let expected = <[u8; 82]>::from_hex(input).expect("Decoding failed"); + assert_eq!(encoded, expected); + } } fn tranche_id_from_hex(hex: &str) -> TrancheId { From eb7855595df203121327bde30cea406f6a91b7c1 Mon Sep 17 00:00:00 2001 From: nuno Date: Tue, 7 Feb 2023 09:37:11 +0100 Subject: [PATCH 20/45] Fix MissingTranchePrice error --- pallets/connectors/src/message.rs | 18 +++++++++++++----- .../src/xcm/development/tests/connectors.rs | 7 +++++-- 2 files changed, 18 insertions(+), 7 deletions(-) diff --git a/pallets/connectors/src/message.rs b/pallets/connectors/src/message.rs index 4b022bad35..35e9122b4d 100644 --- a/pallets/connectors/src/message.rs +++ b/pallets/connectors/src/message.rs @@ -210,6 +210,7 @@ mod tests { pub mod encode { use cfg_utils::vec_to_fixed_array; + use super::*; use crate::{Domain, ParachainId}; @@ -324,7 +325,10 @@ mod tests { let msg = Message::::UpdateMember { pool_id: 2, tranche_id: <[u8; 16]>::from_hex("811acd5b3f17c06841c7e41e9e04cb1b").expect(""), - address: <[u8; 32]>::from_hex("1231231231231231231231231231231231231231231231231231231231231231").expect(""), + address: <[u8; 32]>::from_hex( + "1231231231231231231231231231231231231231231231231231231231231231", + ) + .expect(""), valid_until: 1706260138, }; let encoded = msg.encode(); @@ -340,7 +344,10 @@ mod tests { pool_id: 1, tranche_id: tranche_id_from_hex("811acd5b3f17c06841c7e41e9e04cb1b"), domain: Domain::Parachain(ParachainId::Moonbeam), - destination: <[u8; 32]>::from_hex("1231231231231231231231231231231231231231231231231231231231231231").expect(""), + destination: <[u8; 32]>::from_hex( + "1231231231231231231231231231231231231231231231231231231231231231", + ) + .expect(""), amount: 123 * CURRENCY, }; let encoded = msg.encode(); @@ -357,7 +364,10 @@ mod tests { pool_id: 1, tranche_id: tranche_id_from_hex("811acd5b3f17c06841c7e41e9e04cb1b"), domain: Domain::EVM(43114), - destination: <[u8; 32]>::from_hex("1231231231231231231231231231231231231231231231231231231231231231").expect(""), + destination: <[u8; 32]>::from_hex( + "1231231231231231231231231231231231231231231231231231231231231231", + ) + .expect(""), amount: 123 * CURRENCY, }; let encoded = msg.encode(); @@ -373,5 +383,3 @@ mod tests { <[u8; 16]>::from_hex(hex).expect("Should be valid tranche id") } } - - diff --git a/runtime/integration-tests/src/xcm/development/tests/connectors.rs b/runtime/integration-tests/src/xcm/development/tests/connectors.rs index bd6215e2d8..3006bc827f 100644 --- a/runtime/integration-tests/src/xcm/development/tests/connectors.rs +++ b/runtime/integration-tests/src/xcm/development/tests/connectors.rs @@ -37,8 +37,8 @@ use cfg_types::{ }; use codec::Encode; use development_runtime::{ - Balances, Connectors, OrmlAssetRegistry, OrmlTokens, Permissions, PoolSystem, RuntimeOrigin, - XTokens, XcmTransactor, + Balances, Connectors, Loans, OrmlAssetRegistry, OrmlTokens, Permissions, PoolSystem, + RuntimeOrigin, XTokens, XcmTransactor, }; use frame_support::{assert_noop, assert_ok, dispatch::Weight, traits::Get}; use hex::FromHex; @@ -141,6 +141,9 @@ fn add_tranche() { .tranche_id(TrancheLoc::Index(0)) .expect("Tranche at index 0 exists"); + Loans::update_nav(RuntimeOrigin::signed(ALICE.into()), pool_id.clone()) + .expect("Should update nav"); + // Finally, verify we can call Connectors::add_tranche successfully // when given a valid pool + tranche id pair. assert_ok!(Connectors::add_tranche( From eea37ae251b1f461a19ed7f1abfb5fe52cab004e Mon Sep 17 00:00:00 2001 From: nuno Date: Tue, 7 Feb 2023 14:57:04 +0100 Subject: [PATCH 21/45] Redesign DomainAddress type --- pallets/connectors/src/lib.rs | 64 +++++++++++++------ pallets/connectors/src/message.rs | 64 +++++++------------ .../src/xcm/development/tests/connectors.rs | 19 +++--- 3 files changed, 74 insertions(+), 73 deletions(-) diff --git a/pallets/connectors/src/lib.rs b/pallets/connectors/src/lib.rs index f2fb7785ae..78c5596490 100644 --- a/pallets/connectors/src/lib.rs +++ b/pallets/connectors/src/lib.rs @@ -45,10 +45,6 @@ pub enum ParachainId { Moonbeam, } -/// The EVM chain ID -/// The type should accomodate all chain ids listed on https://chainlist.org/. -type EVMChainId = u64; - /// A Domain is a chain or network we can send a Connectors message to. /// The domain indices need to match those used in the EVM contracts and these /// need to pass the Centrifuge domain to send tranche tokens from the other @@ -56,12 +52,18 @@ type EVMChainId = u64; #[derive(Encode, Decode, Clone, PartialEq, TypeInfo, MaxEncodedLen)] #[cfg_attr(feature = "std", derive(Debug))] pub enum Domain { + /// Referring to the Centrifuge Parachain. Will be used for handling incoming messages. + /// NOTE: Connectors messages CAN NOT be sent directly from the Centrifuge chain to the + /// Centrifuge chain itself. + Centrifuge, /// An EVM domain, identified by its EVM Chain Id EVM(EVMChainId), - /// A Polkadot Parachain domain - Parachain(ParachainId), } +/// The EVM Chain ID +/// The type should accomodate all chain ids listed on https://chainlist.org/. +type EVMChainId = u64; + #[derive(Encode, Decode, Clone, Eq, PartialEq, TypeInfo)] pub struct DomainLocator { pub domain: Domain, @@ -71,14 +73,36 @@ impl TypeId for DomainLocator { const TYPE_ID: [u8; 4] = *b"domn"; } -#[derive(Encode, Decode, Default, Clone, PartialEq, TypeInfo)] +#[derive(Encode, Decode, Clone, PartialEq, TypeInfo)] #[cfg_attr(feature = "std", derive(Debug))] -pub struct DomainAddress { - pub domain: Domain, - pub address: [u8; 32], +pub enum DomainAddress { + Centrifuge([u8; 32]), + EVM(EVMChainId, [u8; 20]), +} + +impl Into for DomainAddress { + fn into(self) -> Domain { + match self { + Self::Centrifuge(_) => Domain::Centrifuge, + Self::EVM(chain_id, _) => Domain::EVM(chain_id), + } + } +} + +impl DomainAddress { + /// Get the address in a 32-byte long representation. + /// For EVM addresses, append 12 zeros. + fn get_address(&self) -> [u8; 32] { + match self.clone() { + Self::Centrifuge(x) => x, + Self::EVM(_, x) => vec_to_fixed_array(x.to_vec()), + } + } } -impl TypeId for DomainAddress { +// TODO(nuno): `DomainAddress` needs a custom encode function + +impl TypeId for DomainAddress { const TYPE_ID: [u8; 4] = *b"dadr"; } @@ -315,7 +339,7 @@ pub mod pallet { #[pallet::weight(< T as Config >::WeightInfo::update_member())] pub fn update_member( origin: OriginFor, - address: DomainAddress, + address: DomainAddress, pool_id: PoolIdOf, tranche_id: TrancheIdOf, valid_until: Moment, @@ -345,9 +369,9 @@ pub mod pallet { pool_id, tranche_id, valid_until, - address: address.address, + address: address.get_address(), }, - address.domain, + address.into(), )?; Ok(()) @@ -359,7 +383,7 @@ pub mod pallet { origin: OriginFor, pool_id: PoolIdOf, tranche_id: TrancheIdOf, - address: DomainAddress, + address: DomainAddress, amount: ::Balance, ) -> DispatchResult { let who = ensure_signed(origin.clone())?; @@ -380,8 +404,8 @@ pub mod pallet { T::Tokens::transfer( T::TrancheCurrency::generate(pool_id.clone(), tranche_id.clone()).into(), &who, - &DomainLocator { - domain: address.domain.clone(), + &DomainLocator:: { + domain: address.clone().into(), } .into_account_truncating(), amount, @@ -394,10 +418,10 @@ pub mod pallet { pool_id, tranche_id, amount, - domain: address.clone().domain, - destination: address.clone().address, + domain: address.clone().into(), + destination: address.clone().get_address(), }, - address.domain, + address.into(), )?; Ok(()) diff --git a/pallets/connectors/src/message.rs b/pallets/connectors/src/message.rs index 35e9122b4d..0713ec1a2d 100644 --- a/pallets/connectors/src/message.rs +++ b/pallets/connectors/src/message.rs @@ -212,7 +212,7 @@ mod tests { use cfg_utils::vec_to_fixed_array; use super::*; - use crate::{Domain, ParachainId}; + use crate::Domain; #[test] fn invalid() { @@ -221,33 +221,33 @@ mod tests { assert_eq!(msg.encode(), vec![0]); } - #[test] - fn encoding_domain_evm_ethereum_mainnet() { - let domain = Domain::EVM(1); - - let expected_hex = "000100000000000000"; - let expected = <[u8; 9]>::from_hex(expected_hex).expect("Decoding failed"); - assert_eq!(domain.encode(), expected); - } + // #[test] + // fn encoding_domain_evm_ethereum_mainnet() { + // let domain = Domain::EVM(1); + // + // let expected_hex = "000100000000000000"; + // let expected = <[u8; 9]>::from_hex(expected_hex).expect("Decoding failed"); + // assert_eq!(domain.encode(), expected); + // } + // + // #[test] + // fn encoding_domain_evm_avalanche() { + // let domain = Domain::EVM(43114); + // + // let expected_hex = "006aa8000000000000"; + // let expected = <[u8; 9]>::from_hex(expected_hex).expect("Decoding failed"); + // assert_eq!(domain.encode(), expected); + // } #[test] - fn encoding_domain_evm_avalanche() { - let domain = Domain::EVM(43114); + fn encoding_domain_moonbeam() { + let domain = Domain::EVM(1284); - let expected_hex = "006aa8000000000000"; + let expected_hex = "010000000000000504"; let expected = <[u8; 9]>::from_hex(expected_hex).expect("Decoding failed"); assert_eq!(domain.encode(), expected); } - #[test] - fn encoding_domain_parachain() { - let domain = Domain::Parachain(ParachainId::Moonbeam); - - let expected_hex = "0100"; - let expected = <[u8; 2]>::from_hex(expected_hex).expect("Decoding failed"); - assert_eq!(domain.encode(), expected); - } - #[test] fn add_pool_zero() { let msg = Message::::AddPool { pool_id: 0 }; @@ -343,7 +343,7 @@ mod tests { let msg = Message::::Transfer { pool_id: 1, tranche_id: tranche_id_from_hex("811acd5b3f17c06841c7e41e9e04cb1b"), - domain: Domain::Parachain(ParachainId::Moonbeam), + domain: Domain::EVM(1284), destination: <[u8; 32]>::from_hex( "1231231231231231231231231231231231231231231231231231231231231231", ) @@ -357,26 +357,6 @@ mod tests { let expected = <[u8; 75]>::from_hex(input).expect("Decoding failed"); assert_eq!(encoded, expected); } - - #[test] - fn transfer_evm_domain() { - let msg = Message::::Transfer { - pool_id: 1, - tranche_id: tranche_id_from_hex("811acd5b3f17c06841c7e41e9e04cb1b"), - domain: Domain::EVM(43114), - destination: <[u8; 32]>::from_hex( - "1231231231231231231231231231231231231231231231231231231231231231", - ) - .expect(""), - amount: 123 * CURRENCY, - }; - let encoded = msg.encode(); - - let input = "050000000000000001811acd5b3f17c06841c7e41e9e04cb1b006aa8000000000000123123123123123123123123123123123123123123123123123123123123123100000c6d51c8f7aa0600000000000000"; - - let expected = <[u8; 82]>::from_hex(input).expect("Decoding failed"); - assert_eq!(encoded, expected); - } } fn tranche_id_from_hex(hex: &str) -> TrancheId { diff --git a/runtime/integration-tests/src/xcm/development/tests/connectors.rs b/runtime/integration-tests/src/xcm/development/tests/connectors.rs index 3006bc827f..7256a39151 100644 --- a/runtime/integration-tests/src/xcm/development/tests/connectors.rs +++ b/runtime/integration-tests/src/xcm/development/tests/connectors.rs @@ -89,7 +89,7 @@ fn add_pool() { Connectors::add_pool( RuntimeOrigin::signed(ALICE.into()), pool_id, - Domain::Parachain(ParachainId::Moonbeam), + Domain::EVM(1284), ), pallet_connectors::Error::::PoolNotFound ); @@ -101,7 +101,7 @@ fn add_pool() { assert_ok!(Connectors::add_pool( RuntimeOrigin::signed(ALICE.into()), pool_id, - Domain::Parachain(ParachainId::Moonbeam), + Domain::EVM(1284), )); }); } @@ -129,7 +129,7 @@ fn add_tranche() { RuntimeOrigin::signed(ALICE.into()), pool_id.clone(), nonexistent_tranche, - Domain::Parachain(ParachainId::Moonbeam), + Domain::EVM(1284), ), pallet_connectors::Error::::TrancheNotFound ); @@ -150,7 +150,7 @@ fn add_tranche() { RuntimeOrigin::signed(ALICE.into()), pool_id.clone(), tranche_id, - Domain::Parachain(ParachainId::Moonbeam), + Domain::EVM(1284), )); // TODO(nuno): figure out how to convert the tranche metadata set by pool_system into the 32-bounded array expected by the Connectors::AddTranche message. }); @@ -174,10 +174,7 @@ fn transfer() { .tranche_id(TrancheLoc::Index(0)) .expect("Tranche at index 0 exists"); - let dest_address = DomainAddress { - domain: Domain::Parachain(ParachainId::Moonbeam), - address: [99; 32], - }; + let dest_address = DomainAddress::EVM(1284, [99; 20]); // Verify that we first need the destination address to be whitelisted assert_noop!( @@ -228,8 +225,8 @@ fn transfer() { // The account to which the tranche should have been transferred // to on Centrifuge for bookkeeping purposes. - let domain_account: AccountId = DomainLocator { - domain: dest_address.domain.clone(), + let domain_account: AccountId = DomainLocator:: { + domain: dest_address.clone().into(), } .into_account_truncating(); @@ -358,7 +355,7 @@ mod utils { assert_ok!(Connectors::set_domain_router( RuntimeOrigin::root(), - Domain::Parachain(ParachainId::Moonbeam), + Domain::EVM(1284), Router::Xcm(XcmDomain { location: moonbeam_location .clone() From 493969e34bbd3ae32a1625c46d79cd87959f1866 Mon Sep 17 00:00:00 2001 From: nuno Date: Tue, 7 Feb 2023 16:41:48 +0100 Subject: [PATCH 22/45] Add trait ConnectorEncode + update tests --- pallets/connectors/src/lib.rs | 33 ++++++++++++-- pallets/connectors/src/message.rs | 73 +++++++++++++++---------------- 2 files changed, 66 insertions(+), 40 deletions(-) diff --git a/pallets/connectors/src/lib.rs b/pallets/connectors/src/lib.rs index 78c5596490..87ab0138bc 100644 --- a/pallets/connectors/src/lib.rs +++ b/pallets/connectors/src/lib.rs @@ -25,7 +25,7 @@ pub use pallet::*; use scale_info::TypeInfo; use sp_core::{TypeId, U256}; use sp_runtime::{traits::AtLeast32BitUnsigned, FixedPointNumber}; -use sp_std::{boxed::Box, convert::TryInto, vec::Vec}; +use sp_std::{boxed::Box, convert::TryInto, vec, vec::Vec}; pub mod weights; mod message; @@ -60,6 +60,35 @@ pub enum Domain { EVM(EVMChainId), } +pub(crate) trait ConnectorEncode { + fn connector_encode(&self) -> Vec; +} + +/// Custom encode implementation for the `Domain` type +/// Domain is encoded as a 9-byte long bytearray, where: +/// Byte 0 - Flags the Domain variant, i.e, either Domain::Centrifuge (0) or Domain::EVM (1) +/// Byte 1-9 - Encodes the domain id if applicable; +/// - For Domain::Centrifuge there's no id, so we append 8 zeros +/// - For Domain::EVM, encode the respective chain id (8 bytes) as little endian +/// +/// We need to impl this as a custom encode to not overlap with the `#[derive(Encode, Decode)]` +/// that are necessary for `Domain` to be used in the storage as a key. +impl ConnectorEncode for Domain { + fn connector_encode(&self) -> Vec { + match self { + Self::Centrifuge => vec![0; 9], + Self::EVM(chain_id) => { + let mut output = vec![]; + output.push(1u8); + let mut domain_id = chain_id.encode(); + domain_id.reverse(); + output.append(&mut domain_id); + output + } + } + } +} + /// The EVM Chain ID /// The type should accomodate all chain ids listed on https://chainlist.org/. type EVMChainId = u64; @@ -100,8 +129,6 @@ impl DomainAddress { } } -// TODO(nuno): `DomainAddress` needs a custom encode function - impl TypeId for DomainAddress { const TYPE_ID: [u8; 4] = *b"dadr"; } diff --git a/pallets/connectors/src/message.rs b/pallets/connectors/src/message.rs index 0713ec1a2d..00c319cc1b 100644 --- a/pallets/connectors/src/message.rs +++ b/pallets/connectors/src/message.rs @@ -82,7 +82,7 @@ impl< } impl< - Domain: Encode + Decode, + Domain: ConnectorEncode + Encode + Decode, PoolId: Encode + Decode, TrancheId: Encode + Decode, Balance: Encode + Decode, @@ -183,7 +183,7 @@ impl< message.append(&mut encoded_pool_id); message.append(&mut tranche_id.encode()); - message.append(&mut domain.encode()); + message.append(&mut domain.connector_encode()); message.append(&mut destination.encode()); message.append(&mut amount.encode()); @@ -212,7 +212,7 @@ mod tests { use cfg_utils::vec_to_fixed_array; use super::*; - use crate::Domain; + use crate::{Domain, DomainAddress}; #[test] fn invalid() { @@ -221,31 +221,30 @@ mod tests { assert_eq!(msg.encode(), vec![0]); } - // #[test] - // fn encoding_domain_evm_ethereum_mainnet() { - // let domain = Domain::EVM(1); - // - // let expected_hex = "000100000000000000"; - // let expected = <[u8; 9]>::from_hex(expected_hex).expect("Decoding failed"); - // assert_eq!(domain.encode(), expected); - // } - // - // #[test] - // fn encoding_domain_evm_avalanche() { - // let domain = Domain::EVM(43114); - // - // let expected_hex = "006aa8000000000000"; - // let expected = <[u8; 9]>::from_hex(expected_hex).expect("Decoding failed"); - // assert_eq!(domain.encode(), expected); - // } - #[test] - fn encoding_domain_moonbeam() { - let domain = Domain::EVM(1284); - - let expected_hex = "010000000000000504"; - let expected = <[u8; 9]>::from_hex(expected_hex).expect("Decoding failed"); - assert_eq!(domain.encode(), expected); + fn encoding_domain() { + use crate::ConnectorEncode; + + // The Centrifuge substrate chain + assert_eq!( + hex::encode(Domain::Centrifuge.connector_encode()), + "000000000000000000" + ); + // Ethereum MainNet + assert_eq!( + hex::encode(Domain::EVM(1).connector_encode()), + "010000000000000001" + ); + // Moonbeam EVM chain + assert_eq!( + hex::encode(Domain::EVM(1284).connector_encode()), + "010000000000000504" + ); + // Avalanche Chain + assert_eq!( + hex::encode(Domain::EVM(43114).connector_encode()), + "01000000000000a86a" + ); } #[test] @@ -339,23 +338,23 @@ mod tests { } #[test] - fn transfer_xcm_domain() { + fn transfer_to_moonbeam() { + let domain_address = DomainAddress::EVM( + 1284, + <[u8; 20]>::from_hex("1231231231231231231231231231231231231231").expect(""), + ); + let msg = Message::::Transfer { pool_id: 1, tranche_id: tranche_id_from_hex("811acd5b3f17c06841c7e41e9e04cb1b"), - domain: Domain::EVM(1284), - destination: <[u8; 32]>::from_hex( - "1231231231231231231231231231231231231231231231231231231231231231", - ) - .expect(""), + domain: domain_address.clone().into(), + destination: domain_address.get_address(), amount: 123 * CURRENCY, }; let encoded = msg.encode(); + let expected = "050000000000000001811acd5b3f17c06841c7e41e9e04cb1b010000000000000504123123123123123123123123123123123123123100000000000000000000000000000c6d51c8f7aa0600000000000000"; - let input = "050000000000000001811acd5b3f17c06841c7e41e9e04cb1b0100123123123123123123123123123123123123123123123123123123123123123100000c6d51c8f7aa0600000000000000"; - - let expected = <[u8; 75]>::from_hex(input).expect("Decoding failed"); - assert_eq!(encoded, expected); + assert_eq!(hex::encode(encoded), expected); } } From 520d313c623e04110b88061f12d388e77f8f4bd5 Mon Sep 17 00:00:00 2001 From: nuno Date: Tue, 7 Feb 2023 20:21:26 +0100 Subject: [PATCH 23/45] Fix transfer encoding/decoding --- pallets/connectors/src/lib.rs | 2 +- pallets/connectors/src/message.rs | 37 +++++++++++++++++++++++++------ 2 files changed, 31 insertions(+), 8 deletions(-) diff --git a/pallets/connectors/src/lib.rs b/pallets/connectors/src/lib.rs index 87ab0138bc..9a79977d0b 100644 --- a/pallets/connectors/src/lib.rs +++ b/pallets/connectors/src/lib.rs @@ -446,7 +446,7 @@ pub mod pallet { tranche_id, amount, domain: address.clone().into(), - destination: address.clone().get_address(), + address: address.clone().get_address(), }, address.into(), )?; diff --git a/pallets/connectors/src/message.rs b/pallets/connectors/src/message.rs index 00c319cc1b..d69c0a14e4 100644 --- a/pallets/connectors/src/message.rs +++ b/pallets/connectors/src/message.rs @@ -49,9 +49,9 @@ where Transfer { pool_id: PoolId, tranche_id: TrancheId, - domain: Domain, - destination: Address, + address: Address, amount: Balance, + domain: Domain, }, } @@ -172,7 +172,7 @@ impl< pool_id, tranche_id, domain, - destination, + address, amount, } => { let mut message: Vec = vec![]; @@ -183,9 +183,13 @@ impl< message.append(&mut encoded_pool_id); message.append(&mut tranche_id.encode()); + message.append(&mut address.encode()); + + let mut encoded_amount = amount.encode(); + encoded_amount.reverse(); + message.append(&mut encoded_amount); + message.append(&mut domain.connector_encode()); - message.append(&mut destination.encode()); - message.append(&mut amount.encode()); message } @@ -348,12 +352,31 @@ mod tests { pool_id: 1, tranche_id: tranche_id_from_hex("811acd5b3f17c06841c7e41e9e04cb1b"), domain: domain_address.clone().into(), - destination: domain_address.get_address(), + address: domain_address.get_address(), amount: 123 * CURRENCY, }; let encoded = msg.encode(); - let expected = "050000000000000001811acd5b3f17c06841c7e41e9e04cb1b010000000000000504123123123123123123123123123123123123123100000000000000000000000000000c6d51c8f7aa0600000000000000"; + let expected = "050000000000000001811acd5b3f17c06841c7e41e9e04cb1b12312312312312312312312312312312312312310000000000000000000000000000000000000006aaf7c8516d0c0000010000000000000504"; + + assert_eq!(hex::encode(encoded), expected); + } + + #[test] + fn transfer_to_centrifuge() { + let address = <[u8; 20]>::from_hex("1231231231231231231231231231231231231231").expect(""); + + let msg = Message::::Transfer { + pool_id: 1, + tranche_id: tranche_id_from_hex("811acd5b3f17c06841c7e41e9e04cb1b"), + domain: Domain::Centrifuge, + address: vec_to_fixed_array(address.to_vec()), + amount: 1000000000000000000000000000, + }; + let encoded = msg.encode(); + + let expected = "050000000000000001811acd5b3f17c06841c7e41e9e04cb1b123123123123123123123123123123123123123100000000000000000000000000000000033b2e3c9fd0803ce8000000000000000000000000"; + // solidity is 172 chars, 86 bytes assert_eq!(hex::encode(encoded), expected); } } From 3a04c84a35a57e7bed410f86d3625ee0dba370a2 Mon Sep 17 00:00:00 2001 From: nuno Date: Tue, 7 Feb 2023 20:34:37 +0100 Subject: [PATCH 24/45] fmt --- pallets/connectors/src/message.rs | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/pallets/connectors/src/message.rs b/pallets/connectors/src/message.rs index d69c0a14e4..ed9ff4ed2b 100644 --- a/pallets/connectors/src/message.rs +++ b/pallets/connectors/src/message.rs @@ -210,8 +210,6 @@ mod tests { type TrancheId = [u8; 16]; type Balance = cfg_primitives::Balance; - const CURRENCY: Balance = 1_000_000_000_000_000_000; - pub mod encode { use cfg_utils::vec_to_fixed_array; @@ -353,17 +351,18 @@ mod tests { tranche_id: tranche_id_from_hex("811acd5b3f17c06841c7e41e9e04cb1b"), domain: domain_address.clone().into(), address: domain_address.get_address(), - amount: 123 * CURRENCY, + amount: 1000000000000000000000000000, }; let encoded = msg.encode(); - let expected = "050000000000000001811acd5b3f17c06841c7e41e9e04cb1b12312312312312312312312312312312312312310000000000000000000000000000000000000006aaf7c8516d0c0000010000000000000504"; + let expected = "050000000000000001811acd5b3f17c06841c7e41e9e04cb1b123123123123123123123123123123123123123100000000000000000000000000000000033b2e3c9fd0803ce8000000010000000000000504"; assert_eq!(hex::encode(encoded), expected); } #[test] fn transfer_to_centrifuge() { - let address = <[u8; 20]>::from_hex("1231231231231231231231231231231231231231").expect(""); + let address = + <[u8; 20]>::from_hex("1231231231231231231231231231231231231231").expect(""); let msg = Message::::Transfer { pool_id: 1, From 17411af1bfb15cecf9a8b3b0001d1d5e2e1bd07a Mon Sep 17 00:00:00 2001 From: nuno Date: Wed, 8 Feb 2023 09:48:24 +0100 Subject: [PATCH 25/45] dev: Bump spec_version to 1011 --- runtime/development/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/runtime/development/src/lib.rs b/runtime/development/src/lib.rs index 8f1d56ac78..d2d4c422e8 100644 --- a/runtime/development/src/lib.rs +++ b/runtime/development/src/lib.rs @@ -123,7 +123,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { spec_name: create_runtime_str!("centrifuge-devel"), impl_name: create_runtime_str!("centrifuge-devel"), authoring_version: 1, - spec_version: 1010, + spec_version: 1011, impl_version: 1, #[cfg(not(feature = "disable-runtime-api"))] apis: RUNTIME_API_VERSIONS, From c6e8ece120c61d0bec016803618e308f264ada28 Mon Sep 17 00:00:00 2001 From: nuno Date: Fri, 10 Feb 2023 09:19:40 +0100 Subject: [PATCH 26/45] Encode valid_until directly as be instead of mut reverse --- pallets/connectors/src/message.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/pallets/connectors/src/message.rs b/pallets/connectors/src/message.rs index ed9ff4ed2b..838a51308f 100644 --- a/pallets/connectors/src/message.rs +++ b/pallets/connectors/src/message.rs @@ -162,9 +162,7 @@ impl< message.append(&mut tranche_id.encode()); message.append(&mut address.encode()); - let mut encoded_valid_until = valid_until.encode(); - encoded_valid_until.reverse(); - message.append(&mut encoded_valid_until); + message.append(&mut valid_until.to_be_bytes().to_vec()); message } From d591200f7d7a1fc4d0d4716ec2504160afd62a0f Mon Sep 17 00:00:00 2001 From: nuno Date: Fri, 10 Feb 2023 09:37:18 +0100 Subject: [PATCH 27/45] Clean some code --- pallets/connectors/src/lib.rs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/pallets/connectors/src/lib.rs b/pallets/connectors/src/lib.rs index 9a79977d0b..988950a9be 100644 --- a/pallets/connectors/src/lib.rs +++ b/pallets/connectors/src/lib.rs @@ -78,11 +78,9 @@ impl ConnectorEncode for Domain { match self { Self::Centrifuge => vec![0; 9], Self::EVM(chain_id) => { - let mut output = vec![]; - output.push(1u8); - let mut domain_id = chain_id.encode(); - domain_id.reverse(); - output.append(&mut domain_id); + let mut output: Vec = 1u8.encode(); + output.append(&mut chain_id.to_be_bytes().to_vec()); + output } } From 290337122ccdd294887885d4ae3b34e5e1be9662 Mon Sep 17 00:00:00 2001 From: nuno Date: Mon, 13 Feb 2023 11:07:52 +0100 Subject: [PATCH 28/45] Add TrancheInvestor if not already one --- pallets/connectors/src/lib.rs | 43 +++++++++++++++++++++++++++++------ 1 file changed, 36 insertions(+), 7 deletions(-) diff --git a/pallets/connectors/src/lib.rs b/pallets/connectors/src/lib.rs index 988950a9be..db49acef1d 100644 --- a/pallets/connectors/src/lib.rs +++ b/pallets/connectors/src/lib.rs @@ -364,7 +364,7 @@ pub mod pallet { #[pallet::weight(< T as Config >::WeightInfo::update_member())] pub fn update_member( origin: OriginFor, - address: DomainAddress, + domain_address: DomainAddress, pool_id: PoolIdOf, tranche_id: TrancheIdOf, valid_until: Moment, @@ -381,12 +381,21 @@ pub mod pallet { BadOrigin ); - // Now add the destination address as a TrancheInvestor of the given tranche - T::Permission::add( + // Now add the destination address as a TrancheInvestor of the given tranche if + // not already one. This check is necessary shall a user have called `update_member` + // already but the call has failed on the EVM side and needs to be retried. + if !T::Permission::has( PermissionScope::Pool(pool_id), - address.into_account_truncating(), + domain_address.into_account_truncating(), Role::PoolRole(PoolRole::TrancheInvestor(tranche_id, valid_until)), - )?; + ) { + T::Permission::add( + PermissionScope::Pool(pool_id), + domain_address.into_account_truncating(), + Role::PoolRole(PoolRole::TrancheInvestor(tranche_id, valid_until)), + )?; + } + Self::do_send_message( who, @@ -394,9 +403,9 @@ pub mod pallet { pool_id, tranche_id, valid_until, - address: address.get_address(), + address: domain_address.get_address(), }, - address.into(), + domain_address.into(), )?; Ok(()) @@ -539,3 +548,23 @@ pub mod pallet { } } } + +#[cfg(test)] +mod tests { + use cfg_primitives::AccountId; + use sp_runtime::traits::AccountIdConversion; + + use super::DomainAddress; + + #[test] + fn domain_address_derivation() { + assert_eq!( + account_from(DomainAddress::EVM(1284, [9; 20])), + account_from(DomainAddress::EVM(1284, [3; 20])), + ) + } + + fn account_from(domain_address: DomainAddress) -> AccountId { + domain_address.into_account_truncating() + } +} From e75bfeaa3ad7c979662ae3440e540a812e453538 Mon Sep 17 00:00:00 2001 From: nuno Date: Mon, 13 Feb 2023 11:21:59 +0100 Subject: [PATCH 29/45] Test DomainAddress account derivation --- pallets/connectors/src/lib.rs | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/pallets/connectors/src/lib.rs b/pallets/connectors/src/lib.rs index db49acef1d..84ceca7c67 100644 --- a/pallets/connectors/src/lib.rs +++ b/pallets/connectors/src/lib.rs @@ -396,7 +396,6 @@ pub mod pallet { )?; } - Self::do_send_message( who, Message::UpdateMember { @@ -557,14 +556,15 @@ mod tests { use super::DomainAddress; #[test] - fn domain_address_derivation() { + fn domain_address_account_derivation() { assert_eq!( - account_from(DomainAddress::EVM(1284, [9; 20])), - account_from(DomainAddress::EVM(1284, [3; 20])), - ) - } - - fn account_from(domain_address: DomainAddress) -> AccountId { - domain_address.into_account_truncating() + DomainAddress::EVM(1284, [9; 20]).into_account_truncating(), + DomainAddress::EVM(1284, [9; 20]).into_account_truncating(), + ); + + assert_ne!( + DomainAddress::EVM(1284, [42; 20]).into_account_truncating(), + DomainAddress::EVM(1284, [24; 20]).into_account_truncating(), + ); } } From efbae754509850dbc30d1a7d966d955b33679929 Mon Sep 17 00:00:00 2001 From: nuno Date: Mon, 13 Feb 2023 14:32:10 +0100 Subject: [PATCH 30/45] e2e: Test update_member --- .../src/xcm/development/tests/connectors.rs | 70 ++++++++++++++++++- 1 file changed, 69 insertions(+), 1 deletion(-) diff --git a/runtime/integration-tests/src/xcm/development/tests/connectors.rs b/runtime/integration-tests/src/xcm/development/tests/connectors.rs index 7256a39151..93a21a622c 100644 --- a/runtime/integration-tests/src/xcm/development/tests/connectors.rs +++ b/runtime/integration-tests/src/xcm/development/tests/connectors.rs @@ -28,7 +28,7 @@ use ::xcm::{ VersionedMultiLocation, }; use cfg_primitives::{currency_decimals, parachains, AccountId, Balance, PoolId, TrancheId}; -use cfg_traits::PoolMutate; +use cfg_traits::{Permissions as _, PoolMutate}; use cfg_types::{ fixed_point::Rate, permissions::{PermissionScope, PoolRole, Role, UNION}, @@ -156,6 +156,74 @@ fn add_tranche() { }); } +#[test] +fn update_member() { + TestNet::reset(); + + Development::execute_with(|| { + utils::setup_pre_requirements(); + + // Now create the pool + let pool_id: u64 = 42; + utils::create_pool(pool_id); + + // Find the right tranche id + let pool_details = PoolSystem::pool(pool_id).expect("Pool should exist"); + let tranche_id = pool_details + .tranches + .tranche_id(TrancheLoc::Index(0)) + .expect("Tranche at index 0 exists"); + + Loans::update_nav(RuntimeOrigin::signed(ALICE.into()), pool_id.clone()) + .expect("Should update nav"); + + // Finally, verify we can call Connectors::add_tranche successfully + // when given a valid pool + tranche id pair. + let new_member = DomainAddress::EVM(1284, [3; 20]); + let valid_until = 2555583502; + + // Verify it fails if the origin is not a MemberListAdmin + assert_noop!( + Connectors::update_member( + RuntimeOrigin::signed(ALICE.into()), + new_member.clone(), + pool_id.clone(), + tranche_id.clone(), + valid_until.clone(), + ), + BadOrigin + ); + + // Make ALICE the MembersListAdmin of this Pool + assert_ok!(Permissions::add( + RuntimeOrigin::root(), + Role::PoolRole(PoolRole::PoolAdmin), + ALICE.into(), + PermissionScope::Pool(pool_id.clone()), + Role::PoolRole(PoolRole::MemberListAdmin), + )); + + // Verify it now works + assert_ok!(Connectors::update_member( + RuntimeOrigin::signed(ALICE.into()), + new_member.clone(), + pool_id.clone(), + tranche_id.clone(), + valid_until.clone(), + )); + + // Verify the Investor role was set as expected in Permissions + assert!(Permissions::has( + PermissionScope::Pool(pool_id.clone()), + new_member.into_account_truncating(), + Role::PoolRole(PoolRole::TrancheInvestor( + tranche_id.clone(), + valid_until.clone() + )), + )); + }); +} + #[test] fn transfer() { TestNet::reset(); From a023d5c9e9b5beff20631805635c23c342740401 Mon Sep 17 00:00:00 2001 From: nuno Date: Mon, 13 Feb 2023 15:11:11 +0100 Subject: [PATCH 31/45] Fix type inference issue --- pallets/connectors/src/lib.rs | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/pallets/connectors/src/lib.rs b/pallets/connectors/src/lib.rs index 84ceca7c67..a2346b26b5 100644 --- a/pallets/connectors/src/lib.rs +++ b/pallets/connectors/src/lib.rs @@ -558,13 +558,17 @@ mod tests { #[test] fn domain_address_account_derivation() { assert_eq!( - DomainAddress::EVM(1284, [9; 20]).into_account_truncating(), - DomainAddress::EVM(1284, [9; 20]).into_account_truncating(), + account_from(DomainAddress::EVM(1284, [9; 20])), + account_from(DomainAddress::EVM(1284, [9; 20])), ); assert_ne!( - DomainAddress::EVM(1284, [42; 20]).into_account_truncating(), - DomainAddress::EVM(1284, [24; 20]).into_account_truncating(), + account_from(DomainAddress::EVM(1284, [42; 20])), + account_from(DomainAddress::EVM(1284, [24; 20])), ); } + + fn account_from(domain_address: DomainAddress) -> AccountId { + domain_address.into_account_truncating() + } } From fce7c8ae668637926b491f1a128d2f24137a91b6 Mon Sep 17 00:00:00 2001 From: nuno Date: Mon, 13 Feb 2023 15:47:49 +0100 Subject: [PATCH 32/45] e2e: Test update_token_price --- .../src/xcm/development/tests/connectors.rs | 47 ++++++++++++++++++- 1 file changed, 46 insertions(+), 1 deletion(-) diff --git a/runtime/integration-tests/src/xcm/development/tests/connectors.rs b/runtime/integration-tests/src/xcm/development/tests/connectors.rs index 93a21a622c..923c943c5f 100644 --- a/runtime/integration-tests/src/xcm/development/tests/connectors.rs +++ b/runtime/integration-tests/src/xcm/development/tests/connectors.rs @@ -152,7 +152,6 @@ fn add_tranche() { tranche_id, Domain::EVM(1284), )); - // TODO(nuno): figure out how to convert the tranche metadata set by pool_system into the 32-bounded array expected by the Connectors::AddTranche message. }); } @@ -224,6 +223,52 @@ fn update_member() { }); } +#[test] +fn update_token_price() { + TestNet::reset(); + + Development::execute_with(|| { + utils::setup_pre_requirements(); + + // Now create the pool + let pool_id: u64 = 42; + utils::create_pool(pool_id); + + // Find the right tranche id + let pool_details = PoolSystem::pool(pool_id).expect("Pool should exist"); + let tranche_id = pool_details + .tranches + .tranche_id(TrancheLoc::Index(0)) + .expect("Tranche at index 0 exists"); + + + // Verify we first need to call `Loands::update_nav` + // Verify it fails if the origin is not a MemberListAdmin + assert_noop!( + Connectors::update_token_price( + RuntimeOrigin::signed(ALICE.into()), + pool_id.clone(), + tranche_id.clone(), + Domain::EVM(1284), + ), + pallet_connectors::Error::::MissingTranchePrice + ); + + Loans::update_nav(RuntimeOrigin::signed(ALICE.into()), pool_id.clone()) + .expect("Should update nav"); + + // Verify it now works + assert_ok!( + Connectors::update_token_price( + RuntimeOrigin::signed(ALICE.into()), + pool_id.clone(), + tranche_id.clone(), + Domain::EVM(1284), + ) + ); + }); +} + #[test] fn transfer() { TestNet::reset(); From f120eba67a2d3e863e285c8444601e5efd5974f9 Mon Sep 17 00:00:00 2001 From: nuno Date: Mon, 13 Feb 2023 15:55:58 +0100 Subject: [PATCH 33/45] extend update_member test --- .../src/xcm/development/tests/connectors.rs | 24 ++++++++++++------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/runtime/integration-tests/src/xcm/development/tests/connectors.rs b/runtime/integration-tests/src/xcm/development/tests/connectors.rs index 923c943c5f..e87651ac84 100644 --- a/runtime/integration-tests/src/xcm/development/tests/connectors.rs +++ b/runtime/integration-tests/src/xcm/development/tests/connectors.rs @@ -220,6 +220,15 @@ fn update_member() { valid_until.clone() )), )); + + // Verify it can be called for another member + assert_ok!(Connectors::update_member( + RuntimeOrigin::signed(ALICE.into()), + DomainAddress::EVM(1284, [9; 20]), + pool_id.clone(), + tranche_id.clone(), + valid_until.clone(), + )); }); } @@ -241,7 +250,6 @@ fn update_token_price() { .tranche_id(TrancheLoc::Index(0)) .expect("Tranche at index 0 exists"); - // Verify we first need to call `Loands::update_nav` // Verify it fails if the origin is not a MemberListAdmin assert_noop!( @@ -258,14 +266,12 @@ fn update_token_price() { .expect("Should update nav"); // Verify it now works - assert_ok!( - Connectors::update_token_price( - RuntimeOrigin::signed(ALICE.into()), - pool_id.clone(), - tranche_id.clone(), - Domain::EVM(1284), - ) - ); + assert_ok!(Connectors::update_token_price( + RuntimeOrigin::signed(ALICE.into()), + pool_id.clone(), + tranche_id.clone(), + Domain::EVM(1284), + )); }); } From eec6ea192e20867183a1937022395aa6c12b5d21 Mon Sep 17 00:00:00 2001 From: nuno Date: Mon, 13 Feb 2023 16:24:10 +0100 Subject: [PATCH 34/45] Revert temporary CI changes --- .github/workflows/build-nix.yml | 2 +- .github/workflows/build.yml | 2 +- .github/workflows/docker-nix.yml | 2 +- .github/workflows/docker.yml | 2 +- .github/workflows/lints.yml | 2 +- .github/workflows/tests.yml | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/build-nix.yml b/.github/workflows/build-nix.yml index ba87335c8b..8476901543 100644 --- a/.github/workflows/build-nix.yml +++ b/.github/workflows/build-nix.yml @@ -2,7 +2,7 @@ name: nix-build on: pull_request: push: - branches: [main, 'release-v**', 'connectors-v0.1.0'] + branches: [main, 'release-v**'] jobs: build: runs-on: ubuntu-latest diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 01f3f6a3a7..7d6936d629 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -1,6 +1,6 @@ on: push: - branches: [main, 'release-v**', 'connectors-v0.1.0'] + branches: [main, 'release-v**'] pull_request: name: Build jobs: diff --git a/.github/workflows/docker-nix.yml b/.github/workflows/docker-nix.yml index be3b65b405..b695af4bfe 100644 --- a/.github/workflows/docker-nix.yml +++ b/.github/workflows/docker-nix.yml @@ -1,7 +1,7 @@ name: docker on: push: - branches: [main, 'release-v**', 'connectors-v0.1.0'] + branches: [main, 'release-v**'] jobs: docker: strategy: diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index 82d6ef79a7..63e5671f23 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -1,7 +1,7 @@ name: docker on: push: - branches: [main, 'release-v**', 'connectors-v0.1.0'] + branches: [main, 'release-v**'] workflow_dispatch: inputs: docker_tag: diff --git a/.github/workflows/lints.yml b/.github/workflows/lints.yml index 8c7ca8ae3e..6d94b7b983 100644 --- a/.github/workflows/lints.yml +++ b/.github/workflows/lints.yml @@ -1,6 +1,6 @@ on: push: - branches: [main, 'release-v**', 'connectors-v0.1.0'] + branches: [main, 'release-v**'] pull_request: name: Lints jobs: diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index bb17ddfb76..a516aca493 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -1,6 +1,6 @@ on: push: - branches: [main, 'release-v**', 'connectors-v0.1.0'] + branches: [main, 'release-v**'] pull_request: name: Tests jobs: From b6da4dec246552a51b734b4542356d05a0fff5cc Mon Sep 17 00:00:00 2001 From: nuno Date: Mon, 13 Feb 2023 16:53:33 +0100 Subject: [PATCH 35/45] Clean up Message type param type bounds Domain only needs ConnectorEncode and let's drop Decode since it's not needed for now. --- pallets/connectors/src/lib.rs | 38 ++++++++++++++++++------------- pallets/connectors/src/message.rs | 30 ++++++++---------------- 2 files changed, 32 insertions(+), 36 deletions(-) diff --git a/pallets/connectors/src/lib.rs b/pallets/connectors/src/lib.rs index a2346b26b5..d556775533 100644 --- a/pallets/connectors/src/lib.rs +++ b/pallets/connectors/src/lib.rs @@ -60,7 +60,7 @@ pub enum Domain { EVM(EVMChainId), } -pub(crate) trait ConnectorEncode { +pub trait ConnectorEncode { fn connector_encode(&self) -> Vec; } @@ -119,12 +119,16 @@ impl Into for DomainAddress { impl DomainAddress { /// Get the address in a 32-byte long representation. /// For EVM addresses, append 12 zeros. - fn get_address(&self) -> [u8; 32] { + fn address(&self) -> [u8; 32] { match self.clone() { Self::Centrifuge(x) => x, Self::EVM(_, x) => vec_to_fixed_array(x.to_vec()), } } + + fn domain(&self) -> Domain { + self.clone().into() + } } impl TypeId for DomainAddress { @@ -315,8 +319,9 @@ pub mod pallet { .ok_or(Error::::TrancheMetadataNotFound)?; let token_name = vec_to_fixed_array(metadata.name); let token_symbol = vec_to_fixed_array(metadata.symbol); - let latest_price = T::PoolInspect::get_tranche_token_price(pool_id, tranche_id) - .ok_or(Error::::MissingTranchePrice)?; + let price = T::PoolInspect::get_tranche_token_price(pool_id, tranche_id) + .ok_or(Error::::MissingTranchePrice)? + .price; // Send the message to the domain Self::do_send_message( @@ -326,7 +331,7 @@ pub mod pallet { tranche_id, token_name, token_symbol, - price: latest_price.price, + price, }, domain, )?; @@ -344,15 +349,16 @@ pub mod pallet { ) -> DispatchResult { let who = ensure_signed(origin.clone())?; - let latest_price = T::PoolInspect::get_tranche_token_price(pool_id, tranche_id) - .ok_or(Error::::MissingTranchePrice)?; + let price = T::PoolInspect::get_tranche_token_price(pool_id, tranche_id) + .ok_or(Error::::MissingTranchePrice)? + .price; Self::do_send_message( who, Message::UpdateTokenPrice { pool_id, tranche_id, - price: latest_price.price, + price, }, domain, )?; @@ -402,9 +408,9 @@ pub mod pallet { pool_id, tranche_id, valid_until, - address: domain_address.get_address(), + address: domain_address.address(), }, - domain_address.into(), + domain_address.domain(), )?; Ok(()) @@ -416,7 +422,7 @@ pub mod pallet { origin: OriginFor, pool_id: PoolIdOf, tranche_id: TrancheIdOf, - address: DomainAddress, + domain_address: DomainAddress, amount: ::Balance, ) -> DispatchResult { let who = ensure_signed(origin.clone())?; @@ -425,7 +431,7 @@ pub mod pallet { ensure!( T::Permission::has( PermissionScope::Pool(pool_id), - address.into_account_truncating(), + domain_address.into_account_truncating(), Role::PoolRole(PoolRole::TrancheInvestor(tranche_id, Self::now())) ), Error::::UnauthorizedTransfer @@ -438,7 +444,7 @@ pub mod pallet { T::TrancheCurrency::generate(pool_id.clone(), tranche_id.clone()).into(), &who, &DomainLocator:: { - domain: address.clone().into(), + domain: domain_address.domain(), } .into_account_truncating(), amount, @@ -451,10 +457,10 @@ pub mod pallet { pool_id, tranche_id, amount, - domain: address.clone().into(), - address: address.clone().get_address(), + domain: domain_address.domain(), + address: domain_address.address(), }, - address.into(), + domain_address.domain(), )?; Ok(()) diff --git a/pallets/connectors/src/message.rs b/pallets/connectors/src/message.rs index 838a51308f..8b33494cc3 100644 --- a/pallets/connectors/src/message.rs +++ b/pallets/connectors/src/message.rs @@ -18,11 +18,11 @@ pub const TOKEN_SYMBOL_SIZE: usize = 32; #[cfg_attr(feature = "std", derive(Debug))] pub enum Message where - Domain: Encode + Decode, - PoolId: Encode + Decode, - TrancheId: Encode + Decode, - Balance: Encode + Decode, - Rate: Encode + Decode, + Domain: ConnectorEncode, + PoolId: Encode, + TrancheId: Encode, + Balance: Encode, + Rate: Encode, { Invalid, AddPool { @@ -55,13 +55,8 @@ where }, } -impl< - Domain: Encode + Decode, - PoolId: Encode + Decode, - TrancheId: Encode + Decode, - Balance: Encode + Decode, - Rate: Encode + Decode, - > Message +impl + Message { /// The call type that identifies a specific Message variant. This value is used /// to encode/decode a Message to/from a bytearray, whereas the head of the bytearray @@ -81,13 +76,8 @@ impl< } } -impl< - Domain: ConnectorEncode + Encode + Decode, - PoolId: Encode + Decode, - TrancheId: Encode + Decode, - Balance: Encode + Decode, - Rate: Encode + Decode, - > Encode for Message +impl + Encode for Message { fn encode(&self) -> Vec { match self { @@ -348,7 +338,7 @@ mod tests { pool_id: 1, tranche_id: tranche_id_from_hex("811acd5b3f17c06841c7e41e9e04cb1b"), domain: domain_address.clone().into(), - address: domain_address.get_address(), + address: domain_address.address(), amount: 1000000000000000000000000000, }; let encoded = msg.encode(); From ee4fedf621963c58e26e87e36cf04029b4daadcc Mon Sep 17 00:00:00 2001 From: nuno Date: Tue, 14 Feb 2023 10:42:16 +0100 Subject: [PATCH 36/45] Re-order Transfer fields --- pallets/connectors/src/message.rs | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/pallets/connectors/src/message.rs b/pallets/connectors/src/message.rs index 8b33494cc3..fe4c59c706 100644 --- a/pallets/connectors/src/message.rs +++ b/pallets/connectors/src/message.rs @@ -49,9 +49,9 @@ where Transfer { pool_id: PoolId, tranche_id: TrancheId, + domain: Domain, address: Address, amount: Balance, - domain: Domain, }, } @@ -171,14 +171,13 @@ impl Date: Tue, 14 Feb 2023 11:06:49 +0100 Subject: [PATCH 37/45] Clean up big-endian custom encoding --- pallets/connectors/src/message.rs | 53 ++++++++++--------------------- 1 file changed, 16 insertions(+), 37 deletions(-) diff --git a/pallets/connectors/src/message.rs b/pallets/connectors/src/message.rs index 387ba590b6..1d9c71e84b 100644 --- a/pallets/connectors/src/message.rs +++ b/pallets/connectors/src/message.rs @@ -85,10 +85,7 @@ impl { let mut message: Vec = vec![]; message.push(self.call_type()); - - let mut encoded_pool_id = pool_id.encode(); - encoded_pool_id.reverse(); - message.append(&mut encoded_pool_id); + message.append(&mut to_be(pool_id)); message } @@ -101,18 +98,11 @@ impl { let mut message: Vec = vec![]; message.push(self.call_type()); - - let mut encoded_pool_id = pool_id.encode(); - encoded_pool_id.reverse(); - message.append(&mut encoded_pool_id); - + message.append(&mut to_be(pool_id)); message.append(&mut tranche_id.encode()); message.append(&mut token_name.encode()); message.append(&mut token_symbol.encode()); - - let mut encoded_price = price.encode(); - encoded_price.reverse(); - message.append(&mut encoded_price); + message.append(&mut to_be(price)); message } @@ -123,16 +113,9 @@ impl { let mut message: Vec = vec![]; message.push(self.call_type()); - - let mut encoded_pool_id = pool_id.encode(); - encoded_pool_id.reverse(); - message.append(&mut encoded_pool_id); - + message.append(&mut to_be(pool_id)); message.append(&mut tranche_id.encode()); - - let mut encoded_price = price.encode(); - encoded_price.reverse(); - message.append(&mut encoded_price); + message.append(&mut to_be(price)); message } @@ -144,14 +127,9 @@ impl { let mut message: Vec = vec![]; message.push(self.call_type()); - - let mut encoded_pool_id = pool_id.encode(); - encoded_pool_id.reverse(); - message.append(&mut encoded_pool_id); - + message.append(&mut to_be(pool_id)); message.append(&mut tranche_id.encode()); message.append(&mut address.encode()); - message.append(&mut valid_until.to_be_bytes().to_vec()); message @@ -165,18 +143,11 @@ impl { let mut message: Vec = vec![]; message.push(self.call_type()); - - let mut encoded_pool_id = pool_id.encode(); - encoded_pool_id.reverse(); - message.append(&mut encoded_pool_id); - + message.append(&mut to_be(pool_id)); message.append(&mut tranche_id.encode()); message.append(&mut domain.connector_encode()); message.append(&mut address.encode()); - - let mut encoded_amount = amount.encode(); - encoded_amount.reverse(); - message.append(&mut encoded_amount); + message.append(&mut to_be(amount)); message } @@ -184,6 +155,14 @@ impl Vec { + let mut output = x.encode(); + output.reverse(); + output +} + #[cfg(test)] mod tests { use cfg_types::fixed_point::Rate; From 3ab269c387d45c076a73a25af3ecdf19e6eee8c2 Mon Sep 17 00:00:00 2001 From: nuno Date: Tue, 14 Feb 2023 14:20:15 +0100 Subject: [PATCH 38/45] Fix clippy --- pallets/connectors/src/lib.rs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/pallets/connectors/src/lib.rs b/pallets/connectors/src/lib.rs index c24b6aeadc..204f3eb275 100644 --- a/pallets/connectors/src/lib.rs +++ b/pallets/connectors/src/lib.rs @@ -67,9 +67,9 @@ pub trait ConnectorEncode { /// Custom encode implementation for the `Domain` type /// Domain is encoded as a 9-byte long bytearray, where: /// Byte 0 - Flags the Domain variant, i.e, either Domain::Centrifuge (0) or Domain::EVM (1) -/// Byte 1-9 - Encodes the domain id if applicable; -/// - For Domain::Centrifuge there's no id, so we append 8 zeros -/// - For Domain::EVM, encode the respective chain id (8 bytes) as little endian +/// Byte 1-9 - Encodes the chain id if applicable: +/// - For Domain::Centrifuge there's no id, so we append 8 zeros +/// - For Domain::EVM, encode the respective chain id (8 bytes) as little endian /// /// We need to impl this as a custom encode to not overlap with the `#[derive(Encode, Decode)]` /// that are necessary for `Domain` to be used in the storage as a key. @@ -107,11 +107,11 @@ pub enum DomainAddress { EVM(EVMChainId, [u8; 20]), } -impl Into for DomainAddress { - fn into(self) -> Domain { - match self { - Self::Centrifuge(_) => Domain::Centrifuge, - Self::EVM(chain_id, _) => Domain::EVM(chain_id), +impl From for Domain { + fn from(x: DomainAddress) -> Self { + match x { + DomainAddress::Centrifuge(_) => Domain::Centrifuge, + DomainAddress::EVM(chain_id, _) => Domain::EVM(chain_id), } } } From 353d0074bff4c2bb9b452d1dbdd2c61516982507 Mon Sep 17 00:00:00 2001 From: nuno Date: Tue, 14 Feb 2023 14:48:43 +0100 Subject: [PATCH 39/45] Document max_gas_limit to transact max weight --- pallets/connectors/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pallets/connectors/src/lib.rs b/pallets/connectors/src/lib.rs index 204f3eb275..65ac75c882 100644 --- a/pallets/connectors/src/lib.rs +++ b/pallets/connectors/src/lib.rs @@ -498,7 +498,7 @@ pub mod pallet { ethereum_xcm_call, OriginKind::SovereignAccount, TransactWeights { - // Specify a conservative max weight + // Convert the max gas_limit into a max transact weight following Moonbeam's formula. transact_required_weight_at_most: xcm_domain.max_gas_limit * 25_000 + 100_000_000, overall_weight: None, From 695f2b7589ffcd5d2dd7d8de0ace5e5be2be4f20 Mon Sep 17 00:00:00 2001 From: nuno Date: Tue, 14 Feb 2023 16:55:22 +0100 Subject: [PATCH 40/45] Fix clippy --- pallets/connectors/src/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pallets/connectors/src/lib.rs b/pallets/connectors/src/lib.rs index 65ac75c882..d03d0998d3 100644 --- a/pallets/connectors/src/lib.rs +++ b/pallets/connectors/src/lib.rs @@ -68,8 +68,8 @@ pub trait ConnectorEncode { /// Domain is encoded as a 9-byte long bytearray, where: /// Byte 0 - Flags the Domain variant, i.e, either Domain::Centrifuge (0) or Domain::EVM (1) /// Byte 1-9 - Encodes the chain id if applicable: -/// - For Domain::Centrifuge there's no id, so we append 8 zeros -/// - For Domain::EVM, encode the respective chain id (8 bytes) as little endian +/// - For Domain::Centrifuge there's no id, so we append 8 zeros +/// - For Domain::EVM, encode the respective chain id (8 bytes) as little endian /// /// We need to impl this as a custom encode to not overlap with the `#[derive(Encode, Decode)]` /// that are necessary for `Domain` to be used in the storage as a key. From 92327a7a36888802da34250f830025919bdfe7c7 Mon Sep 17 00:00:00 2001 From: Nuno Alexandre Date: Wed, 15 Feb 2023 19:07:11 +0100 Subject: [PATCH 41/45] Update pallets/connectors/src/message.rs Co-authored-by: William Freudenberger --- pallets/connectors/src/message.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pallets/connectors/src/message.rs b/pallets/connectors/src/message.rs index 1d9c71e84b..c77931d526 100644 --- a/pallets/connectors/src/message.rs +++ b/pallets/connectors/src/message.rs @@ -155,8 +155,8 @@ impl Vec { let mut output = x.encode(); output.reverse(); From 9840154f0e41bdf1aeb0e76f349685e03ebd8542 Mon Sep 17 00:00:00 2001 From: nuno Date: Wed, 15 Feb 2023 19:23:33 +0100 Subject: [PATCH 42/45] Clean up message encoding tests --- pallets/connectors/src/message.rs | 49 +++++++------------------------ 1 file changed, 11 insertions(+), 38 deletions(-) diff --git a/pallets/connectors/src/message.rs b/pallets/connectors/src/message.rs index c77931d526..7482284544 100644 --- a/pallets/connectors/src/message.rs +++ b/pallets/connectors/src/message.rs @@ -220,9 +220,8 @@ mod tests { let msg = Message::::AddPool { pool_id: 0 }; let encoded = msg.encode(); - let expected_hex = "010000000000000000"; - let expected = <[u8; 9]>::from_hex(expected_hex).expect("Decoding failed"); - assert_eq!(encoded, expected); + let expected = "010000000000000000"; + assert_eq!(hex::encode(encoded), expected); } #[test] @@ -231,9 +230,8 @@ mod tests { Message::::AddPool { pool_id: 12378532 }; let encoded = msg.encode(); - let expected_hex = "010000000000bce1a4"; - let expected = <[u8; 9]>::from_hex(expected_hex).expect("Decoding failed"); - assert_eq!(encoded, expected); + let expected = "010000000000bce1a4"; + assert_eq!(hex::encode(encoded), expected); } #[test] @@ -245,17 +243,10 @@ mod tests { token_symbol: vec_to_fixed_array("SYMBOL".to_string().into_bytes()), price: Rate::one(), }; - let encoded_bytes = msg.encode(); - - // We encode the encoded bytes as hex to verify it's what we expect - let encoded_hex = hex::encode(encoded_bytes.clone()); - let expected_hex = "020000000000bce1a4811acd5b3f17c06841c7e41e9e04cb1b536f6d65204e616d65000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000053594d424f4c000000000000000000000000000000000000000000000000000000000000033b2e3c9fd0803ce8000000"; - assert_eq!(expected_hex, encoded_hex); + let encoded = msg.encode(); - // Now decode the bytes encoded as hex back to bytes and verify it's the same as - // the original `encoded_bytes` - let hex_as_bytes = hex::decode(encoded_hex).expect("Should go vec -> hex -> vec"); - assert_eq!(hex_as_bytes, encoded_bytes); + let expected = "020000000000bce1a4811acd5b3f17c06841c7e41e9e04cb1b536f6d65204e616d65000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000053594d424f4c000000000000000000000000000000000000000000000000000000000000033b2e3c9fd0803ce8000000"; + assert_eq!(hex::encode(encoded), expected); } #[test] @@ -267,28 +258,12 @@ mod tests { }; let encoded = msg.encode(); - let input = "030000000000000001811acd5b3f17c06841c7e41e9e04cb1b00000000033b2e3c9fd0803ce8000000"; - let expected = <[u8; 41]>::from_hex(input).expect("Decoding failed"); - assert_eq!(encoded, expected); + let expected = "030000000000000001811acd5b3f17c06841c7e41e9e04cb1b00000000033b2e3c9fd0803ce8000000"; + assert_eq!(hex::encode(encoded), expected); } #[test] fn update_member() { - let msg = Message::::UpdateMember { - pool_id: 1, - tranche_id: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1], - address: [1; 32], - valid_until: 100, - }; - let encoded = msg.encode(); - - let input = "0400000000000000010000000000000000000000000000000101010101010101010101010101010101010101010101010101010101010101010000000000000064"; - let expected = <[u8; 65]>::from_hex(input).expect("Decoding failed"); - assert_eq!(encoded, expected); - } - - #[test] - fn update_member_that_failed() { let msg = Message::::UpdateMember { pool_id: 2, tranche_id: <[u8; 16]>::from_hex("811acd5b3f17c06841c7e41e9e04cb1b").expect(""), @@ -300,9 +275,8 @@ mod tests { }; let encoded = msg.encode(); - let input = "040000000000000002811acd5b3f17c06841c7e41e9e04cb1b12312312312312312312312312312312312312312312312312312312312312310000000065b376aa"; - let expected = <[u8; 65]>::from_hex(input).expect("Decoding failed"); - assert_eq!(hex::encode(encoded), hex::encode(expected)); + let expected = "040000000000000002811acd5b3f17c06841c7e41e9e04cb1b12312312312312312312312312312312312312312312312312312312312312310000000065b376aa"; + assert_eq!(hex::encode(encoded), expected); } #[test] @@ -341,7 +315,6 @@ mod tests { let expected = "050000000000000001811acd5b3f17c06841c7e41e9e04cb1b000000000000000000123123123123123123123123123123123123123100000000000000000000000000000000033b2e3c9fd0803ce8000000"; - // solidity is 172 chars, 86 bytes assert_eq!(hex::encode(encoded), expected); } } From 16c85bcef63ee317284444f6648a103729091e80 Mon Sep 17 00:00:00 2001 From: nuno Date: Wed, 15 Feb 2023 19:25:36 +0100 Subject: [PATCH 43/45] Extend domain_address_account_derivation Thanks William --- pallets/connectors/src/lib.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/pallets/connectors/src/lib.rs b/pallets/connectors/src/lib.rs index d03d0998d3..e06588e467 100644 --- a/pallets/connectors/src/lib.rs +++ b/pallets/connectors/src/lib.rs @@ -571,6 +571,11 @@ mod tests { account_from(DomainAddress::EVM(1284, [42; 20])), account_from(DomainAddress::EVM(1284, [24; 20])), ); + + assert_ne!( + account_from(DomainAddress::EVM(1284, [9; 20])), + account_from(DomainAddress::EVM(1285, [9; 20])), + ); } fn account_from(domain_address: DomainAddress) -> AccountId { From b18e3306cbbb6e5baa0a35fb0a89a5e7da009f78 Mon Sep 17 00:00:00 2001 From: nuno Date: Wed, 15 Feb 2023 19:28:32 +0100 Subject: [PATCH 44/45] Document DomainAddress variants --- pallets/connectors/src/lib.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/pallets/connectors/src/lib.rs b/pallets/connectors/src/lib.rs index e06588e467..8ff261f0ca 100644 --- a/pallets/connectors/src/lib.rs +++ b/pallets/connectors/src/lib.rs @@ -103,7 +103,9 @@ impl TypeId for DomainLocator { #[derive(Encode, Decode, Clone, PartialEq, Eq, TypeInfo)] #[cfg_attr(feature = "std", derive(Debug))] pub enum DomainAddress { + /// A Centrifuge-Chain based account address, 32-bytes long Centrifuge([u8; 32]), + /// An EVM chain address, 20-bytes long EVM(EVMChainId, [u8; 20]), } From 1879ab5174bac3566c30b43027baf0d1e00a18f0 Mon Sep 17 00:00:00 2001 From: nuno Date: Thu, 16 Feb 2023 14:59:35 +0100 Subject: [PATCH 45/45] Drop ConnectorEncode and impl Encode+Decode for Domain --- pallets/connectors/src/lib.rs | 58 ++++++++++++++++++++++--------- pallets/connectors/src/message.rs | 23 ++++++------ 2 files changed, 51 insertions(+), 30 deletions(-) diff --git a/pallets/connectors/src/lib.rs b/pallets/connectors/src/lib.rs index 8ff261f0ca..d8873e93e5 100644 --- a/pallets/connectors/src/lib.rs +++ b/pallets/connectors/src/lib.rs @@ -15,7 +15,7 @@ use core::convert::TryFrom; use cfg_traits::PoolInspect; use cfg_utils::vec_to_fixed_array; -use codec::{Decode, Encode, MaxEncodedLen}; +use codec::{Decode, Encode, EncodeLike, Input, MaxEncodedLen}; use frame_support::traits::{ fungibles::{Inspect, Mutate, Transfer}, OriginTrait, @@ -49,7 +49,7 @@ pub enum ParachainId { /// The domain indices need to match those used in the EVM contracts and these /// need to pass the Centrifuge domain to send tranche tokens from the other /// domain here. Therefore, DO NOT remove or move variants around. -#[derive(Encode, Decode, Clone, PartialEq, Eq, TypeInfo, MaxEncodedLen)] +#[derive(Clone, PartialEq, Eq, TypeInfo, MaxEncodedLen)] #[cfg_attr(feature = "std", derive(Debug))] pub enum Domain { /// Referring to the Centrifuge Parachain. Will be used for handling incoming messages. @@ -60,21 +60,8 @@ pub enum Domain { EVM(EVMChainId), } -pub trait ConnectorEncode { - fn connector_encode(&self) -> Vec; -} - -/// Custom encode implementation for the `Domain` type -/// Domain is encoded as a 9-byte long bytearray, where: -/// Byte 0 - Flags the Domain variant, i.e, either Domain::Centrifuge (0) or Domain::EVM (1) -/// Byte 1-9 - Encodes the chain id if applicable: -/// - For Domain::Centrifuge there's no id, so we append 8 zeros -/// - For Domain::EVM, encode the respective chain id (8 bytes) as little endian -/// -/// We need to impl this as a custom encode to not overlap with the `#[derive(Encode, Decode)]` -/// that are necessary for `Domain` to be used in the storage as a key. -impl ConnectorEncode for Domain { - fn connector_encode(&self) -> Vec { +impl Encode for Domain { + fn encode(&self) -> Vec { match self { Self::Centrifuge => vec![0; 9], Self::EVM(chain_id) => { @@ -87,6 +74,26 @@ impl ConnectorEncode for Domain { } } +impl EncodeLike for Domain {} + +impl Decode for Domain { + fn decode(input: &mut I) -> Result { + let variant = input.read_byte()?; + + match variant { + 0 => Ok(Self::Centrifuge), + 1 => { + let mut chain_id_be_bytes = [0; 8]; + input.read(&mut chain_id_be_bytes[..])?; + + let chain_id = EVMChainId::from_be_bytes(chain_id_be_bytes); + Ok(Self::EVM(chain_id)) + } + _ => Err(codec::Error::from("Unknown Domain variant")), + } + } +} + /// The EVM Chain ID /// The type should accomodate all chain ids listed on https://chainlist.org/. type EVMChainId = u64; @@ -558,9 +565,26 @@ pub mod pallet { #[cfg(test)] mod tests { use cfg_primitives::AccountId; + use codec::{Decode, Encode}; use sp_runtime::traits::AccountIdConversion; use super::DomainAddress; + use crate::Domain; + + #[test] + fn test_domain_encode_decode() { + test_domain_identity(Domain::Centrifuge); + test_domain_identity(Domain::EVM(1284)); + test_domain_identity(Domain::EVM(1)); + } + + /// Test that decode . encode results in the original value + fn test_domain_identity(domain: Domain) { + let encoded = domain.encode(); + let decoded: Domain = Domain::decode(&mut encoded.as_slice()).expect(""); + + assert_eq!(domain, decoded); + } #[test] fn domain_address_account_derivation() { diff --git a/pallets/connectors/src/message.rs b/pallets/connectors/src/message.rs index 7482284544..f47c23016d 100644 --- a/pallets/connectors/src/message.rs +++ b/pallets/connectors/src/message.rs @@ -18,7 +18,7 @@ pub const TOKEN_SYMBOL_SIZE: usize = 32; #[cfg_attr(feature = "std", derive(Debug))] pub enum Message where - Domain: ConnectorEncode, + Domain: Encode, PoolId: Encode, TrancheId: Encode, Balance: Encode, @@ -55,7 +55,7 @@ where }, } -impl +impl Message { /// The call type that identifies a specific Message variant. This value is used @@ -76,8 +76,8 @@ impl - Encode for Message +impl Encode + for Message { fn encode(&self) -> Vec { match self { @@ -145,7 +145,7 @@ impl