pdao_colony_common/
lib.rs

1pub mod test_suite;
2
3use pdao_beacon_chain_common::message as pbc_message;
4use pdao_colony_contract_common::*;
5use rust_decimal::prelude::*;
6use serde::{Deserialize, Serialize};
7use serde_tc::*;
8use std::collections::HashMap;
9use thiserror::Error;
10
11/// A contract type.
12#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
13pub enum ContractType {
14    Treasury,
15    LightClient,
16    Custom { name: String, description: String },
17}
18
19/// Information of a contract.
20#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
21pub struct ContractInfo {
22    /// The address of the contract.
23    pub address: String,
24    /// The type of the contract.
25    pub contract_type: ContractType,
26    /// The increasing sequence that is for preventing the replay attack.
27    ///
28    /// A valid message from PBC MUST carry the same number with this,
29    /// in order to succesfully convince the contract. (i.e., this number is something that the consensus should have finalized on-chain).
30    ///
31    /// - Note1: this is totally irrelevant to the account sequence.
32    /// - Note2: the light client contract doesn't need this because the 'block height' provides the same safety guard.
33    pub sequence: u64,
34}
35
36/// An error that can occur when interacting with the contract.
37#[derive(Error, Debug, Serialize, Deserialize, Clone)]
38pub enum Error {
39    /// When there is a problem to access to the full node.
40    #[error("connection error: {0}")]
41    ConnectionError(String),
42    /// When the transaction is rejected by the full node, before it gets to the contract.
43    #[error("transaction rejected: {0}")]
44    TransactionRejected(String),
45    /// When the contract fails to decode the input data.
46    #[error("failed to parse the payload of the transaction")]
47    FailedToParseTransactionPayload,
48    /// When the given proof is invalid.
49    #[error("invalid proof given: got merkle root of {0} but expected {1}")]
50    InvalidProof(String, String),
51    /// When the given message is well decoded and verified, but the message argument is invalid.
52    #[error("invalid message argument given: {0}")]
53    InvalidMessageArgument(String),
54    /// When the relayer account has not enough balance to execute the transaction.
55    #[error("not enough balance: got {0}")]
56    NotEnoughBalance(u64),
57    /// When the account sequence given in the transaction is invalid.
58    #[error("invalid account sequence; expected {0} but got {1}")]
59    InvalidAccountSequence(u64, u64),
60    /// When the contract sequence given in the transaction is invalid.
61    #[error("invalid contract sequence; expected {0} but got {1}")]
62    InvalidContractSequence(u64, u64),
63    /// When the contract fails to execute the transaction with its own error.
64    #[error("internal contract error: {0}")]
65    InternalContractError(String),
66    /// When the contract is missing.
67    #[error("no such contract: {0}")]
68    NoSuchContract(String),
69    /// An unknown error.
70    #[error("unknown error: {0}")]
71    Unknown(String),
72}
73
74/// An abstract information about a block.
75#[derive(PartialEq, Eq, Debug, Serialize, Deserialize, Clone)]
76pub struct Block {
77    /// The height of the block.
78    pub height: u64,
79    /// The UNIX timestamp of the block in seconds.
80    pub timestamp: u64,
81}
82
83/// An abstraction of a colony chain, which is viewed by the relayer and the explorer.
84///
85/// Every colony chains MUST have at least two types of contracts: the light client and the treasury.
86/// This interface directly specifies the actions applicable to the two essential contracts,
87/// whereas it is generalized as an opaque packet for those non-essential, chain-local and application-specific contracts (custom contracts).
88///
89/// One trivial implementation of this trait would carry the address of the full node and
90/// the relayer account used to submit message delivering transactions.
91#[serde_tc_full]
92pub trait ColonyChain: Send + Sync {
93    /// Returns the name of the chain.
94    async fn get_chain_name(&self) -> String;
95
96    /// Checks whether the chain is healthy and the full node is running.
97    async fn check_connection(&self) -> Result<(), Error>;
98
99    /// Getes the latest finalized block on the chain.
100    async fn get_last_block(&self) -> Result<Block, Error>;
101
102    /// Returns the list of the contracts that are available on the chain
103    async fn get_contract_list(&self) -> Result<Vec<ContractInfo>, Error>;
104
105    /// Returns the address and the current balance (which is used to pay the gas fee) of the relayer account in this chain.
106    ///
107    /// Note that there is no authority of the relayer account; it is just a convenient account to pay the gas fee
108    /// (i.e., there is no need to check the transaction submitter by the contract).
109    async fn get_relayer_account_info(&self) -> Result<(String, Decimal), Error>;
110
111    /// Returns the latest header that the light client has verified.
112    async fn get_light_client_header(&self) -> Result<Header, Error>;
113
114    /// Returns the current balance of fungible tokens in the treasury contract.
115    async fn get_treasury_fungible_token_balance(&self) -> Result<HashMap<String, Decimal>, Error>;
116
117    /// Returns the current balance of non-fungible tokens in the treasury contract, identified as `(collection address, token index)`.
118    ///
119    /// Note that the representation of the token index is specific to the chain, so we just provide as a string.
120    async fn get_treasury_non_fungible_token_balance(&self)
121        -> Result<Vec<(String, String)>, Error>;
122
123    /// Updates the light client state by providing the next, valid block header and its proof.
124    ///
125    /// This is one of the message delivery methods; a transaction that carries the given data will be submitted to the chain.
126    async fn update_light_client(
127        &self,
128        header: light_client::Header,
129        proof: light_client::BlockFinalizationProof,
130    ) -> Result<(), Error>;
131
132    /// Transfers a given amount of fungible tokens from the treasury contract to the destination address.
133    ///
134    /// This is one of the message delivery methods; a transaction that carries the given data and the proof will be submitted to the chain.
135    async fn transfer_treasury_fungible_token(
136        &self,
137        message: pbc_message::FungibleTokenTransfer,
138        block_height: u64,
139        proof: MerkleProof,
140    ) -> Result<(), Error>;
141
142    /// Transfers an NFT from the treasury contract to the destination address.
143    ///
144    /// This is one of the message methods; a transaction that carries the given data and the proof will be submitted to the chain.
145    async fn transfer_treasury_non_fungible_token(
146        &self,
147        message: pbc_message::NonFungibleTokenTransfer,
148        block_height: u64,
149        proof: MerkleProof,
150    ) -> Result<(), Error>;
151
152    /// Delivers an arbitrary message, which is an opaque `String`, to one of the 'custom' contracts in this chain except the light client and the treasury,
153    ///
154    /// This is one of the message delivery methods; a transaction that carries the given data and the proof will be submitted to the chain.
155    /// The target contract is the one with the type of `ContractType::Custom` and the name of `contract_name`.
156    async fn deliver_custom_order(
157        &self,
158        contract_name: &str,
159        message: pbc_message::Custom,
160        block_height: u64,
161        proof: MerkleProof,
162    ) -> Result<(), Error>;
163}
164
165impl serde_tc::http::HttpInterface for dyn ColonyChain {}