diff --git a/core/src/codechain_machine.rs b/core/src/codechain_machine.rs index d75ccf3361..9d10dcf0aa 100644 --- a/core/src/codechain_machine.rs +++ b/core/src/codechain_machine.rs @@ -18,7 +18,7 @@ use ckey::Address; use cstate::{StateError, TopState, TopStateView}; use ctypes::errors::{HistoryError, SyntaxError}; -use ctypes::transaction::{Action, AssetTransferInput, OrderOnTransfer, Timelock}; +use ctypes::transaction::{Action, AssetTransferInput, Timelock}; use ctypes::{CommonParams, Header}; use crate::block::{ExecutedBlock, IsBlock}; @@ -28,14 +28,12 @@ use crate::transaction::{SignedTransaction, UnverifiedTransaction}; pub struct CodeChainMachine { params: CommonParams, - is_order_disabled: bool, } impl CodeChainMachine { pub fn new(params: CommonParams) -> Self { CodeChainMachine { params, - is_order_disabled: is_order_disabled(), } } @@ -58,7 +56,7 @@ impl CodeChainMachine { } .into()) } - tx.verify_with_params(common_params, self.is_order_disabled)?; + tx.verify_with_params(common_params)?; Ok(()) } @@ -79,7 +77,6 @@ impl CodeChainMachine { ) -> Result<(), Error> { if let Action::TransferAsset { inputs, - orders, expiration, .. } = &tx.action @@ -88,7 +85,6 @@ impl CodeChainMachine { if verify_timelock { Self::verify_transfer_timelock(inputs, header, client)?; } - Self::verify_transfer_order_expired(orders, header)?; } // FIXME: Filter transactions. Ok(()) @@ -176,19 +172,6 @@ impl CodeChainMachine { Ok(()) } - fn verify_transfer_order_expired(orders: &[OrderOnTransfer], header: &Header) -> Result<(), Error> { - for order_tx in orders { - if order_tx.order.expiration < header.timestamp() { - return Err(HistoryError::OrderExpired { - expiration: order_tx.order.expiration, - timestamp: header.timestamp(), - } - .into()) - } - } - Ok(()) - } - pub fn min_cost(params: &CommonParams, action: &Action) -> u64 { match action { Action::MintAsset { @@ -250,16 +233,3 @@ impl CodeChainMachine { Ok(()) } } - -fn is_order_disabled() -> bool { - #[cfg(test)] - const DEFAULT_ORDER_DISABLED: bool = false; - #[cfg(not(test))] - const DEFAULT_ORDER_DISABLED: bool = true; - let var = std::env::var("ENABLE_ORDER"); - match var.as_ref().map(|x| x.trim()) { - Ok(value) => !value.parse::().unwrap(), - Err(std::env::VarError::NotPresent) => DEFAULT_ORDER_DISABLED, - Err(err) => unreachable!("{:?}", err), - } -} diff --git a/core/src/miner/mem_pool.rs b/core/src/miner/mem_pool.rs index cd0d8d5d18..0ceb45dd02 100644 --- a/core/src/miner/mem_pool.rs +++ b/core/src/miner/mem_pool.rs @@ -1273,7 +1273,6 @@ pub mod test { burns: vec![], inputs: vec![], outputs: vec![], - orders: vec![], metadata: "".into(), approvals: vec![], expiration: None, diff --git a/core/src/transaction.rs b/core/src/transaction.rs index 0521e7ac5a..5820a3ff5f 100644 --- a/core/src/transaction.rs +++ b/core/src/transaction.rs @@ -137,7 +137,7 @@ impl UnverifiedTransaction { } /// Verify transactiosn with the common params. Does not attempt signer recovery. - pub fn verify_with_params(&self, params: &CommonParams, is_order_disabled: bool) -> Result<(), SyntaxError> { + pub fn verify_with_params(&self, params: &CommonParams) -> Result<(), SyntaxError> { if self.network_id != params.network_id() { return Err(SyntaxError::InvalidNetworkId(self.network_id)) } @@ -145,7 +145,7 @@ impl UnverifiedTransaction { if byte_size >= params.max_body_size() { return Err(SyntaxError::TransactionIsTooBig) } - self.action.verify_with_params(params, is_order_disabled) + self.action.verify_with_params(params) } } diff --git a/rpc/src/v1/impls/devel.rs b/rpc/src/v1/impls/devel.rs index 042923600b..e916b8ec56 100644 --- a/rpc/src/v1/impls/devel.rs +++ b/rpc/src/v1/impls/devel.rs @@ -174,7 +174,6 @@ where burns: vec![], inputs: $inputs, outputs: $outputs, - orders: vec![], metadata: "".to_string(), approvals: vec![], expiration: None, diff --git a/rpc/src/v1/types/action.rs b/rpc/src/v1/types/action.rs index 4552c2a448..02160c57d5 100644 --- a/rpc/src/v1/types/action.rs +++ b/rpc/src/v1/types/action.rs @@ -24,7 +24,7 @@ use primitives::{Bytes, H160, H256}; use rustc_serialize::hex::{FromHex, ToHex}; use super::super::errors::ConversionError; -use super::{AssetMintOutput, AssetTransferInput, AssetTransferOutput, OrderOnTransfer}; +use super::{AssetMintOutput, AssetTransferInput, AssetTransferOutput}; #[derive(Debug, Deserialize, PartialEq)] #[serde(rename_all = "camelCase", tag = "type")] @@ -48,7 +48,6 @@ pub enum Action { burns: Vec, inputs: Vec, outputs: Vec, - orders: Vec, metadata: String, approvals: Vec, @@ -151,7 +150,9 @@ pub enum ActionWithTracker { burns: Vec, inputs: Vec, outputs: Vec, - orders: Vec, + // NOTE: The orders field is removed in the core but it remains to + // support the old version of the SDK + orders: Vec<()>, metadata: String, approvals: Vec, @@ -269,7 +270,6 @@ impl ActionWithTracker { burns, inputs, outputs, - orders, metadata, approvals, expiration, @@ -278,7 +278,7 @@ impl ActionWithTracker { burns: burns.into_iter().map(From::from).collect(), inputs: inputs.into_iter().map(From::from).collect(), outputs: outputs.into_iter().map(From::from).collect(), - orders: orders.into_iter().map(From::from).collect(), + orders: vec![], metadata, approvals, expiration: expiration.map(From::from), @@ -449,20 +449,17 @@ impl TryFrom for ActionType { burns, inputs, outputs, - orders, metadata, approvals, expiration, } => { let outputs = outputs.into_iter().map(TryFrom::try_from).collect::>()?; - let orders = orders.into_iter().map(TryFrom::try_from).collect::>()?; ActionType::TransferAsset { network_id, burns: burns.into_iter().map(From::from).collect(), inputs: inputs.into_iter().map(From::from).collect(), outputs, - orders, metadata, approvals, expiration: expiration.map(From::from), diff --git a/rpc/src/v1/types/asset.rs b/rpc/src/v1/types/asset.rs index cff4fd085e..bba19e06e9 100644 --- a/rpc/src/v1/types/asset.rs +++ b/rpc/src/v1/types/asset.rs @@ -18,7 +18,7 @@ use std::ops::Deref; use cjson::uint::Uint; use cstate::{Asset as AssetType, OwnedAsset as OwnedAssetType}; -use primitives::{H160, H256}; +use primitives::H160; use rustc_serialize::hex::ToHex; #[derive(Clone, Debug, PartialEq, Serialize)] @@ -35,7 +35,6 @@ pub struct OwnedAsset { asset: Asset, lock_script_hash: H160, parameters: Vec, - order_hash: Option, } impl From for Asset { @@ -55,7 +54,6 @@ impl From for OwnedAsset { quantity: asset.quantity().into(), }, lock_script_hash: *asset.lock_script_hash(), - order_hash: *asset.order_hash(), parameters: asset.parameters().iter().map(Deref::deref).map(<[u8]>::to_hex).collect(), } } diff --git a/rpc/src/v1/types/mod.rs b/rpc/src/v1/types/mod.rs index a11dec6110..59ab24ad1c 100644 --- a/rpc/src/v1/types/mod.rs +++ b/rpc/src/v1/types/mod.rs @@ -20,7 +20,6 @@ mod asset_input; mod asset_output; mod asset_scheme; mod block; -mod order; mod text; mod transaction; mod unsigned_transaction; @@ -29,9 +28,8 @@ mod work; use primitives::H256; use self::asset::Asset; -use self::asset_input::{AssetOutPoint, AssetTransferInput}; +use self::asset_input::AssetTransferInput; use self::asset_output::{AssetMintOutput, AssetTransferOutput}; -use self::order::OrderOnTransfer; pub use self::action::{Action, ActionWithTracker}; pub use self::asset::OwnedAsset; diff --git a/rpc/src/v1/types/order.rs b/rpc/src/v1/types/order.rs deleted file mode 100644 index c9396ff20d..0000000000 --- a/rpc/src/v1/types/order.rs +++ /dev/null @@ -1,144 +0,0 @@ -// Copyright 2018-2019 Kodebox, Inc. -// This file is part of CodeChain. -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as -// published by the Free Software Foundation, either version 3 of the -// License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public License -// along with this program. If not, see . - -use std::convert::{TryFrom, TryInto}; - -use cjson::uint::Uint; -use ctypes::transaction::{Order as OrderType, OrderOnTransfer as OrderOnTransferType}; -use ctypes::ShardId; -use primitives::H160; -use rustc_serialize::hex::{FromHex, FromHexError, ToHex}; - -use super::AssetOutPoint; - -#[derive(Debug, Deserialize, PartialEq, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct Order { - pub asset_type_from: H160, - pub asset_type_to: H160, - pub asset_type_fee: H160, - pub shard_id_from: ShardId, - pub shard_id_to: ShardId, - pub shard_id_fee: ShardId, - pub asset_quantity_from: Uint, - pub asset_quantity_to: Uint, - pub asset_quantity_fee: Uint, - pub origin_outputs: Vec, - pub expiration: Uint, - pub lock_script_hash_from: H160, - pub parameters_from: Vec, - pub lock_script_hash_fee: H160, - pub parameters_fee: Vec, -} - -impl From for Order { - fn from(from: OrderType) -> Self { - Order { - asset_type_from: from.asset_type_from, - asset_type_to: from.asset_type_to, - asset_type_fee: from.asset_type_fee, - shard_id_from: from.shard_id_from, - shard_id_to: from.shard_id_to, - shard_id_fee: from.shard_id_fee, - asset_quantity_from: from.asset_quantity_from.into(), - asset_quantity_to: from.asset_quantity_to.into(), - asset_quantity_fee: from.asset_quantity_fee.into(), - origin_outputs: from.origin_outputs.into_iter().map(From::from).collect(), - expiration: from.expiration.into(), - lock_script_hash_from: from.lock_script_hash_from, - parameters_from: from.parameters_from.into_iter().map(|param| param.to_hex()).collect(), - lock_script_hash_fee: from.lock_script_hash_fee, - parameters_fee: from.parameters_fee.into_iter().map(|param| param.to_hex()).collect(), - } - } -} - -impl TryFrom for OrderType { - type Error = FromHexError; - fn try_from(from: Order) -> Result { - let parameters_from = - from.parameters_from.into_iter().map(|param| param.from_hex()).collect::>()?; - let parameters_fee = from.parameters_fee.into_iter().map(|param| param.from_hex()).collect::>()?; - Ok(OrderType { - asset_type_from: from.asset_type_from, - asset_type_to: from.asset_type_to, - asset_type_fee: from.asset_type_fee, - shard_id_from: from.shard_id_from, - shard_id_to: from.shard_id_to, - shard_id_fee: from.shard_id_fee, - asset_quantity_from: from.asset_quantity_from.into(), - asset_quantity_to: from.asset_quantity_to.into(), - asset_quantity_fee: from.asset_quantity_fee.into(), - origin_outputs: from.origin_outputs.into_iter().map(From::from).collect(), - expiration: from.expiration.into(), - lock_script_hash_from: from.lock_script_hash_from, - parameters_from, - lock_script_hash_fee: from.lock_script_hash_fee, - parameters_fee, - }) - } -} - -#[derive(Debug, Deserialize, PartialEq, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct OrderOnTransfer { - pub order: Order, - /// Spent quantity of asset_type_from - pub spent_quantity: Uint, - // Indices of asset_type_from - pub input_from_indices: Vec, - // Indices of asset_type_fee - pub input_fee_indices: Vec, - // Indices of remain asset_type_from - pub output_from_indices: Vec, - // Indices of asset_type_to - pub output_to_indices: Vec, - // Indices of ramain asset_type_fee - pub output_owned_fee_indices: Vec, - // Indices of paid asset_type_fee - pub output_transferred_fee_indices: Vec, -} - -impl From for OrderOnTransfer { - fn from(from: OrderOnTransferType) -> Self { - OrderOnTransfer { - order: from.order.into(), - spent_quantity: from.spent_quantity.into(), - input_from_indices: from.input_from_indices, - input_fee_indices: from.input_fee_indices, - output_from_indices: from.output_from_indices, - output_to_indices: from.output_to_indices, - output_owned_fee_indices: from.output_owned_fee_indices, - output_transferred_fee_indices: from.output_transferred_fee_indices, - } - } -} - -impl TryFrom for OrderOnTransferType { - type Error = FromHexError; - fn try_from(from: OrderOnTransfer) -> Result { - Ok(OrderOnTransferType { - order: from.order.try_into()?, - spent_quantity: from.spent_quantity.into(), - input_from_indices: from.input_from_indices, - input_fee_indices: from.input_fee_indices, - output_from_indices: from.output_from_indices, - output_to_indices: from.output_to_indices, - output_owned_fee_indices: from.output_owned_fee_indices, - output_transferred_fee_indices: from.output_transferred_fee_indices, - }) - } -} diff --git a/spec/Asset-Exchange-Protocol.md b/spec/Asset-Exchange-Protocol.md deleted file mode 100644 index 648cdfbc8d..0000000000 --- a/spec/Asset-Exchange-Protocol.md +++ /dev/null @@ -1,75 +0,0 @@ -CodeChain supports an on-chain order to support DEX(Decentralized Exchange). - -## Order - -An order can be either a _point-to-point order_ between a maker and a taker, or a _broadcast order_ between a maker, a relayer and takers. -Point-to-point orders allow two parties(makers and takers) to directly exchange assets between each other. -Broadcast orders are similar to point-to-point orders, but also allow relayers to take fee assets from makers and takers. Broadcast orders are usually used in decentralized exchange platforms. - -Orders on CodeChain are implemented on UTXO forms. -Basically, an order is like a tag on products in grocery stores. Orders can be put on inputs and outputs of transfer transactions. If an input/output has an order, it means that that specific input/output should be exchanged as its order says. Think about this situation: Let’s say we have an order to exchange 10 gold to 100 silver, and we've put that order on a 10-gold input. Then there should be a 100-silver output with the same order of 10 gold to 100 silver. If there isn’t enough gold, there would perhaps be a 5-gold output and a 50-silver output, both with the same order, or, whatever outputs with the same order while maintaining the order equilibrium. - -Assets with orders must be able to be spent by takers or relayers without any permission. But in the CodeChain UTXO form, those parties should provide a lock script and an unlock script to prove the ownership of the assets. In order to solve the problem, if there are orders on inputs, CodeChain runs VM on **orders**, not *transactions*, if there are orders on inputs. If there are no orders on inputs, CodeChain runs VM on transactions as usual. Partial signing is not allowed on transactions with orders. With this convention, takers and relayers can take the ownership of the assets with orders with unlock scripts which are provided by makers. - - -## Order format - -The format of `Order` is as shown below. - -| Name | Data Type | Description | -|--------------------|-----------------|-----------------------------------------------------------------------------------------------------------| -| assetTypeFrom | H160 | The type of the asset offered by maker | -| assetTypeTo | H160 | The type of the asset requested by maker | -| assetTypeFee | H160 | The type of the asset offered by maker to give as fees | -| shardIdFrom | ShardId | The shard ID of the asset offered by maker | -| shardIdTo | ShardId | The shard ID of the asset requested by maker | -| shardIdFee | ShardId | The shard ID of the asset offered by maker to give as fees | -| assetQuantityFrom | U64 | Total quantity of assets with the type assetTypeFrom | -| assetQuantityTo | U64 | Total quantity of assets with the type assetTypeTo | -| assetQuantityFee | U64 | Total quantity of assets with the type assetTypeFee | -| originOutputs | AssetOutPoint[] | The previous outputs composed of assetTypeFrom / assetTypeFee assets, which the order starts from | -| expiration | U64 | Time at which the order expires | -| lockScriptHashFrom | H160 | Lock script hash provided by maker, which should be written in every output with the order except fee | -| parametersFrom | Bytes[] | Parameters provided by maker, which should be written in every output with the order except fee | -| lockScriptHashFee | H160 | Lock script hash provided by relayer, which should be written in every fee output with the order | -| parametersFee | Bytes[] | Parameters provided by relayer, which should be written in every fee output with the order | - -To make a point-to-point order, put a zero on the `assetQuantityFee` field. -To write an order on a transfer transaction, the order should be wrapped once more, to `OrderOnTransfer`. - -## OrderOnTransfer format - -If there are inputs and outputs with the same order, it is wasteful to put the order in every input/output. Therefore, orders are wrapped into `OrderOnTransfer`. - -| Name | Data Type | Description | -| --------------------------- | --------- | -------------------------------------------------------------------------------- | -| order | Order | The order to write on the transfer transaction | -| spentQuantity | U64 | The spent quantity of `assetTypeFrom` of the order in the transfer transaction | -| inputFromIndices | Index[] | The indices of the transfer inputs that are protected by the order ( assetFrom) | -| inputFeeIndices | Index[] | The indices of the transfer inputs that are protected by the order (assetFee) | -| outputFromIndices | Index[] | The indices of the transfer outputs that are protected by the order (assetFrom) | -| outputToIndices | Index[] | The indices of the transfer outputs that are protected by the order (assetTo) | -| outputOwnedFeeIndices | Index[] | The indices of the transfer outputs that are protected by the order (assetFee) | -| outputTransferredFeeIndices | Index[] | The indices of the transfer outputs that are protected by the order (assetFee) | - -And the format of transfer transaction is as shown below. - -| Name | Data Type | -|---------------|-----------------------| -| networkId | NetworkId | -| burns | AssetTransferInput[] | -| inputs | AssetTransferInput[] | -| outputs | AssetTransferOutput[] | -| orders | OrderOnTransfer[] | - -## How to support partial fills? - -As described above in the 10-gold-to-100-silver order, it is possible to make a transfer transaction which has a 10-gold input that results in a 5-gold and 50-silver output, tagged with the same order. (Other inputs/outputs should be provided by a taker or a relayer). After this transaction, an asset contains the hash of the *consumed order*, which is a 5-gold-to-50-silver order, not a 10-gold-to-100-silver order. To use the 5-gold output, provide the 5-gold-to-50-silver order with the same information except for the `assetQuantityFrom` and the `assetQuantityTo` field. Neither a lock script nor an unlock script is needed for the 5-gold input. CodeChain will compare the order of an input and the order of the corresponding previous output, and will not run VM on the order if those orders are identical. - -## How to support cancellation? - -An order can be cancelled by the maker before it is completely filled. Let's use the described 10-gold-to-100-silver order example again. Suppose the maker wants to cancel the order after the 5-gold and 50-silver transaction is processed. Unlike the previous partial fill case, this time the maker has to prove the ownership of the remaining asset. Both a lock script and an unlock script is needed for the 5-gold input. Writing a new transaction with empty `orders` field with this input makes CodeChain cancel the remaining 5-gold and 50-silver order. - -## How to handle matched two orders with different exchange ratios? - -Suppose Alice and Bob want to exchange their own assets through a DEX platform. Alice offered a 10-gold-to-100-silver exchange ratio but Bob offered a 5-gold-to-100-silver exchange ratio, which has higher gold to silver ratio compared to the Alice's offer. For DEX platforms to satisfy both Alice and Bob, the minimum conditions are "Alice gets at least 100 silvers at the expense of 5 golds" and "Bob gets at least 5 golds at the expense of 100 silvers". Satisfying these conditions, there are extra 5 golds. Because CodeChain only checks the minimum conditions, DEX platforms have a freedom of how they dispose these extra assets. As long as the minimum conditions are satisfied, any possible choice of transaction could be accepted. \ No newline at end of file diff --git a/spec/JSON-RPC.md b/spec/JSON-RPC.md index 15a552e9ca..940676b59d 100644 --- a/spec/JSON-RPC.md +++ b/spec/JSON-RPC.md @@ -79,7 +79,6 @@ A string that starts with "(NetworkID)c", and Bech32 string follows. For example - burns: `AssetTransferInput[]` - inputs: `AssetTransferInput[]` - outputs: `AssetTransferOutput[]` - - orders: `OrderOnTransfer[]` - metadata: `string` - approvals: `Signature[]` - expiration: `Expiration time` | `null` @@ -215,29 +214,6 @@ When `Transaction` is included in any response, there will be an additional fiel - shardId: `number` - quantity: `U64` -### Order - - - assetTypeFrom: `H160` - - assetTypeTo: `H160` - - assetTypeFee: `H160` - - shardIdFrom: `number` - - shardIdTo: `number` - - shardIdFee: `number` - - assetQuantityFrom: `U64` - - assetQuantityTo: `U64` - - assetQuantityFee: `U64` - - originOutputs: `AssetOutPoint[]` - - expiration: `number` - - lockScriptHash: `H160` - - parameters: `string[]` - -### OrderOnTransfer - - - order: `Order` - - spentQuantity: `U64` - - inputIndices: `number[]` - - outputIndices: `number[]` - ## Signature `H520` for ECDSA signature | `H512` for Schnorr signature @@ -1578,7 +1554,7 @@ Errors: `Transfer Only` ``` curl \ -H 'Content-Type: application/json' \ - -d '{"jsonrpc": "2.0", "method": "chain_executeVM", "params": [{"type":"assetTransfer","data":{"networkId":"tc","burns":[],"inputs":[{"prevOut":{"transactionHash":"0x56774a7e53abd17d70789af6d6f89b4ac23048c07430d1fbe7a8fe0688ecd250","index":0,"assetType":"0x53000000ec7f404207fc5f6bfaad91ed3bf4532b94f508fbea86223409eb189c","quantity":"0x64"},"timelock":null,"lockScript":[53,1,148,17,34,255,128],"unlockScript":[50,65,57,113,98,163,242,125,128,229,140,240,213,154,218,70,232,138,150,84,215,67,109,128,156,81,100,57,53,194,83,70,149,63,53,138,140,11,7,42,34,206,32,244,60,3,191,57,24,132,44,10,175,13,218,20,62,152,175,40,8,240,76,185,246,37,0,50,1,3,50,64,179,217,97,169,96,174,90,169,141,98,170,45,70,139,251,168,8,238,200,83,24,49,115,158,81,199,69,29,229,191,88,173,232,249,178,39,56,223,68,148,75,92,15,236,37,56,88,197,38,111,93,69,232,65,2,247,239,134,191,115,159,238,196,201]}],"outputs":[{"lockScriptHash":"0x5f5960a7bca6ceeeb0c97bc717562914e7a1de04","parameters":[[170,45,255,58,152,57,253,189,84,170,233,14,217,172,65,78,188,106,99,109]],"assetType":"0x53000000ec7f404207fc5f6bfaad91ed3bf4532b94f508fbea86223409eb189c","quantity":"0x64"}],"orders":[]}}, [[[123,110,101,117,85,125,64,83,80,25,37,104,84,81,160,50,198,212,89,125]]], [0]], "id": null}' \ + -d '{"jsonrpc": "2.0", "method": "chain_executeVM", "params": [{"type":"assetTransfer","data":{"networkId":"tc","burns":[],"inputs":[{"prevOut":{"transactionHash":"0x56774a7e53abd17d70789af6d6f89b4ac23048c07430d1fbe7a8fe0688ecd250","index":0,"assetType":"0x53000000ec7f404207fc5f6bfaad91ed3bf4532b94f508fbea86223409eb189c","quantity":"0x64"},"timelock":null,"lockScript":[53,1,148,17,34,255,128],"unlockScript":[50,65,57,113,98,163,242,125,128,229,140,240,213,154,218,70,232,138,150,84,215,67,109,128,156,81,100,57,53,194,83,70,149,63,53,138,140,11,7,42,34,206,32,244,60,3,191,57,24,132,44,10,175,13,218,20,62,152,175,40,8,240,76,185,246,37,0,50,1,3,50,64,179,217,97,169,96,174,90,169,141,98,170,45,70,139,251,168,8,238,200,83,24,49,115,158,81,199,69,29,229,191,88,173,232,249,178,39,56,223,68,148,75,92,15,236,37,56,88,197,38,111,93,69,232,65,2,247,239,134,191,115,159,238,196,201]}],"outputs":[{"lockScriptHash":"0x5f5960a7bca6ceeeb0c97bc717562914e7a1de04","parameters":[[170,45,255,58,152,57,253,189,84,170,233,14,217,172,65,78,188,106,99,109]],"assetType":"0x53000000ec7f404207fc5f6bfaad91ed3bf4532b94f508fbea86223409eb189c","quantity":"0x64"}]}}, [[[123,110,101,117,85,125,64,83,80,25,37,104,84,81,160,50,198,212,89,125]]], [0]], "id": null}' \ localhost:8080 ``` diff --git a/spec/Transaction.md b/spec/Transaction.md index f084846eca..354a7ee53e 100644 --- a/spec/Transaction.md +++ b/spec/Transaction.md @@ -80,7 +80,6 @@ TransferAsset { burns: Vec, inputs: Vec, outputs: Vec, - orders: Vec, metadata: String, approvals: Vec, @@ -129,11 +128,6 @@ enum Timelock { } ``` -### Order - -Order is used for the DEX. -Please see [this page](./Asset-Exchange-Protocol.md) for more information. - ## ChangeAssetScheme It changes the asset scheme. diff --git a/state/src/impls/shard_level.rs b/state/src/impls/shard_level.rs index 48da78ff47..0a079f1d7c 100644 --- a/state/src/impls/shard_level.rs +++ b/state/src/impls/shard_level.rs @@ -23,8 +23,8 @@ use ckey::Address; use cmerkle::{self, TrieError, TrieFactory}; use ctypes::errors::{RuntimeError, UnlockFailureReason}; use ctypes::transaction::{ - AssetMintOutput, AssetOutPoint, AssetTransferInput, AssetTransferOutput, AssetWrapCCCOutput, Order, - OrderOnTransfer, PartialHashing, ShardTransaction, + AssetMintOutput, AssetOutPoint, AssetTransferInput, AssetTransferOutput, AssetWrapCCCOutput, PartialHashing, + ShardTransaction, }; use ctypes::util::unexpected::Mismatch; use ctypes::{BlockNumber, ShardId}; @@ -137,7 +137,6 @@ impl<'db> ShardLevelState<'db> { burns, inputs, outputs, - orders, .. } => { debug_assert!(outputs.len() <= 512); @@ -148,7 +147,6 @@ impl<'db> ShardLevelState<'db> { burns, inputs, outputs, - orders, client, parent_block_number, parent_block_timestamp, @@ -261,7 +259,6 @@ impl<'db> ShardLevelState<'db> { output.lock_script_hash, output.parameters.clone(), output.supply, - None, )?; ctrace!(TX, "Created asset on {}:{}:{}", self.shard_id, transaction_tracker, 0); Ok(()) @@ -277,24 +274,14 @@ impl<'db> ShardLevelState<'db> { burns: &[AssetTransferInput], inputs: &[AssetTransferInput], outputs: &[AssetTransferOutput], - orders: &[OrderOnTransfer], client: &C, parent_block_number: BlockNumber, parent_block_timestamp: u64, ) -> StateResult<()> { - let mut values_to_hash = vec![None; inputs.len()]; - for order_tx in orders { - let order = &order_tx.order; - for input_idx in order_tx.input_from_indices.iter().chain(order_tx.input_fee_indices.iter()) { - values_to_hash[*input_idx] = Some(order); - } - } - - for (input, transaction, order, burn) in inputs + for (input, transaction, burn) in inputs .iter() - .enumerate() - .map(|(index, input)| (input, transaction, values_to_hash[index], false)) - .chain(burns.iter().map(|input| (input, transaction, None, true))) + .map(|input| (input, transaction, false)) + .chain(burns.iter().map(|input| (input, transaction, true))) { if input.prev_out.shard_id != self.shard_id { continue @@ -302,7 +289,6 @@ impl<'db> ShardLevelState<'db> { self.check_and_run_input_script( input, transaction, - order, burn, sender, approvers, @@ -312,21 +298,6 @@ impl<'db> ShardLevelState<'db> { )?; } - self.check_orders(orders, inputs)?; - let mut output_order_hashes = vec![None; outputs.len()]; - for order_tx in orders { - let order = &order_tx.order; - for output_idx in order_tx - .output_from_indices - .iter() - .chain(order_tx.output_to_indices.iter()) - .chain(order_tx.output_owned_fee_indices.iter()) - .chain(order_tx.output_transferred_fee_indices.iter()) - { - output_order_hashes[*output_idx] = Some(order.consume(order_tx.spent_quantity).hash()); - } - } - let mut deleted_asset = Vec::with_capacity(inputs.len() + burns.len()); for input in inputs.iter().chain(burns) { if input.prev_out.shard_id != self.shard_id { @@ -348,7 +319,6 @@ impl<'db> ShardLevelState<'db> { output.lock_script_hash, output.parameters.clone(), output.quantity, - output_order_hashes[index], )?; } let mut reduced_supplies = Vec::with_capacity(burns.len()); @@ -373,41 +343,6 @@ impl<'db> ShardLevelState<'db> { Ok(()) } - fn check_orders(&self, orders: &[OrderOnTransfer], inputs: &[AssetTransferInput]) -> StateResult<()> { - for order_tx in orders { - let order = &order_tx.order; - let mut counter: usize = 0; - for input_idx in order_tx.input_from_indices.iter().chain(order_tx.input_fee_indices.iter()) { - let input = &inputs[*input_idx]; - let tracker = input.prev_out.tracker; - let index = input.prev_out.index; - if input.prev_out.shard_id != self.shard_id { - continue - } - let asset = self.asset(tracker, index)?.ok_or_else(|| RuntimeError::AssetNotFound { - shard_id: self.shard_id, - tracker, - index, - })?; - - match &asset.order_hash() { - Some(order_hash) if *order_hash == order.hash() => {} - _ => { - if order.origin_outputs.contains(&input.prev_out) { - counter += 1; - } else { - return Err(RuntimeError::InvalidOriginOutputs(order.hash()).into()) - } - } - } - } - if counter > 0 && counter != order.origin_outputs.len() { - return Err(RuntimeError::InvalidOriginOutputs(order.hash()).into()) - } - } - Ok(()) - } - fn approved_by_registrar(&self, asset_type: H160, sender: &Address, approvers: &[Address]) -> StateResult { let asset_scheme = self.asset_scheme(asset_type)?.ok_or_else(|| RuntimeError::AssetSchemeNotFound { asset_type, @@ -493,7 +428,6 @@ impl<'db> ShardLevelState<'db> { output.lock_script_hash, output.parameters.clone(), output.supply, - None, )?; ctrace!(TX, "Increased asset supply {:?} {:?} => {:?}", asset_type, previous_supply, output.supply); ctrace!(TX, "Created asset on {}:{}", self.shard_id, transaction_tracker); @@ -588,7 +522,6 @@ impl<'db> ShardLevelState<'db> { &self, input: &AssetTransferInput, transaction: &PartialHashing, - order: Option<&Order>, burn: bool, sender: &Address, approvers: &[Address], @@ -596,25 +529,12 @@ impl<'db> ShardLevelState<'db> { parent_block_number: BlockNumber, parent_block_timestamp: u64, ) -> StateResult<()> { - debug_assert!(!burn || order.is_none()); - let (asset, from_regulator) = self.check_input_asset(input, sender, approvers)?; if from_regulator { return Ok(()) // Don't execute scripts when regulator sends the transaction. } - let to_hash: &PartialHashing = if let Some(order) = order { - if let Some(order_hash) = &asset.order_hash() { - if *order_hash == order.hash() { - // If an order on an input and an order on the corresponding prev_out(asset) is same, - // then skip checking lock script and running VM. - return Ok(()) - } - } - order - } else { - transaction - }; + let to_hash: &PartialHashing = transaction; if *asset.lock_script_hash() != Blake::blake(&input.lock_script) { return Err(RuntimeError::ScriptHashMismatch(Mismatch { @@ -685,7 +605,7 @@ impl<'db> ShardLevelState<'db> { let mut asset_scheme = self.get_asset_scheme_mut(self.shard_id, asset_type)?; asset_scheme.increase_supply(quantity)?; - self.create_asset(*tx_hash, 0, asset_type, *lock_script_hash, parameters.to_vec(), quantity, None)?; + self.create_asset(*tx_hash, 0, asset_type, *lock_script_hash, parameters.to_vec(), quantity)?; ctrace!(TX, "Created Wrapped CCC on {}:{}:{}", self.shard_id, tx_hash, 0); Ok(()) } @@ -704,7 +624,6 @@ impl<'db> ShardLevelState<'db> { self.check_and_run_input_script( burn, transaction, - None, true, sender, &approvers, @@ -762,10 +681,9 @@ impl<'db> ShardLevelState<'db> { lock_script_hash: H160, parameters: Vec, quantity: u64, - order_hash: Option, ) -> cmerkle::Result { self.cache.create_asset(&OwnedAssetAddress::new(tracker, index, self.shard_id), || { - OwnedAsset::new(asset_type, lock_script_hash, parameters, quantity, order_hash) + OwnedAsset::new(asset_type, lock_script_hash, parameters, quantity) }) } @@ -874,8 +792,6 @@ impl<'db> ShardStateView for ReadOnlyShardLevelState<'db> { #[cfg(test)] mod tests { - use ctypes::transaction::AssetOutPoint; - use super::super::super::StateError; use super::super::test_helper::SHARD_ID; use super::*; @@ -1090,7 +1006,6 @@ mod tests { assert_eq!(Ok(()), state.apply(&mint, &sender, &[sender], &[], &get_test_client(), 0, 0)); - check_shard_level_state!(state, [ (scheme: (asset_type) => { metadata: metadata, supply: amount, allowed_script_hashes: allowed_script_hashes}), (asset: (mint_tracker, 0) => { asset_type: asset_type, quantity: amount }) @@ -1139,6 +1054,7 @@ mod tests { assert_eq!(Ok(()), state.apply(&mint, &sender, &[sender], &[], &get_test_client(), 0, 0)); + check_shard_level_state!(state, [ (scheme: (asset_type) => { metadata: metadata, supply: amount, allowed_script_hashes: allowed_script_hashes}), (asset: (mint_tracker, 0) => { asset_type: asset_type, quantity: amount }) @@ -1453,91 +1369,6 @@ mod tests { ]); } - fn mint_for_transfer(state: &mut ShardLevelState, sender: Address, metadata: String, amount: u64) -> AssetOutPoint { - let lock_script_hash = H160::from("b042ad154a3359d276835c903587ebafefea22af"); - let mint = asset_mint!(asset_mint_output!(lock_script_hash, supply: amount), metadata.clone()); - let mint_tracker = mint.tracker(); - let asset_type = Blake::blake(mint_tracker); - assert_eq!(Ok(()), state.apply(&mint, &sender, &[sender], &[], &get_test_client(), 0, 0)); - - check_shard_level_state!(state, [ - (scheme: (asset_type) => { metadata: metadata.clone(), supply: amount }), - (asset: (mint_tracker, 0) => { asset_type: asset_type, quantity: amount }) - ]); - - asset_out_point!(mint_tracker, 0, asset_type, amount) - } - - #[test] - #[allow(clippy::cognitive_complexity)] - fn mint_three_times_and_transfer_with_order() { - let sender = address(); - let mut state_db = RefCell::new(get_temp_state_db()); - let mut shard_cache = ShardCache::default(); - let mut state = get_temp_shard_state(&mut state_db, SHARD_ID, &mut shard_cache); - - let mint_output_1 = mint_for_transfer(&mut state, sender, "metadata1".to_string(), 30); - let mint_output_2 = mint_for_transfer(&mut state, sender, "metadata2".to_string(), 30); - let mint_output_3 = mint_for_transfer(&mut state, sender, "metadata3".to_string(), 30); - let asset_type_1 = mint_output_1.asset_type; - let asset_type_2 = mint_output_2.asset_type; - let asset_type_3 = mint_output_3.asset_type; - - let lock_script_hash = H160::from("b042ad154a3359d276835c903587ebafefea22af"); - let order = order!(from: (asset_type_1, 20), to: (asset_type_2, 10), fee: (asset_type_3, 20), - [mint_output_1.clone(), mint_output_3.clone()], - 10, - lock_script_hash - ); - let order_consumed = order.consume(20); - let order_consumed_hash = order_consumed.hash(); - - let transfer = asset_transfer!( - inputs: - asset_transfer_inputs![ - (mint_output_1.clone(), vec![0x30, 0x01]), - (mint_output_2.clone(), vec![0x30, 0x01]), - (mint_output_3.clone(), vec![0x30, 0x01]), - ], - asset_transfer_outputs![ - (lock_script_hash, asset_type_1, 10), - (lock_script_hash, asset_type_2, 10), - (lock_script_hash, asset_type_3, 10), - (lock_script_hash, asset_type_1, 20), - (lock_script_hash, asset_type_2, 20), - (lock_script_hash, vec![vec![0x1]], asset_type_3, 20), - ], - vec![order_on_transfer! ( - order, - 20, - input_from_indices: [0], - input_fee_indices: [2], - output_from_indices: [0], - output_to_indices: [1], - output_owned_fee_indices: [2], - output_transferred_fee_indices: [5] - )] - ); - let transfer_tracker = transfer.tracker(); - - assert_eq!(Ok(()), state.apply(&transfer, &sender, &[sender], &[], &get_test_client(), 0, 0)); - - check_shard_level_state!(state, [ - (scheme: (asset_type_1) => { metadata: "metadata1".to_string(), supply: 30 }), - (scheme: (asset_type_2) => { metadata: "metadata2".to_string(), supply: 30 }), - (scheme: (asset_type_3) => { metadata: "metadata3".to_string(), supply: 30 }), - (asset: (mint_output_1.tracker, 0)), - (asset: (mint_output_2.tracker, 0)), - (asset: (mint_output_3.tracker, 0)), - (asset: (transfer_tracker, 0) => { asset_type: asset_type_1, quantity: 10, order: order_consumed_hash }), - (asset: (transfer_tracker, 1) => { asset_type: asset_type_2, quantity: 10, order: order_consumed_hash }), - (asset: (transfer_tracker, 2) => { asset_type: asset_type_3, quantity: 10, order: order_consumed_hash }), - (asset: (transfer_tracker, 3) => { asset_type: asset_type_1, quantity: 20, order }), - (asset: (transfer_tracker, 4) => { asset_type: asset_type_2, quantity: 20, order }), - (asset: (transfer_tracker, 5) => { asset_type: asset_type_3, quantity: 20, order: order_consumed_hash }) - ]); - } - #[test] fn wrap_and_unwrap_ccc() { let sender = address(); diff --git a/state/src/impls/test_helper.rs b/state/src/impls/test_helper.rs index cfe4999226..78544c9b71 100644 --- a/state/src/impls/test_helper.rs +++ b/state/src/impls/test_helper.rs @@ -211,7 +211,6 @@ macro_rules! transfer_asset { burns: Vec::new(), inputs: $inputs, outputs: $outputs, - orders: Vec::new(), metadata: "".into(), approvals: vec![], expiration: None, @@ -223,19 +222,17 @@ macro_rules! transfer_asset { burns: Vec::new(), inputs: $inputs, outputs: $outputs, - orders: Vec::new(), metadata: "".into(), approvals: $approvals, expiration: None, } }; - (inputs: $inputs:expr, $outputs:expr, $orders:expr) => { + (inputs: $inputs:expr, $outputs:expr) => { $crate::ctypes::transaction::Action::TransferAsset { network_id: $crate::impls::test_helper::NETWORK_ID.into(), burns: Vec::new(), inputs: $inputs, outputs: $outputs, - orders: $orders, metadata: "".into(), approvals: vec![], expiration: None, @@ -247,7 +244,6 @@ macro_rules! transfer_asset { burns: $burns, inputs: Vec::new(), outputs: Vec::new(), - orders: Vec::new(), metadata: "".into(), approvals: vec![], expiration: None, @@ -262,16 +258,14 @@ macro_rules! asset_transfer { burns: Vec::new(), inputs: $inputs, outputs: $outputs, - orders: Vec::new(), } }; - (inputs: $inputs:expr, $outputs:expr, $orders:expr) => { + (inputs: $inputs:expr, $outputs:expr) => { $crate::ctypes::transaction::ShardTransaction::TransferAsset { network_id: $crate::impls::test_helper::NETWORK_ID.into(), burns: Vec::new(), inputs: $inputs, outputs: $outputs, - orders: $orders, } }; (burns: $burns:expr) => { @@ -280,50 +274,10 @@ macro_rules! asset_transfer { burns: $burns, inputs: Vec::new(), outputs: Vec::new(), - orders: Vec::new(), } }; } -macro_rules! order { - (from: ($from:expr, $from_quantity:expr), to: ($to:expr, $to_quantity:expr), fee: ($fee:expr, $fee_quantity:expr), [$($output:expr),*], $expiration:expr, $lock_script_hash:expr) => { - $crate::ctypes::transaction::Order { - asset_type_from: $from, - asset_type_to: $to, - asset_type_fee: $fee, - shard_id_from: $crate::impls::test_helper::SHARD_ID, - shard_id_to: $crate::impls::test_helper::SHARD_ID, - shard_id_fee: $crate::impls::test_helper::SHARD_ID, - asset_quantity_from: $from_quantity, - asset_quantity_to: $to_quantity, - asset_quantity_fee: $fee_quantity, - origin_outputs: vec![$($output,)*], - expiration: $expiration, - lock_script_hash_from: $lock_script_hash, - parameters_from: Vec::new(), - lock_script_hash_fee: $lock_script_hash, - parameters_fee: vec![vec![0x1]], - } - } -} - -macro_rules! order_on_transfer { - ($order:expr, $spent_quantity:expr, input_from_indices: [$($input_from:expr),*], input_fee_indices: [$($input_fee:expr),*], - output_from_indices: [$($output_from:expr),*], output_to_indices: [$($output_to:expr),*], output_owned_fee_indices: [$($output_owned:expr),*], - output_transferred_fee_indices: [$($output_transferred:expr),*]) => { - $crate::ctypes::transaction::OrderOnTransfer { - order: $order, - spent_quantity: $spent_quantity, - input_from_indices: vec![$($input_from,)*], - input_fee_indices: vec![$($input_fee,)*], - output_from_indices: vec![$($output_from,)*], - output_to_indices: vec![$($output_to,)*], - output_owned_fee_indices: vec![$($output_owned,)*], - output_transferred_fee_indices: vec![$($output_transferred,)*] - } - } -} - macro_rules! asset_wrap_ccc_output { ($lock_script_hash:expr, $quantity:expr) => { $crate::ctypes::transaction::AssetWrapCCCOutput { @@ -499,7 +453,7 @@ macro_rules! set_top_level_state { set_top_level_state!($state, [$($x),*]); }; ($state:expr, [(asset: ($shard:expr, $tx_hash:expr, $index:expr) => { asset_type: $asset_type: expr, quantity: $quantity:expr, lock_script_hash: $lock_script_hash:expr }) $(,$x:tt)*]) => { - assert_eq!(Ok((true)), $state.create_asset($shard, $tx_hash, $index, $asset_type, $lock_script_hash, Vec::new(), $quantity, None)); + assert_eq!(Ok((true)), $state.create_asset($shard, $tx_hash, $index, $asset_type, $lock_script_hash, Vec::new(), $quantity)); set_top_level_state!($state, [$($x),*]); }; @@ -696,23 +650,21 @@ macro_rules! check_shard_level_state { check_shard_level_state!($state, [$($x),*]); }; - ($state:expr, [(asset: ($tx_hash:expr, $index:expr) => { asset_type: $asset_type:expr, quantity: $quantity:expr, order: $order:expr }) $(,$x:tt)*]) => { + ($state:expr, [(asset: ($tx_hash:expr, $index:expr) => { asset_type: $asset_type:expr, quantity: $quantity:expr }) $(,$x:tt)*]) => { let asset = $state.asset($tx_hash, $index) .expect(&format!("Cannot read Asset from {}:{}:{}", $state.shard_id(), $tx_hash, $index)) .expect(&format!("Asset for {}:{}:{} not exist", $state.shard_id(), $tx_hash, $index)); assert_eq!(&$asset_type, asset.asset_type()); assert_eq!($quantity, asset.quantity()); - assert_eq!(Some(&$order), asset.order_hash().as_ref()); check_shard_level_state!($state, [$($x),*]); }; - ($state:expr, [(asset: ($tx_hash:expr, $index:expr) => { asset_type: $asset_type:expr, quantity: $quantity:expr, order }) $(,$x:tt)*]) => { + ($state:expr, [(asset: ($tx_hash:expr, $index:expr) => { asset_type: $asset_type:expr, quantity: $quantity:expr }) $(,$x:tt)*]) => { let asset = $state.asset($tx_hash, $index) .expect(&format!("Cannot read Asset from {}:{}:{}", $state.shard_id(), $tx_hash, $index)) .expect(&format!("Asset for {}:{}:{} not exist", $state.shard_id(), $tx_hash, $index)); assert_eq!(&$asset_type, asset.asset_type()); assert_eq!($quantity, asset.quantity()); - assert_eq!(&None, asset.order_hash()); check_shard_level_state!($state, [$($x),*]); }; diff --git a/state/src/impls/top_level.rs b/state/src/impls/top_level.rs index 53c46cd04a..ba4fe10b79 100644 --- a/state/src/impls/top_level.rs +++ b/state/src/impls/top_level.rs @@ -751,13 +751,12 @@ impl TopLevelState { lock_script_hash: H160, parameters: Vec, amount: u64, - order_hash: Option, ) -> TrieResult { match self.shard_root(shard_id)? { Some(shard_root) => { let mut shard_cache = self.shard_caches.entry(shard_id).or_default(); let state = ShardLevelState::from_existing(shard_id, &mut self.db, shard_root, &mut shard_cache)?; - state.create_asset(tx_hash, index, asset_type, lock_script_hash, parameters, amount, order_hash)?; + state.create_asset(tx_hash, index, asset_type, lock_script_hash, parameters, amount)?; Ok(true) } None => Ok(false), diff --git a/state/src/item/asset.rs b/state/src/item/asset.rs index 9a8619a2a8..70552d2805 100644 --- a/state/src/item/asset.rs +++ b/state/src/item/asset.rs @@ -48,17 +48,10 @@ pub struct OwnedAsset { asset: Asset, lock_script_hash: H160, parameters: Vec, - order_hash: Option, } impl OwnedAsset { - pub fn new( - asset_type: H160, - lock_script_hash: H160, - parameters: Vec, - quantity: u64, - order_hash: Option, - ) -> Self { + pub fn new(asset_type: H160, lock_script_hash: H160, parameters: Vec, quantity: u64) -> Self { Self { asset: Asset { asset_type, @@ -66,7 +59,6 @@ impl OwnedAsset { }, lock_script_hash, parameters, - order_hash, } } @@ -85,10 +77,6 @@ impl OwnedAsset { pub fn quantity(&self) -> u64 { self.asset.quantity() } - - pub fn order_hash(&self) -> &Option { - &self.order_hash - } } impl Default for OwnedAsset { @@ -100,7 +88,6 @@ impl Default for OwnedAsset { }, lock_script_hash: H160::zero(), parameters: vec![], - order_hash: None, } } } @@ -123,7 +110,8 @@ impl Encodable for OwnedAsset { .append(&self.asset.quantity()) .append(&self.lock_script_hash) .append(&self.parameters) - .append(&self.order_hash); + // NOTE: The order_hash field removed. + .append(&Option::::None); } } @@ -142,6 +130,11 @@ impl Decodable for OwnedAsset { cdebug!(STATE, "{} is not an expected prefix for asset", prefix); return Err(DecoderError::Custom("Unexpected prefix")) } + let order_hash = rlp.val_at::>(5)?; + if let Some(h) = order_hash { + cdebug!(STATE, "order_hash must be None but Some({}) is given", h); + return Err(DecoderError::Custom("order_hash must be None")) + } Ok(Self { asset: Asset { asset_type: rlp.val_at(1)?, @@ -149,7 +142,6 @@ impl Decodable for OwnedAsset { }, lock_script_hash: rlp.val_at(3)?, parameters: rlp.val_at(4)?, - order_hash: rlp.val_at(5)?, }) } } diff --git a/test/src/e2e.long/orders.test.ts b/test/src/e2e.long/orders.test.ts deleted file mode 100644 index e8ddabb26d..0000000000 --- a/test/src/e2e.long/orders.test.ts +++ /dev/null @@ -1,2988 +0,0 @@ -// Copyright 2018-2019 Kodebox, Inc. -// This file is part of CodeChain. -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as -// published by the Free Software Foundation, either version 3 of the -// License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public License -// along with this program. If not, see . - -import { expect } from "chai"; -import { Asset, AssetAddress, H160, U64 } from "codechain-sdk/lib/core/classes"; -import * as _ from "lodash"; -import "mocha"; -import { faucetAddress, faucetSecret } from "../helper/constants"; -import { ERROR } from "../helper/error"; -import CodeChain from "../helper/spawn"; - -describe("orders", function() { - let node: CodeChain; - - before(async function() { - node = new CodeChain({ - env: { - ENABLE_ORDER: "true" - } - }); - await node.start(); - }); - - describe("AssetTransfer with orders", function() { - describe("Mint one asset", function() { - let aliceAddress: AssetAddress; - - let gold: Asset; - - beforeEach(async function() { - aliceAddress = await node.createP2PKHAddress(); - gold = await node.mintAsset({ - supply: 10000, - recipient: aliceAddress - }); - }); - - it("Wrong order - originOutputs are wrong (asset type from/to is same)", async function() { - const splitTx = node.sdk.core - .createTransferAssetTransaction() - .addInputs(gold) - .addOutputs( - _.times(2, () => ({ - recipient: aliceAddress, - quantity: 5000, - assetType: gold.assetType, - shardId: 0 - })) - ); - await node.signTransactionInput(splitTx, 0); - - const splitHash = await node.sendAssetTransaction(splitTx); - expect(await node.sdk.rpc.chain.containsTransaction(splitHash)) - .be.true; - expect(await node.sdk.rpc.chain.getTransaction(splitHash)).not - .null; - - const splitGolds = splitTx.getTransferredAssets(); - const splitGoldInputs = splitGolds.map((g: Asset) => - g.createTransferInput() - ); - - const expiration = Math.round(Date.now() / 1000) + 120; - const order = node.sdk.core.createOrder({ - assetTypeFrom: gold.assetType, - assetTypeTo: H160.zero(), // Fake asset type - shardIdFrom: 0, - shardIdTo: 0, - assetQuantityFrom: 5000, - assetQuantityTo: 5000, - expiration, - originOutputs: [splitGoldInputs[0].prevOut], - recipientFrom: aliceAddress - }); - - (order.assetTypeTo as any) = gold.assetType; - - const transferTx = node.sdk.core - .createTransferAssetTransaction() - .addInputs(splitGoldInputs) - .addOutputs( - { - recipient: aliceAddress, - quantity: 5000, - assetType: gold.assetType, - shardId: 0 - }, - { - recipient: aliceAddress, - quantity: 5000, - assetType: gold.assetType, - shardId: 0 - } - ) - .addOrder({ - order, - spentQuantity: 5000, - inputFromIndices: [0], - inputFeeIndices: [], - outputFromIndices: [0], - outputToIndices: [], - outputOwnedFeeIndices: [], - outputTransferredFeeIndices: [] - }); - await node.signTransactionInput(transferTx, 0); - await node.signTransactionInput(transferTx, 1); - - const signed = transferTx.sign({ - secret: faucetSecret, - fee: 10, - seq: await node.sdk.rpc.chain.getSeq(faucetAddress) - }); - try { - await node.sdk.rpc.chain.sendSignedTransaction(signed); - expect.fail(); - } catch (e) { - expect(e).is.similarTo(ERROR.INVALID_ORDER_ASSET_TYPES); - } - }); - }); - - describe("Mint two assets", function() { - let aliceAddress: AssetAddress; - let bobAddress: AssetAddress; - - let gold: Asset; - let silver: Asset; - - beforeEach(async function() { - aliceAddress = await node.createP2PKHAddress(); - bobAddress = await node.createP2PKHAddress(); - gold = await node.mintAsset({ - supply: 10000, - recipient: aliceAddress - }); - silver = await node.mintAsset({ - supply: 10000, - recipient: bobAddress - }); - }); - - it("Correct order, correct transfer", async function() { - const goldInput = gold.createTransferInput(); - const silverInput = silver.createTransferInput(); - - const expiration = Math.round(Date.now() / 1000) + 120; - const order = node.sdk.core.createOrder({ - assetTypeFrom: gold.assetType, - assetTypeTo: silver.assetType, - shardIdFrom: 0, - shardIdTo: 0, - assetQuantityFrom: 100, - assetQuantityTo: 1000, - expiration, - originOutputs: [goldInput.prevOut], - recipientFrom: aliceAddress - }); - const transferTx = node.sdk.core - .createTransferAssetTransaction() - .addInputs(goldInput, silverInput) - .addOutputs( - { - recipient: aliceAddress, - quantity: 9900, - assetType: gold.assetType, - shardId: 0 - }, - { - recipient: aliceAddress, - quantity: 1000, - assetType: silver.assetType, - shardId: 0 - }, - { - recipient: bobAddress, - quantity: 100, - assetType: gold.assetType, - shardId: 0 - }, - { - recipient: bobAddress, - quantity: 9000, - assetType: silver.assetType, - shardId: 0 - } - ) - .addOrder({ - order, - spentQuantity: 100, - inputFromIndices: [0], - inputFeeIndices: [], - outputFromIndices: [0], - outputToIndices: [1], - outputOwnedFeeIndices: [], - outputTransferredFeeIndices: [] - }); - await node.signTransactionInput(transferTx, 0); - await node.signTransactionInput(transferTx, 1); - - const hash = await node.sendAssetTransaction(transferTx); - expect(await node.sdk.rpc.chain.containsTransaction(hash)).be - .true; - expect(await node.sdk.rpc.chain.getTransaction(hash)).not.null; - }); - - it("Correct order, correct transfer - Many originOutputs", async function() { - // Split minted gold asset to 10 assets - const splitTx = node.sdk.core - .createTransferAssetTransaction() - .addInputs(gold) - .addOutputs( - _.times(10, () => ({ - recipient: aliceAddress, - quantity: 1000, - assetType: gold.assetType, - shardId: 0 - })) - ); - await node.signTransactionInput(splitTx, 0); - - const splitHash = await node.sendAssetTransaction(splitTx); - expect(await node.sdk.rpc.chain.containsTransaction(splitHash)) - .be.true; - expect(await node.sdk.rpc.chain.getTransaction(splitHash)).not - .null; - - const splitGolds = splitTx.getTransferredAssets(); - const splitGoldInputs = splitGolds.map(g => - g.createTransferInput() - ); - const silverInput = silver.createTransferInput(); - - const expiration = Math.round(Date.now() / 1000) + 120; - const order = node.sdk.core.createOrder({ - assetTypeFrom: gold.assetType, - assetTypeTo: silver.assetType, - shardIdFrom: 0, - shardIdTo: 0, - assetQuantityFrom: 100, - assetQuantityTo: 1000, - expiration, - originOutputs: splitGoldInputs.map(input => input.prevOut), - recipientFrom: aliceAddress - }); - - const transferTx = node.sdk.core - .createTransferAssetTransaction() - .addInputs(splitGoldInputs) - .addInputs(silverInput) - .addOutputs( - { - recipient: aliceAddress, - quantity: 9900, - assetType: gold.assetType, - shardId: 0 - }, - { - recipient: aliceAddress, - quantity: 1000, - assetType: silver.assetType, - shardId: 0 - }, - { - recipient: bobAddress, - quantity: 100, - assetType: gold.assetType, - shardId: 0 - }, - { - recipient: bobAddress, - quantity: 9000, - assetType: silver.assetType, - shardId: 0 - } - ) - .addOrder({ - order, - spentQuantity: 100, - inputFromIndices: _.range(10), - inputFeeIndices: [], - outputFromIndices: [0], - outputToIndices: [1], - outputOwnedFeeIndices: [], - outputTransferredFeeIndices: [] - }); - await Promise.all( - _.range((transferTx as any)._transaction.inputs.length).map( - i => node.signTransactionInput(transferTx, i) - ) - ); - - const hash = await node.sendAssetTransaction(transferTx); - expect(await node.sdk.rpc.chain.containsTransaction(hash)).be - .true; - expect(await node.sdk.rpc.chain.getTransaction(hash)).not.null; - }).timeout(10_000); - - it("Correct order, correct transfer - Output(to) is empty", async function() { - const goldInput = gold.createTransferInput(); - const silverInput = silver.createTransferInput(); - - const expiration = Math.round(Date.now() / 1000) + 120; - const order = node.sdk.core.createOrder({ - assetTypeFrom: gold.assetType, - assetTypeTo: silver.assetType, - shardIdFrom: 0, - shardIdTo: 0, - assetQuantityFrom: 10000, - assetQuantityTo: 1000, - expiration, - originOutputs: [goldInput.prevOut], - recipientFrom: aliceAddress - }); - const transferTx = node.sdk.core - .createTransferAssetTransaction() - .addInputs(goldInput, silverInput) - .addOutputs( - { - recipient: aliceAddress, - quantity: 1000, - assetType: silver.assetType, - shardId: 0 - }, - { - recipient: bobAddress, - quantity: 10000, - assetType: gold.assetType, - shardId: 0 - }, - { - recipient: bobAddress, - quantity: 9000, - assetType: silver.assetType, - shardId: 0 - } - ) - .addOrder({ - order, - spentQuantity: 10000, - inputFromIndices: [0], - inputFeeIndices: [], - outputFromIndices: [], - outputToIndices: [0], - outputOwnedFeeIndices: [], - outputTransferredFeeIndices: [] - }); - await node.signTransactionInput(transferTx, 0); - await node.signTransactionInput(transferTx, 1); - - const hash = await node.sendAssetTransaction(transferTx); - expect(await node.sdk.rpc.chain.containsTransaction(hash)).be - .true; - expect(await node.sdk.rpc.chain.getTransaction(hash)).not.null; - }); - - it("Correct order, correct transfer - Splitted output", async function() { - const goldInput = gold.createTransferInput(); - const silverInput = silver.createTransferInput(); - - const expiration = Math.round(Date.now() / 1000) + 120; - const order = node.sdk.core.createOrder({ - assetTypeFrom: gold.assetType, - assetTypeTo: silver.assetType, - shardIdFrom: 0, - shardIdTo: 0, - assetQuantityFrom: 1000, - assetQuantityTo: 1000, - expiration, - originOutputs: [goldInput.prevOut], - recipientFrom: aliceAddress - }); - const transferTx = node.sdk.core - .createTransferAssetTransaction() - .addInputs(goldInput, silverInput) - .addOutputs( - { - recipient: aliceAddress, - quantity: 1000, - assetType: silver.assetType, - shardId: 0 - }, - { - recipient: aliceAddress, - quantity: 9000, - assetType: gold.assetType, - shardId: 0 - }, - { - recipient: bobAddress, - quantity: 1000, - assetType: gold.assetType, - shardId: 0 - }, - { - recipient: bobAddress, - quantity: 4500, - assetType: silver.assetType, - shardId: 0 - }, - { - recipient: bobAddress, - quantity: 4500, - assetType: silver.assetType, - shardId: 0 - } - ) - .addOrder({ - order, - spentQuantity: 1000, - inputFromIndices: [0], - inputFeeIndices: [], - outputFromIndices: [1], - outputToIndices: [0], - outputOwnedFeeIndices: [], - outputTransferredFeeIndices: [] - }); - await node.signTransactionInput(transferTx, 0); - await node.signTransactionInput(transferTx, 1); - - const hash = await node.sendAssetTransaction(transferTx); - expect(await node.sdk.rpc.chain.containsTransaction(hash)).be - .true; - expect(await node.sdk.rpc.chain.getTransaction(hash)).not.null; - }); - - it("Correct two orders, correct transfer - Ratio is same", async function() { - const goldInput = gold.createTransferInput(); - const silverInput = silver.createTransferInput(); - - const expiration = Math.round(Date.now() / 1000) + 120; - const aliceOrder = node.sdk.core.createOrder({ - assetTypeFrom: gold.assetType, - assetTypeTo: silver.assetType, - shardIdFrom: 0, - shardIdTo: 0, - assetQuantityFrom: 100, - assetQuantityTo: 1000, - expiration, - originOutputs: [goldInput.prevOut], - recipientFrom: aliceAddress - }); - - const bobOrder = node.sdk.core.createOrder({ - assetTypeFrom: silver.assetType, - assetTypeTo: gold.assetType, - shardIdFrom: 0, - shardIdTo: 0, - assetQuantityFrom: 1000, - assetQuantityTo: 100, - expiration, - originOutputs: [silverInput.prevOut], - recipientFrom: bobAddress - }); - - const transferTx = node.sdk.core - .createTransferAssetTransaction() - .addInputs(goldInput, silverInput) - .addOutputs( - { - recipient: aliceAddress, - quantity: 9900, - assetType: gold.assetType, - shardId: 0 - }, - { - recipient: aliceAddress, - quantity: 1000, - assetType: silver.assetType, - shardId: 0 - }, - { - recipient: bobAddress, - quantity: 100, - assetType: gold.assetType, - shardId: 0 - }, - { - recipient: bobAddress, - quantity: 9000, - assetType: silver.assetType, - shardId: 0 - } - ) - .addOrder({ - order: aliceOrder, - spentQuantity: 100, - inputFromIndices: [0], - inputFeeIndices: [], - outputFromIndices: [0], - outputToIndices: [1], - outputOwnedFeeIndices: [], - outputTransferredFeeIndices: [] - }) - .addOrder({ - order: bobOrder, - spentQuantity: 1000, - inputFromIndices: [1], - inputFeeIndices: [], - outputFromIndices: [3], - outputToIndices: [2], - outputOwnedFeeIndices: [], - outputTransferredFeeIndices: [] - }); - await node.signTransactionInput(transferTx, 0); - await node.signTransactionInput(transferTx, 1); - - const hash = await node.sendAssetTransaction(transferTx); - expect(await node.sdk.rpc.chain.containsTransaction(hash)).be - .true; - expect(await node.sdk.rpc.chain.getTransaction(hash)).not.null; - }); - - it("Correct two orders, correct transfer - Ratio is different", async function() { - const goldInput = gold.createTransferInput(); - const silverInput = silver.createTransferInput(); - - const expiration = Math.round(Date.now() / 1000) + 120; - const aliceOrder = node.sdk.core.createOrder({ - assetTypeFrom: gold.assetType, - assetTypeTo: silver.assetType, - shardIdFrom: 0, - shardIdTo: 0, - assetQuantityFrom: 100, - assetQuantityTo: 1000, - expiration, - originOutputs: [goldInput.prevOut], - recipientFrom: aliceAddress - }); - - const bobOrder = node.sdk.core.createOrder({ - assetTypeFrom: silver.assetType, - assetTypeTo: gold.assetType, - shardIdFrom: 0, - shardIdTo: 0, - assetQuantityFrom: 1000, - assetQuantityTo: 50, - expiration, - originOutputs: [silverInput.prevOut], - recipientFrom: bobAddress - }); - - const transferTx = node.sdk.core - .createTransferAssetTransaction() - .addInputs(goldInput, silverInput) - .addOutputs( - { - recipient: aliceAddress, - quantity: 9900, - assetType: gold.assetType, - shardId: 0 - }, - { - recipient: aliceAddress, - quantity: 1000, - assetType: silver.assetType, - shardId: 0 - }, - // Bob gets more gold than he wanted. - // If there's a relayer, relayer may take it. - { - recipient: bobAddress, - quantity: 100, - assetType: gold.assetType, - shardId: 0 - }, - { - recipient: bobAddress, - quantity: 9000, - assetType: silver.assetType, - shardId: 0 - } - ) - .addOrder({ - order: aliceOrder, - spentQuantity: 100, - inputFromIndices: [0], - inputFeeIndices: [], - outputFromIndices: [0], - outputToIndices: [1], - outputOwnedFeeIndices: [], - outputTransferredFeeIndices: [] - }) - .addOrder({ - order: bobOrder, - spentQuantity: 1000, - inputFromIndices: [1], - inputFeeIndices: [], - outputFromIndices: [3], - outputToIndices: [2], - outputOwnedFeeIndices: [], - outputTransferredFeeIndices: [] - }); - await node.signTransactionInput(transferTx, 0); - await node.signTransactionInput(transferTx, 1); - - const hash = await node.sendAssetTransaction(transferTx); - expect(await node.sdk.rpc.chain.containsTransaction(hash)).be - .true; - expect(await node.sdk.rpc.chain.getTransaction(hash)).not.null; - }); - - it("Correct order, correct transfer - Charlie get some of asset without order", async function() { - const charlieAddress = await node.createP2PKHAddress(); - // Split minted gold asset to 10 assets - const splitTx = node.sdk.core - .createTransferAssetTransaction() - .addInputs(gold) - .addOutputs( - _.times(10, () => ({ - recipient: aliceAddress, - quantity: 1000, - assetType: gold.assetType, - shardId: 0 - })) - ); - await node.signTransactionInput(splitTx, 0); - - const splitHash = await node.sendAssetTransaction(splitTx); - expect(await node.sdk.rpc.chain.containsTransaction(splitHash)) - .be.true; - expect(await node.sdk.rpc.chain.getTransaction(splitHash)).not - .null; - - const splitGolds = splitTx.getTransferredAssets(); - const splitGoldInputs = splitGolds.map(g => - g.createTransferInput() - ); - const silverInput = silver.createTransferInput(); - - const expiration = Math.round(Date.now() / 1000) + 120; - const order = node.sdk.core.createOrder({ - assetTypeFrom: gold.assetType, - assetTypeTo: silver.assetType, - shardIdFrom: 0, - shardIdTo: 0, - assetQuantityFrom: 3000, - assetQuantityTo: 7500, - expiration, - originOutputs: [splitGoldInputs[0].prevOut], - recipientFrom: aliceAddress - }); - - const transferTx = node.sdk.core - .createTransferAssetTransaction() - .addInputs([...splitGoldInputs.slice(0, 3), silverInput]) - .addOutputs( - { - recipient: aliceAddress, - quantity: 2500, - assetType: silver.assetType, - shardId: 0 - }, - { - recipient: bobAddress, - quantity: 1000, - assetType: gold.assetType, - shardId: 0 - }, - { - recipient: bobAddress, - quantity: 7500, - assetType: silver.assetType, - shardId: 0 - }, - { - recipient: charlieAddress, - quantity: 2000, - assetType: gold.assetType, - shardId: 0 - } - ) - .addOrder({ - order, - spentQuantity: 1000, - inputFromIndices: [0], - inputFeeIndices: [], - outputFromIndices: [], - outputToIndices: [0], - outputOwnedFeeIndices: [], - outputTransferredFeeIndices: [] - }); - await node.signTransactionInput(transferTx, 0); - await node.signTransactionInput(transferTx, 1); - await node.signTransactionInput(transferTx, 2); - await node.signTransactionInput(transferTx, 3); - - const hash = await node.sendAssetTransaction(transferTx); - expect(await node.sdk.rpc.chain.containsTransaction(hash)).be - .true; - expect(await node.sdk.rpc.chain.getTransaction(hash)).not.null; - }); - - it("Correct order, wrong transfer - Output(from) is empty", async function() { - const goldInput = gold.createTransferInput(); - const silverInput = silver.createTransferInput(); - - const expiration = Math.round(Date.now() / 1000) + 120; - const order = node.sdk.core.createOrder({ - assetTypeFrom: gold.assetType, - assetTypeTo: silver.assetType, - shardIdFrom: 0, - shardIdTo: 0, - assetQuantityFrom: 10000, - assetQuantityTo: 1000, - expiration, - originOutputs: [goldInput.prevOut], - recipientFrom: aliceAddress - }); - const transferTx = node.sdk.core - .createTransferAssetTransaction() - .addInputs(goldInput, silverInput) - .addOutputs( - { - recipient: aliceAddress, - quantity: 10000, - assetType: gold.assetType, - shardId: 0 - }, - { - recipient: bobAddress, - quantity: 10000, - assetType: silver.assetType, - shardId: 0 - } - ) - .addOrder({ - order, - spentQuantity: 0, - inputFromIndices: [0], - inputFeeIndices: [], - outputFromIndices: [0], - outputToIndices: [], - outputOwnedFeeIndices: [], - outputTransferredFeeIndices: [] - }); - await node.signTransactionInput(transferTx, 0); - await node.signTransactionInput(transferTx, 1); - - const signed = transferTx.sign({ - secret: faucetSecret, - fee: 10, - seq: await node.sdk.rpc.chain.getSeq(faucetAddress) - }); - - try { - await node.sdk.rpc.chain.sendSignedTransaction(signed); - expect.fail(); - } catch (e) { - expect(e).is.similarTo( - ERROR.INCONSISTENT_TRANSACTION_IN_OUT_WITH_ORDERS - ); - } - }); - - it("Correct order, wrong transfer - Spend too much", async function() { - const goldInput = gold.createTransferInput(); - const silverInput = silver.createTransferInput(); - - const expiration = Math.round(Date.now() / 1000) + 120; - const order = node.sdk.core.createOrder({ - assetTypeFrom: gold.assetType, - assetTypeTo: silver.assetType, - shardIdFrom: 0, - shardIdTo: 0, - assetQuantityFrom: 100, - assetQuantityTo: 1000, - expiration, - originOutputs: [goldInput.prevOut], - recipientFrom: aliceAddress - }); - const transferTx = node.sdk.core - .createTransferAssetTransaction() - .addInputs(goldInput, silverInput) - .addOutputs( - { - recipient: aliceAddress, - quantity: 9800, - assetType: gold.assetType, - shardId: 0 - }, - { - recipient: aliceAddress, - quantity: 2000, - assetType: silver.assetType, - shardId: 0 - }, - { - recipient: bobAddress, - quantity: 200, - assetType: gold.assetType, - shardId: 0 - }, - { - recipient: bobAddress, - quantity: 8000, - assetType: silver.assetType, - shardId: 0 - } - ) - .addOrder({ - order, - spentQuantity: 200, - inputFromIndices: [0], - inputFeeIndices: [], - outputFromIndices: [0], - outputToIndices: [1], - outputOwnedFeeIndices: [], - outputTransferredFeeIndices: [] - }); - await node.signTransactionInput(transferTx, 0); - await node.signTransactionInput(transferTx, 1); - - const signed = transferTx.sign({ - secret: faucetSecret, - fee: 10, - seq: await node.sdk.rpc.chain.getSeq(faucetAddress) - }); - - try { - await node.sdk.rpc.chain.sendSignedTransaction(signed); - expect.fail(); - } catch (e) { - expect(e).is.similarTo(ERROR.INVALID_SPENT_QUANTITY); - } - }); - - it("Correct order, wrong transfer - Ratio is wrong", async function() { - const goldInput = gold.createTransferInput(); - const silverInput = silver.createTransferInput(); - - const expiration = Math.round(Date.now() / 1000) + 120; - const order = node.sdk.core.createOrder({ - assetTypeFrom: gold.assetType, - assetTypeTo: silver.assetType, - shardIdFrom: 0, - shardIdTo: 0, - assetQuantityFrom: 100, - assetQuantityTo: 1000, - expiration, - originOutputs: [goldInput.prevOut], - recipientFrom: aliceAddress - }); - const transferTx = node.sdk.core - .createTransferAssetTransaction() - .addInputs(goldInput, silverInput) - .addOutputs( - { - recipient: aliceAddress, - quantity: 9900, - assetType: gold.assetType, - shardId: 0 - }, - { - recipient: aliceAddress, - quantity: 1000 - 10, - assetType: silver.assetType, - shardId: 0 - }, - { - recipient: bobAddress, - quantity: 100, - assetType: gold.assetType, - shardId: 0 - }, - { - recipient: bobAddress, - quantity: 9000 + 10, - assetType: silver.assetType, - shardId: 0 - } - ) - .addOrder({ - order, - spentQuantity: 100, - inputFromIndices: [0], - inputFeeIndices: [], - outputFromIndices: [0], - outputToIndices: [1], - outputOwnedFeeIndices: [], - outputTransferredFeeIndices: [] - }); - await node.signTransactionInput(transferTx, 0); - await node.signTransactionInput(transferTx, 1); - - const signed = transferTx.sign({ - secret: faucetSecret, - fee: 10, - seq: await node.sdk.rpc.chain.getSeq(faucetAddress) - }); - - try { - await node.sdk.rpc.chain.sendSignedTransaction(signed); - expect.fail(); - } catch (e) { - expect(e).is.similarTo( - ERROR.INCONSISTENT_TRANSACTION_IN_OUT_WITH_ORDERS - ); - } - }); - - it("Correct order, wrong transfer - Lock script hash of maker is wrong", async function() { - const goldInput = gold.createTransferInput(); - const silverInput = silver.createTransferInput(); - - const expiration = Math.round(Date.now() / 1000) + 120; - const order = node.sdk.core.createOrder({ - assetTypeFrom: gold.assetType, - assetTypeTo: silver.assetType, - shardIdFrom: 0, - shardIdTo: 0, - assetQuantityFrom: 100, - assetQuantityTo: 1000, - expiration, - originOutputs: [goldInput.prevOut], - recipientFrom: aliceAddress - }); - - const transferTx = node.sdk.core - .createTransferAssetTransaction() - .addInputs(goldInput, silverInput) - .addOutputs( - { - recipient: aliceAddress, - quantity: 9900, - assetType: gold.assetType, - shardId: 0 - }, - { - recipient: aliceAddress, - quantity: 1000, - assetType: silver.assetType, - shardId: 0 - }, - { - recipient: bobAddress, - quantity: 100, - assetType: gold.assetType, - shardId: 0 - }, - { - recipient: bobAddress, - quantity: 9000, - assetType: silver.assetType, - shardId: 0 - } - ) - .addOrder({ - order, - spentQuantity: 100, - inputFromIndices: [0], - inputFeeIndices: [], - outputFromIndices: [0], - outputToIndices: [1], - outputOwnedFeeIndices: [], - outputTransferredFeeIndices: [] - }); - - (transferTx.orders()[0].order - .lockScriptHashFrom as any) = new H160( - "0000000000000000000000000000000000000000" - ); - - await node.signTransactionInput(transferTx, 0); - await node.signTransactionInput(transferTx, 1); - - const signed = transferTx.sign({ - secret: faucetSecret, - fee: 10, - seq: await node.sdk.rpc.chain.getSeq(faucetAddress) - }); - - try { - await node.sdk.rpc.chain.sendSignedTransaction(signed); - expect.fail(); - } catch (e) { - expect(e).is.similarTo( - ERROR.INVALID_ORDER_LOCK_SCRIPT_HASH - ); - } - }); - - it("Correct order, wrong transfer - Parameters of maker are wrong", async function() { - const goldInput = gold.createTransferInput(); - const silverInput = silver.createTransferInput(); - - const expiration = Math.round(Date.now() / 1000) + 120; - const order = node.sdk.core.createOrder({ - assetTypeFrom: gold.assetType, - assetTypeTo: silver.assetType, - shardIdFrom: 0, - shardIdTo: 0, - assetQuantityFrom: 100, - assetQuantityTo: 1000, - expiration, - originOutputs: [goldInput.prevOut], - recipientFrom: aliceAddress - }); - const transferTx = node.sdk.core - .createTransferAssetTransaction() - .addInputs(goldInput, silverInput) - .addOutputs( - { - recipient: aliceAddress, - quantity: 9900, - assetType: gold.assetType, - shardId: 0 - }, - { - recipient: aliceAddress, - quantity: 1000, - assetType: silver.assetType, - shardId: 0 - }, - { - recipient: bobAddress, - quantity: 100, - assetType: gold.assetType, - shardId: 0 - }, - { - recipient: bobAddress, - quantity: 9000, - assetType: silver.assetType, - shardId: 0 - } - ) - .addOrder({ - order, - spentQuantity: 100, - inputFromIndices: [0], - inputFeeIndices: [], - outputFromIndices: [0], - outputToIndices: [1], - outputOwnedFeeIndices: [], - outputTransferredFeeIndices: [] - }); - - (transferTx.orders()[0].order.parametersFrom as any) = []; - - await node.signTransactionInput(transferTx, 0); - await node.signTransactionInput(transferTx, 1); - - const signed = transferTx.sign({ - secret: faucetSecret, - fee: 10, - seq: await node.sdk.rpc.chain.getSeq(faucetAddress) - }); - - try { - await node.sdk.rpc.chain.sendSignedTransaction(signed); - expect.fail(); - } catch (e) { - expect(e).is.similarTo(ERROR.INVALID_ORDER_PARAMETERS); - } - }); - - it("Correct order, Correct transfer - many outputs (from)", async function() { - const goldInput = gold.createTransferInput(); - const silverInput = silver.createTransferInput(); - - const expiration = Math.round(Date.now() / 1000) + 120; - const order = node.sdk.core.createOrder({ - assetTypeFrom: gold.assetType, - assetTypeTo: silver.assetType, - shardIdFrom: 0, - shardIdTo: 0, - assetQuantityFrom: 100, - assetQuantityTo: 1000, - expiration, - originOutputs: [goldInput.prevOut], - recipientFrom: aliceAddress - }); - const transferTx = node.sdk.core - .createTransferAssetTransaction() - .addInputs(goldInput, silverInput) - .addOutputs( - { - recipient: aliceAddress, - quantity: 9900 - 100, - assetType: gold.assetType, - shardId: 0 - }, - { - recipient: aliceAddress, - quantity: 100, - assetType: gold.assetType, - shardId: 0 - }, - { - recipient: aliceAddress, - quantity: 1000, - assetType: silver.assetType, - shardId: 0 - }, - { - recipient: bobAddress, - quantity: 100, - assetType: gold.assetType, - shardId: 0 - }, - { - recipient: bobAddress, - quantity: 9000, - assetType: silver.assetType, - shardId: 0 - } - ) - .addOrder({ - order, - spentQuantity: 100, - inputFromIndices: [0], - inputFeeIndices: [], - outputFromIndices: [0, 1], - outputToIndices: [2], - outputOwnedFeeIndices: [], - outputTransferredFeeIndices: [] - }); - await node.signTransactionInput(transferTx, 0); - await node.signTransactionInput(transferTx, 1); - - const hash = await node.sendAssetTransaction(transferTx); - expect(await node.sdk.rpc.chain.containsTransaction(hash)).be - .true; - expect(await node.sdk.rpc.chain.getTransaction(hash)).not.null; - }); - - it("Correct order, Correct transfer - many outputs (to)", async function() { - const goldInput = gold.createTransferInput(); - const silverInput = silver.createTransferInput(); - - const expiration = Math.round(Date.now() / 1000) + 120; - const order = node.sdk.core.createOrder({ - assetTypeFrom: gold.assetType, - assetTypeTo: silver.assetType, - shardIdFrom: 0, - shardIdTo: 0, - assetQuantityFrom: 100, - assetQuantityTo: 1000, - expiration, - originOutputs: [goldInput.prevOut], - recipientFrom: aliceAddress - }); - const transferTx = node.sdk.core - .createTransferAssetTransaction() - .addInputs(goldInput, silverInput) - .addOutputs( - { - recipient: aliceAddress, - quantity: 9900, - assetType: gold.assetType, - shardId: 0 - }, - { - recipient: aliceAddress, - quantity: 1000 - 100, - assetType: silver.assetType, - shardId: 0 - }, - { - recipient: aliceAddress, - quantity: 100, - assetType: silver.assetType, - shardId: 0 - }, - { - recipient: bobAddress, - quantity: 100, - assetType: gold.assetType, - shardId: 0 - }, - { - recipient: bobAddress, - quantity: 9000, - assetType: silver.assetType, - shardId: 0 - } - ) - .addOrder({ - order, - spentQuantity: 100, - inputFromIndices: [0], - inputFeeIndices: [], - outputFromIndices: [0], - outputToIndices: [1, 2], - outputOwnedFeeIndices: [], - outputTransferredFeeIndices: [] - }); - await node.signTransactionInput(transferTx, 0); - await node.signTransactionInput(transferTx, 1); - - const hash = await node.sendAssetTransaction(transferTx); - expect(await node.sdk.rpc.chain.containsTransaction(hash)).be - .true; - expect(await node.sdk.rpc.chain.getTransaction(hash)).not.null; - }); - - it("Correct order, Correct transfer - many outputs (both)", async function() { - const goldInput = gold.createTransferInput(); - const silverInput = silver.createTransferInput(); - - const expiration = Math.round(Date.now() / 1000) + 120; - const order = node.sdk.core.createOrder({ - assetTypeFrom: gold.assetType, - assetTypeTo: silver.assetType, - shardIdFrom: 0, - shardIdTo: 0, - assetQuantityFrom: 100, - assetQuantityTo: 1000, - expiration, - originOutputs: [goldInput.prevOut], - recipientFrom: aliceAddress - }); - const transferTx = node.sdk.core - .createTransferAssetTransaction() - .addInputs(goldInput, silverInput) - .addOutputs( - { - recipient: aliceAddress, - quantity: 9900 - 100, - assetType: gold.assetType, - shardId: 0 - }, - { - recipient: aliceAddress, - quantity: 100, - assetType: gold.assetType, - shardId: 0 - }, - { - recipient: aliceAddress, - quantity: 1000 - 100, - assetType: silver.assetType, - shardId: 0 - }, - { - recipient: aliceAddress, - quantity: 100, - assetType: silver.assetType, - shardId: 0 - }, - { - recipient: bobAddress, - quantity: 100, - assetType: gold.assetType, - shardId: 0 - }, - { - recipient: bobAddress, - quantity: 9000, - assetType: silver.assetType, - shardId: 0 - } - ) - .addOrder({ - order, - spentQuantity: 100, - inputFromIndices: [0], - inputFeeIndices: [], - outputFromIndices: [0, 1], - outputToIndices: [2, 3], - outputOwnedFeeIndices: [], - outputTransferredFeeIndices: [] - }); - await node.signTransactionInput(transferTx, 0); - await node.signTransactionInput(transferTx, 1); - - const hash = await node.sendAssetTransaction(transferTx); - expect(await node.sdk.rpc.chain.containsTransaction(hash)).be - .true; - expect(await node.sdk.rpc.chain.getTransaction(hash)).not.null; - }); - - it("Wrong order - originOutputs are wrong (empty)", async function() { - const goldInput = gold.createTransferInput(); - const silverInput = silver.createTransferInput(); - - const expiration = Math.round(Date.now() / 1000) + 120; - const order = node.sdk.core.createOrder({ - assetTypeFrom: gold.assetType, - assetTypeTo: silver.assetType, - shardIdFrom: 0, - shardIdTo: 0, - assetQuantityFrom: 100, - assetQuantityTo: 1000, - expiration, - originOutputs: [goldInput.prevOut], - recipientFrom: aliceAddress - }); - (order.originOutputs as any) = []; - - const transferTx = node.sdk.core - .createTransferAssetTransaction() - .addInputs(goldInput, silverInput) - .addOutputs( - { - recipient: aliceAddress, - quantity: 9900, - assetType: gold.assetType, - shardId: 0 - }, - { - recipient: aliceAddress, - quantity: 1000, - assetType: silver.assetType, - shardId: 0 - }, - { - recipient: bobAddress, - quantity: 100, - assetType: gold.assetType, - shardId: 0 - }, - { - recipient: bobAddress, - quantity: 9000, - assetType: silver.assetType, - shardId: 0 - } - ) - .addOrder({ - order, - spentQuantity: 100, - inputFromIndices: [0], - inputFeeIndices: [], - outputFromIndices: [0], - outputToIndices: [1], - outputOwnedFeeIndices: [], - outputTransferredFeeIndices: [] - }); - await node.signTransactionInput(transferTx, 0); - await node.signTransactionInput(transferTx, 1); - - const signed = transferTx.sign({ - secret: faucetSecret, - fee: 10, - seq: await node.sdk.rpc.chain.getSeq(faucetAddress) - }); - - try { - await node.sdk.rpc.chain.sendSignedTransaction(signed); - expect.fail(); - } catch (e) { - expect(e).is.similarTo(ERROR.INVALID_ORIGIN_OUTPUTS); - } - }); - - it("Wrong order - originOutputs are wrong (prevOut does not match)", async function() { - const goldInput = gold.createTransferInput(); - const silverInput = silver.createTransferInput(); - - const expiration = Math.round(Date.now() / 1000) + 120; - const order = node.sdk.core.createOrder({ - assetTypeFrom: gold.assetType, - assetTypeTo: silver.assetType, - shardIdFrom: 0, - shardIdTo: 0, - assetQuantityFrom: 100, - assetQuantityTo: 1000, - expiration, - originOutputs: [silverInput.prevOut], - recipientFrom: aliceAddress - }); - - const transferTx = node.sdk.core - .createTransferAssetTransaction() - .addInputs(goldInput, silverInput) - .addOutputs( - { - recipient: aliceAddress, - quantity: 9900, - assetType: gold.assetType, - shardId: 0 - }, - { - recipient: aliceAddress, - quantity: 1000, - assetType: silver.assetType, - shardId: 0 - }, - { - recipient: bobAddress, - quantity: 100, - assetType: gold.assetType, - shardId: 0 - }, - { - recipient: bobAddress, - quantity: 9000, - assetType: silver.assetType, - shardId: 0 - } - ) - .addOrder({ - order, - spentQuantity: 100, - inputFromIndices: [0], - inputFeeIndices: [], - outputFromIndices: [0], - outputToIndices: [1], - outputOwnedFeeIndices: [], - outputTransferredFeeIndices: [] - }); - await node.signTransactionInput(transferTx, 0); - await node.signTransactionInput(transferTx, 1); - - const signed = transferTx.sign({ - secret: faucetSecret, - fee: 10, - seq: await node.sdk.rpc.chain.getSeq(faucetAddress) - }); - - try { - await node.sdk.rpc.chain.sendSignedTransaction(signed); - expect.fail(); - } catch (e) { - expect(e).is.similarTo(ERROR.INVALID_ORIGIN_OUTPUTS); - } - }); - - it("Wrong order - originOutputs are wrong (Quantity is not enough)", async function() { - // Split minted gold asset to 10 assets - const splitTx = node.sdk.core - .createTransferAssetTransaction() - .addInputs(gold) - .addOutputs( - _.times(10, () => ({ - recipient: aliceAddress, - quantity: 1000, - assetType: gold.assetType, - shardId: 0 - })) - ); - await node.signTransactionInput(splitTx, 0); - - const splitHash = await node.sendAssetTransaction(splitTx); - expect(await node.sdk.rpc.chain.containsTransaction(splitHash)) - .be.true; - expect(await node.sdk.rpc.chain.getTransaction(splitHash)).not - .null; - - const splitGolds = splitTx.getTransferredAssets(); - const splitGoldInputs = splitGolds.map(g => - g.createTransferInput() - ); - const silverInput = silver.createTransferInput(); - - const expiration = Math.round(Date.now() / 1000) + 120; - const order = node.sdk.core.createOrder({ - assetTypeFrom: gold.assetType, - assetTypeTo: silver.assetType, - shardIdFrom: 0, - shardIdTo: 0, - assetQuantityFrom: 3000, - assetQuantityTo: 7500, - expiration, - originOutputs: [splitGoldInputs[0].prevOut], - recipientFrom: aliceAddress - }); - - const transferTx = node.sdk.core - .createTransferAssetTransaction() - .addInputs([...splitGoldInputs.slice(0, 3), silverInput]) - .addOutputs( - { - recipient: aliceAddress, - quantity: 7500, - assetType: silver.assetType, - shardId: 0 - }, - { - recipient: bobAddress, - quantity: 3000, - assetType: gold.assetType, - shardId: 0 - }, - { - recipient: bobAddress, - quantity: 2500, - assetType: silver.assetType, - shardId: 0 - } - ) - .addOrder({ - order, - spentQuantity: 3000, - inputFromIndices: [0, 1, 2], - inputFeeIndices: [], - outputFromIndices: [], - outputToIndices: [0], - outputOwnedFeeIndices: [], - outputTransferredFeeIndices: [] - }); - await node.signTransactionInput(transferTx, 1); - - await node.sendAssetTransactionExpectedToFail(transferTx); - }).timeout(10_000); - - it("Wrong order - originOutputs are wrong (few outputs)", async function() { - // Split minted gold asset to 10 assets - const splitTx = node.sdk.core - .createTransferAssetTransaction() - .addInputs(gold) - .addOutputs( - _.times(10, () => ({ - recipient: aliceAddress, - quantity: 1000, - assetType: gold.assetType, - shardId: 0 - })) - ); - await node.signTransactionInput(splitTx, 0); - - const splitHash = await node.sendAssetTransaction(splitTx); - expect(await node.sdk.rpc.chain.containsTransaction(splitHash)) - .be.true; - expect(await node.sdk.rpc.chain.getTransaction(splitHash)).not - .null; - - const splitGolds = splitTx.getTransferredAssets(); - const splitGoldInputs = splitGolds.map(g => - g.createTransferInput() - ); - const silverInput = silver.createTransferInput(); - - const expiration = Math.round(Date.now() / 1000) + 120; - const order = node.sdk.core.createOrder({ - assetTypeFrom: gold.assetType, - assetTypeTo: silver.assetType, - shardIdFrom: 0, - shardIdTo: 0, - assetQuantityFrom: 100, - assetQuantityTo: 1000, - expiration, - originOutputs: splitGoldInputs - .slice(0, 9) - .map(input => input.prevOut), - recipientFrom: aliceAddress - }); - - const transferTx = node.sdk.core - .createTransferAssetTransaction() - .addInputs(splitGoldInputs) - .addInputs(silverInput) - .addOutputs( - { - recipient: aliceAddress, - quantity: 9900, - assetType: gold.assetType, - shardId: 0 - }, - { - recipient: aliceAddress, - quantity: 1000, - assetType: silver.assetType, - shardId: 0 - }, - { - recipient: bobAddress, - quantity: 100, - assetType: gold.assetType, - shardId: 0 - }, - { - recipient: bobAddress, - quantity: 9000, - assetType: silver.assetType, - shardId: 0 - } - ) - .addOrder({ - order, - spentQuantity: 100, - inputFromIndices: _.range(10), - inputFeeIndices: [], - outputFromIndices: [0], - outputToIndices: [1], - outputOwnedFeeIndices: [], - outputTransferredFeeIndices: [] - }); - await Promise.all( - _.range((transferTx as any)._transaction.inputs.length).map( - i => node.signTransactionInput(transferTx, i) - ) - ); - - await node.sendAssetTransactionExpectedToFail(transferTx); - }).timeout(10_000); - - it("Wrong order - originOutputs are wrong (many outputs)", async function() { - // Split minted gold asset to 10 assets - const splitTx = node.sdk.core - .createTransferAssetTransaction() - .addInputs(gold) - .addOutputs( - _.times(10, () => ({ - recipient: aliceAddress, - quantity: 1000, - assetType: gold.assetType, - shardId: 0 - })) - ); - await node.signTransactionInput(splitTx, 0); - - const splitHash = await node.sendAssetTransaction(splitTx); - expect(await node.sdk.rpc.chain.containsTransaction(splitHash)) - .be.true; - expect(await node.sdk.rpc.chain.getTransaction(splitHash)).not - .null; - - const splitGolds = splitTx.getTransferredAssets(); - const splitGoldInputs = splitGolds.map(g => - g.createTransferInput() - ); - const silverInput = silver.createTransferInput(); - - const expiration = Math.round(Date.now() / 1000) + 120; - const order = node.sdk.core.createOrder({ - assetTypeFrom: gold.assetType, - assetTypeTo: silver.assetType, - shardIdFrom: 0, - shardIdTo: 0, - assetQuantityFrom: 100, - assetQuantityTo: 1000, - expiration, - originOutputs: splitGoldInputs.map(input => input.prevOut), - recipientFrom: aliceAddress - }); - - const transferTx = node.sdk.core - .createTransferAssetTransaction() - .addInputs(splitGoldInputs.slice(0, 9)) - .addInputs(silverInput) - .addOutputs( - { - recipient: aliceAddress, - quantity: 8900, - assetType: gold.assetType, - shardId: 0 - }, - { - recipient: aliceAddress, - quantity: 1000, - assetType: silver.assetType, - shardId: 0 - }, - { - recipient: bobAddress, - quantity: 100, - assetType: gold.assetType, - shardId: 0 - }, - { - recipient: bobAddress, - quantity: 9000, - assetType: silver.assetType, - shardId: 0 - } - ) - .addOrder({ - order, - spentQuantity: 100, - inputFromIndices: _.range(9), - inputFeeIndices: [], - outputFromIndices: [0], - outputToIndices: [1], - outputOwnedFeeIndices: [], - outputTransferredFeeIndices: [] - }); - await Promise.all( - _.range((transferTx as any)._transaction.inputs.length).map( - i => node.signTransactionInput(transferTx, i) - ) - ); - - await node.sendAssetTransactionExpectedToFail(transferTx); - }).timeout(10_000); - - it("Wrong order - Ratio is wrong (from is zero)", async function() { - const goldInput = gold.createTransferInput(); - const silverInput = silver.createTransferInput(); - - const expiration = Math.round(Date.now() / 1000) + 120; - const order = node.sdk.core.createOrder({ - assetTypeFrom: gold.assetType, - assetTypeTo: silver.assetType, - shardIdFrom: 0, - shardIdTo: 0, - assetQuantityFrom: 100, - assetQuantityTo: 1000, - expiration, - originOutputs: [goldInput.prevOut], - recipientFrom: aliceAddress - }); - (order.assetQuantityFrom as any) = new U64(0); - - const transferTx = node.sdk.core - .createTransferAssetTransaction() - .addInputs(goldInput, silverInput) - .addOutputs( - { - recipient: aliceAddress, - quantity: 9900, - assetType: gold.assetType, - shardId: 0 - }, - { - recipient: aliceAddress, - quantity: 1000, - assetType: silver.assetType, - shardId: 0 - }, - { - recipient: bobAddress, - quantity: 100, - assetType: gold.assetType, - shardId: 0 - }, - { - recipient: bobAddress, - quantity: 9000, - assetType: silver.assetType, - shardId: 0 - } - ) - .addOrder({ - order, - spentQuantity: 100, - inputFromIndices: [0], - inputFeeIndices: [], - outputFromIndices: [0], - outputToIndices: [1], - outputOwnedFeeIndices: [], - outputTransferredFeeIndices: [] - }); - await node.signTransactionInput(transferTx, 0); - await node.signTransactionInput(transferTx, 1); - - const signed = transferTx.sign({ - secret: faucetSecret, - fee: 10, - seq: await node.sdk.rpc.chain.getSeq(faucetAddress) - }); - - try { - await node.sdk.rpc.chain.sendSignedTransaction(signed); - expect.fail(); - } catch (e) { - expect(e).is.similarTo( - ERROR.INVALID_ORDER_ASSET_QUANTITIES - ); - } - }); - - it("Wrong order - Ratio is wrong (to is zero)", async function() { - const goldInput = gold.createTransferInput(); - const silverInput = silver.createTransferInput(); - - const expiration = Math.round(Date.now() / 1000) + 120; - const order = node.sdk.core.createOrder({ - assetTypeFrom: gold.assetType, - assetTypeTo: silver.assetType, - shardIdFrom: 0, - shardIdTo: 0, - assetQuantityFrom: 100, - assetQuantityTo: 1000, - expiration, - originOutputs: [goldInput.prevOut], - recipientFrom: aliceAddress - }); - (order.assetQuantityTo as any) = new U64(0); - - const transferTx = node.sdk.core - .createTransferAssetTransaction() - .addInputs(goldInput, silverInput) - .addOutputs( - { - recipient: aliceAddress, - quantity: 9900, - assetType: gold.assetType, - shardId: 0 - }, - { - recipient: aliceAddress, - quantity: 1000, - assetType: silver.assetType, - shardId: 0 - }, - { - recipient: bobAddress, - quantity: 100, - assetType: gold.assetType, - shardId: 0 - }, - { - recipient: bobAddress, - quantity: 9000, - assetType: silver.assetType, - shardId: 0 - } - ) - .addOrder({ - order, - spentQuantity: 100, - inputFromIndices: [0], - inputFeeIndices: [], - outputFromIndices: [0], - outputToIndices: [1], - outputOwnedFeeIndices: [], - outputTransferredFeeIndices: [] - }); - await node.signTransactionInput(transferTx, 0); - await node.signTransactionInput(transferTx, 1); - - const signed = transferTx.sign({ - secret: faucetSecret, - fee: 10, - seq: await node.sdk.rpc.chain.getSeq(faucetAddress) - }); - - try { - await node.sdk.rpc.chain.sendSignedTransaction(signed); - expect.fail(); - } catch (e) { - expect(e).is.similarTo( - ERROR.INVALID_ORDER_ASSET_QUANTITIES - ); - } - }); - - it("Wrong order - Expiration is old", async function() { - const goldInput = gold.createTransferInput(); - const silverInput = silver.createTransferInput(); - - const expiration = 0; - const order = node.sdk.core.createOrder({ - assetTypeFrom: gold.assetType, - assetTypeTo: silver.assetType, - shardIdFrom: 0, - shardIdTo: 0, - assetQuantityFrom: 100, - assetQuantityTo: 1000, - expiration, - originOutputs: [goldInput.prevOut], - recipientFrom: aliceAddress - }); - const transferTx = node.sdk.core - .createTransferAssetTransaction() - .addInputs(goldInput, silverInput) - .addOutputs( - { - recipient: aliceAddress, - quantity: 9900, - assetType: gold.assetType, - shardId: 0 - }, - { - recipient: aliceAddress, - quantity: 1000, - assetType: silver.assetType, - shardId: 0 - }, - { - recipient: bobAddress, - quantity: 100, - assetType: gold.assetType, - shardId: 0 - }, - { - recipient: bobAddress, - quantity: 9000, - assetType: silver.assetType, - shardId: 0 - } - ) - .addOrder({ - order, - spentQuantity: 100, - inputFromIndices: [0], - inputFeeIndices: [], - outputFromIndices: [0], - outputToIndices: [1], - outputOwnedFeeIndices: [], - outputTransferredFeeIndices: [] - }); - await node.signTransactionInput(transferTx, 0); - await node.signTransactionInput(transferTx, 1); - - const signed = transferTx.sign({ - secret: faucetSecret, - fee: 10, - seq: await node.sdk.rpc.chain.getSeq(faucetAddress) - }); - - try { - await node.sdk.rpc.chain.sendSignedTransaction(signed); - expect.fail(); - } catch (e) { - expect(e).is.similarTo(ERROR.ORDER_EXPIRED); - } - }); - - it("Successful partial fills", async function() { - const goldInput = gold.createTransferInput(); - const silverInput = silver.createTransferInput(); - - const expiration = Math.round(Date.now() / 1000) + 120; - const order = node.sdk.core.createOrder({ - assetTypeFrom: gold.assetType, - assetTypeTo: silver.assetType, - shardIdFrom: 0, - shardIdTo: 0, - assetQuantityFrom: 100, - assetQuantityTo: 1000, - expiration, - originOutputs: [goldInput.prevOut], - recipientFrom: aliceAddress - }); - - const transferTx1 = node.sdk.core - .createTransferAssetTransaction() - .addInputs(goldInput, silverInput) - .addOutputs( - { - recipient: aliceAddress, - quantity: 9950, - assetType: gold.assetType, - shardId: 0 - }, - { - recipient: aliceAddress, - quantity: 500, - assetType: silver.assetType, - shardId: 0 - }, - { - recipient: bobAddress, - quantity: 50, - assetType: gold.assetType, - shardId: 0 - }, - { - recipient: bobAddress, - quantity: 9500, - assetType: silver.assetType, - shardId: 0 - } - ) - .addOrder({ - order, - spentQuantity: 50, - inputFromIndices: [0], - inputFeeIndices: [], - outputFromIndices: [0], - outputToIndices: [1], - outputOwnedFeeIndices: [], - outputTransferredFeeIndices: [] - }); - await node.signTransactionInput(transferTx1, 0); - await node.signTransactionInput(transferTx1, 1); - - const hash1 = await node.sendAssetTransaction(transferTx1); - expect(await node.sdk.rpc.chain.containsTransaction(hash1)).be - .true; - expect(await node.sdk.rpc.chain.getTransaction(hash1)).not.null; - - const orderConsumed = order.consume(50); - const transferTx2 = node.sdk.core - .createTransferAssetTransaction() - .addInputs( - transferTx1.getTransferredAsset(0), - transferTx1.getTransferredAsset(3) - ) - .addOutputs( - { - recipient: aliceAddress, - quantity: 9900, - assetType: gold.assetType, - shardId: 0 - }, - { - recipient: aliceAddress, - quantity: 500, - assetType: silver.assetType, - shardId: 0 - }, - { - recipient: bobAddress, - quantity: 50, - assetType: gold.assetType, - shardId: 0 - }, - { - recipient: bobAddress, - quantity: 9000, - assetType: silver.assetType, - shardId: 0 - } - ) - .addOrder({ - order: orderConsumed, - spentQuantity: 50, - inputFromIndices: [0], - inputFeeIndices: [], - outputFromIndices: [0], - outputToIndices: [1], - outputOwnedFeeIndices: [], - outputTransferredFeeIndices: [] - }); - // Sign on input 0 is not needed - await node.signTransactionInput(transferTx2, 1); - - const hash2 = await node.sendAssetTransaction(transferTx2); - expect(await node.sdk.rpc.chain.containsTransaction(hash2)).be - .true; - expect(await node.sdk.rpc.chain.getTransaction(hash2)).not.null; - }).timeout(10_000); - - it("Successful mutual partial fills", async function() { - const goldInput = gold.createTransferInput(); - const silverInput = silver.createTransferInput(); - - const expiration = Math.round(Date.now() / 1000) + 120; - const aliceOrder = node.sdk.core.createOrder({ - assetTypeFrom: gold.assetType, - assetTypeTo: silver.assetType, - shardIdFrom: 0, - shardIdTo: 0, - assetQuantityFrom: 100, - assetQuantityTo: 1000, - expiration, - originOutputs: [goldInput.prevOut], - recipientFrom: aliceAddress - }); - const bobOrder = node.sdk.core.createOrder({ - assetTypeFrom: silver.assetType, - assetTypeTo: gold.assetType, - shardIdFrom: 0, - shardIdTo: 0, - assetQuantityFrom: 1000, - assetQuantityTo: 50, - expiration, - originOutputs: [silverInput.prevOut], - recipientFrom: bobAddress - }); - - const transferTx1 = node.sdk.core - .createTransferAssetTransaction() - .addInputs(goldInput, silverInput) - .addOutputs( - { - recipient: aliceAddress, - quantity: 9990, - assetType: gold.assetType, - shardId: 0 - }, - { - recipient: aliceAddress, - quantity: 100, - assetType: silver.assetType, - shardId: 0 - }, - { - recipient: bobAddress, - quantity: 10, - assetType: gold.assetType, - shardId: 0 - }, - { - recipient: bobAddress, - quantity: 9900, - assetType: silver.assetType, - shardId: 0 - } - ) - .addOrder({ - order: aliceOrder, - spentQuantity: 10, - inputFromIndices: [0], - inputFeeIndices: [], - outputFromIndices: [0], - outputToIndices: [1], - outputOwnedFeeIndices: [], - outputTransferredFeeIndices: [] - }) - .addOrder({ - order: bobOrder, - spentQuantity: 100, - inputFromIndices: [1], - inputFeeIndices: [], - outputFromIndices: [3], - outputToIndices: [2], - outputOwnedFeeIndices: [], - outputTransferredFeeIndices: [] - }); - await node.signTransactionInput(transferTx1, 0); - await node.signTransactionInput(transferTx1, 1); - - const hash1 = await node.sendAssetTransaction(transferTx1); - expect(await node.sdk.rpc.chain.containsTransaction(hash1)).be - .true; - expect(await node.sdk.rpc.chain.getTransaction(hash1)).not.null; - - const aliceOrderConsumed = aliceOrder.consume(10); - const bobOrderConsumed = bobOrder.consume(100); - const transferTx2 = node.sdk.core - .createTransferAssetTransaction() - .addInputs( - transferTx1.getTransferredAsset(0), - transferTx1.getTransferredAsset(3) - ) - .addOutputs( - { - recipient: aliceAddress, - quantity: 9990 - 50, - assetType: gold.assetType, - shardId: 0 - }, - { - recipient: aliceAddress, - quantity: 500, - assetType: silver.assetType, - shardId: 0 - }, - { - recipient: bobAddress, - quantity: 50, - assetType: gold.assetType, - shardId: 0 - }, - { - recipient: bobAddress, - quantity: 9900 - 500, - assetType: silver.assetType, - shardId: 0 - } - ) - .addOrder({ - order: aliceOrderConsumed, - spentQuantity: 50, - inputFromIndices: [0], - inputFeeIndices: [], - outputFromIndices: [0], - outputToIndices: [1], - outputOwnedFeeIndices: [], - outputTransferredFeeIndices: [] - }) - .addOrder({ - order: bobOrderConsumed, - spentQuantity: 500, - inputFromIndices: [1], - inputFeeIndices: [], - outputFromIndices: [3], - outputToIndices: [2], - outputOwnedFeeIndices: [], - outputTransferredFeeIndices: [] - }); - // Sign on both inputs 0, 1 are not needed - - const hash2 = await node.sendAssetTransaction(transferTx2); - expect(await node.sdk.rpc.chain.containsTransaction(hash2)).be - .true; - expect(await node.sdk.rpc.chain.getTransaction(hash2)).not.null; - }).timeout(10_000); - - it("Successful partial cancel", async function() { - const goldInput = gold.createTransferInput(); - const silverInput = silver.createTransferInput(); - - const expiration = Math.round(Date.now() / 1000) + 120; - const order = node.sdk.core.createOrder({ - assetTypeFrom: gold.assetType, - assetTypeTo: silver.assetType, - shardIdFrom: 0, - shardIdTo: 0, - assetQuantityFrom: 100, - assetQuantityTo: 1000, - expiration, - originOutputs: [goldInput.prevOut], - recipientFrom: aliceAddress - }); - const transferTx1 = node.sdk.core - .createTransferAssetTransaction() - .addInputs(goldInput, silverInput) - .addOutputs( - { - recipient: aliceAddress, - quantity: 9950, - assetType: gold.assetType, - shardId: 0 - }, - { - recipient: aliceAddress, - quantity: 500, - assetType: silver.assetType, - shardId: 0 - }, - { - recipient: bobAddress, - quantity: 50, - assetType: gold.assetType, - shardId: 0 - }, - { - recipient: bobAddress, - quantity: 9500, - assetType: silver.assetType, - shardId: 0 - } - ) - .addOrder({ - order, - spentQuantity: 50, - inputFromIndices: [0], - inputFeeIndices: [], - outputFromIndices: [0], - outputToIndices: [1], - outputOwnedFeeIndices: [], - outputTransferredFeeIndices: [] - }); - await node.signTransactionInput(transferTx1, 0); - await node.signTransactionInput(transferTx1, 1); - - const hash1 = await node.sendAssetTransaction(transferTx1); - expect(await node.sdk.rpc.chain.containsTransaction(hash1)).be - .true; - expect(await node.sdk.rpc.chain.getTransaction(hash1)).not.null; - - const transferTx2 = node.sdk.core - .createTransferAssetTransaction() - .addInputs( - transferTx1.getTransferredAsset(0), - transferTx1.getTransferredAsset(3) - ) - .addOutputs( - { - recipient: aliceAddress, - quantity: 9500, - assetType: silver.assetType, - shardId: 0 - }, - { - recipient: bobAddress, - quantity: 9950, - assetType: gold.assetType, - shardId: 0 - } - ); - await node.signTransactionInput(transferTx2, 0); - await node.signTransactionInput(transferTx2, 1); - - const hash2 = await node.sendAssetTransaction(transferTx2); - expect(await node.sdk.rpc.chain.containsTransaction(hash2)).be - .true; - expect(await node.sdk.rpc.chain.getTransaction(hash2)).not.null; - }); - }).timeout(10_000); - - describe("Mint three assets ", function() { - let aliceAddress: AssetAddress; - let bobAddress: AssetAddress; - let charlieAddress: AssetAddress; - - let gold: Asset; - let silver: Asset; - let bronze: Asset; - let feeAsset: Asset; - - beforeEach(async function() { - aliceAddress = await node.createP2PKHAddress(); - bobAddress = await node.createP2PKHAddress(); - charlieAddress = await node.createP2PKHAddress(); - const FeeOwnerAddress = await node.createP2PKHAddress(); - gold = await node.mintAsset({ - supply: 10000, - recipient: aliceAddress - }); - silver = await node.mintAsset({ - supply: 10000, - recipient: bobAddress - }); - bronze = await node.mintAsset({ - supply: 10000, - recipient: FeeOwnerAddress - }); - - const bronzeInput = bronze.createTransferInput(); - const transferTx1 = node.sdk.core - .createTransferAssetTransaction() - .addInputs(bronzeInput) - .addOutputs({ - recipient: aliceAddress, - quantity: 10000, - assetType: bronze.assetType, - shardId: 0 - }); - await node.signTransactionInput(transferTx1, 0); - await node.sendAssetTransaction(transferTx1); - feeAsset = transferTx1.getTransferredAsset(0); - }); - - it("Correct order - originOutputs fee is not enough but Ok", async function() { - const goldInput = gold.createTransferInput(); - const silverInput = silver.createTransferInput(); - const feeInput = feeAsset.createTransferInput(); - - // Split minted gold asset to 10 assets - const splitTx = node.sdk.core - .createTransferAssetTransaction() - .addInputs(feeInput) - .addOutputs( - _.times(10, () => ({ - recipient: aliceAddress, - quantity: 1000, - assetType: bronze.assetType, - shardId: 0 - })) - ); - await node.signTransactionInput(splitTx, 0); - - const splitHash = await node.sendAssetTransaction(splitTx); - expect(await node.sdk.rpc.chain.containsTransaction(splitHash)) - .be.true; - expect(await node.sdk.rpc.chain.getTransaction(splitHash)).not - .null; - - const splitFees = splitTx.getTransferredAssets(); - const splitFeeInputs = splitFees.map(g => - g.createTransferInput() - ); - - const expiration = Math.round(Date.now() / 1000) + 120; - const order = node.sdk.core.createOrder({ - assetTypeFrom: gold.assetType, - assetTypeTo: silver.assetType, - assetTypeFee: bronze.assetType, - shardIdFrom: 0, - shardIdTo: 0, - shardIdFee: 0, - assetQuantityFrom: 1000, - assetQuantityTo: 10000, - assetQuantityFee: 2000, - expiration, - originOutputs: [ - goldInput.prevOut, - splitFeeInputs[0].prevOut - ], - recipientFrom: aliceAddress, - recipientFee: charlieAddress - }); - const transferTx = node.sdk.core - .createTransferAssetTransaction() - .addInputs(goldInput, silverInput, splitFeeInputs[0]) - .addOutputs( - { - recipient: aliceAddress, - quantity: 9900, - assetType: gold.assetType, - shardId: 0 - }, - { - recipient: aliceAddress, - quantity: 1000, - assetType: silver.assetType, - shardId: 0 - }, - { - recipient: aliceAddress, - quantity: 800, - assetType: bronze.assetType, - shardId: 0 - }, - { - recipient: bobAddress, - quantity: 100, - assetType: gold.assetType, - shardId: 0 - }, - { - recipient: bobAddress, - quantity: 9000, - assetType: silver.assetType, - shardId: 0 - }, - { - recipient: charlieAddress, - quantity: 200, - assetType: bronze.assetType, - shardId: 0 - } - ) - .addOrder({ - order, - spentQuantity: 100, - inputFromIndices: [0], - inputFeeIndices: [2], - outputFromIndices: [0], - outputToIndices: [1], - outputOwnedFeeIndices: [2], - outputTransferredFeeIndices: [5] - }); - await node.signTransactionInput(transferTx, 0); - await node.signTransactionInput(transferTx, 1); - await node.signTransactionInput(transferTx, 2); - - const hash = await node.sendAssetTransaction(transferTx); - expect(await node.sdk.rpc.chain.containsTransaction(hash)).be - .true; - expect(await node.sdk.rpc.chain.getTransaction(hash)).not.null; - }); - - it("Correct order, correct transfer", async function() { - const goldInput = gold.createTransferInput(); - const silverInput = silver.createTransferInput(); - const feeInput = feeAsset.createTransferInput(); - - const expiration = Math.round(Date.now() / 1000) + 120; - const order = node.sdk.core.createOrder({ - assetTypeFrom: gold.assetType, - assetTypeTo: silver.assetType, - assetTypeFee: bronze.assetType, - shardIdFrom: 0, - shardIdTo: 0, - shardIdFee: 0, - assetQuantityFrom: 100, - assetQuantityTo: 1000, - assetQuantityFee: 200, - expiration, - originOutputs: [goldInput.prevOut, feeInput.prevOut], - recipientFrom: aliceAddress, - recipientFee: charlieAddress - }); - const transferTx = node.sdk.core - .createTransferAssetTransaction() - .addInputs(goldInput, silverInput, feeInput) - .addOutputs( - { - recipient: aliceAddress, - quantity: 9900, - assetType: gold.assetType, - shardId: 0 - }, - { - recipient: aliceAddress, - quantity: 1000, - assetType: silver.assetType, - shardId: 0 - }, - { - recipient: aliceAddress, - quantity: 9800, - assetType: bronze.assetType, - shardId: 0 - }, - { - recipient: bobAddress, - quantity: 100, - assetType: gold.assetType, - shardId: 0 - }, - { - recipient: bobAddress, - quantity: 9000, - assetType: silver.assetType, - shardId: 0 - }, - { - recipient: charlieAddress, - quantity: 200, - assetType: bronze.assetType, - shardId: 0 - } - ) - .addOrder({ - order, - spentQuantity: 100, - inputFromIndices: [0], - inputFeeIndices: [2], - outputFromIndices: [0], - outputToIndices: [1], - outputOwnedFeeIndices: [2], - outputTransferredFeeIndices: [5] - }); - await node.signTransactionInput(transferTx, 0); - await node.signTransactionInput(transferTx, 1); - await node.signTransactionInput(transferTx, 2); - - const hash = await node.sendAssetTransaction(transferTx); - expect(await node.sdk.rpc.chain.containsTransaction(hash)).be - .true; - expect(await node.sdk.rpc.chain.getTransaction(hash)).not.null; - }); - - it("Correct two orders, correct transfer - Ratio is same", async function() { - const goldInput = gold.createTransferInput(); - const silverInput = silver.createTransferInput(); - const feeInput = feeAsset.createTransferInput(); - - const splitTx = node.sdk.core - .createTransferAssetTransaction() - .addInputs(feeInput) - .addOutputs( - { - recipient: aliceAddress, - quantity: 5000, - assetType: bronze.assetType, - shardId: 0 - }, - { - recipient: bobAddress, - quantity: 5000, - assetType: bronze.assetType, - shardId: 0 - } - ); - await node.signTransactionInput(splitTx, 0); - - const splitHash = await node.sendAssetTransaction(splitTx); - expect(await node.sdk.rpc.chain.containsTransaction(splitHash)) - .be.true; - expect(await node.sdk.rpc.chain.getTransaction(splitHash)).not - .null; - - const splitFees = splitTx.getTransferredAssets(); - const aliceFeeInput = splitFees[0].createTransferInput(); - const bobFeeInput = splitFees[1].createTransferInput(); - - const expiration = Math.round(Date.now() / 1000) + 120; - const aliceOrder = node.sdk.core.createOrder({ - assetTypeFrom: gold.assetType, - assetTypeTo: silver.assetType, - assetTypeFee: bronze.assetType, - shardIdFrom: 0, - shardIdTo: 0, - shardIdFee: 0, - assetQuantityFrom: 100, - assetQuantityTo: 1000, - assetQuantityFee: 200, - expiration, - originOutputs: [goldInput.prevOut, aliceFeeInput.prevOut], - recipientFrom: aliceAddress, - recipientFee: charlieAddress - }); - - const bobOrder = node.sdk.core.createOrder({ - assetTypeFrom: silver.assetType, - assetTypeTo: gold.assetType, - assetTypeFee: bronze.assetType, - shardIdFrom: 0, - shardIdTo: 0, - assetQuantityFrom: 1000, - assetQuantityTo: 100, - assetQuantityFee: 2000, - expiration, - originOutputs: [silverInput.prevOut, bobFeeInput.prevOut], - recipientFrom: bobAddress, - recipientFee: charlieAddress - }); - - const transferTx = node.sdk.core - .createTransferAssetTransaction() - .addInputs( - goldInput, - aliceFeeInput, - silverInput, - bobFeeInput - ) - .addOutputs( - { - recipient: aliceAddress, - quantity: 9900, - assetType: gold.assetType, - shardId: 0 - }, - { - recipient: aliceAddress, - quantity: 1000, - assetType: silver.assetType, - shardId: 0 - }, - { - recipient: aliceAddress, - quantity: 5000 - 200, - assetType: bronze.assetType, - shardId: 0 - }, - { - recipient: charlieAddress, - quantity: 200, - assetType: bronze.assetType, - shardId: 0 - }, - { - recipient: bobAddress, - quantity: 100, - assetType: gold.assetType, - shardId: 0 - }, - { - recipient: bobAddress, - quantity: 9000, - assetType: silver.assetType, - shardId: 0 - }, - { - recipient: bobAddress, - quantity: 5000 - 2000, - assetType: bronze.assetType, - shardId: 0 - }, - { - recipient: charlieAddress, - quantity: 2000, - assetType: bronze.assetType, - shardId: 0 - } - ) - .addOrder({ - order: aliceOrder, - spentQuantity: 100, - inputFromIndices: [0], - inputFeeIndices: [1], - outputFromIndices: [0], - outputToIndices: [1], - outputOwnedFeeIndices: [2], - outputTransferredFeeIndices: [3] - }) - .addOrder({ - order: bobOrder, - spentQuantity: 1000, - inputFromIndices: [2], - inputFeeIndices: [3], - outputFromIndices: [5], - outputToIndices: [4], - outputOwnedFeeIndices: [6], - outputTransferredFeeIndices: [7] - }); - await node.signTransactionInput(transferTx, 0); - await node.signTransactionInput(transferTx, 1); - await node.signTransactionInput(transferTx, 2); - await node.signTransactionInput(transferTx, 3); - - const hash = await node.sendAssetTransaction(transferTx); - expect(await node.sdk.rpc.chain.containsTransaction(hash)).be - .true; - expect(await node.sdk.rpc.chain.getTransaction(hash)).not.null; - }); - - it("Correct two orders, correct transfer - Ratio is different, fee Recipient intrecepts leftover", async function() { - const goldInput = gold.createTransferInput(); - const silverInput = silver.createTransferInput(); - const feeInput = feeAsset.createTransferInput(); - - const splitTx = node.sdk.core - .createTransferAssetTransaction() - .addInputs(feeInput) - .addOutputs( - { - recipient: aliceAddress, - quantity: 5000, - assetType: bronze.assetType, - shardId: 0 - }, - { - recipient: bobAddress, - quantity: 5000, - assetType: bronze.assetType, - shardId: 0 - } - ); - await node.signTransactionInput(splitTx, 0); - - const splitHash = await node.sendAssetTransaction(splitTx); - expect(await node.sdk.rpc.chain.containsTransaction(splitHash)) - .be.true; - expect(await node.sdk.rpc.chain.getTransaction(splitHash)).not - .null; - - const splitFees = splitTx.getTransferredAssets(); - const aliceFeeInput = splitFees[0].createTransferInput(); - const bobFeeInput = splitFees[1].createTransferInput(); - - const expiration = Math.round(Date.now() / 1000) + 120; - const aliceOrder = node.sdk.core.createOrder({ - assetTypeFrom: gold.assetType, - assetTypeTo: silver.assetType, - assetTypeFee: bronze.assetType, - shardIdFrom: 0, - shardIdTo: 0, - shardIdFee: 0, - assetQuantityFrom: 100, - assetQuantityTo: 1000, - assetQuantityFee: 200, - expiration, - originOutputs: [goldInput.prevOut, aliceFeeInput.prevOut], - recipientFrom: aliceAddress, - recipientFee: charlieAddress - }); - - const bobOrder = node.sdk.core.createOrder({ - assetTypeFrom: silver.assetType, - assetTypeTo: gold.assetType, - assetTypeFee: bronze.assetType, - shardIdFrom: 0, - shardIdTo: 0, - assetQuantityFrom: 1000, - assetQuantityTo: 50, - assetQuantityFee: 2000, - expiration, - originOutputs: [silverInput.prevOut, bobFeeInput.prevOut], - recipientFrom: bobAddress, - recipientFee: charlieAddress - }); - - const transferTx = node.sdk.core - .createTransferAssetTransaction() - .addInputs( - goldInput, - aliceFeeInput, - silverInput, - bobFeeInput - ) - .addOutputs( - { - recipient: aliceAddress, - quantity: 9900, - assetType: gold.assetType, - shardId: 0 - }, - { - recipient: aliceAddress, - quantity: 1000, - assetType: silver.assetType, - shardId: 0 - }, - { - recipient: aliceAddress, - quantity: 5000 - 200, - assetType: bronze.assetType, - shardId: 0 - }, - { - recipient: charlieAddress, - quantity: 200, - assetType: bronze.assetType, - shardId: 0 - }, - { - recipient: charlieAddress, - quantity: 50, - assetType: gold.assetType, - shardId: 0 - }, - { - recipient: bobAddress, - quantity: 50, - assetType: gold.assetType, - shardId: 0 - }, - { - recipient: bobAddress, - quantity: 9000, - assetType: silver.assetType, - shardId: 0 - }, - { - recipient: bobAddress, - quantity: 5000 - 2000, - assetType: bronze.assetType, - shardId: 0 - }, - { - recipient: charlieAddress, - quantity: 2000, - assetType: bronze.assetType, - shardId: 0 - } - ) - .addOrder({ - order: aliceOrder, - spentQuantity: 100, - inputFromIndices: [0], - inputFeeIndices: [1], - outputFromIndices: [0], - outputToIndices: [1], - outputOwnedFeeIndices: [2], - outputTransferredFeeIndices: [3] - }) - .addOrder({ - order: bobOrder, - spentQuantity: 1000, - inputFromIndices: [2], - inputFeeIndices: [3], - outputFromIndices: [6], - outputToIndices: [5], - outputOwnedFeeIndices: [7], - outputTransferredFeeIndices: [8] - }); - await node.signTransactionInput(transferTx, 0); - await node.signTransactionInput(transferTx, 1); - await node.signTransactionInput(transferTx, 2); - await node.signTransactionInput(transferTx, 3); - - const hash = await node.sendAssetTransaction(transferTx); - expect(await node.sdk.rpc.chain.containsTransaction(hash)).be - .true; - expect(await node.sdk.rpc.chain.getTransaction(hash)).not.null; - }); - - it("Wrong order - feeInput Omitted in OriginOutputs", async function() { - const goldInput = gold.createTransferInput(); - const silverInput = silver.createTransferInput(); - const feeInput = feeAsset.createTransferInput(); - - const expiration = Math.round(Date.now() / 1000) + 120; - const order = node.sdk.core.createOrder({ - assetTypeFrom: gold.assetType, - assetTypeTo: silver.assetType, - assetTypeFee: bronze.assetType, - shardIdFrom: 0, - shardIdTo: 0, - shardIdFee: 0, - assetQuantityFrom: 100, - assetQuantityTo: 1000, - assetQuantityFee: 200, - expiration, - originOutputs: [goldInput.prevOut], - recipientFrom: aliceAddress, - recipientFee: charlieAddress - }); - const transferTx = node.sdk.core - .createTransferAssetTransaction() - .addInputs(goldInput, silverInput, feeInput) - .addOutputs( - { - recipient: aliceAddress, - quantity: 9900, - assetType: gold.assetType, - shardId: 0 - }, - { - recipient: aliceAddress, - quantity: 1000, - assetType: silver.assetType, - shardId: 0 - }, - { - recipient: aliceAddress, - quantity: 9800, - assetType: bronze.assetType, - shardId: 0 - }, - { - recipient: bobAddress, - quantity: 100, - assetType: gold.assetType, - shardId: 0 - }, - { - recipient: bobAddress, - quantity: 9000, - assetType: silver.assetType, - shardId: 0 - }, - { - recipient: charlieAddress, - quantity: 200, - assetType: bronze.assetType, - shardId: 0 - } - ) - .addOrder({ - order, - spentQuantity: 100, - inputFromIndices: [0], - inputFeeIndices: [2], - outputFromIndices: [0], - outputToIndices: [1], - outputOwnedFeeIndices: [2], - outputTransferredFeeIndices: [5] - }); - await node.signTransactionInput(transferTx, 0); - await node.signTransactionInput(transferTx, 1); - await node.signTransactionInput(transferTx, 2); - - await node.sendAssetTransactionExpectedToFail(transferTx); - }); - }); - - describe("Mint five assets", function() { - let addresses: AssetAddress[]; - let assets: Asset[]; - - beforeEach(async function() { - addresses = []; - assets = []; - for (let i = 0; i < 5; i++) { - const address = await node.createP2PKHAddress(); - const asset = await node.mintAsset({ - supply: 10000, - recipient: address - }); - addresses.push(address); - assets.push(asset); - } - }); - - it("Multiple orders", async function() { - const inputs = assets.map(asset => asset.createTransferInput()); - - const transferTx = node.sdk.core - .createTransferAssetTransaction() - .addInputs(inputs) - .addOutputs([ - ..._.range(5).map(i => ({ - recipient: addresses[i], - quantity: 50, - assetType: assets[(i + 1) % 5].assetType, - shardId: 0 - })), - ..._.range(5).map(i => ({ - recipient: addresses[i], - quantity: 9950, - assetType: assets[i].assetType, - shardId: 0 - })) - ]); - - for (let i = 0; i < 5; i++) { - const order = node.sdk.core.createOrder({ - assetTypeFrom: assets[i].assetType, - assetTypeTo: assets[(i + 1) % 5].assetType, - shardIdFrom: 0, - shardIdTo: 0, - assetQuantityFrom: 100, - assetQuantityTo: 100, - expiration: U64.MAX_VALUE, - originOutputs: [inputs[i].prevOut], - recipientFrom: addresses[i] - }); - transferTx.addOrder({ - order, - spentQuantity: 50, - inputFromIndices: [i], - inputFeeIndices: [], - outputFromIndices: [i + 5], - outputToIndices: [i], - outputOwnedFeeIndices: [], - outputTransferredFeeIndices: [] - }); - } - - await Promise.all( - _.range((transferTx as any)._transaction.inputs.length).map( - i => node.signTransactionInput(transferTx, i) - ) - ); - - const hash = await node.sendAssetTransaction(transferTx); - expect(await node.sdk.rpc.chain.containsTransaction(hash)).be - .true; - expect(await node.sdk.rpc.chain.getTransaction(hash)).not.null; - }).timeout(10_000); - }); - }); - - afterEach(function() { - if (this.currentTest!.state === "failed") { - node.keepLogs(); - } - }); - - after(async function() { - await node.clean(); - }); -}); diff --git a/test/src/e2e.long/ordersDisabled.test.ts b/test/src/e2e.long/ordersDisabled.test.ts deleted file mode 100644 index a802e14362..0000000000 --- a/test/src/e2e.long/ordersDisabled.test.ts +++ /dev/null @@ -1,3019 +0,0 @@ -// Copyright 2018-2019 Kodebox, Inc. -// This file is part of CodeChain. -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as -// published by the Free Software Foundation, either version 3 of the -// License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public License -// along with this program. If not, see . - -import { expect } from "chai"; -import { Asset, AssetAddress, H160, U64 } from "codechain-sdk/lib/core/classes"; -import * as _ from "lodash"; -import "mocha"; -import { faucetAddress, faucetSecret } from "../helper/constants"; -import { ERROR } from "../helper/error"; -import CodeChain from "../helper/spawn"; - -describe("order is disabled", function() { - let node: CodeChain; - - before(async function() { - node = new CodeChain(); - await node.start(); - }); - - describe("AssetTransfer with orders", function() { - describe("Mint one asset", function() { - let aliceAddress: AssetAddress; - - let gold: Asset; - - beforeEach(async function() { - aliceAddress = await node.createP2PKHAddress(); - gold = await node.mintAsset({ - supply: 10000, - recipient: aliceAddress - }); - }); - - it("Wrong order - originOutputs are wrong (asset type from/to is same)", async function() { - const splitTx = node.sdk.core - .createTransferAssetTransaction() - .addInputs(gold) - .addOutputs( - _.times(2, () => ({ - recipient: aliceAddress, - quantity: 5000, - assetType: gold.assetType, - shardId: 0 - })) - ); - await node.signTransactionInput(splitTx, 0); - - const splitHash = await node.sendAssetTransaction(splitTx); - expect(await node.sdk.rpc.chain.containsTransaction(splitHash)) - .be.true; - expect(await node.sdk.rpc.chain.getTransaction(splitHash)).not - .null; - - const splitGolds = splitTx.getTransferredAssets(); - const splitGoldInputs = splitGolds.map((g: Asset) => - g.createTransferInput() - ); - - const expiration = Math.round(Date.now() / 1000) + 120; - const order = node.sdk.core.createOrder({ - assetTypeFrom: gold.assetType, - assetTypeTo: H160.zero(), // Fake asset type - shardIdFrom: 0, - shardIdTo: 0, - assetQuantityFrom: 5000, - assetQuantityTo: 5000, - expiration, - originOutputs: [splitGoldInputs[0].prevOut], - recipientFrom: aliceAddress - }); - - (order.assetTypeTo as any) = gold.assetType; - - const transferTx = node.sdk.core - .createTransferAssetTransaction() - .addInputs(splitGoldInputs) - .addOutputs( - { - recipient: aliceAddress, - quantity: 5000, - assetType: gold.assetType, - shardId: 0 - }, - { - recipient: aliceAddress, - quantity: 5000, - assetType: gold.assetType, - shardId: 0 - } - ) - .addOrder({ - order, - spentQuantity: 5000, - inputFromIndices: [0], - inputFeeIndices: [], - outputFromIndices: [0], - outputToIndices: [], - outputOwnedFeeIndices: [], - outputTransferredFeeIndices: [] - }); - await node.signTransactionInput(transferTx, 0); - await node.signTransactionInput(transferTx, 1); - - const signed = transferTx.sign({ - secret: faucetSecret, - fee: 10, - seq: await node.sdk.rpc.chain.getSeq(faucetAddress) - }); - try { - await node.sdk.rpc.chain.sendSignedTransaction(signed); - expect.fail(); - } catch (e) { - expect(e).is.similarTo(ERROR.INVALID_ORDER_ASSET_TYPES); - } - }); - }); - - describe("Mint two assets", function() { - let aliceAddress: AssetAddress; - let bobAddress: AssetAddress; - - let gold: Asset; - let silver: Asset; - - beforeEach(async function() { - aliceAddress = await node.createP2PKHAddress(); - bobAddress = await node.createP2PKHAddress(); - gold = await node.mintAsset({ - supply: 10000, - recipient: aliceAddress - }); - silver = await node.mintAsset({ - supply: 10000, - recipient: bobAddress - }); - }); - - it("Correct order, correct transfer", async function() { - const goldInput = gold.createTransferInput(); - const silverInput = silver.createTransferInput(); - - const expiration = Math.round(Date.now() / 1000) + 120; - const order = node.sdk.core.createOrder({ - assetTypeFrom: gold.assetType, - assetTypeTo: silver.assetType, - shardIdFrom: 0, - shardIdTo: 0, - assetQuantityFrom: 100, - assetQuantityTo: 1000, - expiration, - originOutputs: [goldInput.prevOut], - recipientFrom: aliceAddress - }); - const transferTx = node.sdk.core - .createTransferAssetTransaction() - .addInputs(goldInput, silverInput) - .addOutputs( - { - recipient: aliceAddress, - quantity: 9900, - assetType: gold.assetType, - shardId: 0 - }, - { - recipient: aliceAddress, - quantity: 1000, - assetType: silver.assetType, - shardId: 0 - }, - { - recipient: bobAddress, - quantity: 100, - assetType: gold.assetType, - shardId: 0 - }, - { - recipient: bobAddress, - quantity: 9000, - assetType: silver.assetType, - shardId: 0 - } - ) - .addOrder({ - order, - spentQuantity: 100, - inputFromIndices: [0], - inputFeeIndices: [], - outputFromIndices: [0], - outputToIndices: [1], - outputOwnedFeeIndices: [], - outputTransferredFeeIndices: [] - }); - await node.signTransactionInput(transferTx, 0); - await node.signTransactionInput(transferTx, 1); - - const signed = transferTx.sign({ - secret: faucetSecret, - fee: 10, - seq: await node.sdk.rpc.chain.getSeq(faucetAddress) - }); - try { - await node.sdk.rpc.chain.sendSignedTransaction(signed); - expect.fail(); - } catch (e) { - expect(e).is.similarTo(ERROR.DISABLED_TRANSACTION); - } - }); - - it("Correct order, correct transfer - Many originOutputs", async function() { - // Split minted gold asset to 10 assets - const splitTx = node.sdk.core - .createTransferAssetTransaction() - .addInputs(gold) - .addOutputs( - _.times(10, () => ({ - recipient: aliceAddress, - quantity: 1000, - assetType: gold.assetType, - shardId: 0 - })) - ); - await node.signTransactionInput(splitTx, 0); - - const splitHash = await node.sendAssetTransaction(splitTx); - expect(await node.sdk.rpc.chain.containsTransaction(splitHash)) - .be.true; - expect(await node.sdk.rpc.chain.getTransaction(splitHash)).not - .null; - - const splitGolds = splitTx.getTransferredAssets(); - const splitGoldInputs = splitGolds.map(g => - g.createTransferInput() - ); - const silverInput = silver.createTransferInput(); - - const expiration = Math.round(Date.now() / 1000) + 120; - const order = node.sdk.core.createOrder({ - assetTypeFrom: gold.assetType, - assetTypeTo: silver.assetType, - shardIdFrom: 0, - shardIdTo: 0, - assetQuantityFrom: 100, - assetQuantityTo: 1000, - expiration, - originOutputs: splitGoldInputs.map(input => input.prevOut), - recipientFrom: aliceAddress - }); - - const transferTx = node.sdk.core - .createTransferAssetTransaction() - .addInputs(splitGoldInputs) - .addInputs(silverInput) - .addOutputs( - { - recipient: aliceAddress, - quantity: 9900, - assetType: gold.assetType, - shardId: 0 - }, - { - recipient: aliceAddress, - quantity: 1000, - assetType: silver.assetType, - shardId: 0 - }, - { - recipient: bobAddress, - quantity: 100, - assetType: gold.assetType, - shardId: 0 - }, - { - recipient: bobAddress, - quantity: 9000, - assetType: silver.assetType, - shardId: 0 - } - ) - .addOrder({ - order, - spentQuantity: 100, - inputFromIndices: _.range(10), - inputFeeIndices: [], - outputFromIndices: [0], - outputToIndices: [1], - outputOwnedFeeIndices: [], - outputTransferredFeeIndices: [] - }); - await Promise.all( - _.range((transferTx as any)._transaction.inputs.length).map( - i => node.signTransactionInput(transferTx, i) - ) - ); - - const signed = transferTx.sign({ - secret: faucetSecret, - fee: 10, - seq: await node.sdk.rpc.chain.getSeq(faucetAddress) - }); - try { - await node.sdk.rpc.chain.sendSignedTransaction(signed); - expect.fail(); - } catch (e) { - expect(e).is.similarTo(ERROR.DISABLED_TRANSACTION); - } - }).timeout(10_000); - - it("Correct order, correct transfer - Output(to) is empty", async function() { - const goldInput = gold.createTransferInput(); - const silverInput = silver.createTransferInput(); - - const expiration = Math.round(Date.now() / 1000) + 120; - const order = node.sdk.core.createOrder({ - assetTypeFrom: gold.assetType, - assetTypeTo: silver.assetType, - shardIdFrom: 0, - shardIdTo: 0, - assetQuantityFrom: 10000, - assetQuantityTo: 1000, - expiration, - originOutputs: [goldInput.prevOut], - recipientFrom: aliceAddress - }); - const transferTx = node.sdk.core - .createTransferAssetTransaction() - .addInputs(goldInput, silverInput) - .addOutputs( - { - recipient: aliceAddress, - quantity: 1000, - assetType: silver.assetType, - shardId: 0 - }, - { - recipient: bobAddress, - quantity: 10000, - assetType: gold.assetType, - shardId: 0 - }, - { - recipient: bobAddress, - quantity: 9000, - assetType: silver.assetType, - shardId: 0 - } - ) - .addOrder({ - order, - spentQuantity: 10000, - inputFromIndices: [0], - inputFeeIndices: [], - outputFromIndices: [], - outputToIndices: [0], - outputOwnedFeeIndices: [], - outputTransferredFeeIndices: [] - }); - await node.signTransactionInput(transferTx, 0); - await node.signTransactionInput(transferTx, 1); - - const signed = transferTx.sign({ - secret: faucetSecret, - fee: 10, - seq: await node.sdk.rpc.chain.getSeq(faucetAddress) - }); - try { - await node.sdk.rpc.chain.sendSignedTransaction(signed); - expect.fail(); - } catch (e) { - expect(e).is.similarTo(ERROR.DISABLED_TRANSACTION); - } - }); - - it("Correct order, correct transfer - Splitted output", async function() { - const goldInput = gold.createTransferInput(); - const silverInput = silver.createTransferInput(); - - const expiration = Math.round(Date.now() / 1000) + 120; - const order = node.sdk.core.createOrder({ - assetTypeFrom: gold.assetType, - assetTypeTo: silver.assetType, - shardIdFrom: 0, - shardIdTo: 0, - assetQuantityFrom: 1000, - assetQuantityTo: 1000, - expiration, - originOutputs: [goldInput.prevOut], - recipientFrom: aliceAddress - }); - const transferTx = node.sdk.core - .createTransferAssetTransaction() - .addInputs(goldInput, silverInput) - .addOutputs( - { - recipient: aliceAddress, - quantity: 1000, - assetType: silver.assetType, - shardId: 0 - }, - { - recipient: aliceAddress, - quantity: 9000, - assetType: gold.assetType, - shardId: 0 - }, - { - recipient: bobAddress, - quantity: 1000, - assetType: gold.assetType, - shardId: 0 - }, - { - recipient: bobAddress, - quantity: 4500, - assetType: silver.assetType, - shardId: 0 - }, - { - recipient: bobAddress, - quantity: 4500, - assetType: silver.assetType, - shardId: 0 - } - ) - .addOrder({ - order, - spentQuantity: 1000, - inputFromIndices: [0], - inputFeeIndices: [], - outputFromIndices: [1], - outputToIndices: [0], - outputOwnedFeeIndices: [], - outputTransferredFeeIndices: [] - }); - await node.signTransactionInput(transferTx, 0); - await node.signTransactionInput(transferTx, 1); - - const signed = transferTx.sign({ - secret: faucetSecret, - fee: 10, - seq: await node.sdk.rpc.chain.getSeq(faucetAddress) - }); - try { - await node.sdk.rpc.chain.sendSignedTransaction(signed); - expect.fail(); - } catch (e) { - expect(e).is.similarTo(ERROR.DISABLED_TRANSACTION); - } - }); - - it("Correct two orders, correct transfer - Ratio is same", async function() { - const goldInput = gold.createTransferInput(); - const silverInput = silver.createTransferInput(); - - const expiration = Math.round(Date.now() / 1000) + 120; - const aliceOrder = node.sdk.core.createOrder({ - assetTypeFrom: gold.assetType, - assetTypeTo: silver.assetType, - shardIdFrom: 0, - shardIdTo: 0, - assetQuantityFrom: 100, - assetQuantityTo: 1000, - expiration, - originOutputs: [goldInput.prevOut], - recipientFrom: aliceAddress - }); - - const bobOrder = node.sdk.core.createOrder({ - assetTypeFrom: silver.assetType, - assetTypeTo: gold.assetType, - shardIdFrom: 0, - shardIdTo: 0, - assetQuantityFrom: 1000, - assetQuantityTo: 100, - expiration, - originOutputs: [silverInput.prevOut], - recipientFrom: bobAddress - }); - - const transferTx = node.sdk.core - .createTransferAssetTransaction() - .addInputs(goldInput, silverInput) - .addOutputs( - { - recipient: aliceAddress, - quantity: 9900, - assetType: gold.assetType, - shardId: 0 - }, - { - recipient: aliceAddress, - quantity: 1000, - assetType: silver.assetType, - shardId: 0 - }, - { - recipient: bobAddress, - quantity: 100, - assetType: gold.assetType, - shardId: 0 - }, - { - recipient: bobAddress, - quantity: 9000, - assetType: silver.assetType, - shardId: 0 - } - ) - .addOrder({ - order: aliceOrder, - spentQuantity: 100, - inputFromIndices: [0], - inputFeeIndices: [], - outputFromIndices: [0], - outputToIndices: [1], - outputOwnedFeeIndices: [], - outputTransferredFeeIndices: [] - }) - .addOrder({ - order: bobOrder, - spentQuantity: 1000, - inputFromIndices: [1], - inputFeeIndices: [], - outputFromIndices: [3], - outputToIndices: [2], - outputOwnedFeeIndices: [], - outputTransferredFeeIndices: [] - }); - await node.signTransactionInput(transferTx, 0); - await node.signTransactionInput(transferTx, 1); - - const signed = transferTx.sign({ - secret: faucetSecret, - fee: 10, - seq: await node.sdk.rpc.chain.getSeq(faucetAddress) - }); - try { - await node.sdk.rpc.chain.sendSignedTransaction(signed); - expect.fail(); - } catch (e) { - expect(e).is.similarTo(ERROR.DISABLED_TRANSACTION); - } - }); - - it("Correct two orders, correct transfer - Ratio is different", async function() { - const goldInput = gold.createTransferInput(); - const silverInput = silver.createTransferInput(); - - const expiration = Math.round(Date.now() / 1000) + 120; - const aliceOrder = node.sdk.core.createOrder({ - assetTypeFrom: gold.assetType, - assetTypeTo: silver.assetType, - shardIdFrom: 0, - shardIdTo: 0, - assetQuantityFrom: 100, - assetQuantityTo: 1000, - expiration, - originOutputs: [goldInput.prevOut], - recipientFrom: aliceAddress - }); - - const bobOrder = node.sdk.core.createOrder({ - assetTypeFrom: silver.assetType, - assetTypeTo: gold.assetType, - shardIdFrom: 0, - shardIdTo: 0, - assetQuantityFrom: 1000, - assetQuantityTo: 50, - expiration, - originOutputs: [silverInput.prevOut], - recipientFrom: bobAddress - }); - - const transferTx = node.sdk.core - .createTransferAssetTransaction() - .addInputs(goldInput, silverInput) - .addOutputs( - { - recipient: aliceAddress, - quantity: 9900, - assetType: gold.assetType, - shardId: 0 - }, - { - recipient: aliceAddress, - quantity: 1000, - assetType: silver.assetType, - shardId: 0 - }, - // Bob gets more gold than he wanted. - // If there's a relayer, relayer may take it. - { - recipient: bobAddress, - quantity: 100, - assetType: gold.assetType, - shardId: 0 - }, - { - recipient: bobAddress, - quantity: 9000, - assetType: silver.assetType, - shardId: 0 - } - ) - .addOrder({ - order: aliceOrder, - spentQuantity: 100, - inputFromIndices: [0], - inputFeeIndices: [], - outputFromIndices: [0], - outputToIndices: [1], - outputOwnedFeeIndices: [], - outputTransferredFeeIndices: [] - }) - .addOrder({ - order: bobOrder, - spentQuantity: 1000, - inputFromIndices: [1], - inputFeeIndices: [], - outputFromIndices: [3], - outputToIndices: [2], - outputOwnedFeeIndices: [], - outputTransferredFeeIndices: [] - }); - await node.signTransactionInput(transferTx, 0); - await node.signTransactionInput(transferTx, 1); - - const signed = transferTx.sign({ - secret: faucetSecret, - fee: 10, - seq: await node.sdk.rpc.chain.getSeq(faucetAddress) - }); - try { - await node.sdk.rpc.chain.sendSignedTransaction(signed); - expect.fail(); - } catch (e) { - expect(e).is.similarTo(ERROR.DISABLED_TRANSACTION); - } - }); - - it("Correct order, correct transfer - Charlie get some of asset without order", async function() { - const charlieAddress = await node.createP2PKHAddress(); - // Split minted gold asset to 10 assets - const splitTx = node.sdk.core - .createTransferAssetTransaction() - .addInputs(gold) - .addOutputs( - _.times(10, () => ({ - recipient: aliceAddress, - quantity: 1000, - assetType: gold.assetType, - shardId: 0 - })) - ); - await node.signTransactionInput(splitTx, 0); - - const splitHash = await node.sendAssetTransaction(splitTx); - expect(await node.sdk.rpc.chain.containsTransaction(splitHash)) - .be.true; - expect(await node.sdk.rpc.chain.getTransaction(splitHash)).not - .null; - - const splitGolds = splitTx.getTransferredAssets(); - const splitGoldInputs = splitGolds.map(g => - g.createTransferInput() - ); - const silverInput = silver.createTransferInput(); - - const expiration = Math.round(Date.now() / 1000) + 120; - const order = node.sdk.core.createOrder({ - assetTypeFrom: gold.assetType, - assetTypeTo: silver.assetType, - shardIdFrom: 0, - shardIdTo: 0, - assetQuantityFrom: 3000, - assetQuantityTo: 7500, - expiration, - originOutputs: [splitGoldInputs[0].prevOut], - recipientFrom: aliceAddress - }); - - const transferTx = node.sdk.core - .createTransferAssetTransaction() - .addInputs([...splitGoldInputs.slice(0, 3), silverInput]) - .addOutputs( - { - recipient: aliceAddress, - quantity: 2500, - assetType: silver.assetType, - shardId: 0 - }, - { - recipient: bobAddress, - quantity: 1000, - assetType: gold.assetType, - shardId: 0 - }, - { - recipient: bobAddress, - quantity: 7500, - assetType: silver.assetType, - shardId: 0 - }, - { - recipient: charlieAddress, - quantity: 2000, - assetType: gold.assetType, - shardId: 0 - } - ) - .addOrder({ - order, - spentQuantity: 1000, - inputFromIndices: [0], - inputFeeIndices: [], - outputFromIndices: [], - outputToIndices: [0], - outputOwnedFeeIndices: [], - outputTransferredFeeIndices: [] - }); - await node.signTransactionInput(transferTx, 0); - await node.signTransactionInput(transferTx, 1); - await node.signTransactionInput(transferTx, 2); - await node.signTransactionInput(transferTx, 3); - - const signed = transferTx.sign({ - secret: faucetSecret, - fee: 10, - seq: await node.sdk.rpc.chain.getSeq(faucetAddress) - }); - try { - await node.sdk.rpc.chain.sendSignedTransaction(signed); - expect.fail(); - } catch (e) { - expect(e).is.similarTo(ERROR.DISABLED_TRANSACTION); - } - }); - - it("Correct order, wrong transfer - Output(from) is empty", async function() { - const goldInput = gold.createTransferInput(); - const silverInput = silver.createTransferInput(); - - const expiration = Math.round(Date.now() / 1000) + 120; - const order = node.sdk.core.createOrder({ - assetTypeFrom: gold.assetType, - assetTypeTo: silver.assetType, - shardIdFrom: 0, - shardIdTo: 0, - assetQuantityFrom: 10000, - assetQuantityTo: 1000, - expiration, - originOutputs: [goldInput.prevOut], - recipientFrom: aliceAddress - }); - const transferTx = node.sdk.core - .createTransferAssetTransaction() - .addInputs(goldInput, silverInput) - .addOutputs( - { - recipient: aliceAddress, - quantity: 10000, - assetType: gold.assetType, - shardId: 0 - }, - { - recipient: bobAddress, - quantity: 10000, - assetType: silver.assetType, - shardId: 0 - } - ) - .addOrder({ - order, - spentQuantity: 0, - inputFromIndices: [0], - inputFeeIndices: [], - outputFromIndices: [0], - outputToIndices: [], - outputOwnedFeeIndices: [], - outputTransferredFeeIndices: [] - }); - await node.signTransactionInput(transferTx, 0); - await node.signTransactionInput(transferTx, 1); - - const signed = transferTx.sign({ - secret: faucetSecret, - fee: 10, - seq: await node.sdk.rpc.chain.getSeq(faucetAddress) - }); - - try { - await node.sdk.rpc.chain.sendSignedTransaction(signed); - expect.fail(); - } catch (e) { - expect(e).is.similarTo( - ERROR.INCONSISTENT_TRANSACTION_IN_OUT_WITH_ORDERS - ); - } - }); - - it("Correct order, wrong transfer - Spend too much", async function() { - const goldInput = gold.createTransferInput(); - const silverInput = silver.createTransferInput(); - - const expiration = Math.round(Date.now() / 1000) + 120; - const order = node.sdk.core.createOrder({ - assetTypeFrom: gold.assetType, - assetTypeTo: silver.assetType, - shardIdFrom: 0, - shardIdTo: 0, - assetQuantityFrom: 100, - assetQuantityTo: 1000, - expiration, - originOutputs: [goldInput.prevOut], - recipientFrom: aliceAddress - }); - const transferTx = node.sdk.core - .createTransferAssetTransaction() - .addInputs(goldInput, silverInput) - .addOutputs( - { - recipient: aliceAddress, - quantity: 9800, - assetType: gold.assetType, - shardId: 0 - }, - { - recipient: aliceAddress, - quantity: 2000, - assetType: silver.assetType, - shardId: 0 - }, - { - recipient: bobAddress, - quantity: 200, - assetType: gold.assetType, - shardId: 0 - }, - { - recipient: bobAddress, - quantity: 8000, - assetType: silver.assetType, - shardId: 0 - } - ) - .addOrder({ - order, - spentQuantity: 200, - inputFromIndices: [0], - inputFeeIndices: [], - outputFromIndices: [0], - outputToIndices: [1], - outputOwnedFeeIndices: [], - outputTransferredFeeIndices: [] - }); - await node.signTransactionInput(transferTx, 0); - await node.signTransactionInput(transferTx, 1); - - const signed = transferTx.sign({ - secret: faucetSecret, - fee: 10, - seq: await node.sdk.rpc.chain.getSeq(faucetAddress) - }); - - try { - await node.sdk.rpc.chain.sendSignedTransaction(signed); - expect.fail(); - } catch (e) { - expect(e).is.similarTo(ERROR.INVALID_SPENT_QUANTITY); - } - }); - - it("Correct order, wrong transfer - Ratio is wrong", async function() { - const goldInput = gold.createTransferInput(); - const silverInput = silver.createTransferInput(); - - const expiration = Math.round(Date.now() / 1000) + 120; - const order = node.sdk.core.createOrder({ - assetTypeFrom: gold.assetType, - assetTypeTo: silver.assetType, - shardIdFrom: 0, - shardIdTo: 0, - assetQuantityFrom: 100, - assetQuantityTo: 1000, - expiration, - originOutputs: [goldInput.prevOut], - recipientFrom: aliceAddress - }); - const transferTx = node.sdk.core - .createTransferAssetTransaction() - .addInputs(goldInput, silverInput) - .addOutputs( - { - recipient: aliceAddress, - quantity: 9900, - assetType: gold.assetType, - shardId: 0 - }, - { - recipient: aliceAddress, - quantity: 1000 - 10, - assetType: silver.assetType, - shardId: 0 - }, - { - recipient: bobAddress, - quantity: 100, - assetType: gold.assetType, - shardId: 0 - }, - { - recipient: bobAddress, - quantity: 9000 + 10, - assetType: silver.assetType, - shardId: 0 - } - ) - .addOrder({ - order, - spentQuantity: 100, - inputFromIndices: [0], - inputFeeIndices: [], - outputFromIndices: [0], - outputToIndices: [1], - outputOwnedFeeIndices: [], - outputTransferredFeeIndices: [] - }); - await node.signTransactionInput(transferTx, 0); - await node.signTransactionInput(transferTx, 1); - - const signed = transferTx.sign({ - secret: faucetSecret, - fee: 10, - seq: await node.sdk.rpc.chain.getSeq(faucetAddress) - }); - - try { - await node.sdk.rpc.chain.sendSignedTransaction(signed); - expect.fail(); - } catch (e) { - expect(e).is.similarTo( - ERROR.INCONSISTENT_TRANSACTION_IN_OUT_WITH_ORDERS - ); - } - }); - - it("Correct order, wrong transfer - Lock script hash of maker is wrong", async function() { - const goldInput = gold.createTransferInput(); - const silverInput = silver.createTransferInput(); - - const expiration = Math.round(Date.now() / 1000) + 120; - const order = node.sdk.core.createOrder({ - assetTypeFrom: gold.assetType, - assetTypeTo: silver.assetType, - shardIdFrom: 0, - shardIdTo: 0, - assetQuantityFrom: 100, - assetQuantityTo: 1000, - expiration, - originOutputs: [goldInput.prevOut], - recipientFrom: aliceAddress - }); - - const transferTx = node.sdk.core - .createTransferAssetTransaction() - .addInputs(goldInput, silverInput) - .addOutputs( - { - recipient: aliceAddress, - quantity: 9900, - assetType: gold.assetType, - shardId: 0 - }, - { - recipient: aliceAddress, - quantity: 1000, - assetType: silver.assetType, - shardId: 0 - }, - { - recipient: bobAddress, - quantity: 100, - assetType: gold.assetType, - shardId: 0 - }, - { - recipient: bobAddress, - quantity: 9000, - assetType: silver.assetType, - shardId: 0 - } - ) - .addOrder({ - order, - spentQuantity: 100, - inputFromIndices: [0], - inputFeeIndices: [], - outputFromIndices: [0], - outputToIndices: [1], - outputOwnedFeeIndices: [], - outputTransferredFeeIndices: [] - }); - - (transferTx.orders()[0].order - .lockScriptHashFrom as any) = new H160( - "0000000000000000000000000000000000000000" - ); - - await node.signTransactionInput(transferTx, 0); - await node.signTransactionInput(transferTx, 1); - - const signed = transferTx.sign({ - secret: faucetSecret, - fee: 10, - seq: await node.sdk.rpc.chain.getSeq(faucetAddress) - }); - - try { - await node.sdk.rpc.chain.sendSignedTransaction(signed); - expect.fail(); - } catch (e) { - expect(e).is.similarTo( - ERROR.INVALID_ORDER_LOCK_SCRIPT_HASH - ); - } - }); - - it("Correct order, wrong transfer - Parameters of maker are wrong", async function() { - const goldInput = gold.createTransferInput(); - const silverInput = silver.createTransferInput(); - - const expiration = Math.round(Date.now() / 1000) + 120; - const order = node.sdk.core.createOrder({ - assetTypeFrom: gold.assetType, - assetTypeTo: silver.assetType, - shardIdFrom: 0, - shardIdTo: 0, - assetQuantityFrom: 100, - assetQuantityTo: 1000, - expiration, - originOutputs: [goldInput.prevOut], - recipientFrom: aliceAddress - }); - const transferTx = node.sdk.core - .createTransferAssetTransaction() - .addInputs(goldInput, silverInput) - .addOutputs( - { - recipient: aliceAddress, - quantity: 9900, - assetType: gold.assetType, - shardId: 0 - }, - { - recipient: aliceAddress, - quantity: 1000, - assetType: silver.assetType, - shardId: 0 - }, - { - recipient: bobAddress, - quantity: 100, - assetType: gold.assetType, - shardId: 0 - }, - { - recipient: bobAddress, - quantity: 9000, - assetType: silver.assetType, - shardId: 0 - } - ) - .addOrder({ - order, - spentQuantity: 100, - inputFromIndices: [0], - inputFeeIndices: [], - outputFromIndices: [0], - outputToIndices: [1], - outputOwnedFeeIndices: [], - outputTransferredFeeIndices: [] - }); - - (transferTx.orders()[0].order.parametersFrom as any) = []; - - await node.signTransactionInput(transferTx, 0); - await node.signTransactionInput(transferTx, 1); - - const signed = transferTx.sign({ - secret: faucetSecret, - fee: 10, - seq: await node.sdk.rpc.chain.getSeq(faucetAddress) - }); - - try { - await node.sdk.rpc.chain.sendSignedTransaction(signed); - expect.fail(); - } catch (e) { - expect(e).is.similarTo(ERROR.INVALID_ORDER_PARAMETERS); - } - }); - - it("Correct order, wrong transfer - Too many outputs (from)", async function() { - const goldInput = gold.createTransferInput(); - const silverInput = silver.createTransferInput(); - - const expiration = Math.round(Date.now() / 1000) + 120; - const order = node.sdk.core.createOrder({ - assetTypeFrom: gold.assetType, - assetTypeTo: silver.assetType, - shardIdFrom: 0, - shardIdTo: 0, - assetQuantityFrom: 100, - assetQuantityTo: 1000, - expiration, - originOutputs: [goldInput.prevOut], - recipientFrom: aliceAddress - }); - const transferTx = node.sdk.core - .createTransferAssetTransaction() - .addInputs(goldInput, silverInput) - .addOutputs( - { - recipient: aliceAddress, - quantity: 9900 - 100, - assetType: gold.assetType, - shardId: 0 - }, - { - recipient: aliceAddress, - quantity: 100, - assetType: gold.assetType, - shardId: 0 - }, - { - recipient: aliceAddress, - quantity: 1000, - assetType: silver.assetType, - shardId: 0 - }, - { - recipient: bobAddress, - quantity: 100, - assetType: gold.assetType, - shardId: 0 - }, - { - recipient: bobAddress, - quantity: 9000, - assetType: silver.assetType, - shardId: 0 - } - ) - .addOrder({ - order, - spentQuantity: 100, - inputFromIndices: [0], - inputFeeIndices: [], - outputFromIndices: [0, 1], - outputToIndices: [2], - outputOwnedFeeIndices: [], - outputTransferredFeeIndices: [] - }); - await node.signTransactionInput(transferTx, 0); - await node.signTransactionInput(transferTx, 1); - - const signed = transferTx.sign({ - secret: faucetSecret, - fee: 10, - seq: await node.sdk.rpc.chain.getSeq(faucetAddress) - }); - - try { - await node.sdk.rpc.chain.sendSignedTransaction(signed); - expect.fail(); - } catch (e) { - expect(e).is.similarTo(ERROR.DISABLED_TRANSACTION); - } - }); - - it("Correct order, wrong transfer - Too many outputs (to)", async function() { - const goldInput = gold.createTransferInput(); - const silverInput = silver.createTransferInput(); - - const expiration = Math.round(Date.now() / 1000) + 120; - const order = node.sdk.core.createOrder({ - assetTypeFrom: gold.assetType, - assetTypeTo: silver.assetType, - shardIdFrom: 0, - shardIdTo: 0, - assetQuantityFrom: 100, - assetQuantityTo: 1000, - expiration, - originOutputs: [goldInput.prevOut], - recipientFrom: aliceAddress - }); - const transferTx = node.sdk.core - .createTransferAssetTransaction() - .addInputs(goldInput, silverInput) - .addOutputs( - { - recipient: aliceAddress, - quantity: 9900, - assetType: gold.assetType, - shardId: 0 - }, - { - recipient: aliceAddress, - quantity: 1000 - 100, - assetType: silver.assetType, - shardId: 0 - }, - { - recipient: aliceAddress, - quantity: 100, - assetType: silver.assetType, - shardId: 0 - }, - { - recipient: bobAddress, - quantity: 100, - assetType: gold.assetType, - shardId: 0 - }, - { - recipient: bobAddress, - quantity: 9000, - assetType: silver.assetType, - shardId: 0 - } - ) - .addOrder({ - order, - spentQuantity: 100, - inputFromIndices: [0], - inputFeeIndices: [], - outputFromIndices: [0], - outputToIndices: [1, 2], - outputOwnedFeeIndices: [], - outputTransferredFeeIndices: [] - }); - await node.signTransactionInput(transferTx, 0); - await node.signTransactionInput(transferTx, 1); - - const signed = transferTx.sign({ - secret: faucetSecret, - fee: 10, - seq: await node.sdk.rpc.chain.getSeq(faucetAddress) - }); - - try { - await node.sdk.rpc.chain.sendSignedTransaction(signed); - expect.fail(); - } catch (e) { - expect(e).is.similarTo(ERROR.DISABLED_TRANSACTION); - } - }); - - it("Correct order, wrong transfer - Too many outputs (both)", async function() { - const goldInput = gold.createTransferInput(); - const silverInput = silver.createTransferInput(); - - const expiration = Math.round(Date.now() / 1000) + 120; - const order = node.sdk.core.createOrder({ - assetTypeFrom: gold.assetType, - assetTypeTo: silver.assetType, - shardIdFrom: 0, - shardIdTo: 0, - assetQuantityFrom: 100, - assetQuantityTo: 1000, - expiration, - originOutputs: [goldInput.prevOut], - recipientFrom: aliceAddress - }); - const transferTx = node.sdk.core - .createTransferAssetTransaction() - .addInputs(goldInput, silverInput) - .addOutputs( - { - recipient: aliceAddress, - quantity: 9900 - 100, - assetType: gold.assetType, - shardId: 0 - }, - { - recipient: aliceAddress, - quantity: 100, - assetType: gold.assetType, - shardId: 0 - }, - { - recipient: aliceAddress, - quantity: 1000 - 100, - assetType: silver.assetType, - shardId: 0 - }, - { - recipient: aliceAddress, - quantity: 100, - assetType: silver.assetType, - shardId: 0 - }, - { - recipient: bobAddress, - quantity: 100, - assetType: gold.assetType, - shardId: 0 - }, - { - recipient: bobAddress, - quantity: 9000, - assetType: silver.assetType, - shardId: 0 - } - ) - .addOrder({ - order, - spentQuantity: 100, - inputFromIndices: [0], - inputFeeIndices: [], - outputFromIndices: [0, 1], - outputToIndices: [2, 3], - outputOwnedFeeIndices: [], - outputTransferredFeeIndices: [] - }); - await node.signTransactionInput(transferTx, 0); - await node.signTransactionInput(transferTx, 1); - - const signed = transferTx.sign({ - secret: faucetSecret, - fee: 10, - seq: await node.sdk.rpc.chain.getSeq(faucetAddress) - }); - - try { - await node.sdk.rpc.chain.sendSignedTransaction(signed); - expect.fail(); - } catch (e) { - expect(e).is.similarTo(ERROR.DISABLED_TRANSACTION); - } - }); - - it("Wrong order - originOutputs are wrong (empty)", async function() { - const goldInput = gold.createTransferInput(); - const silverInput = silver.createTransferInput(); - - const expiration = Math.round(Date.now() / 1000) + 120; - const order = node.sdk.core.createOrder({ - assetTypeFrom: gold.assetType, - assetTypeTo: silver.assetType, - shardIdFrom: 0, - shardIdTo: 0, - assetQuantityFrom: 100, - assetQuantityTo: 1000, - expiration, - originOutputs: [goldInput.prevOut], - recipientFrom: aliceAddress - }); - (order.originOutputs as any) = []; - - const transferTx = node.sdk.core - .createTransferAssetTransaction() - .addInputs(goldInput, silverInput) - .addOutputs( - { - recipient: aliceAddress, - quantity: 9900, - assetType: gold.assetType, - shardId: 0 - }, - { - recipient: aliceAddress, - quantity: 1000, - assetType: silver.assetType, - shardId: 0 - }, - { - recipient: bobAddress, - quantity: 100, - assetType: gold.assetType, - shardId: 0 - }, - { - recipient: bobAddress, - quantity: 9000, - assetType: silver.assetType, - shardId: 0 - } - ) - .addOrder({ - order, - spentQuantity: 100, - inputFromIndices: [0], - inputFeeIndices: [], - outputFromIndices: [0], - outputToIndices: [1], - outputOwnedFeeIndices: [], - outputTransferredFeeIndices: [] - }); - await node.signTransactionInput(transferTx, 0); - await node.signTransactionInput(transferTx, 1); - - const signed = transferTx.sign({ - secret: faucetSecret, - fee: 10, - seq: await node.sdk.rpc.chain.getSeq(faucetAddress) - }); - - try { - await node.sdk.rpc.chain.sendSignedTransaction(signed); - expect.fail(); - } catch (e) { - expect(e).is.similarTo(ERROR.INVALID_ORIGIN_OUTPUTS); - } - }); - - it("Wrong order - originOutputs are wrong (prevOut does not match)", async function() { - const goldInput = gold.createTransferInput(); - const silverInput = silver.createTransferInput(); - - const expiration = Math.round(Date.now() / 1000) + 120; - const order = node.sdk.core.createOrder({ - assetTypeFrom: gold.assetType, - assetTypeTo: silver.assetType, - shardIdFrom: 0, - shardIdTo: 0, - assetQuantityFrom: 100, - assetQuantityTo: 1000, - expiration, - originOutputs: [silverInput.prevOut], - recipientFrom: aliceAddress - }); - - const transferTx = node.sdk.core - .createTransferAssetTransaction() - .addInputs(goldInput, silverInput) - .addOutputs( - { - recipient: aliceAddress, - quantity: 9900, - assetType: gold.assetType, - shardId: 0 - }, - { - recipient: aliceAddress, - quantity: 1000, - assetType: silver.assetType, - shardId: 0 - }, - { - recipient: bobAddress, - quantity: 100, - assetType: gold.assetType, - shardId: 0 - }, - { - recipient: bobAddress, - quantity: 9000, - assetType: silver.assetType, - shardId: 0 - } - ) - .addOrder({ - order, - spentQuantity: 100, - inputFromIndices: [0], - inputFeeIndices: [], - outputFromIndices: [0], - outputToIndices: [1], - outputOwnedFeeIndices: [], - outputTransferredFeeIndices: [] - }); - await node.signTransactionInput(transferTx, 0); - await node.signTransactionInput(transferTx, 1); - - const signed = transferTx.sign({ - secret: faucetSecret, - fee: 10, - seq: await node.sdk.rpc.chain.getSeq(faucetAddress) - }); - - try { - await node.sdk.rpc.chain.sendSignedTransaction(signed); - expect.fail(); - } catch (e) { - expect(e).is.similarTo(ERROR.INVALID_ORIGIN_OUTPUTS); - } - }); - - it("Wrong order - originOutputs are wrong (Quantity is not enough)", async function() { - // Split minted gold asset to 10 assets - const splitTx = node.sdk.core - .createTransferAssetTransaction() - .addInputs(gold) - .addOutputs( - _.times(10, () => ({ - recipient: aliceAddress, - quantity: 1000, - assetType: gold.assetType, - shardId: 0 - })) - ); - await node.signTransactionInput(splitTx, 0); - - const splitHash = await node.sendAssetTransaction(splitTx); - expect(await node.sdk.rpc.chain.containsTransaction(splitHash)) - .be.true; - expect(await node.sdk.rpc.chain.getTransaction(splitHash)).not - .null; - - const splitGolds = splitTx.getTransferredAssets(); - const splitGoldInputs = splitGolds.map(g => - g.createTransferInput() - ); - const silverInput = silver.createTransferInput(); - - const expiration = Math.round(Date.now() / 1000) + 120; - const order = node.sdk.core.createOrder({ - assetTypeFrom: gold.assetType, - assetTypeTo: silver.assetType, - shardIdFrom: 0, - shardIdTo: 0, - assetQuantityFrom: 3000, - assetQuantityTo: 7500, - expiration, - originOutputs: [splitGoldInputs[0].prevOut], - recipientFrom: aliceAddress - }); - - const transferTx = node.sdk.core - .createTransferAssetTransaction() - .addInputs([...splitGoldInputs.slice(0, 3), silverInput]) - .addOutputs( - { - recipient: aliceAddress, - quantity: 7500, - assetType: silver.assetType, - shardId: 0 - }, - { - recipient: bobAddress, - quantity: 3000, - assetType: gold.assetType, - shardId: 0 - }, - { - recipient: bobAddress, - quantity: 2500, - assetType: silver.assetType, - shardId: 0 - } - ) - .addOrder({ - order, - spentQuantity: 3000, - inputFromIndices: [0, 1, 2], - inputFeeIndices: [], - outputFromIndices: [], - outputToIndices: [0], - outputOwnedFeeIndices: [], - outputTransferredFeeIndices: [] - }); - - const signed = transferTx.sign({ - secret: faucetSecret, - fee: 10, - seq: await node.sdk.rpc.chain.getSeq(faucetAddress) - }); - - try { - await node.sdk.rpc.chain.sendSignedTransaction(signed); - expect.fail(); - } catch (e) { - expect(e).is.similarTo(ERROR.DISABLED_TRANSACTION); - } - }).timeout(10_000); - - it("Wrong order - originOutputs are wrong (few outputs)", async function() { - // Split minted gold asset to 10 assets - const splitTx = node.sdk.core - .createTransferAssetTransaction() - .addInputs(gold) - .addOutputs( - _.times(10, () => ({ - recipient: aliceAddress, - quantity: 1000, - assetType: gold.assetType, - shardId: 0 - })) - ); - await node.signTransactionInput(splitTx, 0); - - const splitHash = await node.sendAssetTransaction(splitTx); - expect(await node.sdk.rpc.chain.containsTransaction(splitHash)) - .be.true; - expect(await node.sdk.rpc.chain.getTransaction(splitHash)).not - .null; - - const splitGolds = splitTx.getTransferredAssets(); - const splitGoldInputs = splitGolds.map(g => - g.createTransferInput() - ); - const silverInput = silver.createTransferInput(); - - const expiration = Math.round(Date.now() / 1000) + 120; - const order = node.sdk.core.createOrder({ - assetTypeFrom: gold.assetType, - assetTypeTo: silver.assetType, - shardIdFrom: 0, - shardIdTo: 0, - assetQuantityFrom: 100, - assetQuantityTo: 1000, - expiration, - originOutputs: splitGoldInputs - .slice(0, 9) - .map(input => input.prevOut), - recipientFrom: aliceAddress - }); - - const transferTx = node.sdk.core - .createTransferAssetTransaction() - .addInputs(splitGoldInputs) - .addInputs(silverInput) - .addOutputs( - { - recipient: aliceAddress, - quantity: 9900, - assetType: gold.assetType, - shardId: 0 - }, - { - recipient: aliceAddress, - quantity: 1000, - assetType: silver.assetType, - shardId: 0 - }, - { - recipient: bobAddress, - quantity: 100, - assetType: gold.assetType, - shardId: 0 - }, - { - recipient: bobAddress, - quantity: 9000, - assetType: silver.assetType, - shardId: 0 - } - ) - .addOrder({ - order, - spentQuantity: 100, - inputFromIndices: _.range(10), - inputFeeIndices: [], - outputFromIndices: [0], - outputToIndices: [1], - outputOwnedFeeIndices: [], - outputTransferredFeeIndices: [] - }); - await Promise.all( - _.range((transferTx as any)._transaction.inputs.length).map( - i => node.signTransactionInput(transferTx, i) - ) - ); - - const signed = transferTx.sign({ - secret: faucetSecret, - fee: 10, - seq: await node.sdk.rpc.chain.getSeq(faucetAddress) - }); - - try { - await node.sdk.rpc.chain.sendSignedTransaction(signed); - expect.fail(); - } catch (e) { - expect(e).is.similarTo(ERROR.DISABLED_TRANSACTION); - } - }).timeout(10_000); - - it("Wrong order - originOutputs are wrong (many outputs)", async function() { - // Split minted gold asset to 10 assets - const splitTx = node.sdk.core - .createTransferAssetTransaction() - .addInputs(gold) - .addOutputs( - _.times(10, () => ({ - recipient: aliceAddress, - quantity: 1000, - assetType: gold.assetType, - shardId: 0 - })) - ); - await node.signTransactionInput(splitTx, 0); - - const splitHash = await node.sendAssetTransaction(splitTx); - expect(await node.sdk.rpc.chain.containsTransaction(splitHash)) - .be.true; - expect(await node.sdk.rpc.chain.getTransaction(splitHash)).not - .null; - - const splitGolds = splitTx.getTransferredAssets(); - const splitGoldInputs = splitGolds.map(g => - g.createTransferInput() - ); - const silverInput = silver.createTransferInput(); - - const expiration = Math.round(Date.now() / 1000) + 120; - const order = node.sdk.core.createOrder({ - assetTypeFrom: gold.assetType, - assetTypeTo: silver.assetType, - shardIdFrom: 0, - shardIdTo: 0, - assetQuantityFrom: 100, - assetQuantityTo: 1000, - expiration, - originOutputs: splitGoldInputs.map(input => input.prevOut), - recipientFrom: aliceAddress - }); - - const transferTx = node.sdk.core - .createTransferAssetTransaction() - .addInputs(splitGoldInputs.slice(0, 9)) - .addInputs(silverInput) - .addOutputs( - { - recipient: aliceAddress, - quantity: 8900, - assetType: gold.assetType, - shardId: 0 - }, - { - recipient: aliceAddress, - quantity: 1000, - assetType: silver.assetType, - shardId: 0 - }, - { - recipient: bobAddress, - quantity: 100, - assetType: gold.assetType, - shardId: 0 - }, - { - recipient: bobAddress, - quantity: 9000, - assetType: silver.assetType, - shardId: 0 - } - ) - .addOrder({ - order, - spentQuantity: 100, - inputFromIndices: _.range(9), - inputFeeIndices: [], - outputFromIndices: [0], - outputToIndices: [1], - outputOwnedFeeIndices: [], - outputTransferredFeeIndices: [] - }); - await Promise.all( - _.range((transferTx as any)._transaction.inputs.length).map( - i => node.signTransactionInput(transferTx, i) - ) - ); - - const signed = transferTx.sign({ - secret: faucetSecret, - fee: 10, - seq: await node.sdk.rpc.chain.getSeq(faucetAddress) - }); - - try { - await node.sdk.rpc.chain.sendSignedTransaction(signed); - expect.fail(); - } catch (e) { - expect(e).is.similarTo(ERROR.DISABLED_TRANSACTION); - } - }).timeout(10_000); - - it("Wrong order - Ratio is wrong (from is zero)", async function() { - const goldInput = gold.createTransferInput(); - const silverInput = silver.createTransferInput(); - - const expiration = Math.round(Date.now() / 1000) + 120; - const order = node.sdk.core.createOrder({ - assetTypeFrom: gold.assetType, - assetTypeTo: silver.assetType, - shardIdFrom: 0, - shardIdTo: 0, - assetQuantityFrom: 100, - assetQuantityTo: 1000, - expiration, - originOutputs: [goldInput.prevOut], - recipientFrom: aliceAddress - }); - (order.assetQuantityFrom as any) = new U64(0); - - const transferTx = node.sdk.core - .createTransferAssetTransaction() - .addInputs(goldInput, silverInput) - .addOutputs( - { - recipient: aliceAddress, - quantity: 9900, - assetType: gold.assetType, - shardId: 0 - }, - { - recipient: aliceAddress, - quantity: 1000, - assetType: silver.assetType, - shardId: 0 - }, - { - recipient: bobAddress, - quantity: 100, - assetType: gold.assetType, - shardId: 0 - }, - { - recipient: bobAddress, - quantity: 9000, - assetType: silver.assetType, - shardId: 0 - } - ) - .addOrder({ - order, - spentQuantity: 100, - inputFromIndices: [0], - inputFeeIndices: [], - outputFromIndices: [0], - outputToIndices: [1], - outputOwnedFeeIndices: [], - outputTransferredFeeIndices: [] - }); - await node.signTransactionInput(transferTx, 0); - await node.signTransactionInput(transferTx, 1); - - const signed = transferTx.sign({ - secret: faucetSecret, - fee: 10, - seq: await node.sdk.rpc.chain.getSeq(faucetAddress) - }); - - try { - await node.sdk.rpc.chain.sendSignedTransaction(signed); - expect.fail(); - } catch (e) { - expect(e).is.similarTo( - ERROR.INVALID_ORDER_ASSET_QUANTITIES - ); - } - }); - - it("Wrong order - Ratio is wrong (to is zero)", async function() { - const goldInput = gold.createTransferInput(); - const silverInput = silver.createTransferInput(); - - const expiration = Math.round(Date.now() / 1000) + 120; - const order = node.sdk.core.createOrder({ - assetTypeFrom: gold.assetType, - assetTypeTo: silver.assetType, - shardIdFrom: 0, - shardIdTo: 0, - assetQuantityFrom: 100, - assetQuantityTo: 1000, - expiration, - originOutputs: [goldInput.prevOut], - recipientFrom: aliceAddress - }); - (order.assetQuantityTo as any) = new U64(0); - - const transferTx = node.sdk.core - .createTransferAssetTransaction() - .addInputs(goldInput, silverInput) - .addOutputs( - { - recipient: aliceAddress, - quantity: 9900, - assetType: gold.assetType, - shardId: 0 - }, - { - recipient: aliceAddress, - quantity: 1000, - assetType: silver.assetType, - shardId: 0 - }, - { - recipient: bobAddress, - quantity: 100, - assetType: gold.assetType, - shardId: 0 - }, - { - recipient: bobAddress, - quantity: 9000, - assetType: silver.assetType, - shardId: 0 - } - ) - .addOrder({ - order, - spentQuantity: 100, - inputFromIndices: [0], - inputFeeIndices: [], - outputFromIndices: [0], - outputToIndices: [1], - outputOwnedFeeIndices: [], - outputTransferredFeeIndices: [] - }); - await node.signTransactionInput(transferTx, 0); - await node.signTransactionInput(transferTx, 1); - - const signed = transferTx.sign({ - secret: faucetSecret, - fee: 10, - seq: await node.sdk.rpc.chain.getSeq(faucetAddress) - }); - - try { - await node.sdk.rpc.chain.sendSignedTransaction(signed); - expect.fail(); - } catch (e) { - expect(e).is.similarTo( - ERROR.INVALID_ORDER_ASSET_QUANTITIES - ); - } - }); - - it("Wrong order - Expiration is old", async function() { - const goldInput = gold.createTransferInput(); - const silverInput = silver.createTransferInput(); - - const expiration = 0; - const order = node.sdk.core.createOrder({ - assetTypeFrom: gold.assetType, - assetTypeTo: silver.assetType, - shardIdFrom: 0, - shardIdTo: 0, - assetQuantityFrom: 100, - assetQuantityTo: 1000, - expiration, - originOutputs: [goldInput.prevOut], - recipientFrom: aliceAddress - }); - const transferTx = node.sdk.core - .createTransferAssetTransaction() - .addInputs(goldInput, silverInput) - .addOutputs( - { - recipient: aliceAddress, - quantity: 9900, - assetType: gold.assetType, - shardId: 0 - }, - { - recipient: aliceAddress, - quantity: 1000, - assetType: silver.assetType, - shardId: 0 - }, - { - recipient: bobAddress, - quantity: 100, - assetType: gold.assetType, - shardId: 0 - }, - { - recipient: bobAddress, - quantity: 9000, - assetType: silver.assetType, - shardId: 0 - } - ) - .addOrder({ - order, - spentQuantity: 100, - inputFromIndices: [0], - inputFeeIndices: [], - outputFromIndices: [0], - outputToIndices: [1], - outputOwnedFeeIndices: [], - outputTransferredFeeIndices: [] - }); - await node.signTransactionInput(transferTx, 0); - await node.signTransactionInput(transferTx, 1); - - const signed = transferTx.sign({ - secret: faucetSecret, - fee: 10, - seq: await node.sdk.rpc.chain.getSeq(faucetAddress) - }); - - try { - await node.sdk.rpc.chain.sendSignedTransaction(signed); - expect.fail(); - } catch (e) { - expect(e).is.similarTo(ERROR.DISABLED_TRANSACTION); - } - }); - - it("Successful partial fills", async function() { - const goldInput = gold.createTransferInput(); - const silverInput = silver.createTransferInput(); - - const expiration = Math.round(Date.now() / 1000) + 120; - const order = node.sdk.core.createOrder({ - assetTypeFrom: gold.assetType, - assetTypeTo: silver.assetType, - shardIdFrom: 0, - shardIdTo: 0, - assetQuantityFrom: 100, - assetQuantityTo: 1000, - expiration, - originOutputs: [goldInput.prevOut], - recipientFrom: aliceAddress - }); - - const transferTx1 = node.sdk.core - .createTransferAssetTransaction() - .addInputs(goldInput, silverInput) - .addOutputs( - { - recipient: aliceAddress, - quantity: 9950, - assetType: gold.assetType, - shardId: 0 - }, - { - recipient: aliceAddress, - quantity: 500, - assetType: silver.assetType, - shardId: 0 - }, - { - recipient: bobAddress, - quantity: 50, - assetType: gold.assetType, - shardId: 0 - }, - { - recipient: bobAddress, - quantity: 9500, - assetType: silver.assetType, - shardId: 0 - } - ) - .addOrder({ - order, - spentQuantity: 50, - inputFromIndices: [0], - inputFeeIndices: [], - outputFromIndices: [0], - outputToIndices: [1], - outputOwnedFeeIndices: [], - outputTransferredFeeIndices: [] - }); - await node.signTransactionInput(transferTx1, 0); - await node.signTransactionInput(transferTx1, 1); - - const signed = transferTx1.sign({ - secret: faucetSecret, - fee: 10, - seq: await node.sdk.rpc.chain.getSeq(faucetAddress) - }); - - try { - await node.sdk.rpc.chain.sendSignedTransaction(signed); - expect.fail(); - } catch (e) { - expect(e).is.similarTo(ERROR.DISABLED_TRANSACTION); - } - }).timeout(10_000); - - it("Successful mutual partial fills", async function() { - const goldInput = gold.createTransferInput(); - const silverInput = silver.createTransferInput(); - - const expiration = Math.round(Date.now() / 1000) + 120; - const aliceOrder = node.sdk.core.createOrder({ - assetTypeFrom: gold.assetType, - assetTypeTo: silver.assetType, - shardIdFrom: 0, - shardIdTo: 0, - assetQuantityFrom: 100, - assetQuantityTo: 1000, - expiration, - originOutputs: [goldInput.prevOut], - recipientFrom: aliceAddress - }); - const bobOrder = node.sdk.core.createOrder({ - assetTypeFrom: silver.assetType, - assetTypeTo: gold.assetType, - shardIdFrom: 0, - shardIdTo: 0, - assetQuantityFrom: 1000, - assetQuantityTo: 50, - expiration, - originOutputs: [silverInput.prevOut], - recipientFrom: bobAddress - }); - - const transferTx1 = node.sdk.core - .createTransferAssetTransaction() - .addInputs(goldInput, silverInput) - .addOutputs( - { - recipient: aliceAddress, - quantity: 9990, - assetType: gold.assetType, - shardId: 0 - }, - { - recipient: aliceAddress, - quantity: 100, - assetType: silver.assetType, - shardId: 0 - }, - { - recipient: bobAddress, - quantity: 10, - assetType: gold.assetType, - shardId: 0 - }, - { - recipient: bobAddress, - quantity: 9900, - assetType: silver.assetType, - shardId: 0 - } - ) - .addOrder({ - order: aliceOrder, - spentQuantity: 10, - inputFromIndices: [0], - inputFeeIndices: [], - outputFromIndices: [0], - outputToIndices: [1], - outputOwnedFeeIndices: [], - outputTransferredFeeIndices: [] - }) - .addOrder({ - order: bobOrder, - spentQuantity: 100, - inputFromIndices: [1], - inputFeeIndices: [], - outputFromIndices: [3], - outputToIndices: [2], - outputOwnedFeeIndices: [], - outputTransferredFeeIndices: [] - }); - await node.signTransactionInput(transferTx1, 0); - await node.signTransactionInput(transferTx1, 1); - - const signed = transferTx1.sign({ - secret: faucetSecret, - fee: 10, - seq: await node.sdk.rpc.chain.getSeq(faucetAddress) - }); - - try { - await node.sdk.rpc.chain.sendSignedTransaction(signed); - expect.fail(); - } catch (e) { - expect(e).is.similarTo(ERROR.DISABLED_TRANSACTION); - } - }).timeout(10_000); - - it("Successful partial cancel", async function() { - const goldInput = gold.createTransferInput(); - const silverInput = silver.createTransferInput(); - - const expiration = Math.round(Date.now() / 1000) + 120; - const order = node.sdk.core.createOrder({ - assetTypeFrom: gold.assetType, - assetTypeTo: silver.assetType, - shardIdFrom: 0, - shardIdTo: 0, - assetQuantityFrom: 100, - assetQuantityTo: 1000, - expiration, - originOutputs: [goldInput.prevOut], - recipientFrom: aliceAddress - }); - const transferTx1 = node.sdk.core - .createTransferAssetTransaction() - .addInputs(goldInput, silverInput) - .addOutputs( - { - recipient: aliceAddress, - quantity: 9950, - assetType: gold.assetType, - shardId: 0 - }, - { - recipient: aliceAddress, - quantity: 500, - assetType: silver.assetType, - shardId: 0 - }, - { - recipient: bobAddress, - quantity: 50, - assetType: gold.assetType, - shardId: 0 - }, - { - recipient: bobAddress, - quantity: 9500, - assetType: silver.assetType, - shardId: 0 - } - ) - .addOrder({ - order, - spentQuantity: 50, - inputFromIndices: [0], - inputFeeIndices: [], - outputFromIndices: [0], - outputToIndices: [1], - outputOwnedFeeIndices: [], - outputTransferredFeeIndices: [] - }); - await node.signTransactionInput(transferTx1, 0); - await node.signTransactionInput(transferTx1, 1); - - const signed = transferTx1.sign({ - secret: faucetSecret, - fee: 10, - seq: await node.sdk.rpc.chain.getSeq(faucetAddress) - }); - - try { - await node.sdk.rpc.chain.sendSignedTransaction(signed); - expect.fail(); - } catch (e) { - expect(e).is.similarTo(ERROR.DISABLED_TRANSACTION); - } - }); - }).timeout(10_000); - - describe("Mint three assets ", function() { - let aliceAddress: AssetAddress; - let bobAddress: AssetAddress; - let charlieAddress: AssetAddress; - - let gold: Asset; - let silver: Asset; - let bronze: Asset; - let feeAsset: Asset; - - beforeEach(async function() { - aliceAddress = await node.createP2PKHAddress(); - bobAddress = await node.createP2PKHAddress(); - charlieAddress = await node.createP2PKHAddress(); - const FeeOwnerAddress = await node.createP2PKHAddress(); - gold = await node.mintAsset({ - supply: 10000, - recipient: aliceAddress - }); - silver = await node.mintAsset({ - supply: 10000, - recipient: bobAddress - }); - bronze = await node.mintAsset({ - supply: 10000, - recipient: FeeOwnerAddress - }); - - const bronzeInput = bronze.createTransferInput(); - const transferTx1 = node.sdk.core - .createTransferAssetTransaction() - .addInputs(bronzeInput) - .addOutputs({ - recipient: aliceAddress, - quantity: 10000, - assetType: bronze.assetType, - shardId: 0 - }); - await node.signTransactionInput(transferTx1, 0); - await node.sendAssetTransaction(transferTx1); - feeAsset = transferTx1.getTransferredAsset(0); - }); - - it("Correct order - originOutputs fee is not enough but Ok", async function() { - const goldInput = gold.createTransferInput(); - const silverInput = silver.createTransferInput(); - const feeInput = feeAsset.createTransferInput(); - - // Split minted gold asset to 10 assets - const splitTx = node.sdk.core - .createTransferAssetTransaction() - .addInputs(feeInput) - .addOutputs( - _.times(10, () => ({ - recipient: aliceAddress, - quantity: 1000, - assetType: bronze.assetType, - shardId: 0 - })) - ); - await node.signTransactionInput(splitTx, 0); - - const splitHash = await node.sendAssetTransaction(splitTx); - expect(await node.sdk.rpc.chain.containsTransaction(splitHash)) - .be.true; - expect(await node.sdk.rpc.chain.getTransaction(splitHash)).not - .null; - - const splitFees = splitTx.getTransferredAssets(); - const splitFeeInputs = splitFees.map(g => - g.createTransferInput() - ); - - const expiration = Math.round(Date.now() / 1000) + 120; - const order = node.sdk.core.createOrder({ - assetTypeFrom: gold.assetType, - assetTypeTo: silver.assetType, - assetTypeFee: bronze.assetType, - shardIdFrom: 0, - shardIdTo: 0, - shardIdFee: 0, - assetQuantityFrom: 1000, - assetQuantityTo: 10000, - assetQuantityFee: 2000, - expiration, - originOutputs: [ - goldInput.prevOut, - splitFeeInputs[0].prevOut - ], - recipientFrom: aliceAddress, - recipientFee: charlieAddress - }); - const transferTx = node.sdk.core - .createTransferAssetTransaction() - .addInputs(goldInput, silverInput, splitFeeInputs[0]) - .addOutputs( - { - recipient: aliceAddress, - quantity: 9900, - assetType: gold.assetType, - shardId: 0 - }, - { - recipient: aliceAddress, - quantity: 1000, - assetType: silver.assetType, - shardId: 0 - }, - { - recipient: aliceAddress, - quantity: 800, - assetType: bronze.assetType, - shardId: 0 - }, - { - recipient: bobAddress, - quantity: 100, - assetType: gold.assetType, - shardId: 0 - }, - { - recipient: bobAddress, - quantity: 9000, - assetType: silver.assetType, - shardId: 0 - }, - { - recipient: charlieAddress, - quantity: 200, - assetType: bronze.assetType, - shardId: 0 - } - ) - .addOrder({ - order, - spentQuantity: 100, - inputFromIndices: [0], - inputFeeIndices: [2], - outputFromIndices: [0], - outputToIndices: [1], - outputOwnedFeeIndices: [2], - outputTransferredFeeIndices: [5] - }); - await node.signTransactionInput(transferTx, 0); - await node.signTransactionInput(transferTx, 1); - await node.signTransactionInput(transferTx, 2); - - const signed = transferTx.sign({ - secret: faucetSecret, - fee: 10, - seq: await node.sdk.rpc.chain.getSeq(faucetAddress) - }); - try { - await node.sdk.rpc.chain.sendSignedTransaction(signed); - expect.fail(); - } catch (e) { - expect(e).is.similarTo(ERROR.DISABLED_TRANSACTION); - } - }); - - it("Correct order, correct transfer", async function() { - const goldInput = gold.createTransferInput(); - const silverInput = silver.createTransferInput(); - const feeInput = feeAsset.createTransferInput(); - - const expiration = Math.round(Date.now() / 1000) + 120; - const order = node.sdk.core.createOrder({ - assetTypeFrom: gold.assetType, - assetTypeTo: silver.assetType, - assetTypeFee: bronze.assetType, - shardIdFrom: 0, - shardIdTo: 0, - shardIdFee: 0, - assetQuantityFrom: 100, - assetQuantityTo: 1000, - assetQuantityFee: 200, - expiration, - originOutputs: [goldInput.prevOut, feeInput.prevOut], - recipientFrom: aliceAddress, - recipientFee: charlieAddress - }); - const transferTx = node.sdk.core - .createTransferAssetTransaction() - .addInputs(goldInput, silverInput, feeInput) - .addOutputs( - { - recipient: aliceAddress, - quantity: 9900, - assetType: gold.assetType, - shardId: 0 - }, - { - recipient: aliceAddress, - quantity: 1000, - assetType: silver.assetType, - shardId: 0 - }, - { - recipient: aliceAddress, - quantity: 9800, - assetType: bronze.assetType, - shardId: 0 - }, - { - recipient: bobAddress, - quantity: 100, - assetType: gold.assetType, - shardId: 0 - }, - { - recipient: bobAddress, - quantity: 9000, - assetType: silver.assetType, - shardId: 0 - }, - { - recipient: charlieAddress, - quantity: 200, - assetType: bronze.assetType, - shardId: 0 - } - ) - .addOrder({ - order, - spentQuantity: 100, - inputFromIndices: [0], - inputFeeIndices: [2], - outputFromIndices: [0], - outputToIndices: [1], - outputOwnedFeeIndices: [2], - outputTransferredFeeIndices: [5] - }); - await node.signTransactionInput(transferTx, 0); - await node.signTransactionInput(transferTx, 1); - await node.signTransactionInput(transferTx, 2); - - const signed = transferTx.sign({ - secret: faucetSecret, - fee: 10, - seq: await node.sdk.rpc.chain.getSeq(faucetAddress) - }); - try { - await node.sdk.rpc.chain.sendSignedTransaction(signed); - expect.fail(); - } catch (e) { - expect(e).is.similarTo(ERROR.DISABLED_TRANSACTION); - } - }); - - it("Correct two orders, correct transfer - Ratio is same", async function() { - const goldInput = gold.createTransferInput(); - const silverInput = silver.createTransferInput(); - const feeInput = feeAsset.createTransferInput(); - - const splitTx = node.sdk.core - .createTransferAssetTransaction() - .addInputs(feeInput) - .addOutputs( - { - recipient: aliceAddress, - quantity: 5000, - assetType: bronze.assetType, - shardId: 0 - }, - { - recipient: bobAddress, - quantity: 5000, - assetType: bronze.assetType, - shardId: 0 - } - ); - await node.signTransactionInput(splitTx, 0); - - const splitHash = await node.sendAssetTransaction(splitTx); - expect(await node.sdk.rpc.chain.containsTransaction(splitHash)) - .be.true; - expect(await node.sdk.rpc.chain.getTransaction(splitHash)).not - .null; - - const splitFees = splitTx.getTransferredAssets(); - const aliceFeeInput = splitFees[0].createTransferInput(); - const bobFeeInput = splitFees[1].createTransferInput(); - - const expiration = Math.round(Date.now() / 1000) + 120; - const aliceOrder = node.sdk.core.createOrder({ - assetTypeFrom: gold.assetType, - assetTypeTo: silver.assetType, - assetTypeFee: bronze.assetType, - shardIdFrom: 0, - shardIdTo: 0, - shardIdFee: 0, - assetQuantityFrom: 100, - assetQuantityTo: 1000, - assetQuantityFee: 200, - expiration, - originOutputs: [goldInput.prevOut, aliceFeeInput.prevOut], - recipientFrom: aliceAddress, - recipientFee: charlieAddress - }); - - const bobOrder = node.sdk.core.createOrder({ - assetTypeFrom: silver.assetType, - assetTypeTo: gold.assetType, - assetTypeFee: bronze.assetType, - shardIdFrom: 0, - shardIdTo: 0, - assetQuantityFrom: 1000, - assetQuantityTo: 100, - assetQuantityFee: 2000, - expiration, - originOutputs: [silverInput.prevOut, bobFeeInput.prevOut], - recipientFrom: bobAddress, - recipientFee: charlieAddress - }); - - const transferTx = node.sdk.core - .createTransferAssetTransaction() - .addInputs( - goldInput, - aliceFeeInput, - silverInput, - bobFeeInput - ) - .addOutputs( - { - recipient: aliceAddress, - quantity: 9900, - assetType: gold.assetType, - shardId: 0 - }, - { - recipient: aliceAddress, - quantity: 1000, - assetType: silver.assetType, - shardId: 0 - }, - { - recipient: aliceAddress, - quantity: 5000 - 200, - assetType: bronze.assetType, - shardId: 0 - }, - { - recipient: charlieAddress, - quantity: 200, - assetType: bronze.assetType, - shardId: 0 - }, - { - recipient: bobAddress, - quantity: 100, - assetType: gold.assetType, - shardId: 0 - }, - { - recipient: bobAddress, - quantity: 9000, - assetType: silver.assetType, - shardId: 0 - }, - { - recipient: bobAddress, - quantity: 5000 - 2000, - assetType: bronze.assetType, - shardId: 0 - }, - { - recipient: charlieAddress, - quantity: 2000, - assetType: bronze.assetType, - shardId: 0 - } - ) - .addOrder({ - order: aliceOrder, - spentQuantity: 100, - inputFromIndices: [0], - inputFeeIndices: [1], - outputFromIndices: [0], - outputToIndices: [1], - outputOwnedFeeIndices: [2], - outputTransferredFeeIndices: [3] - }) - .addOrder({ - order: bobOrder, - spentQuantity: 1000, - inputFromIndices: [2], - inputFeeIndices: [3], - outputFromIndices: [5], - outputToIndices: [4], - outputOwnedFeeIndices: [6], - outputTransferredFeeIndices: [7] - }); - await node.signTransactionInput(transferTx, 0); - await node.signTransactionInput(transferTx, 1); - await node.signTransactionInput(transferTx, 2); - await node.signTransactionInput(transferTx, 3); - - const signed = transferTx.sign({ - secret: faucetSecret, - fee: 10, - seq: await node.sdk.rpc.chain.getSeq(faucetAddress) - }); - try { - await node.sdk.rpc.chain.sendSignedTransaction(signed); - expect.fail(); - } catch (e) { - expect(e).is.similarTo(ERROR.DISABLED_TRANSACTION); - } - }); - - it("Correct two orders, correct transfer - Ratio is different, fee Recipient intrecepts leftover", async function() { - const goldInput = gold.createTransferInput(); - const silverInput = silver.createTransferInput(); - const feeInput = feeAsset.createTransferInput(); - - const splitTx = node.sdk.core - .createTransferAssetTransaction() - .addInputs(feeInput) - .addOutputs( - { - recipient: aliceAddress, - quantity: 5000, - assetType: bronze.assetType, - shardId: 0 - }, - { - recipient: bobAddress, - quantity: 5000, - assetType: bronze.assetType, - shardId: 0 - } - ); - await node.signTransactionInput(splitTx, 0); - - const splitHash = await node.sendAssetTransaction(splitTx); - expect(await node.sdk.rpc.chain.containsTransaction(splitHash)) - .be.true; - expect(await node.sdk.rpc.chain.getTransaction(splitHash)).not - .null; - - const splitFees = splitTx.getTransferredAssets(); - const aliceFeeInput = splitFees[0].createTransferInput(); - const bobFeeInput = splitFees[1].createTransferInput(); - - const expiration = Math.round(Date.now() / 1000) + 120; - const aliceOrder = node.sdk.core.createOrder({ - assetTypeFrom: gold.assetType, - assetTypeTo: silver.assetType, - assetTypeFee: bronze.assetType, - shardIdFrom: 0, - shardIdTo: 0, - shardIdFee: 0, - assetQuantityFrom: 100, - assetQuantityTo: 1000, - assetQuantityFee: 200, - expiration, - originOutputs: [goldInput.prevOut, aliceFeeInput.prevOut], - recipientFrom: aliceAddress, - recipientFee: charlieAddress - }); - - const bobOrder = node.sdk.core.createOrder({ - assetTypeFrom: silver.assetType, - assetTypeTo: gold.assetType, - assetTypeFee: bronze.assetType, - shardIdFrom: 0, - shardIdTo: 0, - assetQuantityFrom: 1000, - assetQuantityTo: 50, - assetQuantityFee: 2000, - expiration, - originOutputs: [silverInput.prevOut, bobFeeInput.prevOut], - recipientFrom: bobAddress, - recipientFee: charlieAddress - }); - - const transferTx = node.sdk.core - .createTransferAssetTransaction() - .addInputs( - goldInput, - aliceFeeInput, - silverInput, - bobFeeInput - ) - .addOutputs( - { - recipient: aliceAddress, - quantity: 9900, - assetType: gold.assetType, - shardId: 0 - }, - { - recipient: aliceAddress, - quantity: 1000, - assetType: silver.assetType, - shardId: 0 - }, - { - recipient: aliceAddress, - quantity: 5000 - 200, - assetType: bronze.assetType, - shardId: 0 - }, - { - recipient: charlieAddress, - quantity: 200, - assetType: bronze.assetType, - shardId: 0 - }, - { - recipient: charlieAddress, - quantity: 50, - assetType: gold.assetType, - shardId: 0 - }, - { - recipient: bobAddress, - quantity: 50, - assetType: gold.assetType, - shardId: 0 - }, - { - recipient: bobAddress, - quantity: 9000, - assetType: silver.assetType, - shardId: 0 - }, - { - recipient: bobAddress, - quantity: 5000 - 2000, - assetType: bronze.assetType, - shardId: 0 - }, - { - recipient: charlieAddress, - quantity: 2000, - assetType: bronze.assetType, - shardId: 0 - } - ) - .addOrder({ - order: aliceOrder, - spentQuantity: 100, - inputFromIndices: [0], - inputFeeIndices: [1], - outputFromIndices: [0], - outputToIndices: [1], - outputOwnedFeeIndices: [2], - outputTransferredFeeIndices: [3] - }) - .addOrder({ - order: bobOrder, - spentQuantity: 1000, - inputFromIndices: [2], - inputFeeIndices: [3], - outputFromIndices: [6], - outputToIndices: [5], - outputOwnedFeeIndices: [7], - outputTransferredFeeIndices: [8] - }); - await node.signTransactionInput(transferTx, 0); - await node.signTransactionInput(transferTx, 1); - await node.signTransactionInput(transferTx, 2); - await node.signTransactionInput(transferTx, 3); - - const signed = transferTx.sign({ - secret: faucetSecret, - fee: 10, - seq: await node.sdk.rpc.chain.getSeq(faucetAddress) - }); - try { - await node.sdk.rpc.chain.sendSignedTransaction(signed); - expect.fail(); - } catch (e) { - expect(e).is.similarTo(ERROR.DISABLED_TRANSACTION); - } - }); - - it("Wrong order - feeInput Omitted in OriginOutputs", async function() { - const goldInput = gold.createTransferInput(); - const silverInput = silver.createTransferInput(); - const feeInput = feeAsset.createTransferInput(); - - const expiration = Math.round(Date.now() / 1000) + 120; - const order = node.sdk.core.createOrder({ - assetTypeFrom: gold.assetType, - assetTypeTo: silver.assetType, - assetTypeFee: bronze.assetType, - shardIdFrom: 0, - shardIdTo: 0, - shardIdFee: 0, - assetQuantityFrom: 100, - assetQuantityTo: 1000, - assetQuantityFee: 200, - expiration, - originOutputs: [goldInput.prevOut], - recipientFrom: aliceAddress, - recipientFee: charlieAddress - }); - const transferTx = node.sdk.core - .createTransferAssetTransaction() - .addInputs(goldInput, silverInput, feeInput) - .addOutputs( - { - recipient: aliceAddress, - quantity: 9900, - assetType: gold.assetType, - shardId: 0 - }, - { - recipient: aliceAddress, - quantity: 1000, - assetType: silver.assetType, - shardId: 0 - }, - { - recipient: aliceAddress, - quantity: 9800, - assetType: bronze.assetType, - shardId: 0 - }, - { - recipient: bobAddress, - quantity: 100, - assetType: gold.assetType, - shardId: 0 - }, - { - recipient: bobAddress, - quantity: 9000, - assetType: silver.assetType, - shardId: 0 - }, - { - recipient: charlieAddress, - quantity: 200, - assetType: bronze.assetType, - shardId: 0 - } - ) - .addOrder({ - order, - spentQuantity: 100, - inputFromIndices: [0], - inputFeeIndices: [2], - outputFromIndices: [0], - outputToIndices: [1], - outputOwnedFeeIndices: [2], - outputTransferredFeeIndices: [5] - }); - await node.signTransactionInput(transferTx, 0); - await node.signTransactionInput(transferTx, 1); - await node.signTransactionInput(transferTx, 2); - - const signed = transferTx.sign({ - secret: faucetSecret, - fee: 10, - seq: await node.sdk.rpc.chain.getSeq(faucetAddress) - }); - - try { - await node.sdk.rpc.chain.sendSignedTransaction(signed); - expect.fail(); - } catch (e) { - expect(e).is.similarTo(ERROR.DISABLED_TRANSACTION); - } - }); - }); - - describe("Mint five assets", function() { - let addresses: AssetAddress[]; - let assets: Asset[]; - - beforeEach(async function() { - addresses = []; - assets = []; - for (let i = 0; i < 5; i++) { - const address = await node.createP2PKHAddress(); - const asset = await node.mintAsset({ - supply: 10000, - recipient: address - }); - addresses.push(address); - assets.push(asset); - } - }); - - it("Multiple orders", async function() { - const inputs = assets.map(asset => asset.createTransferInput()); - - const transferTx = node.sdk.core - .createTransferAssetTransaction() - .addInputs(inputs) - .addOutputs([ - ..._.range(5).map(i => ({ - recipient: addresses[i], - quantity: 50, - assetType: assets[(i + 1) % 5].assetType, - shardId: 0 - })), - ..._.range(5).map(i => ({ - recipient: addresses[i], - quantity: 9950, - assetType: assets[i].assetType, - shardId: 0 - })) - ]); - - for (let i = 0; i < 5; i++) { - const order = node.sdk.core.createOrder({ - assetTypeFrom: assets[i].assetType, - assetTypeTo: assets[(i + 1) % 5].assetType, - shardIdFrom: 0, - shardIdTo: 0, - assetQuantityFrom: 100, - assetQuantityTo: 100, - expiration: U64.MAX_VALUE, - originOutputs: [inputs[i].prevOut], - recipientFrom: addresses[i] - }); - transferTx.addOrder({ - order, - spentQuantity: 50, - inputFromIndices: [i], - inputFeeIndices: [], - outputFromIndices: [i + 5], - outputToIndices: [i], - outputOwnedFeeIndices: [], - outputTransferredFeeIndices: [] - }); - } - - await Promise.all( - _.range((transferTx as any)._transaction.inputs.length).map( - i => node.signTransactionInput(transferTx, i) - ) - ); - - const signed = transferTx.sign({ - secret: faucetSecret, - fee: 10, - seq: await node.sdk.rpc.chain.getSeq(faucetAddress) - }); - try { - await node.sdk.rpc.chain.sendSignedTransaction(signed); - expect.fail(); - } catch (e) { - expect(e).is.similarTo(ERROR.DISABLED_TRANSACTION); - } - }).timeout(10_000); - }); - }); - - afterEach(function() { - if (this.currentTest!.state === "failed") { - node.keepLogs(); - } - }); - - after(async function() { - await node.clean(); - }); -}); diff --git a/test/src/helper/error.ts b/test/src/helper/error.ts index fd5daf85f6..e36d1741ad 100644 --- a/test/src/helper/error.ts +++ b/test/src/helper/error.ts @@ -109,56 +109,11 @@ export const ERROR = { data: $containsWord("Syntax(DuplicatedPreviousOutput"), message: $anything }, - ORDER_IS_NOT_EMPTY: { - code: -32099, - message: $anything, - data: $containsWord("OrderIsNotEmpty") - }, - INCONSISTENT_TRANSACTION_IN_OUT_WITH_ORDERS: { - code: -32099, - message: $anything, - data: $containsWord("InconsistentTransactionInOutWithOrders") - }, INVALID_ORIGIN_OUTPUTS: { code: -32099, message: $anything, data: $containsWord("InvalidOriginOutputs") }, - INVALID_ORDER_ASSET_QUANTITIES: { - code: -32099, - message: $anything, - data: $containsWord("InvalidOrderAssetQuantities") - }, - INVALID_ORDER_ASSET_TYPES: { - code: -32099, - message: $anything, - data: $containsWord("InvalidOrderAssetTypes") - }, - INVALID_ORDER_LOCK_SCRIPT_HASH: { - code: -32099, - message: $anything, - data: $containsWord("InvalidOrderLockScriptHash") - }, - INVALID_ORDER_PARAMETERS: { - code: -32099, - message: $anything, - data: $containsWord("InvalidOrderParameters") - }, - INVALID_OUTPUT_WITH_ORDER: { - code: -32099, - message: $anything, - data: $containsWord("InvalidOutputWithOrder") - }, - INVALID_SPENT_QUANTITY: { - code: -32099, - message: $anything, - data: $containsWord("InvalidSpentQuantity") - }, - ORDER_EXPIRED: { - code: -32099, - message: $anything, - data: $containsWord("OrderExpired") - }, DISABLED_TRANSACTION: { code: -32099, message: $anything, diff --git a/types/src/errors/history_error.rs b/types/src/errors/history_error.rs index deadf1074d..d43cfb0722 100644 --- a/types/src/errors/history_error.rs +++ b/types/src/errors/history_error.rs @@ -29,10 +29,6 @@ pub enum Error { LimitReached, /// Transaction is not valid anymore (state already has higher seq) Old, - OrderExpired { - expiration: u64, - timestamp: u64, - }, Timelocked { timelock: Timelock, remaining_time: u64, @@ -50,7 +46,6 @@ pub enum Error { const ERROR_ID_LIMIT_REACHED: u8 = 2; const ERROR_ID_OLD: u8 = 3; -const ERROR_ID_ORDER_EXPIRED: u8 = 4; const ERROR_ID_TIMELOCKED: u8 = 5; const ERROR_ID_TOO_CHEAP_TO_REPLACE: u8 = 6; const ERROR_ID_TX_ALREADY_IMPORTED: u8 = 7; @@ -64,7 +59,6 @@ impl TaggedRlp for RlpHelper { Ok(match tag { ERROR_ID_LIMIT_REACHED => 1, ERROR_ID_OLD => 1, - ERROR_ID_ORDER_EXPIRED => 3, ERROR_ID_TIMELOCKED => 3, ERROR_ID_TOO_CHEAP_TO_REPLACE => 1, ERROR_ID_TX_ALREADY_IMPORTED => 1, @@ -79,10 +73,6 @@ impl Encodable for Error { match self { Error::LimitReached => RlpHelper::new_tagged_list(s, ERROR_ID_LIMIT_REACHED), Error::Old => RlpHelper::new_tagged_list(s, ERROR_ID_OLD), - Error::OrderExpired { - expiration, - timestamp, - } => RlpHelper::new_tagged_list(s, ERROR_ID_ORDER_EXPIRED).append(expiration).append(timestamp), Error::Timelocked { timelock, remaining_time, @@ -103,10 +93,6 @@ impl Decodable for Error { let error = match tag { ERROR_ID_LIMIT_REACHED => Error::LimitReached, ERROR_ID_OLD => Error::Old, - ERROR_ID_ORDER_EXPIRED => Error::OrderExpired { - expiration: rlp.val_at(1)?, - timestamp: rlp.val_at(2)?, - }, ERROR_ID_TIMELOCKED => Error::Timelocked { timelock: rlp.val_at(1)?, remaining_time: rlp.val_at(2)?, @@ -129,10 +115,6 @@ impl Display for Error { match self { Error::LimitReached => write!(f, "Transaction limit reached"), Error::Old => write!(f, "No longer valid"), - Error::OrderExpired { - expiration, - timestamp, - } => write!(f, "The order is expired. Expiration: {}, Block timestamp: {}", expiration, timestamp), Error::Timelocked { timelock, remaining_time, diff --git a/types/src/errors/runtime_error.rs b/types/src/errors/runtime_error.rs index 056fc464d9..63d0fc34de 100644 --- a/types/src/errors/runtime_error.rs +++ b/types/src/errors/runtime_error.rs @@ -79,8 +79,6 @@ pub enum Error { index: usize, mismatch: Mismatch, }, - /// Errors on orders: origin_outputs of order is not satisfied. - InvalidOriginOutputs(H256), /// Failed to decode script. InvalidScript, /// Returned when transaction seq does not match state seq @@ -138,7 +136,6 @@ const ERROR_ID_SCRIPT_NOT_ALLOWED: u8 = 22; const ERROR_ID_TEXT_NOT_EXIST: u8 = 23; const ERROR_ID_TEXT_VERIFICATION_FAIL: u8 = 24; const ERROR_ID_CANNOT_USE_MASTER_KEY: u8 = 25; -const ERROR_ID_INVALID_ORIGIN_OUTPUTS: u8 = 26; const ERROR_ID_INVALID_SCRIPT: u8 = 27; const ERROR_ID_INVALID_SEQ: u8 = 28; const ERROR_ID_ASSET_SUPPLY_OVERFLOW: u8 = 29; @@ -166,7 +163,6 @@ impl TaggedRlp for RlpHelper { ERROR_ID_INSUFFICIENT_PERMISSION => 1, ERROR_ID_INVALID_ASSET_QUANTITY => 6, ERROR_ID_UNEXPECTED_ASSET_TYPE => 3, - ERROR_ID_INVALID_ORIGIN_OUTPUTS => 2, ERROR_ID_INVALID_SCRIPT => 1, ERROR_ID_INVALID_SEQ => 2, ERROR_ID_INVALID_SHARD_ID => 2, @@ -255,9 +251,6 @@ impl Encodable for Error { index, mismatch, } => RlpHelper::new_tagged_list(s, ERROR_ID_UNEXPECTED_ASSET_TYPE).append(index).append(mismatch), - Error::InvalidOriginOutputs(addr) => { - RlpHelper::new_tagged_list(s, ERROR_ID_INVALID_ORIGIN_OUTPUTS).append(addr) - } Error::InvalidScript => RlpHelper::new_tagged_list(s, ERROR_ID_INVALID_SCRIPT), Error::InvalidSeq(mismatch) => RlpHelper::new_tagged_list(s, ERROR_ID_INVALID_SEQ).append(mismatch), Error::InvalidShardId(shard_id) => { @@ -347,7 +340,6 @@ impl Decodable for Error { index: rlp.val_at(1)?, mismatch: rlp.val_at(2)?, }, - ERROR_ID_INVALID_ORIGIN_OUTPUTS => Error::InvalidOriginOutputs(rlp.val_at(1)?), ERROR_ID_INVALID_SCRIPT => Error::InvalidScript, ERROR_ID_INVALID_SEQ => Error::InvalidSeq(rlp.val_at(1)?), ERROR_ID_INVALID_SHARD_ID => Error::InvalidShardId(rlp.val_at(1)?), @@ -423,7 +415,6 @@ impl Display for Error { shard_id, tracker, index, expected, got ), Error::UnexpectedAssetType{index, mismatch} => write!(f, "{}th input has an unexpected asset type: {}", index, mismatch), - Error::InvalidOriginOutputs(addr) => write!(f, "origin_outputs of order({}) is not satisfied", addr), Error::InvalidScript => write!(f, "Failed to decode script"), Error::InvalidSeq(mismatch) => write!(f, "Invalid transaction seq {}", mismatch), Error::InvalidShardId(shard_id) => write!(f, "{} is an invalid shard id", shard_id), diff --git a/types/src/errors/syntax_error.rs b/types/src/errors/syntax_error.rs index 9d9ba40a70..6f8c246f00 100644 --- a/types/src/errors/syntax_error.rs +++ b/types/src/errors/syntax_error.rs @@ -14,11 +14,10 @@ // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . - use std::fmt::{Display, Formatter, Result as FormatResult}; use ckey::NetworkId; -use primitives::{Bytes, H160, H256}; +use primitives::{H160, H256}; use rlp::{Decodable, DecoderError, Encodable, RlpStream, UntrustedRlp}; use super::TaggedRlp; @@ -35,8 +34,6 @@ pub enum Error { EmptyShardOwners(ShardId), /// Returned when the sum of the transaction's inputs is different from the sum of outputs. InconsistentTransactionInOut, - /// the input and output of tx is not consistent with its orders - InconsistentTransactionInOutWithOrders, /// Transaction's fee is below currently set minimal fee requirement. InsufficientFee { /// Minimal expected fee @@ -49,37 +46,9 @@ pub enum Error { InvalidCustomAction(String), /// Invalid network ID given. InvalidNetworkId(NetworkId), - /// invalid asset_quantity_from, asset_quantity_to because of ratio - InvalidOrderAssetQuantities { - from: u64, - to: u64, - fee: u64, - }, - /// asset_type_from and asset_type_to are equal. - InvalidOrderAssetTypes, - /// The input/output indices of the order on transfer indicate assets of different type from the order. - InvalidAssetTypesWithOrder { - asset_type: String, - idx: usize, - }, - /// Owner of the assets indicated by the input/output indices of the order on transfer is not valid - InvalidAssetOwnerWithOrder { - asset_type: String, - idx: usize, - }, - /// The input/output indices of the order on transfer is not valid. - InvalidOrderInOutIndices, - /// the lock script hash of the order is different from the output - InvalidOrderLockScriptHash(H160), - /// the parameters of the order is different from the output - InvalidOrderParameters(Vec), - /// Errors on orders - /// origin_outputs of order is not satisfied. - InvalidOriginOutputs(H256), InvalidApproval(String), /// Max metadata size is exceeded. MetadataTooBig, - OrderRecipientsAreSame, TextContentTooBig, TooManyOutputs(usize), TransactionIsTooBig, @@ -88,10 +57,6 @@ pub enum Error { CannotChangeWcccAssetScheme, DisabledTransaction, InvalidSignerOfWrapCCC, - InvalidSpentQuantity { - asset_quantity_from: u64, - spent_quantity: u64, - }, } const ERORR_ID_DUPLICATED_PREVIOUS_OUTPUT: u8 = 1; @@ -100,24 +65,14 @@ const ERORR_ID_DUPLICATED_PREVIOUS_OUTPUT: u8 = 1; //const ERROR_ID_EMPTY_OUTPUT: u8 = 3; const ERROR_ID_EMPTY_SHARD_OWNERS: u8 = 4; const ERROR_ID_INCONSISTENT_TRANSACTION_IN_OUT: u8 = 5; -const ERROR_ID_INCONSISTENT_TRANSACTION_IN_OUT_WITH_ORDERS: u8 = 6; const ERROR_ID_INSUFFICIENT_FEE: u8 = 7; const ERROR_ID_INVALID_ASSET_TYPE: u8 = 8; /// Deprecated //const ERROR_ID_INVALID_COMPOSED_OUTPUT_AMOUNT: u8 = 9; //const ERROR_ID_INVALID_DECOMPOSED_INPUT_AMOUNT: u8 = 10; const ERROR_ID_INVALID_NETWORK_ID: u8 = 11; -const ERROR_ID_INVALID_ORDER_ASSET_QUANTITIES: u8 = 12; -const ERROR_ID_INVALID_ORDER_ASSET_TYPES: u8 = 13; -const ERROR_ID_INVALID_ASSET_TYPES_WITH_ORDER: u8 = 14; -const ERROR_ID_INVALID_ASSET_OWNER_WITH_ORDER: u8 = 15; -const ERROR_ID_INVALID_ORDER_IN_OUT_INDICES: u8 = 16; -const ERROR_ID_INVALID_ORDER_LOCK_SCRIPT_HASH: u8 = 17; -const ERROR_ID_INVALID_ORDER_PARAMETERS: u8 = 18; -const ERROR_ID_INVALID_ORIGIN_OUTPUTS: u8 = 19; const ERROR_ID_INVALID_APPROVAL: u8 = 21; const ERROR_ID_METADATA_TOO_BIG: u8 = 22; -const ERROR_ID_ORDER_RECIPIENTS_ARE_SAME: u8 = 23; const ERROR_ID_TEXT_CONTENT_TOO_BIG: u8 = 24; const ERROR_ID_TOO_MANY_OUTPUTS: u8 = 26; const ERROR_ID_TX_IS_TOO_BIG: u8 = 27; @@ -126,7 +81,6 @@ const ERROR_ID_CANNOT_CHANGE_WCCC_ASSET_SCHEME: u8 = 29; const ERROR_ID_DISABLED_TRANSACTION: u8 = 30; const ERROR_ID_INVALID_SIGNER_OF_WRAP_CCC: u8 = 31; const ERROR_ID_INVALID_CUSTOM_ACTION: u8 = 32; -const ERROR_ID_INVALID_SPENT_QUANTITY: u8 = 33; struct RlpHelper; impl TaggedRlp for RlpHelper { @@ -137,22 +91,12 @@ impl TaggedRlp for RlpHelper { ERORR_ID_DUPLICATED_PREVIOUS_OUTPUT => 3, ERROR_ID_EMPTY_SHARD_OWNERS => 2, ERROR_ID_INCONSISTENT_TRANSACTION_IN_OUT => 1, - ERROR_ID_INCONSISTENT_TRANSACTION_IN_OUT_WITH_ORDERS => 1, ERROR_ID_INSUFFICIENT_FEE => 3, ERROR_ID_INVALID_ASSET_TYPE => 2, ERROR_ID_INVALID_CUSTOM_ACTION => 2, ERROR_ID_INVALID_NETWORK_ID => 2, - ERROR_ID_INVALID_ORDER_ASSET_QUANTITIES => 4, - ERROR_ID_INVALID_ORDER_ASSET_TYPES => 1, - ERROR_ID_INVALID_ASSET_TYPES_WITH_ORDER => 3, - ERROR_ID_INVALID_ASSET_OWNER_WITH_ORDER => 3, - ERROR_ID_INVALID_ORDER_IN_OUT_INDICES => 1, - ERROR_ID_INVALID_ORDER_LOCK_SCRIPT_HASH => 2, - ERROR_ID_INVALID_ORDER_PARAMETERS => 2, - ERROR_ID_INVALID_ORIGIN_OUTPUTS => 2, ERROR_ID_INVALID_APPROVAL => 2, ERROR_ID_METADATA_TOO_BIG => 1, - ERROR_ID_ORDER_RECIPIENTS_ARE_SAME => 1, ERROR_ID_TEXT_CONTENT_TOO_BIG => 1, ERROR_ID_TOO_MANY_OUTPUTS => 2, ERROR_ID_TX_IS_TOO_BIG => 1, @@ -160,7 +104,6 @@ impl TaggedRlp for RlpHelper { ERROR_ID_CANNOT_CHANGE_WCCC_ASSET_SCHEME => 1, ERROR_ID_DISABLED_TRANSACTION => 1, ERROR_ID_INVALID_SIGNER_OF_WRAP_CCC => 1, - ERROR_ID_INVALID_SPENT_QUANTITY => 3, _ => return Err(DecoderError::Custom("Invalid SyntaxError")), }) } @@ -179,9 +122,6 @@ impl Encodable for Error { Error::InconsistentTransactionInOut => { RlpHelper::new_tagged_list(s, ERROR_ID_INCONSISTENT_TRANSACTION_IN_OUT) } - Error::InconsistentTransactionInOutWithOrders => { - RlpHelper::new_tagged_list(s, ERROR_ID_INCONSISTENT_TRANSACTION_IN_OUT_WITH_ORDERS) - } Error::InsufficientFee { minimal, got, @@ -193,36 +133,8 @@ impl Encodable for Error { Error::InvalidNetworkId(network_id) => { RlpHelper::new_tagged_list(s, ERROR_ID_INVALID_NETWORK_ID).append(network_id) } - Error::InvalidOrderAssetQuantities { - from, - to, - fee, - } => RlpHelper::new_tagged_list(s, ERROR_ID_INVALID_ORDER_ASSET_QUANTITIES) - .append(from) - .append(to) - .append(fee), - Error::InvalidOrderAssetTypes => RlpHelper::new_tagged_list(s, ERROR_ID_INVALID_ORDER_ASSET_TYPES), - Error::InvalidAssetTypesWithOrder { - asset_type, - idx, - } => RlpHelper::new_tagged_list(s, ERROR_ID_INVALID_ASSET_TYPES_WITH_ORDER).append(asset_type).append(idx), - Error::InvalidAssetOwnerWithOrder { - asset_type, - idx, - } => RlpHelper::new_tagged_list(s, ERROR_ID_INVALID_ASSET_OWNER_WITH_ORDER).append(asset_type).append(idx), - Error::InvalidOrderInOutIndices => RlpHelper::new_tagged_list(s, ERROR_ID_INVALID_ORDER_IN_OUT_INDICES), - Error::InvalidOrderLockScriptHash(lock_script_hash) => { - RlpHelper::new_tagged_list(s, ERROR_ID_INVALID_ORDER_LOCK_SCRIPT_HASH).append(lock_script_hash) - } - Error::InvalidOrderParameters(parameters) => { - RlpHelper::new_tagged_list(s, ERROR_ID_INVALID_ORDER_PARAMETERS).append(parameters) - } - Error::InvalidOriginOutputs(order_hash) => { - RlpHelper::new_tagged_list(s, ERROR_ID_INVALID_ORIGIN_OUTPUTS).append(order_hash) - } Error::InvalidApproval(err) => RlpHelper::new_tagged_list(s, ERROR_ID_INVALID_APPROVAL).append(err), Error::MetadataTooBig => RlpHelper::new_tagged_list(s, ERROR_ID_METADATA_TOO_BIG), - Error::OrderRecipientsAreSame => RlpHelper::new_tagged_list(s, ERROR_ID_ORDER_RECIPIENTS_ARE_SAME), Error::TextContentTooBig => RlpHelper::new_tagged_list(s, ERROR_ID_TEXT_CONTENT_TOO_BIG), Error::TooManyOutputs(num) => RlpHelper::new_tagged_list(s, ERROR_ID_TOO_MANY_OUTPUTS).append(num), Error::TransactionIsTooBig => RlpHelper::new_tagged_list(s, ERROR_ID_TX_IS_TOO_BIG), @@ -232,12 +144,6 @@ impl Encodable for Error { } Error::DisabledTransaction => RlpHelper::new_tagged_list(s, ERROR_ID_DISABLED_TRANSACTION), Error::InvalidSignerOfWrapCCC => RlpHelper::new_tagged_list(s, ERROR_ID_INVALID_SIGNER_OF_WRAP_CCC), - Error::InvalidSpentQuantity { - asset_quantity_from, - spent_quantity, - } => RlpHelper::new_tagged_list(s, ERROR_ID_INVALID_SPENT_QUANTITY) - .append(asset_quantity_from) - .append(spent_quantity), }; } } @@ -252,7 +158,6 @@ impl Decodable for Error { }, ERROR_ID_EMPTY_SHARD_OWNERS => Error::EmptyShardOwners(rlp.val_at(1)?), ERROR_ID_INCONSISTENT_TRANSACTION_IN_OUT => Error::InconsistentTransactionInOut, - ERROR_ID_INCONSISTENT_TRANSACTION_IN_OUT_WITH_ORDERS => Error::InconsistentTransactionInOutWithOrders, ERROR_ID_INSUFFICIENT_FEE => Error::InsufficientFee { minimal: rlp.val_at(1)?, got: rlp.val_at(2)?, @@ -260,27 +165,8 @@ impl Decodable for Error { ERROR_ID_INVALID_ASSET_TYPE => Error::InvalidAssetType(rlp.val_at(1)?), ERROR_ID_INVALID_CUSTOM_ACTION => Error::InvalidCustomAction(rlp.val_at(1)?), ERROR_ID_INVALID_NETWORK_ID => Error::InvalidNetworkId(rlp.val_at(1)?), - ERROR_ID_INVALID_ORDER_ASSET_QUANTITIES => Error::InvalidOrderAssetQuantities { - from: rlp.val_at(1)?, - to: rlp.val_at(2)?, - fee: rlp.val_at(3)?, - }, - ERROR_ID_INVALID_ORDER_ASSET_TYPES => Error::InvalidOrderAssetTypes, - ERROR_ID_INVALID_ASSET_TYPES_WITH_ORDER => Error::InvalidAssetTypesWithOrder { - asset_type: rlp.val_at(1)?, - idx: rlp.val_at(2)?, - }, - ERROR_ID_INVALID_ASSET_OWNER_WITH_ORDER => Error::InvalidAssetOwnerWithOrder { - asset_type: rlp.val_at(1)?, - idx: rlp.val_at(2)?, - }, - ERROR_ID_INVALID_ORDER_IN_OUT_INDICES => Error::InvalidOrderInOutIndices, - ERROR_ID_INVALID_ORDER_LOCK_SCRIPT_HASH => Error::InvalidOrderLockScriptHash(rlp.val_at(1)?), - ERROR_ID_INVALID_ORDER_PARAMETERS => Error::InvalidOrderParameters(rlp.val_at(1)?), - ERROR_ID_INVALID_ORIGIN_OUTPUTS => Error::InvalidOriginOutputs(rlp.val_at(1)?), ERROR_ID_INVALID_APPROVAL => Error::InvalidApproval(rlp.val_at(1)?), ERROR_ID_METADATA_TOO_BIG => Error::MetadataTooBig, - ERROR_ID_ORDER_RECIPIENTS_ARE_SAME => Error::OrderRecipientsAreSame, ERROR_ID_TEXT_CONTENT_TOO_BIG => Error::TextContentTooBig, ERROR_ID_TOO_MANY_OUTPUTS => Error::TooManyOutputs(rlp.val_at(1)?), ERROR_ID_TX_IS_TOO_BIG => Error::TransactionIsTooBig, @@ -288,10 +174,6 @@ impl Decodable for Error { ERROR_ID_CANNOT_CHANGE_WCCC_ASSET_SCHEME => Error::CannotChangeWcccAssetScheme, ERROR_ID_DISABLED_TRANSACTION => Error::DisabledTransaction, ERROR_ID_INVALID_SIGNER_OF_WRAP_CCC => Error::InvalidSignerOfWrapCCC, - ERROR_ID_INVALID_SPENT_QUANTITY => Error::InvalidSpentQuantity { - asset_quantity_from: rlp.val_at(1)?, - spent_quantity: rlp.val_at(2)?, - }, _ => return Err(DecoderError::Custom("Invalid SyntaxError")), }; RlpHelper::check_size(rlp, tag)?; @@ -299,7 +181,6 @@ impl Decodable for Error { } } - impl Display for Error { fn fmt(&self, f: &mut Formatter) -> FormatResult { match self { @@ -307,50 +188,26 @@ impl Display for Error { tracker, index, } => write!(f, "The previous output of inputs/burns are duplicated: ({}, {})", tracker, index), - Error::EmptyShardOwners (shard_id) => write!(f, "Shard({}) must have at least one owner", shard_id), - Error::InconsistentTransactionInOut => write!(f, "The sum of the transaction's inputs is different from the sum of the transaction's outputs"), - Error::InconsistentTransactionInOutWithOrders => write!(f, "The transaction's input and output do not follow its orders"), + Error::EmptyShardOwners(shard_id) => write!(f, "Shard({}) must have at least one owner", shard_id), + Error::InconsistentTransactionInOut => { + write!(f, "The sum of the transaction's inputs is different from the sum of the transaction's outputs") + } Error::InsufficientFee { minimal, got, } => write!(f, "Insufficient fee. Min={}, Given={}", minimal, got), - Error::InvalidAssetType (addr) => write!(f, "Asset type is invalid: {}", addr), + Error::InvalidAssetType(addr) => write!(f, "Asset type is invalid: {}", addr), Error::InvalidCustomAction(err) => write!(f, "Invalid custom action: {}", err), - Error::InvalidNetworkId (network_id) => write!(f, "{} is an invalid network id", network_id), - Error::InvalidOrderAssetQuantities { - from, - to, - fee, - } => write!(f, "The asset exchange ratio of the order is invalid: from:to:fee = {}:{}:{}", from, to, fee), - Error::InvalidOrderAssetTypes => write!(f, "There are same shard asset types in the order"), - Error::InvalidAssetTypesWithOrder { - asset_type, - idx - } => write!(f, "{}th {} asset has a different type from the order", idx, asset_type), - Error::InvalidAssetOwnerWithOrder { - asset_type, - idx - } => write!(f, "Owner of the {}th {} assets is not valid", idx, asset_type), - Error::InvalidOrderInOutIndices => write!(f, "The order on transfer is invalid because its input/output indices are wrong or overlapped with other orders"), - Error::InvalidOrderLockScriptHash (lock_script_hash) => write!(f, "The lock script hash of the order is different from the output: {}", lock_script_hash), - Error::InvalidOrderParameters (parameters) => write!(f, "The parameters of the order is different from the output: {:?}", parameters), - Error::InvalidOriginOutputs (order_hash) => write!(f, "The order({}) is invalid because its origin outputs are wrong", order_hash), + Error::InvalidNetworkId(network_id) => write!(f, "{} is an invalid network id", network_id), Error::InvalidApproval(err) => write!(f, "Transaction has an invalid approval :{}", err), - Error::MetadataTooBig => write!(f, "Metadata size is too big."), - Error::OrderRecipientsAreSame => write!(f, "Both the lock script hash and parameters should not be same between maker and relayer"), - Error::TextContentTooBig => write!(f, "The content of the text is too big"), - Error::TooManyOutputs (num) => write!(f, "The number of outputs is {}. It should be 126 or less.", num), - Error::TransactionIsTooBig => write!(f, "Transaction size exceeded the body size limit"), - Error::ZeroQuantity => write!(f, "A quantity cannot be 0"), + Error::MetadataTooBig => write!(f, "Metadata size is too big."), + Error::TextContentTooBig => write!(f, "The content of the text is too big"), + Error::TooManyOutputs(num) => write!(f, "The number of outputs is {}. It should be 126 or less.", num), + Error::TransactionIsTooBig => write!(f, "Transaction size exceeded the body size limit"), + Error::ZeroQuantity => write!(f, "A quantity cannot be 0"), Error::CannotChangeWcccAssetScheme => write!(f, "Cannot change the asset scheme of WCCC"), Error::DisabledTransaction => write!(f, "Used the disabled transaction"), Error::InvalidSignerOfWrapCCC => write!(f, "The signer of WrapCCC must be matched"), - Error::InvalidSpentQuantity { - asset_quantity_from, - spent_quantity, - } => { - write!(f, "The spentQuantity value {} in an OrderOnTransfer cannot exceed the assetQuantityFrom value {}", spent_quantity, asset_quantity_from) - } } } } diff --git a/types/src/transaction/action.rs b/types/src/transaction/action.rs index 7199859ea5..22e321af63 100644 --- a/types/src/transaction/action.rs +++ b/types/src/transaction/action.rs @@ -22,7 +22,7 @@ use primitives::{Bytes, H160, H256}; use rlp::{Decodable, DecoderError, Encodable, RlpStream, UntrustedRlp}; use crate::errors::SyntaxError; -use crate::transaction::{AssetMintOutput, AssetTransferInput, AssetTransferOutput, OrderOnTransfer, ShardTransaction}; +use crate::transaction::{AssetMintOutput, AssetTransferInput, AssetTransferOutput, ShardTransaction}; use crate::{CommonParams, ShardId}; const PAY: u8 = 0x02; @@ -62,7 +62,6 @@ pub enum Action { burns: Vec, inputs: Vec, outputs: Vec, - orders: Vec, metadata: String, approvals: Vec, expiration: Option, @@ -177,7 +176,6 @@ impl Action { burns, inputs, outputs, - orders, .. } => { if outputs.len() > 512 { @@ -197,11 +195,6 @@ impl Action { if outputs.iter().any(|output| output.quantity == 0) { return Err(SyntaxError::ZeroQuantity) } - for order in orders { - order.order.verify()?; - } - verify_order_indices(orders, inputs.len(), outputs.len())?; - verify_input_and_output_consistent_with_order(orders, inputs, outputs)?; } Action::ChangeAssetScheme { asset_type, @@ -250,7 +243,7 @@ impl Action { Ok(()) } - pub fn verify_with_params(&self, common_params: &CommonParams, is_order_disabled: bool) -> Result<(), SyntaxError> { + pub fn verify_with_params(&self, common_params: &CommonParams) -> Result<(), SyntaxError> { if let Some(network_id) = self.network_id() { let system_network_id = common_params.network_id(); if network_id != system_network_id { @@ -269,7 +262,6 @@ impl Action { } } Action::TransferAsset { - orders, metadata, .. } => { @@ -277,10 +269,6 @@ impl Action { if metadata.len() > max_transfer_metadata_size { return Err(SyntaxError::MetadataTooBig) } - - if is_order_disabled && !orders.is_empty() { - return Err(SyntaxError::DisabledTransaction) - } } Action::ChangeAssetScheme { metadata, @@ -409,14 +397,12 @@ impl From for Option { burns, inputs, outputs, - orders, .. } => Some(ShardTransaction::TransferAsset { network_id, burns, inputs, outputs, - orders, }), Action::ChangeAssetScheme { network_id, @@ -497,18 +483,19 @@ impl Encodable for Action { burns, inputs, outputs, - orders, metadata, approvals, expiration, } => { + let empty: Vec = vec![]; s.begin_list(9) .append(&TRANSFER_ASSET) .append(network_id) .append_list(burns) .append_list(inputs) .append_list(outputs) - .append_list(orders) + // NOTE: The orders field removed. + .append_list(&empty) .append(metadata) .append_list(approvals) .append(expiration); @@ -690,7 +677,6 @@ impl Decodable for Action { burns: rlp.list_at(2)?, inputs: rlp.list_at(3)?, outputs: rlp.list_at(4)?, - orders: rlp.list_at(5)?, metadata: rlp.val_at(6)?, approvals: rlp.list_at(7)?, expiration: rlp.val_at(8)?, @@ -918,205 +904,12 @@ fn check_duplication_in_prev_out( Ok(()) } -fn verify_order_indices(orders: &[OrderOnTransfer], input_len: usize, output_len: usize) -> Result<(), SyntaxError> { - let mut input_check = vec![false; input_len]; - let mut output_check = vec![false; output_len]; - - for order_info in orders { - for input_idx in order_info.input_from_indices.iter().chain(order_info.input_fee_indices.iter()) { - if *input_idx >= input_len || input_check[*input_idx] { - return Err(SyntaxError::InvalidOrderInOutIndices) - } - input_check[*input_idx] = true; - } - - for output_idx in order_info - .output_from_indices - .iter() - .chain(order_info.output_to_indices.iter()) - .chain(order_info.output_owned_fee_indices.iter()) - .chain(order_info.output_transferred_fee_indices.iter()) - { - if *output_idx >= output_len || output_check[*output_idx] { - return Err(SyntaxError::InvalidOrderInOutIndices) - } - output_check[*output_idx] = true; - } - } - Ok(()) -} - -fn verify_input_and_output_consistent_with_order( - orders: &[OrderOnTransfer], - inputs: &[AssetTransferInput], - outputs: &[AssetTransferOutput], -) -> Result<(), SyntaxError> { - for order_tx in orders { - let mut input_quantity_from: u64 = 0; - let mut input_quantity_fee: u64 = 0; - let mut output_quantity_from: u64 = 0; - let mut output_quantity_to: u64 = 0; - let mut output_quantity_fee_remaining: u64 = 0; - let mut output_quantity_fee_given: u64 = 0; - - let order = &order_tx.order; - - // Check if a valid amount is spent - if order_tx.spent_quantity > order.asset_quantity_from { - return Err(SyntaxError::InvalidSpentQuantity { - asset_quantity_from: order.asset_quantity_from, - spent_quantity: order_tx.spent_quantity, - }) - } - - // Check input indices and calculate input_quantity_from and input_quantity_fee - for idx in order_tx.input_from_indices.iter() { - let prev_out = &inputs[*idx].prev_out; - if prev_out.asset_type == order.asset_type_from && prev_out.shard_id == order.shard_id_from { - input_quantity_from += prev_out.quantity - } else { - return Err(SyntaxError::InvalidAssetTypesWithOrder { - asset_type: "INPUT FROM".to_string(), - idx: *idx, - }) - } - } - - for idx in order_tx.input_fee_indices.iter() { - let prev_out = &inputs[*idx].prev_out; - if prev_out.asset_type == order.asset_type_fee && prev_out.shard_id == order.shard_id_fee { - input_quantity_fee += prev_out.quantity - } else { - return Err(SyntaxError::InvalidAssetTypesWithOrder { - asset_type: "INPUT FEE".to_string(), - idx: *idx, - }) - } - } - - // Check output indices and calculate output_quantity_from, output_quantity_to, output_quantity_fee_remaining and output_quantity_fee_given - for idx in order_tx.output_from_indices.iter() { - let output = &outputs[*idx]; - let owned_by_maker = order.check_transfer_output(output)?; - if !owned_by_maker { - return Err(SyntaxError::InvalidAssetOwnerWithOrder { - asset_type: "OUTPUT FROM".to_string(), - idx: *idx, - }) - } - if output.asset_type == order.asset_type_from && output.shard_id == order.shard_id_from { - output_quantity_from += output.quantity - } else { - return Err(SyntaxError::InvalidAssetTypesWithOrder { - asset_type: "OUTPUT FROM".to_string(), - idx: *idx, - }) - } - } - - for idx in order_tx.output_to_indices.iter() { - let output = &outputs[*idx]; - let owned_by_maker = order.check_transfer_output(output)?; - if !owned_by_maker { - return Err(SyntaxError::InvalidAssetOwnerWithOrder { - asset_type: "OUTPUT TO".to_string(), - idx: *idx, - }) - } - if output.asset_type == order.asset_type_to && output.shard_id == order.shard_id_to { - output_quantity_to += output.quantity - } else { - return Err(SyntaxError::InvalidAssetTypesWithOrder { - asset_type: "OUTPUT TO".to_string(), - idx: *idx, - }) - } - } - - for idx in order_tx.output_owned_fee_indices.iter() { - let output = &outputs[*idx]; - let owned_by_maker = order.check_transfer_output(output)?; - if !owned_by_maker { - return Err(SyntaxError::InvalidAssetOwnerWithOrder { - asset_type: "OUTPUT OWNED FEE".to_string(), - idx: *idx, - }) - } - if output.asset_type == order.asset_type_fee && output.shard_id == order.shard_id_fee { - output_quantity_fee_remaining += output.quantity - } else { - return Err(SyntaxError::InvalidAssetTypesWithOrder { - asset_type: "OUTPUT OWNED FEE".to_string(), - idx: *idx, - }) - } - } - - for idx in order_tx.output_transferred_fee_indices.iter() { - let output = &outputs[*idx]; - let owned_by_maker = order.check_transfer_output(output)?; - if owned_by_maker { - return Err(SyntaxError::InvalidAssetOwnerWithOrder { - asset_type: "OUTPUT TRANSFERRED FEE".to_string(), - idx: *idx, - }) - } - if output.asset_type == order.asset_type_fee && output.shard_id == order.shard_id_fee { - output_quantity_fee_given += output.quantity - } else { - return Err(SyntaxError::InvalidAssetTypesWithOrder { - asset_type: "OUTPUT TRANSFERRED FEE".to_string(), - idx: *idx, - }) - } - } - - // NOTE: If input_quantity_from == output_quantity_from, it means the asset is not spent as the order. - // If it's allowed, everyone can move the asset from one to another without permission. - if input_quantity_from <= output_quantity_from - || input_quantity_from - output_quantity_from != order_tx.spent_quantity - { - return Err(SyntaxError::InconsistentTransactionInOutWithOrders) - } - if !is_ratio_greater_or_equal( - order.asset_quantity_from, - order.asset_quantity_to, - order_tx.spent_quantity, - output_quantity_to, - ) { - return Err(SyntaxError::InconsistentTransactionInOutWithOrders) - } - if input_quantity_fee < output_quantity_fee_remaining - || input_quantity_fee - output_quantity_fee_remaining != output_quantity_fee_given - || !is_ratio_equal( - order.asset_quantity_from, - order.asset_quantity_fee, - order_tx.spent_quantity, - output_quantity_fee_given, - ) - { - return Err(SyntaxError::InconsistentTransactionInOutWithOrders) - } - } - Ok(()) -} - -fn is_ratio_equal(from: u64, fee: u64, spent: u64, fee_given: u64) -> bool { - // from:fee = spent:fee_given - u128::from(from) * u128::from(fee_given) == u128::from(fee) * u128::from(spent) -} - -fn is_ratio_greater_or_equal(from: u64, to: u64, spent: u64, output: u64) -> bool { - // from:to <= spent:output - u128::from(from) * u128::from(output) >= u128::from(to) * u128::from(spent) -} - #[cfg(test)] mod tests { use rlp::rlp_encode_and_decode_test; use super::*; - use crate::transaction::{AssetOutPoint, Order}; + use crate::transaction::AssetOutPoint; #[test] fn encode_and_decode_mint_asset() { @@ -1195,7 +988,6 @@ mod tests { let burns = vec![]; let inputs = vec![]; let outputs = vec![]; - let orders = vec![]; let network_id = "tc".into(); let metadata = "".into(); rlp_encode_and_decode_test!(Action::TransferAsset { @@ -1203,7 +995,6 @@ mod tests { burns, inputs, outputs, - orders, metadata, approvals: vec![Signature::random(), Signature::random()], expiration: Some(10), @@ -1266,760 +1057,6 @@ mod tests { }); } - #[test] - fn verify_transfer_transaction_with_order() { - let asset_type_a = H160::random(); - let asset_type_b = H160::random(); - let lock_script_hash = H160::random(); - let parameters = vec![vec![1]]; - let origin_output = AssetOutPoint { - tracker: H256::random(), - index: 0, - asset_type: asset_type_a, - shard_id: 0, - quantity: 30, - }; - let order = Order { - asset_type_from: asset_type_a, - asset_type_to: asset_type_b, - asset_type_fee: H160::zero(), - shard_id_from: 0, - shard_id_to: 0, - shard_id_fee: 0, - asset_quantity_from: 30, - asset_quantity_to: 10, - asset_quantity_fee: 0, - origin_outputs: vec![origin_output.clone()], - expiration: 10, - lock_script_hash_from: lock_script_hash, - parameters_from: parameters.clone(), - lock_script_hash_fee: lock_script_hash, - parameters_fee: parameters.clone(), - }; - - let action = Action::TransferAsset { - network_id: NetworkId::default(), - burns: vec![], - inputs: vec![ - AssetTransferInput { - prev_out: origin_output, - timelock: None, - lock_script: vec![0x30, 0x01], - unlock_script: vec![], - }, - AssetTransferInput { - prev_out: AssetOutPoint { - tracker: H256::random(), - index: 0, - asset_type: asset_type_b, - shard_id: 0, - quantity: 10, - }, - timelock: None, - lock_script: vec![0x30, 0x01], - unlock_script: vec![], - }, - ], - outputs: vec![ - AssetTransferOutput { - lock_script_hash, - parameters: parameters.clone(), - asset_type: asset_type_b, - shard_id: 0, - quantity: 10, - }, - AssetTransferOutput { - lock_script_hash, - parameters: vec![], - asset_type: asset_type_a, - shard_id: 0, - quantity: 30, - }, - ], - orders: vec![OrderOnTransfer { - order, - spent_quantity: 30, - input_from_indices: vec![0], - input_fee_indices: vec![], - output_from_indices: vec![], - output_to_indices: vec![0], - output_owned_fee_indices: vec![], - output_transferred_fee_indices: vec![], - }], - metadata: "".into(), - approvals: vec![], - expiration: None, - }; - assert_eq!(action.verify(), Ok(())); - let mut common_params = CommonParams::default_for_test(); - common_params.set_max_asset_scheme_metadata_size(1000); - common_params.set_max_transfer_metadata_size(1000); - common_params.set_max_text_content_size(1000); - assert_eq!(action.verify_with_params(&common_params, false), Ok(())); - } - - #[test] - fn verify_partial_fill_transfer_transaction_with_order() { - let asset_type_a = H160::random(); - let asset_type_b = H160::random(); - let asset_type_c = H160::random(); - let lock_script_hash = H160::random(); - let parameters1 = vec![vec![1]]; - let parameters2 = vec![vec![2]]; - - let origin_output_1 = AssetOutPoint { - tracker: H256::random(), - index: 0, - asset_type: asset_type_a, - shard_id: 0, - quantity: 40, - }; - let origin_output_2 = AssetOutPoint { - tracker: H256::random(), - index: 0, - asset_type: asset_type_c, - shard_id: 0, - quantity: 30, - }; - - let order = Order { - asset_type_from: asset_type_a, - asset_type_to: asset_type_b, - asset_type_fee: asset_type_c, - shard_id_from: 0, - shard_id_to: 0, - shard_id_fee: 0, - asset_quantity_from: 30, - asset_quantity_to: 20, - asset_quantity_fee: 30, - origin_outputs: vec![origin_output_1.clone(), origin_output_2.clone()], - expiration: 10, - lock_script_hash_from: lock_script_hash, - parameters_from: parameters1.clone(), - lock_script_hash_fee: lock_script_hash, - parameters_fee: parameters2.clone(), - }; - - let action = Action::TransferAsset { - network_id: NetworkId::default(), - burns: vec![], - inputs: vec![ - AssetTransferInput { - prev_out: origin_output_1, - timelock: None, - lock_script: vec![0x30, 0x01], - unlock_script: vec![], - }, - AssetTransferInput { - prev_out: origin_output_2, - timelock: None, - lock_script: vec![0x30, 0x01], - unlock_script: vec![], - }, - AssetTransferInput { - prev_out: AssetOutPoint { - tracker: H256::random(), - index: 0, - asset_type: asset_type_b, - shard_id: 0, - quantity: 10, - }, - timelock: None, - lock_script: vec![0x30, 0x01], - unlock_script: vec![], - }, - ], - outputs: vec![ - AssetTransferOutput { - lock_script_hash, - parameters: parameters1.clone(), - asset_type: asset_type_a, - shard_id: 0, - quantity: 25, - }, - AssetTransferOutput { - lock_script_hash, - parameters: parameters1.clone(), - asset_type: asset_type_b, - shard_id: 0, - quantity: 10, - }, - AssetTransferOutput { - lock_script_hash, - parameters: parameters1.clone(), - asset_type: asset_type_c, - shard_id: 0, - quantity: 15, - }, - AssetTransferOutput { - lock_script_hash, - parameters: vec![], - asset_type: asset_type_a, - shard_id: 0, - quantity: 15, - }, - AssetTransferOutput { - lock_script_hash, - parameters: parameters2.clone(), - asset_type: asset_type_c, - shard_id: 0, - quantity: 15, - }, - ], - orders: vec![OrderOnTransfer { - order, - spent_quantity: 15, - input_from_indices: vec![0], - input_fee_indices: vec![1], - output_from_indices: vec![0], - output_to_indices: vec![1], - output_owned_fee_indices: vec![2], - output_transferred_fee_indices: vec![4], - }], - metadata: "".into(), - approvals: vec![], - expiration: None, - }; - - assert_eq!(action.verify(), Ok(())); - let mut common_params = CommonParams::default_for_test(); - common_params.set_max_asset_scheme_metadata_size(1000); - common_params.set_max_transfer_metadata_size(1000); - common_params.set_max_text_content_size(1000); - assert_eq!(action.verify_with_params(&common_params, false), Ok(())); - } - - #[test] - fn verify_inconsistent_transfer_transaction_with_order() { - let asset_type_a = H160::random(); - let asset_type_b = H160::random(); - let asset_type_c = H160::random(); - let lock_script_hash = H160::random(); - let parameters = vec![vec![1]]; - let parameters_fee = vec![vec![2]]; - - // Case 1: ratio is wrong - let origin_output = AssetOutPoint { - tracker: H256::random(), - index: 0, - asset_type: asset_type_a, - shard_id: 0, - quantity: 30, - }; - let order = Order { - asset_type_from: asset_type_a, - asset_type_to: asset_type_b, - asset_type_fee: H160::zero(), - shard_id_from: 0, - shard_id_to: 0, - shard_id_fee: 0, - asset_quantity_from: 25, - asset_quantity_to: 10, - asset_quantity_fee: 0, - origin_outputs: vec![origin_output.clone()], - expiration: 10, - lock_script_hash_from: lock_script_hash, - parameters_from: parameters.clone(), - lock_script_hash_fee: lock_script_hash, - parameters_fee: parameters_fee.clone(), - }; - - let action = Action::TransferAsset { - network_id: NetworkId::default(), - burns: vec![], - inputs: vec![ - AssetTransferInput { - prev_out: origin_output, - timelock: None, - lock_script: vec![0x30, 0x01], - unlock_script: vec![], - }, - AssetTransferInput { - prev_out: AssetOutPoint { - tracker: H256::random(), - index: 0, - asset_type: asset_type_b, - shard_id: 0, - quantity: 10, - }, - timelock: None, - lock_script: vec![0x30, 0x01], - unlock_script: vec![], - }, - ], - outputs: vec![ - AssetTransferOutput { - lock_script_hash, - parameters: parameters.clone(), - asset_type: asset_type_b, - shard_id: 0, - quantity: 10, - }, - AssetTransferOutput { - lock_script_hash, - parameters: vec![], - asset_type: asset_type_a, - shard_id: 0, - quantity: 30, - }, - ], - orders: vec![OrderOnTransfer { - order, - spent_quantity: 25, - input_from_indices: vec![0], - input_fee_indices: vec![], - output_from_indices: vec![], - output_to_indices: vec![0], - output_owned_fee_indices: vec![], - output_transferred_fee_indices: vec![], - }], - metadata: "".into(), - approvals: vec![], - expiration: None, - }; - assert_eq!(action.verify(), Err(SyntaxError::InconsistentTransactionInOutWithOrders)); - - // Case 2: multiple outputs with same order and asset_type - let origin_output_1 = AssetOutPoint { - tracker: H256::random(), - index: 0, - asset_type: asset_type_a, - shard_id: 0, - quantity: 40, - }; - let origin_output_2 = AssetOutPoint { - tracker: H256::random(), - index: 0, - asset_type: asset_type_c, - shard_id: 0, - quantity: 40, - }; - let order = Order { - asset_type_from: asset_type_a, - asset_type_to: asset_type_b, - asset_type_fee: asset_type_c, - shard_id_from: 0, - shard_id_to: 0, - shard_id_fee: 0, - asset_quantity_from: 30, - asset_quantity_to: 10, - asset_quantity_fee: 30, - origin_outputs: vec![origin_output_1.clone(), origin_output_2.clone()], - expiration: 10, - lock_script_hash_from: lock_script_hash, - parameters_from: parameters.clone(), - lock_script_hash_fee: lock_script_hash, - parameters_fee: parameters_fee.clone(), - }; - - // Case 2-1: asset_type_from - let action = Action::TransferAsset { - network_id: NetworkId::default(), - burns: vec![], - inputs: vec![ - AssetTransferInput { - prev_out: origin_output_1.clone(), - timelock: None, - lock_script: vec![0x30, 0x01], - unlock_script: vec![], - }, - AssetTransferInput { - prev_out: origin_output_2.clone(), - timelock: None, - lock_script: vec![0x30, 0x01], - unlock_script: vec![], - }, - AssetTransferInput { - prev_out: AssetOutPoint { - tracker: H256::random(), - index: 0, - asset_type: asset_type_b, - shard_id: 0, - quantity: 10, - }, - timelock: None, - lock_script: vec![0x30, 0x01], - unlock_script: vec![], - }, - ], - outputs: vec![ - AssetTransferOutput { - lock_script_hash, - parameters: parameters.clone(), - asset_type: asset_type_a, - shard_id: 0, - quantity: 5, - }, - AssetTransferOutput { - lock_script_hash, - parameters: parameters.clone(), - asset_type: asset_type_a, - shard_id: 0, - quantity: 6, - }, - AssetTransferOutput { - lock_script_hash, - parameters: parameters.clone(), - asset_type: asset_type_b, - shard_id: 0, - quantity: 10, - }, - AssetTransferOutput { - lock_script_hash, - parameters: parameters.clone(), - asset_type: asset_type_c, - shard_id: 0, - quantity: 10, - }, - AssetTransferOutput { - lock_script_hash, - parameters: vec![], - asset_type: asset_type_a, - shard_id: 0, - quantity: 29, - }, - AssetTransferOutput { - lock_script_hash, - parameters: parameters_fee.clone(), - asset_type: asset_type_c, - shard_id: 0, - quantity: 30, - }, - ], - orders: vec![OrderOnTransfer { - order: order.clone(), - spent_quantity: 30, - input_from_indices: vec![0], - input_fee_indices: vec![1], - output_from_indices: vec![0, 1], - output_to_indices: vec![2], - output_owned_fee_indices: vec![3], - output_transferred_fee_indices: vec![5], - }], - metadata: "".into(), - approvals: vec![], - expiration: None, - }; - assert_eq!(action.verify(), Err(SyntaxError::InconsistentTransactionInOutWithOrders)); - - // Case 2-2: asset_type_to - let action = Action::TransferAsset { - network_id: NetworkId::default(), - burns: vec![], - inputs: vec![ - AssetTransferInput { - prev_out: origin_output_1.clone(), - timelock: None, - lock_script: vec![0x30, 0x01], - unlock_script: vec![], - }, - AssetTransferInput { - prev_out: origin_output_2.clone(), - timelock: None, - lock_script: vec![0x30, 0x01], - unlock_script: vec![], - }, - AssetTransferInput { - prev_out: AssetOutPoint { - tracker: H256::random(), - index: 0, - asset_type: asset_type_b, - shard_id: 0, - quantity: 10, - }, - timelock: None, - lock_script: vec![0x30, 0x01], - unlock_script: vec![], - }, - ], - outputs: vec![ - AssetTransferOutput { - lock_script_hash, - parameters: parameters.clone(), - asset_type: asset_type_a, - shard_id: 0, - quantity: 10, - }, - AssetTransferOutput { - lock_script_hash, - parameters: parameters.clone(), - asset_type: asset_type_b, - shard_id: 0, - quantity: 5, - }, - AssetTransferOutput { - lock_script_hash, - parameters: parameters.clone(), - asset_type: asset_type_b, - shard_id: 0, - quantity: 4, - }, - AssetTransferOutput { - lock_script_hash, - parameters: parameters.clone(), - asset_type: asset_type_c, - shard_id: 0, - quantity: 10, - }, - AssetTransferOutput { - lock_script_hash, - parameters: vec![], - asset_type: asset_type_a, - shard_id: 0, - quantity: 30, - }, - AssetTransferOutput { - lock_script_hash, - parameters: parameters_fee.clone(), - asset_type: asset_type_c, - shard_id: 0, - quantity: 30, - }, - AssetTransferOutput { - lock_script_hash, - parameters: vec![], - asset_type: asset_type_b, - shard_id: 0, - quantity: 1, - }, - ], - orders: vec![OrderOnTransfer { - order: order.clone(), - spent_quantity: 30, - input_from_indices: vec![0], - input_fee_indices: vec![1], - output_from_indices: vec![0], - output_to_indices: vec![1, 2], - output_owned_fee_indices: vec![3], - output_transferred_fee_indices: vec![5], - }], - metadata: "".into(), - approvals: vec![], - expiration: None, - }; - assert_eq!(action.verify(), Err(SyntaxError::InconsistentTransactionInOutWithOrders)); - - // Case 2-3: asset_type_fee - let action = Action::TransferAsset { - network_id: NetworkId::default(), - burns: vec![], - inputs: vec![ - AssetTransferInput { - prev_out: origin_output_1.clone(), - timelock: None, - lock_script: vec![0x30, 0x01], - unlock_script: vec![], - }, - AssetTransferInput { - prev_out: origin_output_2.clone(), - timelock: None, - lock_script: vec![0x30, 0x01], - unlock_script: vec![], - }, - AssetTransferInput { - prev_out: AssetOutPoint { - tracker: H256::random(), - index: 0, - asset_type: asset_type_b, - shard_id: 0, - quantity: 10, - }, - timelock: None, - lock_script: vec![0x30, 0x01], - unlock_script: vec![], - }, - ], - outputs: vec![ - AssetTransferOutput { - lock_script_hash, - parameters: parameters.clone(), - asset_type: asset_type_a, - shard_id: 0, - quantity: 10, - }, - AssetTransferOutput { - lock_script_hash, - parameters: parameters.clone(), - asset_type: asset_type_b, - shard_id: 0, - quantity: 10, - }, - AssetTransferOutput { - lock_script_hash, - parameters: parameters.clone(), - asset_type: asset_type_c, - shard_id: 0, - quantity: 6, - }, - AssetTransferOutput { - lock_script_hash, - parameters: parameters.clone(), - asset_type: asset_type_c, - shard_id: 0, - quantity: 5, - }, - AssetTransferOutput { - lock_script_hash, - parameters: vec![], - asset_type: asset_type_a, - shard_id: 0, - quantity: 30, - }, - AssetTransferOutput { - lock_script_hash, - parameters: parameters_fee.clone(), - asset_type: asset_type_c, - shard_id: 0, - quantity: 29, - }, - ], - orders: vec![OrderOnTransfer { - order: order.clone(), - spent_quantity: 30, - input_from_indices: vec![0], - input_fee_indices: vec![1], - output_from_indices: vec![0], - output_to_indices: vec![1], - output_owned_fee_indices: vec![2, 3], - output_transferred_fee_indices: vec![5], - }], - metadata: "".into(), - approvals: vec![], - expiration: None, - }; - assert_eq!(action.verify(), Err(SyntaxError::InconsistentTransactionInOutWithOrders)); - } - - #[test] - fn verify_transfer_transaction_with_two_orders() { - let asset_type_a = H160::random(); - let asset_type_b = H160::random(); - let lock_script_hash = H160::random(); - let parameters = vec![vec![1]]; - let origin_output_1 = AssetOutPoint { - tracker: H256::random(), - index: 0, - asset_type: asset_type_a, - shard_id: 0, - quantity: 30, - }; - let origin_output_2 = AssetOutPoint { - tracker: H256::random(), - index: 0, - asset_type: asset_type_b, - shard_id: 0, - quantity: 10, - }; - - let order_1 = Order { - asset_type_from: asset_type_a, - asset_type_to: asset_type_b, - asset_type_fee: H160::zero(), - shard_id_from: 0, - shard_id_to: 0, - shard_id_fee: 0, - asset_quantity_from: 30, - asset_quantity_to: 10, - asset_quantity_fee: 0, - origin_outputs: vec![origin_output_1.clone()], - expiration: 10, - lock_script_hash_from: lock_script_hash, - parameters_from: parameters.clone(), - lock_script_hash_fee: lock_script_hash, - parameters_fee: parameters.clone(), - }; - let order_2 = Order { - asset_type_from: asset_type_b, - asset_type_to: asset_type_a, - asset_type_fee: H160::zero(), - shard_id_from: 0, - shard_id_to: 0, - shard_id_fee: 0, - asset_quantity_from: 10, - asset_quantity_to: 20, - asset_quantity_fee: 0, - origin_outputs: vec![origin_output_2.clone()], - expiration: 10, - lock_script_hash_from: lock_script_hash, - parameters_from: parameters.clone(), - lock_script_hash_fee: lock_script_hash, - parameters_fee: parameters.clone(), - }; - - let action = Action::TransferAsset { - network_id: NetworkId::default(), - burns: vec![], - inputs: vec![ - AssetTransferInput { - prev_out: origin_output_1, - timelock: None, - lock_script: vec![0x30, 0x01], - unlock_script: vec![], - }, - AssetTransferInput { - prev_out: origin_output_2, - timelock: None, - lock_script: vec![0x30, 0x01], - unlock_script: vec![], - }, - ], - outputs: vec![ - AssetTransferOutput { - lock_script_hash, - parameters: parameters.clone(), - asset_type: asset_type_b, - shard_id: 0, - quantity: 10, - }, - AssetTransferOutput { - lock_script_hash, - parameters: parameters.clone(), - asset_type: asset_type_a, - shard_id: 0, - quantity: 20, - }, - AssetTransferOutput { - lock_script_hash, - parameters: vec![], - asset_type: asset_type_a, - shard_id: 0, - quantity: 10, - }, - ], - orders: vec![ - OrderOnTransfer { - order: order_1, - spent_quantity: 30, - input_from_indices: vec![0], - input_fee_indices: vec![], - output_from_indices: vec![], - output_to_indices: vec![0], - output_owned_fee_indices: vec![], - output_transferred_fee_indices: vec![], - }, - OrderOnTransfer { - order: order_2, - spent_quantity: 10, - input_from_indices: vec![1], - input_fee_indices: vec![], - output_from_indices: vec![], - output_to_indices: vec![1], - output_owned_fee_indices: vec![], - output_transferred_fee_indices: vec![], - }, - ], - metadata: "".into(), - approvals: vec![], - expiration: None, - }; - assert_eq!(action.verify(), Ok(())); - let mut common_params = CommonParams::default_for_test(); - common_params.set_max_asset_scheme_metadata_size(1000); - common_params.set_max_transfer_metadata_size(1000); - common_params.set_max_text_content_size(1000); - assert_eq!(action.verify_with_params(&common_params, false), Ok(())); - } - #[test] fn verify_unwrap_ccc_transaction_should_fail() { let tx_zero_quantity = Action::UnwrapCCC { diff --git a/types/src/transaction/mod.rs b/types/src/transaction/mod.rs index a09a3339cf..acbbaa748d 100644 --- a/types/src/transaction/mod.rs +++ b/types/src/transaction/mod.rs @@ -18,7 +18,6 @@ mod action; mod asset_out_point; mod incomplete_transaction; mod input; -mod order; mod output; mod partial_hashing; mod shard; @@ -30,7 +29,6 @@ pub use self::action::Action; pub use self::asset_out_point::AssetOutPoint; pub use self::incomplete_transaction::IncompleteTransaction; pub use self::input::AssetTransferInput; -pub use self::order::{Order, OrderOnTransfer}; pub use self::output::{AssetMintOutput, AssetTransferOutput}; pub use self::partial_hashing::{HashingError, PartialHashing}; pub use self::shard::{AssetWrapCCCOutput, ShardTransaction}; diff --git a/types/src/transaction/order.rs b/types/src/transaction/order.rs deleted file mode 100644 index 5cae34bf93..0000000000 --- a/types/src/transaction/order.rs +++ /dev/null @@ -1,453 +0,0 @@ -// Copyright 2018-2019 Kodebox, Inc. -// This file is part of CodeChain. -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as -// published by the Free Software Foundation, either version 3 of the -// License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public License -// along with this program. If not, see . - -use primitives::{Bytes, H160}; - -use crate::ShardId; - -use super::{AssetOutPoint, AssetTransferOutput}; -use crate::errors::SyntaxError; - -#[derive(Debug, Clone, Eq, PartialEq, RlpDecodable, RlpEncodable)] -pub struct Order { - // Main order information - pub asset_type_from: H160, - pub asset_type_to: H160, - pub asset_type_fee: H160, - pub shard_id_from: ShardId, - pub shard_id_to: ShardId, - pub shard_id_fee: ShardId, - pub asset_quantity_from: u64, - pub asset_quantity_to: u64, - pub asset_quantity_fee: u64, - /// previous outputs that order is started - pub origin_outputs: Vec, - /// expiration time by second - pub expiration: u64, - pub lock_script_hash_from: H160, - pub parameters_from: Vec, - pub lock_script_hash_fee: H160, - pub parameters_fee: Vec, -} - -#[derive(Debug, Clone, Eq, PartialEq, RlpDecodable, RlpEncodable)] -pub struct OrderOnTransfer { - pub order: Order, - /// Spent quantity of asset_type_from - pub spent_quantity: u64, - // Indices of asset_type_from - pub input_from_indices: Vec, - // Indices of asset_type_fee - pub input_fee_indices: Vec, - // Indices of remain asset_type_from - pub output_from_indices: Vec, - // Indices of asset_type_to - pub output_to_indices: Vec, - // Indices of ramain asset_type_fee - pub output_owned_fee_indices: Vec, - // Indices of paid asset_type_fee - pub output_transferred_fee_indices: Vec, -} - -impl Order { - // FIXME: Remove this after the clippy nonminimal bool bug is fixed - // https://rust-lang.github.io/rust-clippy/v0.0.212/#nonminimal_bool - #![cfg_attr(feature = "cargo-clippy", allow(clippy::nonminimal_bool))] - pub fn verify(&self) -> Result<(), SyntaxError> { - // If asset_quantity_fee is zero, it means there's no fee to pay. - // asset_type_from and asset_type_to can be the same with asset_type_fee. - if self.asset_type_from == self.asset_type_to && self.shard_id_from == self.shard_id_to { - return Err(SyntaxError::InvalidOrderAssetTypes) - } - // Invalid asset exchange transaction. The case is naive transfer transaction if either of asset_quantity_from or asset_quantity_to is zero - if (self.asset_quantity_from == 0) ^ (self.asset_quantity_to == 0) { - return Err(SyntaxError::InvalidOrderAssetQuantities { - from: self.asset_quantity_from, - to: self.asset_quantity_to, - fee: self.asset_quantity_fee, - }) - } - // asset_quantity_fee should be mutiples of asset_quantity_from - if self.asset_quantity_from == 0 && self.asset_quantity_fee != 0 - || self.asset_quantity_from != 0 && self.asset_quantity_fee % self.asset_quantity_from != 0 - { - return Err(SyntaxError::InvalidOrderAssetQuantities { - from: self.asset_quantity_from, - to: self.asset_quantity_to, - fee: self.asset_quantity_fee, - }) - } - // fee recipient should not be the same with the one provided asset_type_from - if self.asset_quantity_fee != 0 - && self.lock_script_hash_fee == self.lock_script_hash_from - && self.parameters_fee == self.parameters_from - { - return Err(SyntaxError::OrderRecipientsAreSame) - } - if self.origin_outputs.is_empty() { - return Err(SyntaxError::InvalidOriginOutputs(self.hash())) - } - // Check if the origin_outputs include other types of asset except asset_type_from and asset_type_fee - for origin_output in self.origin_outputs.iter() { - if (origin_output.asset_type != self.asset_type_from || origin_output.shard_id != self.shard_id_from) - && (origin_output.asset_type != self.asset_type_fee || origin_output.shard_id != self.shard_id_fee) - { - return Err(SyntaxError::InvalidOriginOutputs(self.hash())) - } - } - Ok(()) - } - - // Check if an arbitrary output is involved in this order - pub fn check_transfer_output(&self, output: &AssetTransferOutput) -> Result { - if self.asset_quantity_fee != 0 - && self.asset_type_fee == output.asset_type - && self.shard_id_fee == output.shard_id - && self.lock_script_hash_fee == output.lock_script_hash - && self.parameters_fee == output.parameters - { - // owned by relayer - return Ok(false) - } - - if self.lock_script_hash_from != output.lock_script_hash { - return Err(SyntaxError::InvalidOrderLockScriptHash(self.lock_script_hash_from)) - } - if self.parameters_from != output.parameters { - return Err(SyntaxError::InvalidOrderParameters(self.parameters_from.to_vec())) - } - // owned by maker - Ok(true) - } - - pub fn consume(&self, quantity: u64) -> Order { - Order { - asset_type_from: self.asset_type_from, - asset_type_to: self.asset_type_to, - asset_type_fee: self.asset_type_fee, - shard_id_from: self.shard_id_from, - shard_id_to: self.shard_id_to, - shard_id_fee: self.shard_id_fee, - asset_quantity_from: self.asset_quantity_from - quantity, - asset_quantity_to: self.asset_quantity_to - - (u128::from(quantity) * u128::from(self.asset_quantity_to) / u128::from(self.asset_quantity_from)) - as u64, - asset_quantity_fee: self.asset_quantity_fee - - (u128::from(quantity) * u128::from(self.asset_quantity_fee) / u128::from(self.asset_quantity_from)) - as u64, - origin_outputs: self.origin_outputs.clone(), - expiration: self.expiration, - lock_script_hash_from: self.lock_script_hash_from, - parameters_from: self.parameters_from.clone(), - lock_script_hash_fee: self.lock_script_hash_fee, - parameters_fee: self.parameters_fee.clone(), - } - } -} - -#[cfg(test)] -mod tests { - use super::*; - use primitives::H256; - - #[test] - fn verify_order_success() { - let asset_type_from = H160::random(); - let asset_type_to = H160::random(); - let asset_type_fee = H160::random(); - let order = Order { - asset_type_from, - asset_type_to, - asset_type_fee, - shard_id_from: 0, - shard_id_to: 0, - shard_id_fee: 0, - asset_quantity_from: 3, - asset_quantity_to: 2, - asset_quantity_fee: 3, - origin_outputs: vec![AssetOutPoint { - tracker: H256::random(), - index: 0, - asset_type: asset_type_from, - shard_id: 0, - quantity: 10, - }], - expiration: 10, - lock_script_hash_from: H160::random(), - parameters_from: vec![vec![1]], - lock_script_hash_fee: H160::random(), - parameters_fee: vec![vec![1]], - }; - assert_eq!(order.verify(), Ok(())); - - let order = Order { - asset_type_from, - asset_type_to, - asset_type_fee, - shard_id_from: 0, - shard_id_to: 0, - shard_id_fee: 0, - asset_quantity_from: 3, - asset_quantity_to: 2, - asset_quantity_fee: 0, - origin_outputs: vec![AssetOutPoint { - tracker: H256::random(), - index: 0, - asset_type: asset_type_from, - shard_id: 0, - quantity: 10, - }], - expiration: 10, - lock_script_hash_from: H160::random(), - parameters_from: vec![vec![1]], - lock_script_hash_fee: H160::random(), - parameters_fee: vec![vec![1]], - }; - assert_eq!(order.verify(), Ok(())); - - let order = Order { - asset_type_from, - asset_type_to, - asset_type_fee, - shard_id_from: 0, - shard_id_to: 0, - shard_id_fee: 0, - asset_quantity_from: 0, - asset_quantity_to: 0, - asset_quantity_fee: 0, - origin_outputs: vec![AssetOutPoint { - tracker: H256::random(), - index: 0, - asset_type: asset_type_from, - shard_id: 0, - quantity: 10, - }], - expiration: 10, - lock_script_hash_from: H160::random(), - parameters_from: vec![vec![1]], - lock_script_hash_fee: H160::random(), - parameters_fee: vec![vec![1]], - }; - assert_eq!(order.verify(), Ok(())); - } - - #[test] - fn verify_order_fail() { - // 1. origin outputs are invalid - let asset_type_from = H160::random(); - let asset_type_to = H160::random(); - let asset_type_fee = H160::random(); - let order = Order { - asset_type_from, - asset_type_to, - asset_type_fee, - shard_id_from: 0, - shard_id_to: 0, - shard_id_fee: 0, - asset_quantity_from: 3, - asset_quantity_to: 2, - asset_quantity_fee: 3, - origin_outputs: vec![AssetOutPoint { - tracker: H256::random(), - index: 0, - asset_type: H160::random(), - shard_id: 0, - quantity: 10, - }], - expiration: 10, - lock_script_hash_from: H160::random(), - parameters_from: vec![vec![1]], - lock_script_hash_fee: H160::random(), - parameters_fee: vec![vec![1]], - }; - assert_eq!(order.verify(), Err(SyntaxError::InvalidOriginOutputs(order.hash()))); - - let order = Order { - asset_type_from, - asset_type_to, - asset_type_fee, - shard_id_from: 0, - shard_id_to: 0, - shard_id_fee: 0, - asset_quantity_from: 3, - asset_quantity_to: 2, - asset_quantity_fee: 3, - origin_outputs: vec![], - expiration: 10, - lock_script_hash_from: H160::random(), - parameters_from: vec![vec![1]], - lock_script_hash_fee: H160::random(), - parameters_fee: vec![vec![1]], - }; - assert_eq!(order.verify(), Err(SyntaxError::InvalidOriginOutputs(order.hash()))); - - // 2. asset quantitys are invalid - let order = Order { - asset_type_from, - asset_type_to, - asset_type_fee, - shard_id_from: 0, - shard_id_to: 0, - shard_id_fee: 0, - asset_quantity_from: 3, - asset_quantity_to: 0, - asset_quantity_fee: 3, - origin_outputs: vec![AssetOutPoint { - tracker: H256::random(), - index: 0, - asset_type: asset_type_from, - shard_id: 0, - quantity: 10, - }], - expiration: 10, - lock_script_hash_from: H160::random(), - parameters_from: vec![vec![1]], - lock_script_hash_fee: H160::random(), - parameters_fee: vec![vec![1]], - }; - assert_eq!( - order.verify(), - Err(SyntaxError::InvalidOrderAssetQuantities { - from: 3, - to: 0, - fee: 3, - }) - ); - - let order = Order { - asset_type_from, - asset_type_to, - asset_type_fee, - shard_id_from: 0, - shard_id_to: 0, - shard_id_fee: 0, - asset_quantity_from: 0, - asset_quantity_to: 2, - asset_quantity_fee: 3, - origin_outputs: vec![AssetOutPoint { - tracker: H256::random(), - index: 0, - asset_type: asset_type_from, - shard_id: 0, - quantity: 10, - }], - expiration: 10, - lock_script_hash_from: H160::random(), - parameters_from: vec![vec![1]], - lock_script_hash_fee: H160::random(), - parameters_fee: vec![vec![1]], - }; - assert_eq!( - order.verify(), - Err(SyntaxError::InvalidOrderAssetQuantities { - from: 0, - to: 2, - fee: 3, - }) - ); - - let order = Order { - asset_type_from, - asset_type_to, - asset_type_fee, - shard_id_from: 0, - shard_id_to: 0, - shard_id_fee: 0, - asset_quantity_from: 0, - asset_quantity_to: 0, - asset_quantity_fee: 3, - origin_outputs: vec![AssetOutPoint { - tracker: H256::random(), - index: 0, - asset_type: asset_type_from, - shard_id: 0, - quantity: 10, - }], - expiration: 10, - lock_script_hash_from: H160::random(), - parameters_from: vec![vec![1]], - lock_script_hash_fee: H160::random(), - parameters_fee: vec![vec![1]], - }; - assert_eq!( - order.verify(), - Err(SyntaxError::InvalidOrderAssetQuantities { - from: 0, - to: 0, - fee: 3, - }) - ); - - let order = Order { - asset_type_from, - asset_type_to, - asset_type_fee, - shard_id_from: 0, - shard_id_to: 0, - shard_id_fee: 0, - asset_quantity_from: 3, - asset_quantity_to: 2, - asset_quantity_fee: 2, - origin_outputs: vec![AssetOutPoint { - tracker: H256::random(), - index: 0, - asset_type: asset_type_from, - shard_id: 0, - quantity: 10, - }], - expiration: 10, - lock_script_hash_from: H160::random(), - parameters_from: vec![vec![1]], - lock_script_hash_fee: H160::random(), - parameters_fee: vec![vec![1]], - }; - assert_eq!( - order.verify(), - Err(SyntaxError::InvalidOrderAssetQuantities { - from: 3, - to: 2, - fee: 2, - }) - ); - - // 3. asset types are same - let asset_type = H160::random(); - let order = Order { - asset_type_from: asset_type, - asset_type_to: asset_type, - asset_type_fee, - shard_id_from: 0, - shard_id_to: 0, - shard_id_fee: 0, - asset_quantity_from: 3, - asset_quantity_to: 2, - asset_quantity_fee: 3, - origin_outputs: vec![AssetOutPoint { - tracker: H256::random(), - index: 0, - asset_type, - shard_id: 0, - quantity: 10, - }], - expiration: 10, - lock_script_hash_from: H160::random(), - parameters_from: vec![vec![1]], - lock_script_hash_fee: H160::random(), - parameters_fee: vec![vec![1]], - }; - assert_eq!(order.verify(), Err(SyntaxError::InvalidOrderAssetTypes)); - } -} diff --git a/types/src/transaction/shard.rs b/types/src/transaction/shard.rs index 32c705b348..b417d49fe4 100644 --- a/types/src/transaction/shard.rs +++ b/types/src/transaction/shard.rs @@ -19,13 +19,10 @@ use ckey::{Address, NetworkId}; use primitives::{Bytes, H160, H256}; use rlp::{Decodable, DecoderError, Encodable, RlpStream, UntrustedRlp}; -use super::{ - AssetMintOutput, AssetTransferInput, AssetTransferOutput, HashingError, Order, OrderOnTransfer, PartialHashing, -}; +use super::{AssetMintOutput, AssetTransferInput, AssetTransferOutput, HashingError, PartialHashing}; use crate::util::tag::Tag; use crate::ShardId; - /// Shard Transaction type. #[derive(Debug, Clone, PartialEq, Eq)] pub enum ShardTransaction { @@ -43,7 +40,6 @@ pub enum ShardTransaction { burns: Vec, inputs: Vec, outputs: Vec, - orders: Vec, }, ChangeAssetScheme { network_id: NetworkId, @@ -281,12 +277,7 @@ impl PartialHashing for ShardTransaction { burns, inputs, outputs, - orders, } => { - if !orders.is_empty() && (!tag.sign_all_inputs || !tag.sign_all_outputs) { - return Err(HashingError::InvalidFilter) - } - let new_burns = apply_input_scheme(burns, tag.sign_all_inputs, is_burn, cur); let new_inputs = apply_input_scheme(inputs, tag.sign_all_inputs, !is_burn, cur); @@ -302,7 +293,6 @@ impl PartialHashing for ShardTransaction { burns: new_burns, inputs: new_inputs, outputs: new_outputs, - orders: orders.to_vec(), } .rlp_bytes(), &blake128(tag.get_tag()), @@ -337,21 +327,6 @@ impl PartialHashing for ShardTransaction { } } -impl Order { - pub fn hash(&self) -> H256 { - blake256(&self.rlp_bytes()) - } -} - -impl PartialHashing for Order { - fn hash_partially(&self, tag: Tag, _cur: &AssetTransferInput, is_burn: bool) -> Result { - assert!(tag.sign_all_inputs); - assert!(tag.sign_all_outputs); - assert!(!is_burn); - Ok(self.hash()) - } -} - type TransactionId = u8; const ASSET_UNWRAP_CCC_ID: TransactionId = 0x11; const ASSET_MINT_ID: TransactionId = 0x13; @@ -396,12 +371,15 @@ impl Decodable for ShardTransaction { expected: 6, }) } + let orders = d.list_at::(5)?; + if !orders.is_empty() { + return Err(DecoderError::Custom("orders must be an empty list")) + } Ok(ShardTransaction::TransferAsset { network_id: d.val_at(1)?, burns: d.list_at(2)?, inputs: d.list_at(3)?, outputs: d.list_at(4)?, - orders: d.list_at(5)?, }) } ASSET_SCHEME_CHANGE_ID => { @@ -496,15 +474,16 @@ impl Encodable for ShardTransaction { burns, inputs, outputs, - orders, } => { + let empty: Vec = vec![]; s.begin_list(6) .append(&ASSET_TRANSFER_ID) .append(network_id) .append_list(burns) .append_list(inputs) .append_list(outputs) - .append_list(orders); + // NOTE: The orders field removed. + .append_list(&empty); } ShardTransaction::ChangeAssetScheme { network_id, @@ -863,38 +842,6 @@ mod tests { shard_id: 0, quantity: 30, }], - orders: vec![OrderOnTransfer { - order: Order { - asset_type_from: H160::random(), - asset_type_to: H160::random(), - asset_type_fee: H160::random(), - shard_id_from: 0, - shard_id_to: 0, - shard_id_fee: 0, - asset_quantity_from: 10, - asset_quantity_to: 10, - asset_quantity_fee: 0, - origin_outputs: vec![AssetOutPoint { - tracker: H256::random(), - index: 0, - asset_type: H160::random(), - shard_id: 0, - quantity: 30, - }], - expiration: 10, - lock_script_hash_from: H160::random(), - parameters_from: vec![vec![1]], - lock_script_hash_fee: H160::random(), - parameters_fee: vec![vec![1]], - }, - spent_quantity: 10, - input_from_indices: vec![0], - input_fee_indices: vec![], - output_from_indices: vec![], - output_to_indices: vec![0], - output_owned_fee_indices: vec![], - output_transferred_fee_indices: vec![], - }], }; rlp_encode_and_decode_test!(tx); } @@ -942,7 +889,6 @@ mod tests { burns: Vec::new(), inputs: inputs.clone(), outputs: outputs.clone(), - orders: vec![], }; let mut tag: Vec = vec![0b0000_1111 as u8]; for _i in 0..12 { @@ -961,7 +907,6 @@ mod tests { burns: Vec::new(), inputs: inputs.clone(), outputs: outputs.clone(), - orders: vec![], }; tag = vec![0b0000_0111 as u8]; for _i in 0..12 { @@ -980,7 +925,6 @@ mod tests { burns: Vec::new(), inputs, outputs, - orders: vec![], }; tag = vec![0b0000_0011 as u8]; for _i in 0..12 { diff --git a/vm/tests/chk_multi_sig.rs b/vm/tests/chk_multi_sig.rs index 6296bf54d7..29ba62be0a 100644 --- a/vm/tests/chk_multi_sig.rs +++ b/vm/tests/chk_multi_sig.rs @@ -44,7 +44,6 @@ fn valid_multi_sig_0_of_2() { burns: Vec::new(), inputs: Vec::new(), outputs: Vec::new(), - orders: Vec::new(), }; let outpoint = AssetTransferInput { prev_out: AssetOutPoint { @@ -86,7 +85,6 @@ fn valid_multi_sig_1_of_2() { burns: Vec::new(), inputs: Vec::new(), outputs: Vec::new(), - orders: Vec::new(), }; let outpoint = AssetTransferInput { prev_out: AssetOutPoint { @@ -110,7 +108,6 @@ fn valid_multi_sig_1_of_2() { burns: Vec::new(), inputs: Vec::new(), outputs: Vec::new(), - orders: Vec::new(), } .rlp_bytes(), &blake128(&[0b11 as u8]), @@ -140,7 +137,6 @@ fn valid_multi_sig_2_of_2() { burns: Vec::new(), inputs: Vec::new(), outputs: Vec::new(), - orders: Vec::new(), }; let outpoint = AssetTransferInput { prev_out: AssetOutPoint { @@ -164,7 +160,6 @@ fn valid_multi_sig_2_of_2() { burns: Vec::new(), inputs: Vec::new(), outputs: Vec::new(), - orders: Vec::new(), } .rlp_bytes(), &blake128(&[0b11 as u8]), @@ -196,7 +191,6 @@ fn nvalid_multi_sig_2_of_2_duplicated() { burns: Vec::new(), inputs: Vec::new(), outputs: Vec::new(), - orders: Vec::new(), }; let outpoint = AssetTransferInput { prev_out: AssetOutPoint { @@ -220,7 +214,6 @@ fn nvalid_multi_sig_2_of_2_duplicated() { burns: Vec::new(), inputs: Vec::new(), outputs: Vec::new(), - orders: Vec::new(), } .rlp_bytes(), &blake128(&[0b11 as u8]), @@ -254,7 +247,6 @@ fn valid_multi_sig_2_of_3_110() { burns: Vec::new(), inputs: Vec::new(), outputs: Vec::new(), - orders: Vec::new(), }; let outpoint = AssetTransferInput { prev_out: AssetOutPoint { @@ -280,7 +272,6 @@ fn valid_multi_sig_2_of_3_110() { burns: Vec::new(), inputs: Vec::new(), outputs: Vec::new(), - orders: Vec::new(), } .rlp_bytes(), &blake128(&[0b11 as u8]), @@ -313,7 +304,6 @@ fn valid_multi_sig_2_of_3_101() { burns: Vec::new(), inputs: Vec::new(), outputs: Vec::new(), - orders: Vec::new(), }; let outpoint = AssetTransferInput { prev_out: AssetOutPoint { @@ -339,7 +329,6 @@ fn valid_multi_sig_2_of_3_101() { burns: Vec::new(), inputs: Vec::new(), outputs: Vec::new(), - orders: Vec::new(), } .rlp_bytes(), &blake128(&[0b11 as u8]), @@ -372,7 +361,6 @@ fn valid_multi_sig_2_of_3_011() { burns: Vec::new(), inputs: Vec::new(), outputs: Vec::new(), - orders: Vec::new(), }; let outpoint = AssetTransferInput { prev_out: AssetOutPoint { @@ -398,7 +386,6 @@ fn valid_multi_sig_2_of_3_011() { burns: Vec::new(), inputs: Vec::new(), outputs: Vec::new(), - orders: Vec::new(), } .rlp_bytes(), &blake128(&[0b11 as u8]), @@ -431,7 +418,6 @@ fn invalid_multi_sig_1_of_2() { burns: Vec::new(), inputs: Vec::new(), outputs: Vec::new(), - orders: Vec::new(), }; let outpoint = AssetTransferInput { prev_out: AssetOutPoint { @@ -455,7 +441,6 @@ fn invalid_multi_sig_1_of_2() { burns: Vec::new(), inputs: Vec::new(), outputs: Vec::new(), - orders: Vec::new(), } .rlp_bytes(), &blake128(&[0b11 as u8]), @@ -486,7 +471,6 @@ fn invalid_multi_sig_2_of_2() { burns: Vec::new(), inputs: Vec::new(), outputs: Vec::new(), - orders: Vec::new(), }; let outpoint = AssetTransferInput { prev_out: AssetOutPoint { @@ -510,7 +494,6 @@ fn invalid_multi_sig_2_of_2() { burns: Vec::new(), inputs: Vec::new(), outputs: Vec::new(), - orders: Vec::new(), } .rlp_bytes(), &blake128(&[0b11 as u8]), @@ -542,7 +525,6 @@ fn invalid_multi_sig_2_of_2_with_1_invalid_sig() { burns: Vec::new(), inputs: Vec::new(), outputs: Vec::new(), - orders: Vec::new(), }; let outpoint = AssetTransferInput { prev_out: AssetOutPoint { @@ -566,7 +548,6 @@ fn invalid_multi_sig_2_of_2_with_1_invalid_sig() { burns: Vec::new(), inputs: Vec::new(), outputs: Vec::new(), - orders: Vec::new(), } .rlp_bytes(), &blake128(&[0b11 as u8]), @@ -577,7 +558,6 @@ fn invalid_multi_sig_2_of_2_with_1_invalid_sig() { burns: Vec::new(), inputs: Vec::new(), outputs: Vec::new(), - orders: Vec::new(), } .rlp_bytes(), &blake128(&[0b11 as u8]), @@ -601,62 +581,6 @@ fn invalid_multi_sig_2_of_2_with_1_invalid_sig() { ); } -#[test] -fn invalid_multi_sig_2_of_2_with_changed_order_sig() { - let client = TestClient::default(); - let transaction = ShardTransaction::TransferAsset { - network_id: NetworkId::default(), - burns: Vec::new(), - inputs: Vec::new(), - outputs: Vec::new(), - orders: Vec::new(), - }; - let outpoint = AssetTransferInput { - prev_out: AssetOutPoint { - tracker: Default::default(), - index: 0, - asset_type: H160::default(), - shard_id: 0, - quantity: 0, - }, - timelock: None, - lock_script: Vec::new(), - unlock_script: Vec::new(), - }; - let keypair1 = KeyPair::from_private(Private::from(ONE_KEY)).unwrap(); - let keypair2 = KeyPair::from_private(Private::from(MINUS_ONE_KEY)).unwrap(); - let pubkey1 = <&[u8]>::from(keypair1.public()).to_vec(); - let pubkey2 = <&[u8]>::from(keypair2.public()).to_vec(); - let message = blake256_with_key( - &ShardTransaction::TransferAsset { - network_id: NetworkId::default(), - burns: Vec::new(), - inputs: Vec::new(), - outputs: Vec::new(), - orders: Vec::new(), - } - .rlp_bytes(), - &blake128(&[0b11 as u8]), - ); - let signature1 = sign(keypair1.private(), &message).unwrap().to_vec(); - let signature2 = sign(keypair2.private(), &message).unwrap().to_vec(); - - let unlock_script = - vec![Instruction::PushB(vec![0b11 as u8]), Instruction::PushB(signature2), Instruction::PushB(signature1)]; - let lock_script = vec![ - Instruction::PushB(vec![2]), - Instruction::PushB(pubkey1), - Instruction::PushB(pubkey2), - Instruction::PushB(vec![2]), - Instruction::ChkMultiSig, - ]; - - assert_eq!( - execute(&unlock_script, &[], &lock_script, &transaction, VMConfig::default(), &outpoint, false, &client, 0, 0), - Ok(ScriptResult::Fail) - ); -} - #[test] fn invalid_multi_sig_with_less_sig_than_m() { let client = TestClient::default(); @@ -665,7 +589,6 @@ fn invalid_multi_sig_with_less_sig_than_m() { burns: Vec::new(), inputs: Vec::new(), outputs: Vec::new(), - orders: Vec::new(), }; let outpoint = AssetTransferInput { prev_out: AssetOutPoint { @@ -689,7 +612,6 @@ fn invalid_multi_sig_with_less_sig_than_m() { burns: Vec::new(), inputs: Vec::new(), outputs: Vec::new(), - orders: Vec::new(), } .rlp_bytes(), &blake128(&[0b11 as u8]), @@ -719,7 +641,6 @@ fn invalid_multi_sig_with_more_sig_than_m() { burns: Vec::new(), inputs: Vec::new(), outputs: Vec::new(), - orders: Vec::new(), }; let outpoint = AssetTransferInput { prev_out: AssetOutPoint { @@ -743,7 +664,6 @@ fn invalid_multi_sig_with_more_sig_than_m() { burns: Vec::new(), inputs: Vec::new(), outputs: Vec::new(), - orders: Vec::new(), } .rlp_bytes(), &blake128(&[0b11 as u8]), @@ -775,7 +695,6 @@ fn invalid_multi_sig_with_too_many_arg() { burns: Vec::new(), inputs: Vec::new(), outputs: Vec::new(), - orders: Vec::new(), }; let outpoint = AssetTransferInput { prev_out: AssetOutPoint { @@ -797,7 +716,6 @@ fn invalid_multi_sig_with_too_many_arg() { burns: Vec::new(), inputs: Vec::new(), outputs: Vec::new(), - orders: Vec::new(), } .rlp_bytes(), &blake128(&[0b11 as u8]), diff --git a/vm/tests/chk_sig.rs b/vm/tests/chk_sig.rs index c77bade884..dae1a07757 100644 --- a/vm/tests/chk_sig.rs +++ b/vm/tests/chk_sig.rs @@ -44,7 +44,6 @@ fn valid_pay_to_public_key() { burns: Vec::new(), inputs: Vec::new(), outputs: Vec::new(), - orders: Vec::new(), }; let input = AssetTransferInput { prev_out: AssetOutPoint { @@ -66,7 +65,6 @@ fn valid_pay_to_public_key() { burns: Vec::new(), inputs: Vec::new(), outputs: Vec::new(), - orders: Vec::new(), } .rlp_bytes(), &blake128(&[0b11 as u8]), @@ -89,7 +87,6 @@ fn invalid_pay_to_public_key() { burns: Vec::new(), inputs: Vec::new(), outputs: Vec::new(), - orders: Vec::new(), }; let input = AssetTransferInput { prev_out: AssetOutPoint { @@ -111,7 +108,6 @@ fn invalid_pay_to_public_key() { burns: Vec::new(), inputs: Vec::new(), outputs: Vec::new(), - orders: Vec::new(), } .rlp_bytes(), &blake128(&[0b11 as u8]), @@ -180,7 +176,6 @@ fn sign_all_input_all_output() { burns: Vec::new(), inputs: vec![input0.clone(), input1.clone()], outputs: vec![output0.clone(), output1.clone()], - orders: Vec::new(), }; // Execute sciprt in input0 @@ -192,7 +187,6 @@ fn sign_all_input_all_output() { burns: Vec::new(), inputs: vec![input0.clone(), input1], outputs: vec![output0, output1], - orders: Vec::new(), } .rlp_bytes(), &blake128(&[0b11 as u8]), @@ -260,7 +254,6 @@ fn sign_single_input_all_output() { burns: Vec::new(), inputs: vec![input0.clone(), input1.clone()], outputs: vec![output0.clone(), output1.clone()], - orders: Vec::new(), }; // Execute sciprt in input0 @@ -272,7 +265,6 @@ fn sign_single_input_all_output() { burns: Vec::new(), inputs: vec![input0.clone()], outputs: vec![output0, output1], - orders: Vec::new(), } .rlp_bytes(), &blake128(&[0b10 as u8]), @@ -339,7 +331,6 @@ fn sign_all_input_partial_output() { burns: Vec::new(), inputs: vec![input0.clone(), input1.clone()], outputs: vec![output0.clone(), output1.clone()], - orders: Vec::new(), }; // Execute sciprt in input0 @@ -351,7 +342,6 @@ fn sign_all_input_partial_output() { burns: Vec::new(), inputs: vec![input0.clone(), input1], outputs: vec![output0], - orders: Vec::new(), } .rlp_bytes(), &blake128(&[0b1, 0b0000_0101 as u8]), @@ -418,7 +408,6 @@ fn sign_single_input_partial_output() { burns: Vec::new(), inputs: vec![input0.clone(), input1.clone()], outputs: vec![output0.clone(), output1.clone()], - orders: Vec::new(), }; // Execute sciprt in input0 @@ -430,7 +419,6 @@ fn sign_single_input_partial_output() { burns: Vec::new(), inputs: vec![input0.clone()], outputs: vec![output0], - orders: Vec::new(), } .rlp_bytes(), &blake128(&[0b1, 0b0000_0100 as u8]), @@ -475,7 +463,6 @@ fn distinguish_sign_single_input_with_sign_all() { burns: Vec::new(), inputs: vec![input0.clone()], outputs: vec![output0.clone()], - orders: Vec::new(), }; // Execute sciprt in input0 @@ -487,7 +474,6 @@ fn distinguish_sign_single_input_with_sign_all() { burns: Vec::new(), inputs: vec![input0.clone()], outputs: vec![output0], - orders: Vec::new(), } .rlp_bytes(), &blake128(&[0b11 as u8]), @@ -533,7 +519,6 @@ fn distinguish_sign_single_output_with_sign_all() { burns: Vec::new(), inputs: vec![input0.clone()], outputs: vec![output0.clone()], - orders: Vec::new(), }; // Execute sciprt in input0 @@ -545,7 +530,6 @@ fn distinguish_sign_single_output_with_sign_all() { burns: Vec::new(), inputs: vec![input0.clone()], outputs: vec![output0], - orders: Vec::new(), } .rlp_bytes(), &blake128(&[0b11 as u8]), diff --git a/vm/tests/executor.rs b/vm/tests/executor.rs index 52ec106358..9ff0a9fa35 100644 --- a/vm/tests/executor.rs +++ b/vm/tests/executor.rs @@ -39,7 +39,6 @@ fn simple_success() { burns: Vec::new(), inputs: Vec::new(), outputs: Vec::new(), - orders: Vec::new(), }; let input = AssetTransferInput { prev_out: AssetOutPoint { @@ -72,7 +71,6 @@ fn simple_failure() { burns: Vec::new(), inputs: Vec::new(), outputs: Vec::new(), - orders: Vec::new(), }; let input = AssetTransferInput { prev_out: AssetOutPoint { @@ -104,7 +102,6 @@ fn simple_burn() { burns: Vec::new(), inputs: Vec::new(), outputs: Vec::new(), - orders: Vec::new(), }; let input = AssetTransferInput { prev_out: AssetOutPoint { @@ -132,7 +129,6 @@ fn underflow() { burns: Vec::new(), inputs: Vec::new(), outputs: Vec::new(), - orders: Vec::new(), }; let input = AssetTransferInput { prev_out: AssetOutPoint { @@ -160,7 +156,6 @@ fn out_of_memory() { burns: Vec::new(), inputs: Vec::new(), outputs: Vec::new(), - orders: Vec::new(), }; let input = AssetTransferInput { prev_out: AssetOutPoint { @@ -202,7 +197,6 @@ fn invalid_unlock_script() { burns: Vec::new(), inputs: Vec::new(), outputs: Vec::new(), - orders: Vec::new(), }; let input = AssetTransferInput { prev_out: AssetOutPoint { @@ -230,7 +224,6 @@ fn conditional_burn() { burns: Vec::new(), inputs: Vec::new(), outputs: Vec::new(), - orders: Vec::new(), }; let input = AssetTransferInput { prev_out: AssetOutPoint { @@ -285,7 +278,6 @@ fn _blake256() { burns: Vec::new(), inputs: Vec::new(), outputs: Vec::new(), - orders: Vec::new(), }; let input = AssetTransferInput { prev_out: AssetOutPoint { @@ -370,7 +362,6 @@ fn _ripemd160() { burns: Vec::new(), inputs: Vec::new(), outputs: Vec::new(), - orders: Vec::new(), }; let input = AssetTransferInput { prev_out: AssetOutPoint { @@ -463,7 +454,6 @@ fn _sha256() { burns: Vec::new(), inputs: Vec::new(), outputs: Vec::new(), - orders: Vec::new(), }; let input = AssetTransferInput { prev_out: AssetOutPoint { @@ -556,7 +546,6 @@ fn _keccak256() { burns: Vec::new(), inputs: Vec::new(), outputs: Vec::new(), - orders: Vec::new(), }; let input = AssetTransferInput { prev_out: AssetOutPoint { @@ -648,7 +637,6 @@ fn dummy_tx() -> ShardTransaction { burns: Vec::new(), inputs: Vec::new(), outputs: Vec::new(), - orders: Vec::new(), } } @@ -916,7 +904,6 @@ fn copy_stack_underflow() { burns: Vec::new(), inputs: Vec::new(), outputs: Vec::new(), - orders: Vec::new(), }; let input = AssetTransferInput { prev_out: AssetOutPoint {