Skip to content
Merged

Patch #170

Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions node/runtime/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -426,7 +426,7 @@ construct_runtime!(
{
// Basic stuff; balances is uncallable initially.
RandomnessCollectiveFlip: randomness_collective_flip::{Module, Call, Storage},
System: system::{Module, Call, Storage, Config, Event},
System: system::{Module, Call, Storage, Event, Config},

// Must be before session.
Babe: babe::{Module, Call, Storage, Config, Inherent(Timestamp)},
Expand All @@ -439,8 +439,8 @@ construct_runtime!(

// Consensus support.
Authorship: authorship::{Module, Call, Storage, Inherent},
Grandpa: grandpa::{Module, Call, Storage, Config, Event},
ImOnline: im_online::{Module, Call, Storage, Event<T>, ValidateUnsigned, Config<T>},
Grandpa: grandpa::{Module, Call, Storage, Event, Config},
ImOnline: im_online::{default, ValidateUnsigned},
FinalityTracker: finality_tracker::{Module, Call, Inherent},
Offences: offences::{Module, Call, Storage, Event},
Session: session::{Module, Call, Storage, Event, Config<T>},
Expand All @@ -451,7 +451,7 @@ construct_runtime!(
Utility: utility::{Module, Call, Event},

EthRelay: eth_relay::{Module, Call, Storage, Event<T>, Config},
EthBacking: eth_backing::{Module, Call, Storage, Event<T>, Config<T>},
EthBacking: eth_backing,
}
);

Expand Down
22 changes: 10 additions & 12 deletions srml/eth-backing/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,44 +8,42 @@ edition = "2018"

[dependencies]
# crates.io
serde = { version = "1.0.101", optional = true }
codec = { package = "parity-scale-codec", version = "1.0.0", default-features = false, features = ["derive"] }
hex = { version = "0.4", default-features = false }
serde = { version = "1.0.101", optional = true }

# github.com
rstd = { package = "sr-std", git = "https://github.com/darwinia-network/substrate.git", branch = "darwinia-develop", default-features = false }
support = { package = "srml-support", git = "https://github.com/darwinia-network/substrate.git", branch = "darwinia-develop", default-features = false }
system = { package = "srml-system", git = "https://github.com/darwinia-network/substrate.git", branch = "darwinia-develop", default-features = false }
timestamp = { package = "srml-timestamp", git = "https://github.com/darwinia-network/substrate.git", branch = "darwinia-develop", default-features = false }
sr-primitives = { git = "https://github.com/darwinia-network/substrate.git", branch = "darwinia-develop", default-features = false }
primitives = { package = "substrate-primitives", git = "https://github.com/darwinia-network/substrate.git", branch = "darwinia-develop", default-features = false }
ethabi = { git = "https://github.com/darwinia-network/ethabi.git", branch = "with_no_std", default-features = false }

# darwinia
darwinia-support = { package = "darwinia-support", path = "../support", default-features = false }
darwinia-eth-relay = { package = "darwinia-eth-relay", path = "../eth-relay", default-features = false }
sr-eth-primitives = { path = "../../core/sr-eth-primitives", default-features = false }

sr-primitives = { git = "https://github.com/darwinia-network/substrate.git", branch = "darwinia-develop", default-features = false }

primitives = { package = "substrate-primitives", git = "https://github.com/darwinia-network/substrate.git", branch = "darwinia-develop", default-features = false }

ethabi = { git = "https://github.com/darwinia-network/ethabi.git", branch = "with_no_std", default-features = false }

hex = { version = "0.4", default-features = false}

[dev-dependencies]
hex-literal = "0.2.1"

[features]
default = ["std"]
std = [
"codec/std",
"hex/std",
"serde/std",
"hex/std",

"ethabi/std",
"rstd/std",
"sr-primitives/std",
"support/std",
"system/std",
"timestamp/std",

"darwinia-support/std",
"darwinia-eth-relay/std",
"sr-eth-primitives/std",
"ethabi/std",
"sr-primitives/std",
]
193 changes: 98 additions & 95 deletions srml/eth-backing/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,27 +5,24 @@
#![cfg_attr(not(feature = "std"), no_std)]

//use codec::{Decode, Encode};
use rstd::{borrow::ToOwned, result};
use rstd::{marker::PhantomData, prelude::*}; // fmt::Debug,
use ethabi::{Event as EthEvent, EventParam as EthEventParam, ParamType, RawLog};
use rstd::{borrow::ToOwned, convert::TryFrom, marker::PhantomData, result, vec, vec::Vec}; // fmt::Debug
use sr_primitives::traits::{SaturatedConversion, Saturating};
use support::{decl_event, decl_module, decl_storage, ensure, traits::Currency, traits::OnUnbalanced}; // dispatch::Result,
use system::ensure_signed;

use sr_primitives::traits::{SaturatedConversion, Saturating}; // Convert,
use system::ensure_signed; // Convert,

//use sr_primitives::RuntimeDebug;
//use primitives::crypto::UncheckedFrom;
//use core::convert::TryFrom;

use darwinia_eth_relay::{EthReceiptProof, VerifyEthReceipts};
use darwinia_support::{LockableCurrency, OnDepositRedeem};
use ethabi::{Event as EthEvent, EventParam as EthEventParam, ParamType, RawLog};
use sr_eth_primitives::{EthAddress, H256, U256}; // receipt::LogEntry, receipt::Receipt,

//#[cfg(feature = "std")]
//use sr_primitives::{Deserialize, Serialize};

use rstd::vec::Vec;

pub type Balance = u128;
pub type Moment = u64;

type RingBalanceOf<T> = <<T as Trait>::Ring as Currency<<T as system::Trait>::AccountId>>::Balance;
Expand Down Expand Up @@ -89,109 +86,42 @@ decl_module! {
pub fn redeem_ring(origin, proof_record: EthReceiptProof) {
let _relayer = ensure_signed(origin)?;

ensure!(!<RingProofVerified>::exists((proof_record.header_hash, proof_record.index)), "Ring for this proof has already been redeemed.");

let verified_receipt = T::EthRelay::verify_receipt(&proof_record)?;

// event RingBurndropTokens(address indexed token, address indexed owner, uint amount, bytes data);
// https://ropsten.etherscan.io/tx/0x81f699c93b00ab0b7db701f87b6f6045c1e0692862fcaaf8f06755abb0536800
let eth_event = EthEvent {
name: "RingBurndropTokens".to_owned(),
inputs: vec![
EthEventParam {name: "token".to_owned(), kind: ParamType::Address, indexed: true,},
EthEventParam {name: "owner".to_owned(), kind: ParamType::Address, indexed: true,},
EthEventParam {name: "amount".to_owned(), kind: ParamType::Uint(256), indexed: false,},
EthEventParam {name: "data".to_owned(), kind: ParamType::Bytes, indexed: false,}
],
anonymous: false,
};

// H256::from(hex!("38045eaef0a21b74ff176350f18df02d9041a25d6694b5f63e9474b7b6cd6b94")
let log_entry = verified_receipt.logs.iter().find(
|&x| x.address == Self::ring_redeem_address()
&& x.topics[0] == eth_event.signature()
).expect("Log Entry Not Found");

let log = RawLog {
topics: [log_entry.topics[0],log_entry.topics[1],log_entry.topics[2]].to_vec(),
data: log_entry.data.clone()
};

let result = eth_event.parse_log(log).expect("Parse Eth Log Error");

// TODO: div 10**18 and mul 10**9
let mut amount : U256 = result.params[2].value.clone().to_uint().expect("Param Convert to Int Failed.");
amount = amount / U256::from(1_000_000_000u64);

let raw_sub_key : Vec<u8> = result.params[3].value.clone().to_bytes().expect("Param Convert to Bytes Failed.");
ensure!(
!RingProofVerified::exists((proof_record.header_hash, proof_record.index)),
"Ring For This Proof - ALREADY BEEN REDEEMED",
);

let decoded_sub_key = hex::decode(&raw_sub_key[..]).expect("Address Hex decode Failed.");
let darwinia_account = T::DetermineAccountId::account_id_for(&decoded_sub_key[..])?;
let (darwinia_account, redeemed_amount) = Self::parse_proof(&proof_record, "RingBurndropTokens")?;
let redeemed_ring = <RingBalanceOf<T>>::saturated_from(redeemed_amount);
let redeemed_positive_imbalance_ring = T::Ring::deposit_into_existing(&darwinia_account, redeemed_ring)?;

let redeemed_amount = amount.as_u128().saturated_into();
T::RingReward::on_unbalanced(redeemed_positive_imbalance_ring);

RingProofVerified::insert((proof_record.header_hash, proof_record.index), proof_record);
<RingLocked<T>>::mutate(|l| {
*l = l.saturating_sub(redeemed_amount);
*l = l.saturating_sub(redeemed_ring);
});

<RingProofVerified>::insert((proof_record.header_hash, proof_record.index), proof_record);

let redeemed_ring = T::Ring::deposit_into_existing(&darwinia_account, redeemed_amount).expect("Deposit into existing failed.");

T::RingReward::on_unbalanced(redeemed_ring);
}

// event KtonBurndropTokens(address indexed token, address indexed owner, uint amount, bytes data);
pub fn redeem_kton(origin, proof_record: EthReceiptProof) {
let _relayer = ensure_signed(origin)?;

ensure!(!<KtonProofVerified>::exists((proof_record.header_hash, proof_record.index)), "Kton for this proof has already been redeemed.");
ensure!(
!KtonProofVerified::exists((proof_record.header_hash, proof_record.index)),
"Kton For This Proof - ALREADY BEEN REDEEMED",
);

let verified_receipt = T::EthRelay::verify_receipt(&proof_record)?;
let (darwinia_account, redeemed_amount) = Self::parse_proof(&proof_record, "KtonBurndropTokens")?;
let redeemed_kton = <KtonBalanceOf<T>>::saturated_from(redeemed_amount);
let redeemed_positive_imbalance_kton = T::Kton::deposit_into_existing(&darwinia_account, redeemed_kton)?;

// event RingBurndropTokens(address indexed token, address indexed owner, uint amount, bytes data);
// https://ropsten.etherscan.io/tx/0x81f699c93b00ab0b7db701f87b6f6045c1e0692862fcaaf8f06755abb0536800
let eth_event = EthEvent {
name: "KtonBurndropTokens".to_owned(),
inputs: vec![
EthEventParam {name: "token".to_owned(), kind: ParamType::Address, indexed: true,},
EthEventParam {name: "owner".to_owned(), kind: ParamType::Address, indexed: true,},
EthEventParam {name: "amount".to_owned(), kind: ParamType::Uint(256), indexed: false,},
EthEventParam {name: "data".to_owned(), kind: ParamType::Bytes, indexed: false,}
],
anonymous: false,
};

let log_entry = verified_receipt.logs.iter().find(
|&x| x.address == Self::kton_redeem_address()
&& x.topics[0] == eth_event.signature()
).expect("Log Entry Not Found");

let log = RawLog {
topics: [log_entry.topics[0],log_entry.topics[1],log_entry.topics[2]].to_vec(),
data: log_entry.data.clone()
};

let result = eth_event.parse_log(log).expect("Parse Eth Log Error");
// TODO: div 10**18 and mul 10**9
let mut amount : U256 = result.params[2].value.clone().to_uint().expect("Param Convert to Int Failed.");
amount = amount / U256::from(1_000_000_000u64);
let raw_sub_key : Vec<u8> = result.params[3].value.clone().to_bytes().expect("Param Convert to Bytes Failed.");

let decoded_sub_key = hex::decode(&raw_sub_key[..]).expect("Address Hex decode Failed.");
let darwinia_account = T::DetermineAccountId::account_id_for(&decoded_sub_key[..])?;

let redeemed_amount = amount.as_u128().saturated_into();
T::KtonReward::on_unbalanced(redeemed_positive_imbalance_kton);

KtonProofVerified::insert((proof_record.header_hash, proof_record.index), proof_record);
<KtonLocked<T>>::mutate(|l| {
*l = l.saturating_sub(redeemed_amount);
*l = l.saturating_sub(redeemed_kton);
});

<KtonProofVerified>::insert((proof_record.header_hash, proof_record.index), proof_record);

let redeemed_kton = T::Kton::deposit_into_existing(&darwinia_account, redeemed_amount).expect("Deposit into existing failed.");

T::KtonReward::on_unbalanced(redeemed_kton);
}

// https://github.com/evolutionlandorg/bank
Expand Down Expand Up @@ -266,6 +196,79 @@ decl_module! {
}
}

impl<T: Trait> Module<T> {
fn parse_proof(proof: &EthReceiptProof, event_name: &str) -> result::Result<(T::AccountId, Balance), &'static str> {
let verified_receipt = T::EthRelay::verify_receipt(proof)?;

// event RingBurndropTokens(address indexed token, address indexed owner, uint amount, bytes data);
// https://ropsten.etherscan.io/tx/0x81f699c93b00ab0b7db701f87b6f6045c1e0692862fcaaf8f06755abb0536800
// event KtonBurndropTokens(address indexed token, address indexed owner, uint amount, bytes data);
// TODO: address
let result = {
let eth_event = EthEvent {
name: event_name.to_owned(),
inputs: vec![
EthEventParam {
name: "token".to_owned(),
kind: ParamType::Address,
indexed: true,
},
EthEventParam {
name: "owner".to_owned(),
kind: ParamType::Address,
indexed: true,
},
EthEventParam {
name: "amount".to_owned(),
kind: ParamType::Uint(256),
indexed: false,
},
EthEventParam {
name: "data".to_owned(),
kind: ParamType::Bytes,
indexed: false,
},
],
anonymous: false,
};
let log_entry = verified_receipt
.logs
.into_iter()
.find(|x| x.address == Self::ring_redeem_address() && x.topics[0] == eth_event.signature())
.ok_or("Log Entry - NOT FOUND")?;
let log = RawLog {
topics: vec![log_entry.topics[0], log_entry.topics[1], log_entry.topics[2]],
data: log_entry.data.clone(),
};

eth_event.parse_log(log).map_err(|_| "Parse Eth Log - FAILED")?
};
let redeemed_amount = {
// TODO: div 10**18 and mul 10**9
let amount = result.params[2]
.value
.clone()
.to_uint()
.map(|x| x / U256::from(1_000_000_000u64))
.ok_or("Convert to Int - FAILED")?;

Balance::try_from(amount)?
};
let darwinia_account = {
let raw_sub_key = result.params[3]
.value
.clone()
.to_bytes()
.ok_or("Convert to Bytes - FAILED")?;
let decoded_sub_key = hex::decode(&raw_sub_key).map_err(|_| "Decode Address - FAILED")?;

T::DetermineAccountId::account_id_for(&decoded_sub_key)?
};

Ok((darwinia_account, redeemed_amount))
}
}

pub trait AccountIdFor<AccountId> {
// fn contract_address_for(code_hash: &CodeHash, data: &[u8], origin: &AccountId) -> AccountId;
fn account_id_for(decoded_sub_key: &[u8]) -> result::Result<AccountId, &'static str>;
Expand Down