mirror of
https://github.com/serai-dex/serai.git
synced 2025-12-08 12:19:24 +00:00
Move serai-client off serai-runtime, MIT licensing it
Uses a full-fledged serai-abi to do so. Removes use of UncheckedExtrinsic as a pointlessly (for us) length-prefixed block with a more complicated signing algorithm than advantageous. In the future, we should considering consolidating the various primitives crates. I'm not convinced we benefit from one primitives crate per pallet.
This commit is contained in:
@@ -14,11 +14,11 @@ rustdoc-args = ["--cfg", "docsrs"]
|
||||
|
||||
[dependencies]
|
||||
scale = { package = "parity-scale-codec", version = "3", features = ["derive"] }
|
||||
scale-info = { version = "2", features = ["derive"] }
|
||||
|
||||
borsh = { version = "1", features = ["derive", "de_strict_order"], optional = true }
|
||||
serde = { version = "1", features = ["derive", "alloc"], optional = true }
|
||||
|
||||
sp-application-crypto = { git = "https://github.com/serai-dex/substrate" }
|
||||
sp-core = { git = "https://github.com/serai-dex/substrate" }
|
||||
sp-runtime = { git = "https://github.com/serai-dex/substrate" }
|
||||
|
||||
|
||||
@@ -2,13 +2,15 @@ use sp_consensus_babe::EquivocationProof;
|
||||
|
||||
use serai_primitives::Header;
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, Debug, scale::Encode, scale::Decode)]
|
||||
#[derive(Clone, PartialEq, Eq, Debug, scale::Encode, scale::Decode, scale_info::TypeInfo)]
|
||||
pub struct ReportEquivocation {
|
||||
pub equivocation_proof: Box<EquivocationProof<Header>>,
|
||||
pub key_owner_proof: (),
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, Debug, scale::Encode, scale::Decode)]
|
||||
// We could define a Babe Config here and use the literal pallet_babe::Call
|
||||
// The disadvantage to this would be the complexity and presence of junk fields such as `__Ignore`
|
||||
#[derive(Clone, PartialEq, Eq, Debug, scale::Encode, scale::Decode, scale_info::TypeInfo)]
|
||||
pub enum Call {
|
||||
report_equivocation(ReportEquivocation),
|
||||
report_equivocation_unsigned(ReportEquivocation),
|
||||
|
||||
@@ -3,7 +3,7 @@ use serai_primitives::{Balance, SeraiAddress};
|
||||
pub use serai_coins_primitives as primitives;
|
||||
use primitives::OutInstructionWithBalance;
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, Debug, scale::Encode, scale::Decode)]
|
||||
#[derive(Clone, PartialEq, Eq, Debug, scale::Encode, scale::Decode, scale_info::TypeInfo)]
|
||||
#[cfg_attr(feature = "borsh", derive(borsh::BorshSerialize, borsh::BorshDeserialize))]
|
||||
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||
pub enum Call {
|
||||
@@ -12,7 +12,7 @@ pub enum Call {
|
||||
burn_with_instruction { instruction: OutInstructionWithBalance },
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, Debug, scale::Encode, scale::Decode)]
|
||||
#[derive(Clone, PartialEq, Eq, Debug, scale::Encode, scale::Decode, scale_info::TypeInfo)]
|
||||
#[cfg_attr(feature = "borsh", derive(borsh::BorshSerialize, borsh::BorshDeserialize))]
|
||||
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||
pub enum Event {
|
||||
|
||||
@@ -6,7 +6,7 @@ type PoolId = Coin;
|
||||
type PoolCoinId = Coin;
|
||||
type MaxSwapPathLength = sp_core::ConstU32<3>;
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, Debug, scale::Encode, scale::Decode)]
|
||||
#[derive(Clone, PartialEq, Eq, Debug, scale::Encode, scale::Decode, scale_info::TypeInfo)]
|
||||
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||
pub enum Call {
|
||||
add_liquidity {
|
||||
@@ -38,7 +38,7 @@ pub enum Call {
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, Debug, scale::Encode, scale::Decode)]
|
||||
#[derive(Clone, PartialEq, Eq, Debug, scale::Encode, scale::Decode, scale_info::TypeInfo)]
|
||||
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||
pub enum Event {
|
||||
PoolCreated {
|
||||
|
||||
@@ -2,23 +2,24 @@ use sp_consensus_grandpa::EquivocationProof;
|
||||
|
||||
use serai_primitives::{BlockNumber, SeraiAddress};
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, Debug, scale::Encode, scale::Decode)]
|
||||
#[derive(Clone, PartialEq, Eq, Debug, scale::Encode, scale::Decode, scale_info::TypeInfo)]
|
||||
pub struct ReportEquivocation {
|
||||
pub equivocation_proof: Box<EquivocationProof<[u8; 32], BlockNumber>>,
|
||||
pub key_owner_proof: (),
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, Debug, scale::Encode, scale::Decode)]
|
||||
#[derive(Clone, PartialEq, Eq, Debug, scale::Encode, scale::Decode, scale_info::TypeInfo)]
|
||||
pub enum Call {
|
||||
report_equivocation(ReportEquivocation),
|
||||
report_equivocation_unsigned(ReportEquivocation),
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, Debug, scale::Encode, scale::Decode)]
|
||||
#[derive(Clone, PartialEq, Eq, Debug, scale::Encode, scale::Decode, scale_info::TypeInfo)]
|
||||
#[cfg_attr(feature = "borsh", derive(borsh::BorshSerialize, borsh::BorshDeserialize))]
|
||||
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||
pub enum Event {
|
||||
NewAuthorities { authority_set: Vec<(SeraiAddress, u64)> },
|
||||
// TODO: Remove these
|
||||
Paused,
|
||||
Resumed,
|
||||
}
|
||||
|
||||
@@ -3,14 +3,14 @@ use serai_primitives::*;
|
||||
pub use serai_in_instructions_primitives as primitives;
|
||||
use primitives::SignedBatch;
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, Debug, scale::Encode, scale::Decode)]
|
||||
#[derive(Clone, PartialEq, Eq, Debug, scale::Encode, scale::Decode, scale_info::TypeInfo)]
|
||||
#[cfg_attr(feature = "borsh", derive(borsh::BorshSerialize, borsh::BorshDeserialize))]
|
||||
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||
pub enum Call {
|
||||
execute_batch { batch: SignedBatch },
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, Debug, scale::Encode, scale::Decode)]
|
||||
#[derive(Clone, PartialEq, Eq, Debug, scale::Encode, scale::Decode, scale_info::TypeInfo)]
|
||||
#[cfg_attr(feature = "borsh", derive(borsh::BorshSerialize, borsh::BorshDeserialize))]
|
||||
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||
pub enum Event {
|
||||
|
||||
@@ -16,9 +16,11 @@ pub mod grandpa;
|
||||
|
||||
pub use serai_primitives as primitives;
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, Debug, scale::Encode, scale::Decode)]
|
||||
#[derive(Clone, PartialEq, Eq, Debug, scale::Encode, scale::Decode, scale_info::TypeInfo)]
|
||||
pub enum Call {
|
||||
System,
|
||||
Timestamp(timestamp::Call),
|
||||
TransactionPayment,
|
||||
Coins(coins::Call),
|
||||
LiquidityTokens(coins::Call),
|
||||
Dex(dex::Call),
|
||||
@@ -29,14 +31,43 @@ pub enum Call {
|
||||
Grandpa(grandpa::Call),
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, Debug, scale::Encode, scale::Decode)]
|
||||
// TODO: Remove this
|
||||
#[derive(Clone, PartialEq, Eq, Debug, scale::Encode, scale::Decode, scale_info::TypeInfo)]
|
||||
pub enum TransactionPaymentEvent {
|
||||
TransactionFeePaid { who: serai_primitives::SeraiAddress, actual_fee: u64, tip: u64 },
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, Debug, scale::Encode, scale::Decode, scale_info::TypeInfo)]
|
||||
pub enum Event {
|
||||
System(system::Event),
|
||||
Timestamp,
|
||||
TransactionPayment(TransactionPaymentEvent),
|
||||
Coins(coins::Event),
|
||||
LiquidityTokens(coins::Event),
|
||||
Dex(dex::Event),
|
||||
ValidatorSets(validator_sets::Event),
|
||||
InInstructions(in_instructions::Event),
|
||||
Signals(signals::Event),
|
||||
Babe,
|
||||
Grandpa(grandpa::Event),
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Debug, scale::Encode, scale::Decode, scale_info::TypeInfo)]
|
||||
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||
pub struct Extra {
|
||||
pub era: sp_runtime::generic::Era,
|
||||
pub nonce: scale::Compact<u32>,
|
||||
pub tip: scale::Compact<u64>,
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, Debug, scale::Encode, scale::Decode, scale_info::TypeInfo)]
|
||||
#[cfg_attr(feature = "borsh", derive(borsh::BorshSerialize, borsh::BorshDeserialize))]
|
||||
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||
pub struct SignedPayloadExtra {
|
||||
pub spec_version: u32,
|
||||
pub tx_version: u32,
|
||||
pub genesis: [u8; 32],
|
||||
pub mortality_checkpoint: [u8; 32],
|
||||
}
|
||||
|
||||
pub type Transaction = primitives::Transaction<Call, Extra>;
|
||||
|
||||
@@ -5,7 +5,7 @@ use serai_validator_sets_primitives::ValidatorSet;
|
||||
pub use serai_signals_primitives as primitives;
|
||||
use primitives::SignalId;
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, Debug, scale::Encode, scale::Decode)]
|
||||
#[derive(Clone, PartialEq, Eq, Debug, scale::Encode, scale::Decode, scale_info::TypeInfo)]
|
||||
#[cfg_attr(feature = "borsh", derive(borsh::BorshSerialize, borsh::BorshDeserialize))]
|
||||
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||
pub enum Call {
|
||||
@@ -16,7 +16,7 @@ pub enum Call {
|
||||
stand_against { signal_id: SignalId, for_network: NetworkId },
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, Debug, scale::Encode, scale::Decode)]
|
||||
#[derive(Clone, PartialEq, Eq, Debug, scale::Encode, scale::Decode, scale_info::TypeInfo)]
|
||||
#[cfg_attr(feature = "borsh", derive(borsh::BorshSerialize, borsh::BorshDeserialize))]
|
||||
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||
pub enum Event {
|
||||
|
||||
@@ -1,8 +1,14 @@
|
||||
use frame_support::dispatch::{DispatchInfo, DispatchError};
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, Debug, scale::Encode, scale::Decode)]
|
||||
use serai_primitives::SeraiAddress;
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, Debug, scale::Encode, scale::Decode, scale_info::TypeInfo)]
|
||||
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||
pub enum Event {
|
||||
ExtrinsicSuccess { dispatch_info: DispatchInfo },
|
||||
ExtrinsicFailed { dispatch_error: DispatchError, dispatch_info: DispatchInfo },
|
||||
CodeUpdated,
|
||||
NewAccount { account: SeraiAddress },
|
||||
KilledAccount { account: SeraiAddress },
|
||||
Remarked { sender: SeraiAddress, hash: [u8; 32] },
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
#[derive(Clone, PartialEq, Eq, Debug, scale::Encode, scale::Decode)]
|
||||
#[cfg_attr(feature = "borsh", derive(borsh::BorshSerialize, borsh::BorshDeserialize))]
|
||||
#[derive(Clone, PartialEq, Eq, Debug, scale::Encode, scale::Decode, scale_info::TypeInfo)]
|
||||
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||
pub enum Call {
|
||||
set { now: u64 },
|
||||
set { now: scale::Compact<u64> },
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@ pub use serai_validator_sets_primitives as primitives;
|
||||
use serai_primitives::*;
|
||||
use serai_validator_sets_primitives::*;
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, Debug, scale::Encode, scale::Decode)]
|
||||
#[derive(Clone, PartialEq, Eq, Debug, scale::Encode, scale::Decode, scale_info::TypeInfo)]
|
||||
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||
pub enum Call {
|
||||
set_keys {
|
||||
@@ -31,7 +31,7 @@ pub enum Call {
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, Debug, scale::Encode, scale::Decode)]
|
||||
#[derive(Clone, PartialEq, Eq, Debug, scale::Encode, scale::Decode, scale_info::TypeInfo)]
|
||||
#[cfg_attr(feature = "borsh", derive(borsh::BorshSerialize, borsh::BorshDeserialize))]
|
||||
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||
pub enum Event {
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
name = "serai-client"
|
||||
version = "0.1.0"
|
||||
description = "Client library for the Serai network"
|
||||
license = "AGPL-3.0-only"
|
||||
license = "MIT"
|
||||
repository = "https://github.com/serai-dex/serai/tree/develop/substrate/client"
|
||||
authors = ["Luke Parker <lukeparker5132@gmail.com>"]
|
||||
keywords = ["serai"]
|
||||
@@ -19,13 +19,16 @@ thiserror = { version = "1", optional = true }
|
||||
|
||||
hex = "0.4"
|
||||
scale = { package = "parity-scale-codec", version = "3" }
|
||||
serde = { version = "1", features = ["derive"] }
|
||||
serde_json = "1"
|
||||
serde = { version = "1", features = ["derive"], optional = true }
|
||||
serde_json = { version = "1", optional = true }
|
||||
|
||||
sp-core = { git = "https://github.com/serai-dex/substrate" }
|
||||
sp-runtime = { git = "https://github.com/serai-dex/substrate" }
|
||||
serai-runtime = { path = "../runtime", version = "0.1" }
|
||||
simple-request = { path = "../../common/request", version = "0.1" }
|
||||
serai-abi = { path = "../abi", version = "0.1" }
|
||||
|
||||
sp-core = { git = "https://github.com/serai-dex/substrate", optional = true }
|
||||
sp-runtime = { git = "https://github.com/serai-dex/substrate", optional = true }
|
||||
frame-system = { git = "https://github.com/serai-dex/substrate", optional = true }
|
||||
|
||||
simple-request = { path = "../../common/request", version = "0.1", optional = true }
|
||||
|
||||
bitcoin = { version = "0.31", optional = true }
|
||||
|
||||
@@ -48,7 +51,7 @@ dockertest = "0.4"
|
||||
serai-docker-tests = { path = "../../tests/docker" }
|
||||
|
||||
[features]
|
||||
serai = ["thiserror"]
|
||||
serai = ["thiserror", "serde", "serde_json", "sp-core", "sp-runtime", "frame-system", "simple-request"]
|
||||
|
||||
networks = []
|
||||
bitcoin = ["networks", "dep:bitcoin"]
|
||||
|
||||
@@ -1,15 +1,21 @@
|
||||
AGPL-3.0-only license
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2022-2023 Luke Parker
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License Version 3 as
|
||||
published by the Free Software Foundation.
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
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.
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
||||
@@ -6,19 +6,18 @@ mod serai;
|
||||
#[cfg(feature = "serai")]
|
||||
pub use serai::*;
|
||||
|
||||
// If we aren't exposing the Serai client (subxt), still expose all primitives
|
||||
#[cfg(not(feature = "serai"))]
|
||||
pub use serai_runtime::primitives;
|
||||
pub use serai_abi::primitives;
|
||||
#[cfg(not(feature = "serai"))]
|
||||
mod other_primitives {
|
||||
pub mod in_instructions {
|
||||
pub use serai_runtime::in_instructions::primitives;
|
||||
}
|
||||
pub mod coins {
|
||||
pub use serai_runtime::coins::primitives;
|
||||
pub use serai_abi::coins::primitives;
|
||||
}
|
||||
pub mod validator_sets {
|
||||
pub use serai_runtime::validator_sets::primitives;
|
||||
pub use serai_abi::validator_sets::primitives;
|
||||
}
|
||||
pub mod in_instructions {
|
||||
pub use serai_abi::in_instructions::primitives;
|
||||
}
|
||||
}
|
||||
#[cfg(not(feature = "serai"))]
|
||||
|
||||
@@ -1,17 +1,14 @@
|
||||
use scale::Encode;
|
||||
|
||||
use serai_runtime::{
|
||||
primitives::{SeraiAddress, Amount, Coin, Balance},
|
||||
coins, Runtime,
|
||||
};
|
||||
pub use coins::primitives;
|
||||
use serai_abi::primitives::{SeraiAddress, Amount, Coin, Balance};
|
||||
pub use serai_abi::coins::primitives;
|
||||
use primitives::OutInstructionWithBalance;
|
||||
|
||||
use crate::{TemporalSerai, SeraiError};
|
||||
|
||||
const PALLET: &str = "Coins";
|
||||
|
||||
pub type CoinsEvent = coins::Event<Runtime>;
|
||||
pub type CoinsEvent = serai_abi::coins::Event;
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct SeraiCoins<'a>(pub(crate) TemporalSerai<'a>);
|
||||
@@ -24,7 +21,7 @@ impl<'a> SeraiCoins<'a> {
|
||||
self
|
||||
.0
|
||||
.events(|event| {
|
||||
if let serai_runtime::RuntimeEvent::Coins(event) = event {
|
||||
if let serai_abi::Event::Coins(event) = event {
|
||||
Some(event).filter(|event| matches!(event, CoinsEvent::Mint { .. }))
|
||||
} else {
|
||||
None
|
||||
@@ -37,7 +34,7 @@ impl<'a> SeraiCoins<'a> {
|
||||
self
|
||||
.0
|
||||
.events(|event| {
|
||||
if let serai_runtime::RuntimeEvent::Coins(event) = event {
|
||||
if let serai_abi::Event::Coins(event) = event {
|
||||
Some(event).filter(|event| matches!(event, CoinsEvent::BurnWithInstruction { .. }))
|
||||
} else {
|
||||
None
|
||||
@@ -68,22 +65,15 @@ impl<'a> SeraiCoins<'a> {
|
||||
)
|
||||
}
|
||||
|
||||
pub fn transfer(to: SeraiAddress, balance: Balance) -> serai_runtime::RuntimeCall {
|
||||
serai_runtime::RuntimeCall::Coins(serai_runtime::coins::Call::<Runtime>::transfer {
|
||||
to: to.into(),
|
||||
balance,
|
||||
})
|
||||
pub fn transfer(to: SeraiAddress, balance: Balance) -> serai_abi::Call {
|
||||
serai_abi::Call::Coins(serai_abi::coins::Call::transfer { to, balance })
|
||||
}
|
||||
|
||||
pub fn burn(balance: Balance) -> serai_runtime::RuntimeCall {
|
||||
serai_runtime::RuntimeCall::Coins(serai_runtime::coins::Call::<Runtime>::burn { balance })
|
||||
pub fn burn(balance: Balance) -> serai_abi::Call {
|
||||
serai_abi::Call::Coins(serai_abi::coins::Call::burn { balance })
|
||||
}
|
||||
|
||||
pub fn burn_with_instruction(
|
||||
instruction: OutInstructionWithBalance,
|
||||
) -> serai_runtime::RuntimeCall {
|
||||
serai_runtime::RuntimeCall::Coins(
|
||||
serai_runtime::coins::Call::<Runtime>::burn_with_instruction { instruction },
|
||||
)
|
||||
pub fn burn_with_instruction(instruction: OutInstructionWithBalance) -> serai_abi::Call {
|
||||
serai_abi::Call::Coins(serai_abi::coins::Call::burn_with_instruction { instruction })
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,12 +1,9 @@
|
||||
use sp_core::bounded_vec::BoundedVec;
|
||||
use serai_runtime::{
|
||||
primitives::{SeraiAddress, Amount, Coin},
|
||||
dex, Runtime,
|
||||
};
|
||||
use serai_abi::primitives::{SeraiAddress, Amount, Coin};
|
||||
|
||||
use crate::{SeraiError, TemporalSerai};
|
||||
|
||||
pub type DexEvent = dex::Event<Runtime>;
|
||||
pub type DexEvent = serai_abi::dex::Event;
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct SeraiDex<'a>(pub(crate) TemporalSerai<'a>);
|
||||
@@ -14,15 +11,7 @@ impl<'a> SeraiDex<'a> {
|
||||
pub async fn events(&self) -> Result<Vec<DexEvent>, SeraiError> {
|
||||
self
|
||||
.0
|
||||
.events(
|
||||
|event| {
|
||||
if let serai_runtime::RuntimeEvent::Dex(event) = event {
|
||||
Some(event)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
},
|
||||
)
|
||||
.events(|event| if let serai_abi::Event::Dex(event) = event { Some(event) } else { None })
|
||||
.await
|
||||
}
|
||||
|
||||
@@ -33,14 +22,14 @@ impl<'a> SeraiDex<'a> {
|
||||
min_coin_amount: Amount,
|
||||
min_sri_amount: Amount,
|
||||
address: SeraiAddress,
|
||||
) -> serai_runtime::RuntimeCall {
|
||||
serai_runtime::RuntimeCall::Dex(dex::Call::<Runtime>::add_liquidity {
|
||||
) -> serai_abi::Call {
|
||||
serai_abi::Call::Dex(serai_abi::dex::Call::add_liquidity {
|
||||
coin,
|
||||
coin_desired: coin_amount.0,
|
||||
sri_desired: sri_amount.0,
|
||||
coin_min: min_coin_amount.0,
|
||||
sri_min: min_sri_amount.0,
|
||||
mint_to: address.into(),
|
||||
mint_to: address,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -50,7 +39,7 @@ impl<'a> SeraiDex<'a> {
|
||||
amount_in: Amount,
|
||||
amount_out_min: Amount,
|
||||
address: SeraiAddress,
|
||||
) -> serai_runtime::RuntimeCall {
|
||||
) -> serai_abi::Call {
|
||||
let path = if to_coin.is_native() {
|
||||
BoundedVec::try_from(vec![from_coin, Coin::Serai]).unwrap()
|
||||
} else if from_coin.is_native() {
|
||||
@@ -59,11 +48,11 @@ impl<'a> SeraiDex<'a> {
|
||||
BoundedVec::try_from(vec![from_coin, Coin::Serai, to_coin]).unwrap()
|
||||
};
|
||||
|
||||
serai_runtime::RuntimeCall::Dex(dex::Call::<Runtime>::swap_exact_tokens_for_tokens {
|
||||
serai_abi::Call::Dex(serai_abi::dex::Call::swap_exact_tokens_for_tokens {
|
||||
path,
|
||||
amount_in: amount_in.0,
|
||||
amount_out_min: amount_out_min.0,
|
||||
send_to: address.into(),
|
||||
send_to: address,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,13 +1,12 @@
|
||||
use serai_runtime::{in_instructions, Runtime};
|
||||
pub use in_instructions::primitives;
|
||||
pub use serai_abi::in_instructions::primitives;
|
||||
use primitives::SignedBatch;
|
||||
|
||||
use crate::{
|
||||
primitives::{BlockHash, NetworkId},
|
||||
SeraiError, Serai, TemporalSerai,
|
||||
Transaction, SeraiError, Serai, TemporalSerai,
|
||||
};
|
||||
|
||||
pub type InInstructionsEvent = in_instructions::Event<Runtime>;
|
||||
pub type InInstructionsEvent = serai_abi::in_instructions::Event;
|
||||
|
||||
const PALLET: &str = "InInstructions";
|
||||
|
||||
@@ -36,7 +35,7 @@ impl<'a> SeraiInInstructions<'a> {
|
||||
self
|
||||
.0
|
||||
.events(|event| {
|
||||
if let serai_runtime::RuntimeEvent::InInstructions(event) = event {
|
||||
if let serai_abi::Event::InInstructions(event) = event {
|
||||
Some(event).filter(|event| matches!(event, InInstructionsEvent::Batch { .. }))
|
||||
} else {
|
||||
None
|
||||
@@ -45,9 +44,9 @@ impl<'a> SeraiInInstructions<'a> {
|
||||
.await
|
||||
}
|
||||
|
||||
pub fn execute_batch(batch: SignedBatch) -> Vec<u8> {
|
||||
Serai::unsigned(&serai_runtime::RuntimeCall::InInstructions(
|
||||
in_instructions::Call::<Runtime>::execute_batch { batch },
|
||||
pub fn execute_batch(batch: SignedBatch) -> Transaction {
|
||||
Serai::unsigned(serai_abi::Call::InInstructions(
|
||||
serai_abi::in_instructions::Call::execute_batch { batch },
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,11 +10,12 @@ pub use sp_core::{
|
||||
sr25519::{Public, Pair},
|
||||
};
|
||||
|
||||
pub use serai_runtime::primitives;
|
||||
pub use primitives::{SeraiAddress, Signature, Amount};
|
||||
pub use serai_abi as abi;
|
||||
pub use abi::{primitives, Transaction};
|
||||
use abi::*;
|
||||
|
||||
pub use serai_runtime as runtime;
|
||||
use serai_runtime::{Header, Block as SeraiBlock};
|
||||
pub use primitives::{SeraiAddress, Signature, Amount};
|
||||
use primitives::Header;
|
||||
|
||||
pub mod coins;
|
||||
pub use coins::SeraiCoins;
|
||||
@@ -25,36 +26,28 @@ pub use in_instructions::SeraiInInstructions;
|
||||
pub mod validator_sets;
|
||||
pub use validator_sets::SeraiValidatorSets;
|
||||
|
||||
pub type Transaction = serai_runtime::UncheckedExtrinsic;
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct Block(SeraiBlock);
|
||||
#[derive(Clone, PartialEq, Eq, Debug, scale::Encode, scale::Decode)]
|
||||
pub struct Block {
|
||||
pub header: Header,
|
||||
pub transactions: Vec<Transaction>,
|
||||
}
|
||||
impl Block {
|
||||
pub fn hash(&self) -> [u8; 32] {
|
||||
self.0.header.hash().into()
|
||||
self.header.hash().into()
|
||||
}
|
||||
pub fn number(&self) -> u64 {
|
||||
self.0.header.number
|
||||
self.header.number
|
||||
}
|
||||
|
||||
/// Returns the time of this block, set by its producer, in milliseconds since the epoch.
|
||||
pub fn time(&self) -> Result<u64, SeraiError> {
|
||||
for extrinsic in &self.0.extrinsics {
|
||||
if let serai_runtime::RuntimeCall::Timestamp(serai_runtime::timestamp::Call::set { now }) =
|
||||
&extrinsic.function
|
||||
{
|
||||
return Ok(*now);
|
||||
for transaction in &self.transactions {
|
||||
if let Call::Timestamp(timestamp::Call::set { now }) = &transaction.call {
|
||||
return Ok(u64::from(*now));
|
||||
}
|
||||
}
|
||||
Err(SeraiError::InvalidNode("no time was present in block".to_string()))
|
||||
}
|
||||
|
||||
pub fn header(&self) -> &Header {
|
||||
&self.0.header
|
||||
}
|
||||
pub fn transactions(&self) -> &[Transaction] {
|
||||
&self.0.extrinsics
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Error, Debug)]
|
||||
@@ -158,54 +151,37 @@ impl Serai {
|
||||
Ok(res)
|
||||
}
|
||||
|
||||
fn unsigned(call: &serai_runtime::RuntimeCall) -> Vec<u8> {
|
||||
// TODO: Should Serai purge the old transaction code AND set this to 0/1?
|
||||
const EXTRINSIC_FORMAT_VERSION: u8 = 4;
|
||||
|
||||
let mut tx = vec![EXTRINSIC_FORMAT_VERSION];
|
||||
tx.extend(call.encode());
|
||||
|
||||
let mut length_prefixed = Compact(u32::try_from(tx.len()).unwrap()).encode();
|
||||
length_prefixed.extend(tx);
|
||||
length_prefixed
|
||||
fn unsigned(call: Call) -> Transaction {
|
||||
Transaction { call, signature: None }
|
||||
}
|
||||
|
||||
pub fn sign(
|
||||
&self,
|
||||
signer: &Pair,
|
||||
call: &serai_runtime::RuntimeCall,
|
||||
nonce: u32,
|
||||
tip: u64,
|
||||
) -> Vec<u8> {
|
||||
pub fn sign(&self, signer: &Pair, call: Call, nonce: u32, tip: u64) -> Transaction {
|
||||
const SPEC_VERSION: u32 = 1;
|
||||
const TX_VERSION: u32 = 1;
|
||||
const EXTRINSIC_FORMAT_VERSION: u8 = 4;
|
||||
|
||||
let era = sp_runtime::generic::Era::Immortal;
|
||||
let extra = (era, Compact(nonce), Compact(tip));
|
||||
let genesis = self.genesis;
|
||||
let mortality_checkpoint = genesis;
|
||||
let mut signature_payload =
|
||||
(call, extra, SPEC_VERSION, TX_VERSION, genesis, mortality_checkpoint).encode();
|
||||
if signature_payload.len() > 256 {
|
||||
signature_payload = sp_core::blake2_256(&signature_payload).to_vec();
|
||||
}
|
||||
let extra =
|
||||
Extra { era: sp_runtime::generic::Era::Immortal, nonce: Compact(nonce), tip: Compact(tip) };
|
||||
let signature_payload = (
|
||||
&call,
|
||||
&extra,
|
||||
SignedPayloadExtra {
|
||||
spec_version: SPEC_VERSION,
|
||||
tx_version: TX_VERSION,
|
||||
genesis: self.genesis,
|
||||
mortality_checkpoint: self.genesis,
|
||||
},
|
||||
)
|
||||
.encode();
|
||||
let signature = signer.sign(&signature_payload);
|
||||
|
||||
let signed = 1 << 7;
|
||||
let tx = (signed + EXTRINSIC_FORMAT_VERSION, signer.public(), signature, extra, call).encode();
|
||||
|
||||
let mut length_prefixed = Compact(u32::try_from(tx.len()).unwrap()).encode();
|
||||
length_prefixed.extend(tx);
|
||||
length_prefixed
|
||||
Transaction { call, signature: Some((signer.public().into(), signature, extra)) }
|
||||
}
|
||||
|
||||
// TODO: Move this to take in Transaction
|
||||
pub async fn publish(&self, tx: &[u8]) -> Result<(), SeraiError> {
|
||||
pub async fn publish(&self, tx: &Transaction) -> Result<(), SeraiError> {
|
||||
// Drop the returned hash, which is the hash of the raw extrinsic, as extrinsics are allowed
|
||||
// to share hashes and this hash is accordingly useless/unsafe
|
||||
// If we are to return something, it should be block included in and position within block
|
||||
let _: String = self.call("author_submitExtrinsic", [hex::encode(tx)]).await?;
|
||||
let _: String = self.call("author_submitExtrinsic", [hex::encode(tx.encode())]).await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -221,14 +197,15 @@ impl Serai {
|
||||
}
|
||||
|
||||
pub async fn block(&self, hash: [u8; 32]) -> Result<Option<Block>, SeraiError> {
|
||||
// TODO: Remove this wrapping from Serai?
|
||||
#[derive(Deserialize)]
|
||||
struct WrappedBlock {
|
||||
block: SeraiBlock,
|
||||
}
|
||||
let block: Option<WrappedBlock> = self.call("chain_getBlock", [hex::encode(hash)]).await?;
|
||||
let block: Option<String> = self.call("chain_getBlockBin", [hex::encode(hash)]).await?;
|
||||
let Some(block) = block else { return Ok(None) };
|
||||
Ok(Some(Block(block.block)))
|
||||
let Ok(bytes) = Self::hex_decode(block) else {
|
||||
Err(SeraiError::InvalidNode("didn't return a hex-encoded block".to_string()))?
|
||||
};
|
||||
let Ok(block) = Block::decode(&mut bytes.as_slice()) else {
|
||||
Err(SeraiError::InvalidNode("didn't return a block".to_string()))?
|
||||
};
|
||||
Ok(Some(block))
|
||||
}
|
||||
|
||||
pub async fn latest_finalized_block(&self) -> Result<Block, SeraiError> {
|
||||
@@ -276,7 +253,7 @@ impl Serai {
|
||||
let hash = self.block_hash(number).await?;
|
||||
let Some(hash) = hash else { return Ok(None) };
|
||||
let Some(block) = self.block(hash).await? else { return Ok(None) };
|
||||
if !self.is_finalized(&block.0.header).await? {
|
||||
if !self.is_finalized(&block.header).await? {
|
||||
return Ok(None);
|
||||
}
|
||||
Ok(Some(block))
|
||||
@@ -326,14 +303,10 @@ impl<'a> TemporalSerai<'a> {
|
||||
self.0
|
||||
}
|
||||
|
||||
async fn events<E>(
|
||||
&self,
|
||||
filter_map: impl Fn(serai_runtime::RuntimeEvent) -> Option<E>,
|
||||
) -> Result<Vec<E>, SeraiError> {
|
||||
async fn events<E>(&self, filter_map: impl Fn(Event) -> Option<E>) -> Result<Vec<E>, SeraiError> {
|
||||
let mut res = vec![];
|
||||
let all_events: Option<
|
||||
Vec<serai_runtime::system::EventRecord<serai_runtime::RuntimeEvent, [u8; 32]>>,
|
||||
> = self.storage("System", "Events", ()).await?;
|
||||
let all_events: Option<Vec<frame_system::EventRecord<Event, [u8; 32]>>> =
|
||||
self.storage("System", "Events", ()).await?;
|
||||
#[allow(clippy::unwrap_or_default)]
|
||||
for event in all_events.unwrap_or(vec![]) {
|
||||
if let Some(event) = filter_map(event.event) {
|
||||
|
||||
@@ -2,15 +2,18 @@ use scale::Encode;
|
||||
|
||||
use sp_core::sr25519::{Public, Signature};
|
||||
|
||||
use serai_runtime::{primitives::Amount, validator_sets, Runtime};
|
||||
pub use validator_sets::primitives;
|
||||
use serai_abi::primitives::Amount;
|
||||
pub use serai_abi::validator_sets::primitives;
|
||||
use primitives::{Session, ValidatorSet, KeyPair};
|
||||
|
||||
use crate::{primitives::NetworkId, Serai, TemporalSerai, SeraiError};
|
||||
use crate::{
|
||||
primitives::{NetworkId, SeraiAddress},
|
||||
Transaction, Serai, TemporalSerai, SeraiError,
|
||||
};
|
||||
|
||||
const PALLET: &str = "ValidatorSets";
|
||||
|
||||
pub type ValidatorSetsEvent = validator_sets::Event<Runtime>;
|
||||
pub type ValidatorSetsEvent = serai_abi::validator_sets::Event;
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct SeraiValidatorSets<'a>(pub(crate) TemporalSerai<'a>);
|
||||
@@ -23,7 +26,7 @@ impl<'a> SeraiValidatorSets<'a> {
|
||||
self
|
||||
.0
|
||||
.events(|event| {
|
||||
if let serai_runtime::RuntimeEvent::ValidatorSets(event) = event {
|
||||
if let serai_abi::Event::ValidatorSets(event) = event {
|
||||
Some(event).filter(|event| matches!(event, ValidatorSetsEvent::NewSet { .. }))
|
||||
} else {
|
||||
None
|
||||
@@ -36,7 +39,7 @@ impl<'a> SeraiValidatorSets<'a> {
|
||||
self
|
||||
.0
|
||||
.events(|event| {
|
||||
if let serai_runtime::RuntimeEvent::ValidatorSets(event) = event {
|
||||
if let serai_abi::Event::ValidatorSets(event) = event {
|
||||
Some(event).filter(|event| matches!(event, ValidatorSetsEvent::KeyGen { .. }))
|
||||
} else {
|
||||
None
|
||||
@@ -49,7 +52,7 @@ impl<'a> SeraiValidatorSets<'a> {
|
||||
self
|
||||
.0
|
||||
.events(|event| {
|
||||
if let serai_runtime::RuntimeEvent::ValidatorSets(event) = event {
|
||||
if let serai_abi::Event::ValidatorSets(event) = event {
|
||||
Some(event).filter(|event| matches!(event, ValidatorSetsEvent::SetRetired { .. }))
|
||||
} else {
|
||||
None
|
||||
@@ -107,20 +110,22 @@ impl<'a> SeraiValidatorSets<'a> {
|
||||
self.0.storage(PALLET, "Keys", (sp_core::hashing::twox_64(&set.encode()), set)).await
|
||||
}
|
||||
|
||||
pub fn set_keys(network: NetworkId, key_pair: KeyPair, signature: Signature) -> Vec<u8> {
|
||||
Serai::unsigned(&serai_runtime::RuntimeCall::ValidatorSets(
|
||||
validator_sets::Call::<Runtime>::set_keys { network, key_pair, signature },
|
||||
))
|
||||
pub fn set_keys(network: NetworkId, key_pair: KeyPair, signature: Signature) -> Transaction {
|
||||
Serai::unsigned(serai_abi::Call::ValidatorSets(serai_abi::validator_sets::Call::set_keys {
|
||||
network,
|
||||
key_pair,
|
||||
signature,
|
||||
}))
|
||||
}
|
||||
|
||||
pub fn remove_participant(
|
||||
network: NetworkId,
|
||||
to_remove: Public,
|
||||
signers: Vec<Public>,
|
||||
to_remove: SeraiAddress,
|
||||
signers: Vec<SeraiAddress>,
|
||||
signature: Signature,
|
||||
) -> Vec<u8> {
|
||||
Serai::unsigned(&serai_runtime::RuntimeCall::ValidatorSets(
|
||||
validator_sets::Call::<Runtime>::remove_participant {
|
||||
) -> Transaction {
|
||||
Serai::unsigned(serai_abi::Call::ValidatorSets(
|
||||
serai_abi::validator_sets::Call::remove_participant {
|
||||
network,
|
||||
to_remove,
|
||||
signers,
|
||||
|
||||
@@ -67,7 +67,7 @@ serai_test!(
|
||||
let serai = serai.coins();
|
||||
assert_eq!(
|
||||
serai.mint_events().await.unwrap(),
|
||||
vec![CoinsEvent::Mint { to: address.into(), balance }]
|
||||
vec![CoinsEvent::Mint { to: address, balance }]
|
||||
);
|
||||
assert_eq!(serai.coin_supply(coin).await.unwrap(), amount);
|
||||
assert_eq!(serai.coin_balance(coin, address).await.unwrap(), amount);
|
||||
|
||||
@@ -7,7 +7,7 @@ use blake2::{
|
||||
|
||||
use scale::Encode;
|
||||
|
||||
use serai_runtime::coins::primitives::OutInstructionWithBalance;
|
||||
use serai_abi::coins::primitives::OutInstructionWithBalance;
|
||||
use sp_core::Pair;
|
||||
|
||||
use serai_client::{
|
||||
@@ -68,7 +68,7 @@ serai_test!(
|
||||
|
||||
assert_eq!(
|
||||
serai.coins().mint_events().await.unwrap(),
|
||||
vec![CoinsEvent::Mint { to: address.into(), balance }]
|
||||
vec![CoinsEvent::Mint { to: address, balance }]
|
||||
);
|
||||
assert_eq!(serai.coins().coin_supply(coin).await.unwrap(), amount);
|
||||
assert_eq!(serai.coins().coin_balance(coin, address).await.unwrap(), amount);
|
||||
@@ -86,22 +86,17 @@ serai_test!(
|
||||
balance,
|
||||
instruction: OutInstruction { address: external_address, data: Some(data) },
|
||||
};
|
||||
|
||||
let serai = serai.into_inner();
|
||||
let block = publish_tx(
|
||||
serai,
|
||||
&serai
|
||||
.sign(
|
||||
&pair,
|
||||
&SeraiCoins::burn_with_instruction(instruction.clone()),
|
||||
0,
|
||||
0,
|
||||
)
|
||||
&serai.sign(&pair, SeraiCoins::burn_with_instruction(instruction.clone()), 0, 0),
|
||||
)
|
||||
.await;
|
||||
|
||||
let serai = serai.as_of(block).coins();
|
||||
let events = serai.burn_with_instruction_events().await.unwrap();
|
||||
assert_eq!(events, vec![CoinsEvent::BurnWithInstruction { from: address.into(), instruction }]);
|
||||
assert_eq!(events, vec![CoinsEvent::BurnWithInstruction { from: address, instruction }]);
|
||||
assert_eq!(serai.coin_supply(coin).await.unwrap(), Amount(0));
|
||||
assert_eq!(serai.coin_balance(coin, address).await.unwrap(), Amount(0));
|
||||
})
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
use serai_runtime::primitives::{Coin, Amount};
|
||||
use serai_abi::primitives::{Coin, Amount};
|
||||
|
||||
use serai_client::{Serai, SeraiDex};
|
||||
use sp_core::{sr25519::Pair, Pair as PairTrait};
|
||||
@@ -18,7 +18,7 @@ pub async fn add_liquidity(
|
||||
|
||||
let tx = serai.sign(
|
||||
&pair,
|
||||
&SeraiDex::add_liquidity(coin, coin_amount, sri_amount, Amount(1), Amount(1), address.into()),
|
||||
SeraiDex::add_liquidity(coin, coin_amount, sri_amount, Amount(1), Amount(1), address.into()),
|
||||
nonce,
|
||||
0,
|
||||
);
|
||||
@@ -40,7 +40,7 @@ pub async fn swap(
|
||||
|
||||
let tx = serai.sign(
|
||||
&pair,
|
||||
&SeraiDex::swap(from_coin, to_coin, amount_in, amount_out_min, address.into()),
|
||||
SeraiDex::swap(from_coin, to_coin, amount_in, amount_out_min, address.into()),
|
||||
nonce,
|
||||
Default::default(),
|
||||
);
|
||||
|
||||
@@ -2,12 +2,10 @@ use core::time::Duration;
|
||||
|
||||
use tokio::time::sleep;
|
||||
|
||||
use scale::Encode;
|
||||
|
||||
use serai_client::Serai;
|
||||
use serai_client::{Transaction, Serai};
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub async fn publish_tx(serai: &Serai, tx: &[u8]) -> [u8; 32] {
|
||||
pub async fn publish_tx(serai: &Serai, tx: &Transaction) -> [u8; 32] {
|
||||
let mut latest = serai
|
||||
.block(serai.latest_finalized_block_hash().await.unwrap())
|
||||
.await
|
||||
@@ -39,8 +37,8 @@ pub async fn publish_tx(serai: &Serai, tx: &[u8]) -> [u8; 32] {
|
||||
block.unwrap()
|
||||
};
|
||||
|
||||
for transaction in block.transactions() {
|
||||
if transaction.encode() == tx {
|
||||
for transaction in &block.transactions {
|
||||
if transaction == tx {
|
||||
return block.hash();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@ use scale::Encode;
|
||||
|
||||
use sp_core::{Pair as PairTrait, bounded_vec::BoundedVec, hashing::blake2_256};
|
||||
|
||||
use serai_runtime::in_instructions::primitives::DexCall;
|
||||
use serai_abi::in_instructions::primitives::DexCall;
|
||||
|
||||
use serai_client::{
|
||||
primitives::{
|
||||
@@ -37,22 +37,22 @@ serai_test!(
|
||||
vec![
|
||||
DexEvent::PoolCreated {
|
||||
pool_id: Coin::Bitcoin,
|
||||
pool_account: PublicKey::from_raw(blake2_256(&Coin::Bitcoin.encode())),
|
||||
pool_account: PublicKey::from_raw(blake2_256(&Coin::Bitcoin.encode())).into(),
|
||||
lp_token: Coin::Bitcoin,
|
||||
},
|
||||
DexEvent::PoolCreated {
|
||||
pool_id: Coin::Ether,
|
||||
pool_account: PublicKey::from_raw(blake2_256(&Coin::Ether.encode())),
|
||||
pool_account: PublicKey::from_raw(blake2_256(&Coin::Ether.encode())).into(),
|
||||
lp_token: Coin::Ether,
|
||||
},
|
||||
DexEvent::PoolCreated {
|
||||
pool_id: Coin::Dai,
|
||||
pool_account: PublicKey::from_raw(blake2_256(&Coin::Dai.encode())),
|
||||
pool_account: PublicKey::from_raw(blake2_256(&Coin::Dai.encode())).into(),
|
||||
lp_token: Coin::Dai,
|
||||
},
|
||||
DexEvent::PoolCreated {
|
||||
pool_id: Coin::Monero,
|
||||
pool_account: PublicKey::from_raw(blake2_256(&Coin::Monero.encode())),
|
||||
pool_account: PublicKey::from_raw(blake2_256(&Coin::Monero.encode())).into(),
|
||||
lp_token: Coin::Monero,
|
||||
},
|
||||
]
|
||||
@@ -91,8 +91,8 @@ serai_test!(
|
||||
assert_eq!(
|
||||
events,
|
||||
vec![DexEvent::LiquidityAdded {
|
||||
who: pair.public(),
|
||||
mint_to: pair.public(),
|
||||
who: pair.public().into(),
|
||||
mint_to: pair.public().into(),
|
||||
pool_id: Coin::Monero,
|
||||
coin_amount: coin_amount.0,
|
||||
sri_amount: sri_amount.0,
|
||||
@@ -140,8 +140,8 @@ serai_test!(
|
||||
assert_eq!(
|
||||
events,
|
||||
vec![DexEvent::SwapExecuted {
|
||||
who: pair.clone().public(),
|
||||
send_to: pair.public(),
|
||||
who: pair.clone().public().into(),
|
||||
send_to: pair.public().into(),
|
||||
path,
|
||||
amount_in: amount_in.0,
|
||||
amount_out: 16633299966633
|
||||
@@ -160,8 +160,8 @@ serai_test!(
|
||||
assert_eq!(
|
||||
events,
|
||||
vec![DexEvent::SwapExecuted {
|
||||
who: pair.clone().public(),
|
||||
send_to: pair.public(),
|
||||
who: pair.clone().public().into(),
|
||||
send_to: pair.public().into(),
|
||||
path,
|
||||
amount_in: amount_in.0,
|
||||
amount_out: 17254428681101
|
||||
@@ -220,8 +220,8 @@ serai_test!(
|
||||
assert_eq!(
|
||||
events,
|
||||
vec![DexEvent::SwapExecuted {
|
||||
who: pair.clone().public(),
|
||||
send_to: pair.public(),
|
||||
who: pair.clone().public().into(),
|
||||
send_to: pair.public().into(),
|
||||
path,
|
||||
amount_in: amount_in.0,
|
||||
amount_out: 12453103964435,
|
||||
@@ -275,8 +275,8 @@ serai_test!(
|
||||
assert_eq!(
|
||||
events,
|
||||
vec![DexEvent::LiquidityAdded {
|
||||
who: IN_INSTRUCTION_EXECUTOR.into(),
|
||||
mint_to: pair.public(),
|
||||
who: IN_INSTRUCTION_EXECUTOR,
|
||||
mint_to: pair.public().into(),
|
||||
pool_id: Coin::Bitcoin,
|
||||
coin_amount: 10_000_000_000_000, // half of sent amount
|
||||
sri_amount: 6_947_918_403_646,
|
||||
@@ -363,8 +363,8 @@ serai_test!(
|
||||
assert_eq!(
|
||||
events,
|
||||
vec![DexEvent::SwapExecuted {
|
||||
who: IN_INSTRUCTION_EXECUTOR.into(),
|
||||
send_to: IN_INSTRUCTION_EXECUTOR.into(),
|
||||
who: IN_INSTRUCTION_EXECUTOR,
|
||||
send_to: IN_INSTRUCTION_EXECUTOR,
|
||||
path,
|
||||
amount_in: 20_000_000_000_000,
|
||||
amount_out: 11066655622377
|
||||
@@ -402,8 +402,8 @@ serai_test!(
|
||||
assert_eq!(
|
||||
events,
|
||||
vec![DexEvent::SwapExecuted {
|
||||
who: IN_INSTRUCTION_EXECUTOR.into(),
|
||||
send_to: out_address.as_native().unwrap().into(),
|
||||
who: IN_INSTRUCTION_EXECUTOR,
|
||||
send_to: out_address.as_native().unwrap(),
|
||||
path,
|
||||
amount_in: 20_000_000_000_000,
|
||||
amount_out: 26440798801319
|
||||
@@ -440,8 +440,8 @@ serai_test!(
|
||||
assert_eq!(
|
||||
events,
|
||||
vec![DexEvent::SwapExecuted {
|
||||
who: IN_INSTRUCTION_EXECUTOR.into(),
|
||||
send_to: out_address.as_native().unwrap().into(),
|
||||
who: IN_INSTRUCTION_EXECUTOR,
|
||||
send_to: out_address.as_native().unwrap(),
|
||||
path,
|
||||
amount_in: 10_000_000_000_000,
|
||||
amount_out: 10711005507065
|
||||
|
||||
@@ -25,8 +25,10 @@ sp-application-crypto = { git = "https://github.com/serai-dex/substrate", defaul
|
||||
sp-core = { git = "https://github.com/serai-dex/substrate", default-features = false }
|
||||
sp-runtime = { git = "https://github.com/serai-dex/substrate", default-features = false }
|
||||
|
||||
frame-support = { git = "https://github.com/serai-dex/substrate", default-features = false }
|
||||
|
||||
[features]
|
||||
std = ["zeroize", "scale/std", "borsh?/std", "serde?/std", "scale-info/std", "sp-core/std", "sp-runtime/std"]
|
||||
std = ["zeroize", "scale/std", "borsh?/std", "serde?/std", "scale-info/std", "sp-core/std", "sp-runtime/std", "frame-support/std"]
|
||||
borsh = ["dep:borsh"]
|
||||
serde = ["dep:serde"]
|
||||
default = ["std"]
|
||||
|
||||
@@ -50,6 +50,7 @@ pub fn borsh_deserialize_signature<R: borsh::io::Read>(
|
||||
Ok(Signature(signature))
|
||||
}
|
||||
|
||||
// TODO: Remove this for solely Public?
|
||||
#[derive(
|
||||
Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug, Encode, Decode, MaxEncodedLen, TypeInfo,
|
||||
)]
|
||||
|
||||
@@ -32,6 +32,9 @@ pub use balance::*;
|
||||
mod account;
|
||||
pub use account::*;
|
||||
|
||||
mod tx;
|
||||
pub use tx::*;
|
||||
|
||||
#[cfg(feature = "borsh")]
|
||||
pub fn borsh_serialize_bounded_vec<W: borsh::io::Write, T: BorshSerialize, const B: u32>(
|
||||
bounded: &BoundedVec<T, ConstU32<B>>,
|
||||
|
||||
122
substrate/primitives/src/tx.rs
Normal file
122
substrate/primitives/src/tx.rs
Normal file
@@ -0,0 +1,122 @@
|
||||
use scale::Encode;
|
||||
|
||||
use sp_core::sr25519::{Public, Signature};
|
||||
use sp_runtime::traits::Verify;
|
||||
|
||||
use crate::SeraiAddress;
|
||||
|
||||
trait TransactionMember:
|
||||
Clone + PartialEq + Eq + core::fmt::Debug + scale::Encode + scale::Decode + scale_info::TypeInfo
|
||||
{
|
||||
}
|
||||
impl<
|
||||
T: Clone
|
||||
+ PartialEq
|
||||
+ Eq
|
||||
+ core::fmt::Debug
|
||||
+ scale::Encode
|
||||
+ scale::Decode
|
||||
+ scale_info::TypeInfo,
|
||||
> TransactionMember for T
|
||||
{
|
||||
}
|
||||
|
||||
#[allow(private_bounds)]
|
||||
#[derive(Clone, PartialEq, Eq, Debug, scale::Encode, scale::Decode, scale_info::TypeInfo)]
|
||||
pub struct Transaction<Call: TransactionMember, Extra: TransactionMember> {
|
||||
pub call: Call,
|
||||
pub signature: Option<(SeraiAddress, Signature, Extra)>,
|
||||
}
|
||||
|
||||
#[cfg(feature = "serde")]
|
||||
mod _serde {
|
||||
use scale::Encode;
|
||||
use serde::{ser::*, de::*};
|
||||
use super::*;
|
||||
impl<Call: TransactionMember, Extra: TransactionMember> Serialize for Transaction<Call, Extra> {
|
||||
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
|
||||
let encoded = self.encode();
|
||||
serializer.serialize_bytes(&encoded)
|
||||
}
|
||||
}
|
||||
#[cfg(feature = "std")]
|
||||
impl<'a, Call: TransactionMember, Extra: TransactionMember> Deserialize<'a>
|
||||
for Transaction<Call, Extra>
|
||||
{
|
||||
fn deserialize<D: Deserializer<'a>>(de: D) -> Result<Self, D::Error> {
|
||||
let bytes = sp_core::bytes::deserialize(de)?;
|
||||
scale::Decode::decode(&mut &bytes[..])
|
||||
.map_err(|e| serde::de::Error::custom(format!("invalid transaction: {}", e)))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<Call: TransactionMember, Extra: TransactionMember> sp_runtime::traits::Extrinsic
|
||||
for Transaction<Call, Extra>
|
||||
{
|
||||
type Call = Call;
|
||||
type SignaturePayload = (SeraiAddress, Signature, Extra);
|
||||
fn is_signed(&self) -> Option<bool> {
|
||||
Some(self.signature.is_some())
|
||||
}
|
||||
fn new(call: Call, signature: Option<Self::SignaturePayload>) -> Option<Self> {
|
||||
Some(Self { call, signature })
|
||||
}
|
||||
}
|
||||
|
||||
impl<Call: TransactionMember, Extra: TransactionMember> frame_support::traits::ExtrinsicCall
|
||||
for Transaction<Call, Extra>
|
||||
{
|
||||
fn call(&self) -> &Call {
|
||||
&self.call
|
||||
}
|
||||
}
|
||||
|
||||
impl<Call: TransactionMember, Extra: TransactionMember> sp_runtime::traits::ExtrinsicMetadata
|
||||
for Transaction<Call, Extra>
|
||||
where
|
||||
Extra: sp_runtime::traits::SignedExtension,
|
||||
{
|
||||
type SignedExtensions = Extra;
|
||||
|
||||
const VERSION: u8 = 0;
|
||||
}
|
||||
|
||||
impl<Call: TransactionMember, Extra: TransactionMember> frame_support::dispatch::GetDispatchInfo
|
||||
for Transaction<Call, Extra>
|
||||
where
|
||||
Call: frame_support::dispatch::GetDispatchInfo,
|
||||
{
|
||||
fn get_dispatch_info(&self) -> frame_support::dispatch::DispatchInfo {
|
||||
self.call.get_dispatch_info()
|
||||
}
|
||||
}
|
||||
|
||||
impl<Call: TransactionMember, Extra: TransactionMember> sp_runtime::traits::BlindCheckable
|
||||
for Transaction<Call, Extra>
|
||||
where
|
||||
Extra: sp_runtime::traits::SignedExtension,
|
||||
{
|
||||
type Checked = sp_runtime::generic::CheckedExtrinsic<Public, Call, Extra>;
|
||||
|
||||
fn check(
|
||||
self,
|
||||
) -> Result<Self::Checked, sp_runtime::transaction_validity::TransactionValidityError> {
|
||||
Ok(match self.signature {
|
||||
Some((signer, signature, extra)) => {
|
||||
if !signature.verify(
|
||||
(&self.call, &extra, extra.additional_signed()?).encode().as_slice(),
|
||||
&signer.into(),
|
||||
) {
|
||||
Err(sp_runtime::transaction_validity::InvalidTransaction::BadProof)?
|
||||
}
|
||||
|
||||
sp_runtime::generic::CheckedExtrinsic {
|
||||
signed: Some((signer.into(), extra)),
|
||||
function: self.call,
|
||||
}
|
||||
}
|
||||
None => sp_runtime::generic::CheckedExtrinsic { signed: None, function: self.call },
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -44,7 +44,7 @@ use sp_runtime::{
|
||||
Perbill, ApplyExtrinsicResult,
|
||||
};
|
||||
|
||||
use primitives::{PublicKey, SeraiAddress, AccountLookup, Signature, SubstrateAmount};
|
||||
use primitives::{PublicKey, AccountLookup, SubstrateAmount};
|
||||
|
||||
use support::{
|
||||
traits::{ConstU8, ConstU32, ConstU64, Contains},
|
||||
@@ -75,10 +75,9 @@ pub type SignedExtra = (
|
||||
system::CheckWeight<Runtime>,
|
||||
transaction_payment::ChargeTransactionPayment<Runtime>,
|
||||
);
|
||||
pub type UncheckedExtrinsic =
|
||||
generic::UncheckedExtrinsic<SeraiAddress, RuntimeCall, Signature, SignedExtra>;
|
||||
|
||||
pub type Block = generic::Block<Header, UncheckedExtrinsic>;
|
||||
pub type Transaction = serai_primitives::Transaction<RuntimeCall, SignedExtra>;
|
||||
pub type Block = generic::Block<Header, Transaction>;
|
||||
pub type BlockId = generic::BlockId<Block>;
|
||||
|
||||
pub mod opaque {
|
||||
|
||||
Reference in New Issue
Block a user