|
@@ -23,11 +23,11 @@ use std::{
|
|
|
|
|
|
|
|
#[cfg(feature = "async")]
|
|
#[cfg(feature = "async")]
|
|
|
use darkfi_serial::async_trait;
|
|
use darkfi_serial::async_trait;
|
|
|
-use darkfi_serial::{SerialDecodable, SerialEncodable};
|
|
|
|
|
|
|
+use darkfi_serial::{deserialize, SerialDecodable, SerialEncodable};
|
|
|
|
|
|
|
|
use super::{
|
|
use super::{
|
|
|
crypto::{ContractId, SecretKey},
|
|
crypto::{ContractId, SecretKey},
|
|
|
- ContractError, GenericResult,
|
|
|
|
|
|
|
+ ContractError, FeeError, FeeResult, GenericResult,
|
|
|
};
|
|
};
|
|
|
use crate::crypto::{DAO_CONTRACT_ID, DEPLOYOOOR_CONTRACT_ID, MONEY_CONTRACT_ID};
|
|
use crate::crypto::{DAO_CONTRACT_ID, DEPLOYOOOR_CONTRACT_ID, MONEY_CONTRACT_ID};
|
|
|
|
|
|
|
@@ -89,6 +89,15 @@ impl ContractCall {
|
|
|
self.matches_contract_call_type(*MONEY_CONTRACT_ID, 0x00)
|
|
self.matches_contract_call_type(*MONEY_CONTRACT_ID, 0x00)
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ /// Returns the paid native token fee encoded in a `Money::FeeV1` call.
|
|
|
|
|
+ pub fn money_fee_value(&self) -> FeeResult<u64> {
|
|
|
|
|
+ if !self.is_money_fee() || self.data.len() < 9 {
|
|
|
|
|
+ return Err(FeeError::InvalidFeeCall)
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ deserialize(&self.data[1..9]).map_err(|_| FeeError::InvalidFeeCall)
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
/// Returns true if call is a money genesis mint.
|
|
/// Returns true if call is a money genesis mint.
|
|
|
pub fn is_money_genesis_mint(&self) -> bool {
|
|
pub fn is_money_genesis_mint(&self) -> bool {
|
|
|
self.matches_contract_call_type(*MONEY_CONTRACT_ID, 0x01)
|
|
self.matches_contract_call_type(*MONEY_CONTRACT_ID, 0x01)
|
|
@@ -160,6 +169,53 @@ impl ContractCall {
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+#[cfg(test)]
|
|
|
|
|
+mod tests {
|
|
|
|
|
+ use darkfi_serial::serialize;
|
|
|
|
|
+
|
|
|
|
|
+ use super::*;
|
|
|
|
|
+ use crate::crypto::DAO_CONTRACT_ID;
|
|
|
|
|
+
|
|
|
|
|
+ #[test]
|
|
|
|
|
+ fn money_fee_value_extracts_paid_fee() {
|
|
|
|
|
+ let fee = 20_u64;
|
|
|
|
|
+ let mut data = vec![0x00];
|
|
|
|
|
+ data.extend(serialize(&fee));
|
|
|
|
|
+ data.extend([0xab, 0xcd]);
|
|
|
|
|
+
|
|
|
|
|
+ let call = ContractCall { contract_id: *MONEY_CONTRACT_ID, data };
|
|
|
|
|
+
|
|
|
|
|
+ assert_eq!(call.money_fee_value().unwrap(), fee);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ #[test]
|
|
|
|
|
+ fn money_fee_value_rejects_wrong_contract() {
|
|
|
|
|
+ let mut data = vec![0x00];
|
|
|
|
|
+ data.extend(serialize(&20_u64));
|
|
|
|
|
+
|
|
|
|
|
+ let call = ContractCall { contract_id: *DAO_CONTRACT_ID, data };
|
|
|
|
|
+
|
|
|
|
|
+ assert_eq!(call.money_fee_value(), Err(FeeError::InvalidFeeCall));
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ #[test]
|
|
|
|
|
+ fn money_fee_value_rejects_wrong_function() {
|
|
|
|
|
+ let mut data = vec![0x01];
|
|
|
|
|
+ data.extend(serialize(&20_u64));
|
|
|
|
|
+
|
|
|
|
|
+ let call = ContractCall { contract_id: *MONEY_CONTRACT_ID, data };
|
|
|
|
|
+
|
|
|
|
|
+ assert_eq!(call.money_fee_value(), Err(FeeError::InvalidFeeCall));
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ #[test]
|
|
|
|
|
+ fn money_fee_value_rejects_short_data() {
|
|
|
|
|
+ let call = ContractCall { contract_id: *MONEY_CONTRACT_ID, data: vec![0x00, 0x01] };
|
|
|
|
|
+
|
|
|
|
|
+ assert_eq!(call.money_fee_value(), Err(FeeError::InvalidFeeCall));
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
// Avoid showing the data in the debug output since often the calldata is very long.
|
|
// Avoid showing the data in the debug output since often the calldata is very long.
|
|
|
impl Debug for ContractCall {
|
|
impl Debug for ContractCall {
|
|
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|