1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193
#![no_std]
use gmeta::{In, InOut, Metadata, Out};
use gstd::{prelude::*, ActorId};
use primitive_types::U256;
pub struct EscrowMetadata;
impl Metadata for EscrowMetadata {
type Init = In<InitEscrow>;
type Handle = InOut<EscrowAction, EscrowEvent>;
type Others = ();
type Reply = ();
type Signal = ();
type State = Out<EscrowState>;
}
#[derive(Default, Encode, Decode, Clone, TypeInfo)]
#[codec(crate = gstd::codec)]
#[scale_info(crate = gstd::scale_info)]
pub struct EscrowState {
pub ft_program_id: ActorId,
pub wallets: Vec<(WalletId, Wallet)>,
pub id_nonce: WalletId,
pub transaction_id: u64,
pub transactions: Vec<(u64, Option<EscrowAction>)>,
}
/// An escrow wallet ID.
pub type WalletId = U256;
/// Initializes an escrow program.
#[derive(Decode, Encode, TypeInfo)]
#[codec(crate = gstd::codec)]
#[scale_info(crate = gstd::scale_info)]
pub struct InitEscrow {
/// Address of a fungible token program.
pub ft_program_id: ActorId,
}
/// An enum to send the program info about what it should do.
///
/// After a successful processing of this enum, the program replies with [`EscrowEvent`].
#[derive(Clone, Decode, Encode, TypeInfo)]
#[codec(crate = gstd::codec)]
#[scale_info(crate = gstd::scale_info)]
pub enum EscrowAction {
/// Creates one escrow wallet and replies with its ID.
///
/// # Requirements
/// * [`msg::source()`](gstd::msg::source) must be `buyer` or `seller` for this wallet.
/// * `buyer` or `seller` mustn't have the zero address.
///
/// On success, returns [`EscrowEvent::Created`].
Create {
/// A buyer.
buyer: ActorId,
/// A seller.
seller: ActorId,
/// An amount of tokens.
amount: u128,
},
/// Makes a deposit from a buyer to an escrow wallet
/// and changes wallet's [`WalletState`] to [`AwaitingConfirmation`](WalletState::AwaitingConfirmation).
///
/// Transfers tokens to an escrow wallet until a deal is confirmed (by [`EscrowAction::Confirm`]) or cancelled ([`EscrowAction::Cancel`]).
///
/// # Requirements
/// * [`msg::source()`](gstd::msg::source) must be a buyer for this wallet.
/// * Wallet mustn't be paid or closed (that is, wallet's [`WalletState`] must be [`AwaitingDeposit`](WalletState::AwaitingDeposit)).
///
/// On success, returns [`EscrowEvent::Deposited`].
Deposit(
/// A wallet ID.
WalletId,
),
/// Confirms a deal by transferring tokens from an escrow wallet
/// to a seller and changing wallet's [`WalletState`] to [`Closed`](WalletState::Closed).
///
/// Transfers tokens from an escrow wallet to a seller for this wallet.
///
/// # Requirements
/// * [`msg::source()`](gstd::msg::source) must be a buyer for this wallet.
/// * Wallet must be paid and unclosed (that is, wallet's [`WalletState`] must be [`AwaitingDeposit`](WalletState::AwaitingConfirmation)).
///
/// On success, returns [`EscrowEvent::Confirmed`].
Confirm(
/// A wallet ID.
WalletId,
),
/// Refunds tokens from an escrow wallet to a buyer
/// and changes wallet's [`WalletState`] back to [`AwaitingDeposit`](WalletState::AwaitingDeposit)
/// (that is, a wallet can be reused).
///
/// Refunds tokens from an escrow wallet to a buyer for this wallet.
///
/// # Requirements
/// * [`msg::source()`](gstd::msg::source) must be a seller for this wallet.
/// * Wallet must be paid and unclosed (that is, wallet's [`WalletState`] must be [`AwaitingDeposit`](WalletState::AwaitingConfirmation)).
///
/// On success, returns [`EscrowEvent::Refunded`].
Refund(
/// A wallet ID.
WalletId,
),
/// Cancels a deal and closes an escrow wallet by changing its [`WalletState`] to [`Closed`](WalletState::Closed).
///
/// # Requirements
/// * [`msg::source()`](gstd::msg::source) must be a buyer or seller for this wallet.
/// * Wallet mustn't be paid or closed (that is, wallet's [`WalletState`] must be [`AwaitingDeposit`](WalletState::AwaitingDeposit)).
///
/// On success, returns [`EscrowEvent::Cancelled`].
Cancel(
/// A wallet ID.
WalletId,
),
/// Continues the transaction if it fails due to lack of gas
/// or due to an error in the token contract.
///
/// # Requirements:
/// * `transaction_id` should exists in `transactions` table;
///
/// When transaction already processed replies with [`EscrowEvent::TransactionProcessed`].
Continue(
/// Identifier of suspended transaction.
u64,
),
}
/// An enum that contains a result of processed [`EscrowAction`].
#[derive(Decode, Encode, TypeInfo)]
#[codec(crate = gstd::codec)]
#[scale_info(crate = gstd::scale_info)]
pub enum EscrowEvent {
Cancelled(
/// An ID of a wallet with a cancelled deal.
WalletId,
),
Refunded(
/// Transaction id.
u64,
/// An ID of a refunded wallet.
WalletId,
),
Confirmed(
/// Transaction id.
u64,
/// An ID of a wallet with a confirmed deal.
WalletId,
),
Deposited(
/// Transaction id.
u64,
/// An ID of a deposited wallet.
WalletId,
),
Created(
/// An ID of a created wallet.
WalletId,
),
TransactionProcessed,
TransactionFailed,
}
/// Escrow wallet information.
#[derive(Decode, Encode, TypeInfo, Clone, Copy, Debug, PartialEq, Eq)]
#[codec(crate = gstd::codec)]
#[scale_info(crate = gstd::scale_info)]
pub struct Wallet {
/// A buyer.
pub buyer: ActorId,
/// A seller.
pub seller: ActorId,
/// A wallet state.
pub state: WalletState,
/// An amount of tokens that a wallet can have. **Not** a current amount on a wallet balance!
pub amount: u128,
}
/// An escrow wallet state.
#[derive(Decode, Encode, TypeInfo, PartialEq, Eq, Clone, Copy, Debug)]
#[codec(crate = gstd::codec)]
#[scale_info(crate = gstd::scale_info)]
pub enum WalletState {
AwaitingDeposit,
AwaitingConfirmation,
Closed,
}