Skip to content

Commit

Permalink
impl move address (#645)
Browse files Browse the repository at this point in the history
* Support aptos and named address

* Allow deposit to aptos chain

   * Add aptos address type for opreturn

   * Add aptos address binding storage

   * Emit event to deposit to aptos

* Use NMap to storage non-chainx binding address

* Fix ci

* Add default dst chain storage

  Specify the default chain each time you update the address, and deposit to the default chain without filling in the address the next time you deposit.

* Fix strange code

* Bump spec_version into 24

* Simplify code

* Fix note of bitcoin

* More generally dstchain

* Add named chain address config

  * Simple representative named address using prefix and length

  * Register named chain config

  * Check allowed named chain in deposit info

* Follow clippy

* Bump spec_version to 25

* Use dst chain proxy address to cross chain

  Temporarily deposit XBTC to the proxy account and manage the deposit and withdrawals from other chains through the proxy account. Wait for the subsequent implement of ultra-light nodes then cross-chain by burn and mint XBTC.

* Remove trustee xbtc reward

  Due to the inconvenience of calculating the BTC issued at EVM, the XBTC reward of the trustee is temporarily cancelled.

* Fix unnecessary if let

* Fix fmt

* Bump spec_version to 26

Co-authored-by: hacpy <hacpy.lbx@gmail.com>
  • Loading branch information
AAweidai and hacpy authored Sep 8, 2022
1 parent ef4f9de commit d62ce2e
Show file tree
Hide file tree
Showing 13 changed files with 444 additions and 80 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

66 changes: 64 additions & 2 deletions primitives/gateway/bitcoin/src/extractor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@ use sp_core::crypto::AccountId32;
use sp_std::prelude::Vec;

use chainx_primitives::ReferralId;
use xp_gateway_common::{from_ss58_check, transfer_evm_uncheck};
use xp_gateway_common::{
from_ss58_check, transfer_aptos_uncheck, transfer_evm_uncheck, transfer_named_uncheck,
};

pub use xp_gateway_common::AccountExtractor;

Expand Down Expand Up @@ -37,8 +39,13 @@ impl AccountExtractor<AccountId32, ReferralId> for OpReturnExtractor {

let account = if let Some(v) = wasm_account {
OpReturnAccount::Wasm(v)
} else if let Some(v) = transfer_evm_uncheck(account_and_referral[0].as_slice()) {
OpReturnAccount::Evm(v)
} else if let Some(v) = transfer_aptos_uncheck(account_and_referral[0].as_slice()) {
OpReturnAccount::Aptos(v)
} else {
OpReturnAccount::Evm(transfer_evm_uncheck(account_and_referral[0].as_slice())?)
let data = transfer_named_uncheck(account_and_referral[0].as_slice())?;
OpReturnAccount::Named(data.0, data.1)
};

let referral = if account_and_referral.len() > 1 {
Expand Down Expand Up @@ -111,6 +118,61 @@ fn test_opreturn_extractor() {
result,
Some((OpReturnAccount::Evm(evm_addr), Some(b"referral1".to_vec())))
);

let mut key = [0u8; 32];
key.copy_from_slice(
&hex::decode("eeff357ea5c1a4e7bc11b2b17ff2dc2dcca69750bfef1e1ebcaccf8c8018175b")
.unwrap(),
);
let aptos_addr = H256::try_from(key).unwrap();

let result = OpReturnExtractor::extract_account(
"0xeeff357ea5c1a4e7bc11b2b17ff2dc2dcca69750bfef1e1ebcaccf8c8018175b@referral1"
.as_bytes(),
);
assert_eq!(
result,
Some((
OpReturnAccount::Aptos(aptos_addr),
Some(b"referral1".to_vec())
))
);

let result = OpReturnExtractor::extract_account(
"eeff357ea5c1a4e7bc11b2b17ff2dc2dcca69750bfef1e1ebcaccf8c8018175b@referral1".as_bytes(),
);
assert_eq!(
result,
Some((
OpReturnAccount::Aptos(aptos_addr),
Some(b"referral1".to_vec())
))
);

let name = vec![b's', b'u', b'i'];
let addr = hex::decode("1dcba11f07596152cf96a9bd358b675d5d5f9506").unwrap();

let result = OpReturnExtractor::extract_account(
"sui:0x1dcba11f07596152cf96a9bd358b675d5d5f9506@referral1".as_bytes(),
);
assert_eq!(
result,
Some((
OpReturnAccount::Named(name.clone(), addr.clone()),
Some(b"referral1".to_vec())
))
);

let result = OpReturnExtractor::extract_account(
"sui:1dcba11f07596152cf96a9bd358b675d5d5f9506@referral1".as_bytes(),
);
assert_eq!(
result,
Some((
OpReturnAccount::Named(name, addr),
Some(b"referral1".to_vec())
))
);
}
{
set_default_ss58_version(testnet);
Expand Down
84 changes: 82 additions & 2 deletions primitives/gateway/common/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,10 @@

#![cfg_attr(not(feature = "std"), no_std)]
#![deny(missing_docs)]

use codec::{Decode, Encode};
use scale_info::TypeInfo;
use sp_core::{crypto::AccountId32, RuntimeDebug, H160};
use scale_info::{prelude::vec::Vec, TypeInfo};
use sp_core::{crypto::AccountId32, RuntimeDebug, H160, H256};

use frame_support::log::error;

Expand All @@ -17,6 +18,42 @@ pub enum OpReturnAccount<AccountId> {
Evm(H160),
/// Wasm address
Wasm(AccountId),
/// Aptos address
Aptos(H256),
/// Named address: `[prefix]:(0x)[hex]`.
/// eg: `sui:0x1dcba11f07596152cf96a9bd358b675d5d5f9506`;
/// eg: `sui:1dcba11f07596152cf96a9bd358b675d5d5f9506`;
Named(Vec<u8>, Vec<u8>),
}

/// The tokens may not be issued in Chainx, but issued to other chains
#[derive(PartialEq, Eq, Ord, PartialOrd, Clone, Encode, Decode, RuntimeDebug, TypeInfo)]
pub enum DstChain {
/// ChainX Wasm
ChainX,
/// ChainX Evm
ChainXEvm,
/// Aptos Move
Aptos,
/// Chain prefix
Named(Vec<u8>),
}

/// Named chain configuration information
#[derive(PartialEq, Eq, Clone, Encode, Decode, RuntimeDebug, TypeInfo)]
pub struct DstChainConfig {
prefix: Vec<u8>,
length: u32,
}

impl DstChainConfig {
/// Create new [`DstChainConfig`]
pub fn new(prefix: &[u8], length: u32) -> Self {
Self {
prefix: prefix.to_vec(),
length,
}
}
}

/// Trait for extracting the account and possible extra data (e.g. referral) from
Expand Down Expand Up @@ -52,6 +89,49 @@ pub fn transfer_evm_uncheck(raw_account: &[u8]) -> Option<H160> {
H160::try_from(key).ok()
}

/// Transfer slice into unchecked aptos address
pub fn transfer_aptos_uncheck(raw_account: &[u8]) -> Option<H256> {
let data = if raw_account.len() == 32 {
raw_account.to_vec()
} else if raw_account.len() == 64 {
hex::decode(raw_account).ok()?
} else if raw_account.len() == 66 {
let mut key = [0u8; 64];
// remove 0x prefix
key.copy_from_slice(&raw_account[2..66]);
hex::decode(key).ok()?
} else {
return None;
};

let mut key = [0u8; 32];
key.copy_from_slice(&data);
H256::try_from(key).ok()
}

/// Transfer slice into unchecked named address
pub fn transfer_named_uncheck(raw_account: &[u8]) -> Option<(Vec<u8>, Vec<u8>)> {
let name_and_account = raw_account
.split(|x| *x == b':')
.map(|d| d.to_vec())
.collect::<Vec<_>>();

if name_and_account.is_empty() || name_and_account.len() != 2 {
error!(
"[transfer_named_uncheck] Can't transfer_named_uncheck:{:?}",
raw_account
);
return None;
}
let name = name_and_account[0].clone();
let account = if name_and_account[1].starts_with(b"0x") {
hex::decode(name_and_account[1][2..name_and_account[1].len()].to_vec()).ok()?
} else {
hex::decode(name_and_account[1].clone()).ok()?
};
Some((name, account))
}

/// Verify if the raw account is a properly encoded SS58Check address.
pub fn from_ss58_check(raw_account: &[u8]) -> Option<AccountId32> {
// Use custom runtime-interface to provide ss58check from outside of runtime.
Expand Down
2 changes: 1 addition & 1 deletion runtime/chainx/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion {
spec_name: create_runtime_str!("chainx"),
impl_name: create_runtime_str!("chainx-net"),
authoring_version: 1,
spec_version: 23,
spec_version: 26,
impl_version: 1,
apis: RUNTIME_API_VERSIONS,
transaction_version: 5,
Expand Down
2 changes: 1 addition & 1 deletion runtime/dev/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion {
spec_name: create_runtime_str!("chainx"),
impl_name: create_runtime_str!("chainx-dev"),
authoring_version: 1,
spec_version: 23,
spec_version: 26,
impl_version: 1,
apis: RUNTIME_API_VERSIONS,
transaction_version: 5,
Expand Down
2 changes: 1 addition & 1 deletion runtime/malan/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion {
spec_name: create_runtime_str!("chainx"),
impl_name: create_runtime_str!("chainx-malan"),
authoring_version: 1,
spec_version: 23,
spec_version: 26,
impl_version: 1,
apis: RUNTIME_API_VERSIONS,
transaction_version: 5,
Expand Down
10 changes: 9 additions & 1 deletion xpallets/gateway/bitcoin/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -381,12 +381,20 @@ pub mod pallet {
WithdrawalProposalCreated(T::AccountId, Vec<u32>),
/// A trustee voted/vetoed a withdrawal proposal. [trustee, vote_status]
WithdrawalProposalVoted(T::AccountId, bool),
/// A fatal error happened during the withdrwal process. [tx_hash, proposal_hash]
/// A fatal error happened during the withdrawal process. [tx_hash, proposal_hash]
WithdrawalFatalErr(H256, H256),
/// An account deposited some token for evm address. [tx_hash, who, amount]
DepositedEvm(H256, H160, BalanceOf<T>),
/// A unclaimed deposit record was removed for evm address. [depositor, deposit_amount, tx_hash, btc_address]
PendingDepositEvmRemoved(H160, BalanceOf<T>, H256, BtcAddress),
/// An account deposited some token for aptos address. [tx_hash, who, amount]
DepositedAptos(H256, H256, BalanceOf<T>),
/// A unclaimed deposit record was removed for aptos address. [depositor, deposit_amount, tx_hash, btc_address]
PendingDepositAptosRemoved(H256, BalanceOf<T>, H256, BtcAddress),
/// An account deposited some token for named address. [tx_hash, prefix, who, amount]
DepositedNamed(H256, Vec<u8>, Vec<u8>, BalanceOf<T>),
/// A unclaimed deposit record was removed for named address. [prefix, depositor, deposit_amount, tx_hash, btc_address]
PendingDepositNamedRemoved(Vec<u8>, Vec<u8>, BalanceOf<T>, H256, BtcAddress),
}

/// best header info
Expand Down
74 changes: 73 additions & 1 deletion xpallets/gateway/bitcoin/src/tx/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ use sp_core::H160;

use chainx_primitives::AssetId;
use xp_gateway_bitcoin::{BtcDepositInfo, BtcTxMetaType, BtcTxTypeDetector, OpReturnAccount};
use xp_gateway_common::AccountExtractor;
use xp_gateway_common::{AccountExtractor, DstChain};
use xpallet_assets::ChainT;
use xpallet_gateway_common::traits::{AddressBinding, ReferralBinding, TrusteeInfoUpdate};
use xpallet_support::try_str;
Expand Down Expand Up @@ -71,6 +71,8 @@ fn trustee_transition<T: Config>(tx: Transaction) -> BtcTxResult {
}

fn deposit<T: Config>(txid: H256, deposit_info: BtcDepositInfo<T::AccountId>) -> BtcTxResult {
// check address in op_return whether allow binding
let deposit_info = T::AddressBinding::check_allowed_binding(deposit_info);
let account_info = match (deposit_info.op_return, deposit_info.input_addr) {
(Some((account, referral)), Some(input_addr)) => {
let input_addr = input_addr.to_string().into_bytes();
Expand Down Expand Up @@ -154,6 +156,8 @@ fn deposit_token<T: Config>(
match who {
OpReturnAccount::Evm(w) => deposit_evm::<T>(txid, w, balance),
OpReturnAccount::Wasm(w) => deposit_wasm::<T>(txid, w, balance),
OpReturnAccount::Aptos(w) => deposit_aptos::<T>(txid, w, balance),
OpReturnAccount::Named(w1, w2) => deposit_named::<T>(txid, w1.clone(), w2.clone(), balance),
}
}

Expand Down Expand Up @@ -197,6 +201,57 @@ fn deposit_evm<T: Config>(txid: H256, who: &H160, balance: u64) -> DispatchResul
}
}

fn deposit_aptos<T: Config>(txid: H256, who: &H256, balance: u64) -> DispatchResult {
let id: AssetId = <Pallet<T> as ChainT<_>>::ASSET_ID;
let value: BalanceOf<T> = balance.saturated_into();

if let Some(proxy_address) = T::AddressBinding::dst_chain_proxy_address(DstChain::Aptos) {
match <xpallet_gateway_records::Pallet<T>>::deposit(&proxy_address, id, value) {
Ok(()) => {
Pallet::<T>::deposit_event(Event::<T>::DepositedAptos(txid, *who, value));
}
Err(err) => {
error!(
target: "runtime::bitcoin",
"[deposit_token] Deposit error:{:?}, must use root to fix it",
err
);
return Err(err);
}
}
}
Ok(())
}

fn deposit_named<T: Config>(
txid: H256,
prefix: Vec<u8>,
who: Vec<u8>,
balance: u64,
) -> DispatchResult {
let id: AssetId = <Pallet<T> as ChainT<_>>::ASSET_ID;
let value: BalanceOf<T> = balance.saturated_into();

if let Some(proxy_address) =
T::AddressBinding::dst_chain_proxy_address(DstChain::Named(prefix.clone()))
{
match <xpallet_gateway_records::Pallet<T>>::deposit(&proxy_address, id, value) {
Ok(()) => {
Pallet::<T>::deposit_event(Event::<T>::DepositedNamed(txid, prefix, who, value));
}
Err(err) => {
error!(
target: "runtime::bitcoin",
"[deposit_token] Deposit error:{:?}, must use root to fix it",
err
);
return Err(err);
}
}
}
Ok(())
}

pub fn remove_pending_deposit<T: Config>(
input_address: &BtcAddress,
who: &OpReturnAccount<T::AccountId>,
Expand Down Expand Up @@ -229,6 +284,23 @@ pub fn remove_pending_deposit<T: Config>(
input_address.clone(),
));
}
OpReturnAccount::Aptos(w) => {
Pallet::<T>::deposit_event(Event::<T>::PendingDepositAptosRemoved(
w,
record.balance.saturated_into(),
record.txid,
input_address.clone(),
));
}
OpReturnAccount::Named(w1, w2) => {
Pallet::<T>::deposit_event(Event::<T>::PendingDepositNamedRemoved(
w1.clone(),
w2.clone(),
record.balance.saturated_into(),
record.txid,
input_address.clone(),
));
}
}
}
}
Expand Down
2 changes: 2 additions & 0 deletions xpallets/gateway/common/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ pallet-elections-phragmen = { git = "https://github.com/paritytech/substrate", b
chainx-primitives = { path = "../../../primitives", default-features = false }
xp-assets-registrar = { path = "../../../primitives/assets-registrar", default-features = false }
xp-gateway-bitcoin = { path = "../../../primitives/gateway/bitcoin", default-features = false }
xp-gateway-common = { path = "../../../primitives/gateway/common", default-features = false }
# xp-logging = { path = "../../../primitives/logging", default-features = false }
xp-protocol = { path = "../../../primitives/protocol", default-features = false }
xp-rpc = { path = "../../../primitives/rpc", optional = true }
Expand Down Expand Up @@ -71,6 +72,7 @@ std = [
"chainx-primitives/std",
"xp-assets-registrar/std",
"xp-gateway-bitcoin/std",
"xp-gateway-common/std",
"xp-protocol/std",
"xp-rpc",
"xp-runtime/std",
Expand Down
Loading

0 comments on commit d62ce2e

Please sign in to comment.