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
use super::identity::{AccountIdentifierHex, UserId};
#[derive(candid::CandidType, candid::Deserialize, Debug, Clone)]
pub struct Balance {
pub e8s: u64, // 价格,icp,注意是 10^8 形式的
}
#[derive(candid::CandidType, candid::Deserialize, serde::Serialize, Debug, Clone)]
pub struct Price {
pub e8s: u64, // 价格,icp,注意是 10^8 形式的
}
#[derive(candid::CandidType, candid::Deserialize, Debug, Clone)]
pub struct TransferFee {
pub e8s: u64, // 价格,icp,注意是 10^8 形式的
}
#[derive(candid::CandidType, candid::Deserialize, serde::Serialize, Debug, Clone)]
pub enum TransferUser {
#[serde(rename = "address")]
Address(AccountIdentifierHex),
#[serde(rename = "principal")]
Principal(UserId),
}
pub mod ledger_canister {
use crate::identity::CanisterId;
use candid::{CandidType, Deserialize};
// =================== 基本类型 ======================
pub type BlockIndex = u64; // 转账成功后返回
pub type Memo = u64;
#[derive(CandidType, Deserialize, Debug, Clone)]
pub struct Tokens {
pub e8s: u64,
}
#[derive(CandidType, Deserialize, Debug, Clone)]
pub struct TimeStamp {
pub timestamp_nanos: u64,
}
// AccountIdentifier is a 32-byte array.
// The first 4 bytes is big-endian encoding of a CRC32 checksum of the last 28 bytes.
pub type AccountIdentifier = Vec<u8>;
// Subaccount is an arbitrary 32-byte byte array.
// Ledger uses subaccounts to compute the source address, which enables one
// principal to control multiple ledger accounts.
type SubAccount = Vec<u8>;
#[derive(CandidType, Deserialize, Debug, Clone)]
pub struct TransferArgs {
pub memo: Memo, // Transaction memo. See comments for the `Memo` type.
pub amount: Tokens, // The amount that the caller wants to transfer to the destination address.
pub fee: Tokens, // The amount that the caller pays for the transaction. Must be 10000 e8s.
// The subaccount from which the caller wants to transfer funds.
// If null, the ledger uses the default (all zeros) subaccount to compute the source address.
// See comments for the `SubAccount` type.
pub from_subaccount: Option<SubAccount>,
// The destination account. If the transfer is successful, the balance of this address increases by `amount`.
pub to: AccountIdentifier,
// The point in time when the caller created this request. If null, the ledger uses current IC time as the timestamp.
pub created_at_time: Option<TimeStamp>,
}
#[derive(CandidType, Deserialize, Debug, Clone)]
pub enum TransferError {
// The fee that the caller specified in the transfer request was not the one that ledger expects.
// The caller can change the transfer fee to the `expected_fee` and retry the request.
BadFee { expected_fee: Tokens },
// The account specified by the caller doesn't have enough funds.
InsufficientFunds { balance: Tokens },
// The request is too old.
// The ledger only accepts requests created within 24 hours window.
// This is a non-recoverable error.
TxTooOld { allowed_window_nanos: u64 },
// The caller specified `created_at_time` that is too far in future.
// The caller can retry the request later.
TxCreatedInFuture,
// The ledger has already executed the request.
// `duplicate_of` field is equal to the index of the block containing the original transaction.
TxDuplicate { duplicate_of: BlockIndex },
}
pub type TransferResult = Result<BlockIndex, TransferError>;
// Arguments for the `account_balance` call.
#[derive(CandidType, Deserialize, Debug, Clone)]
pub struct AccountBalanceArgs {
pub account: AccountIdentifier,
}
#[derive(CandidType, Deserialize, Debug, Clone)]
pub struct TransferFeeArg {}
#[derive(CandidType, Deserialize, Debug, Clone)]
pub struct TransferFee {
// The fee to pay to perform a transfer
pub transfer_fee: Tokens,
}
// =================== 账本方法 ===================
/// icp 转账
#[allow(unused)]
pub async fn transfer(canister_id: CanisterId, args: TransferArgs) -> TransferResult {
let _call_result: Result<
(TransferResult,),
(ic_cdk::api::call::RejectionCode, std::string::String),
> = ic_cdk::call(canister_id, "transfer", (args,)).await;
_call_result.unwrap().0
}
/// 查询余额
#[allow(unused)]
pub async fn account_balance(canister_id: CanisterId, args: AccountBalanceArgs) -> Tokens {
let _call_result: Result<
(Tokens,),
(ic_cdk::api::call::RejectionCode, std::string::String),
> = ic_cdk::call(canister_id, "account_balance", (args,)).await;
_call_result.unwrap().0
}
/// 查询转账费用
#[allow(unused)]
pub async fn transfer_fee(canister_id: CanisterId, args: TransferFeeArg) -> TransferFee {
let _call_result: Result<
(TransferFee,),
(ic_cdk::api::call::RejectionCode, std::string::String),
> = ic_cdk::call(canister_id, "transfer_fee", (args,)).await;
_call_result.unwrap().0
}
}