Skip to content

Commit

Permalink
fix: contract signature; optimized checks
Browse files Browse the repository at this point in the history
  • Loading branch information
veeso committed Nov 12, 2023
1 parent e9407c5 commit 69f4e1d
Show file tree
Hide file tree
Showing 2 changed files with 95 additions and 6 deletions.
27 changes: 26 additions & 1 deletion src/dilazionato/src/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ impl Dilazionato {
ic_cdk::trap("Unauthorized");
}

ContractStorage::sign_contract(&contract_id, caller())
ContractStorage::sign_contract(&contract_id, Configuration::get_marketplace_canister())
}

/// Update marketplace canister id and update the operator for all the tokens
Expand Down Expand Up @@ -567,6 +567,31 @@ mod test {
assert_eq!(Dilazionato::total_supply(), Nat::from(10));
}

#[tokio::test]
async fn test_should_sign_contract() {
init_canister();
assert!(Configuration::set_marketplace_canister(alice()).is_ok());
let contract = ContractRegistration {
buyers: vec![caller()],
currency: "EUR".to_string(),
expiration: "2040-01-01".to_string(),
id: 1.into(),
installments: 10,
properties: vec![],
r#type: did::dilazionato::ContractType::Financing,
seller: caller(),
value: 100,
};
assert!(Dilazionato::register_contract(contract).await.is_ok());
assert!(Dilazionato::admin_sign_contract(1.into()).is_ok());
assert_eq!(
Dilazionato::get_contract(&1.into()).unwrap().is_signed,
true
);
// verify operator
assert_eq!(Dilazionato::operator_of(1.into()).unwrap(), Some(alice()));
}

#[tokio::test]
async fn test_should_increment_contract_value() {
init_canister();
Expand Down
74 changes: 69 additions & 5 deletions src/dilazionato/src/app/storage/contracts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,18 +56,35 @@ impl ContractStorage {
Ok(())
}

/// Sign contract
/// Sign contract.
/// The contract can be signed only once.
pub fn sign_contract(contract_id: &ID, operator: Principal) -> DilazionatoResult<()> {
// sign contract and get seller and tokens
let (contract_tokens, seller) = with_contract_mut(contract_id, |contract| {
// check if already signed
if contract.is_signed {
return Err(DilazionatoError::Token(TokenError::ContractAlreadySigned(
contract_id.clone(),
)));
}

contract.is_signed = true;

Ok((contract.tokens.clone(), contract.seller))
})?;

Self::assign_minted_tokens(contract_tokens, seller, operator)
}

/// Assign previously minted tokens to the seller and set the operator
fn assign_minted_tokens(
tokens: Vec<Nat>,
seller: Principal,
operator: Principal,
) -> DilazionatoResult<()> {
// make tokens effective
with_tokens_mut(|tokens_storage| {
for token_id in contract_tokens {
for token_id in tokens {
let mut token = match tokens_storage.get(&token_id.clone().into()) {
Some(token) => token.clone(),
None => {
Expand Down Expand Up @@ -100,7 +117,12 @@ impl ContractStorage {
return Err(DilazionatoError::Token(TokenError::ContractHasNoTokens));
}

with_contract_mut(contract_id, |contract| {
let contract_tokens = tokens
.iter()
.map(|t| t.id.clone())
.collect::<Vec<TokenIdentifier>>();

let seller = with_contract_mut(contract_id, |contract| {
if !contract.is_signed {
return Err(DilazionatoError::Token(TokenError::ContractNotSigned(
contract_id.clone(),
Expand All @@ -119,9 +141,10 @@ impl ContractStorage {
contract.value = new_value;
contract.tokens.extend(token_ids);

Ok(())
Ok(contract.seller)
})?;
Self::sign_contract(contract_id, operator)?;

Self::assign_minted_tokens(contract_tokens, seller, operator)?;
Ok(())
}

Expand Down Expand Up @@ -467,6 +490,11 @@ mod test {
ContractStorage::tokens_by_operator(Principal::management_canister()).len(),
2
);

// don't sign twice
assert!(
ContractStorage::sign_contract(&contract_id, Principal::management_canister()).is_err()
);
}

#[test]
Expand Down Expand Up @@ -987,4 +1015,40 @@ mod test {
200
);
}

#[test]
fn test_should_not_increment_tokens_if_unsigned_contract() {
let seller =
Principal::from_text("zrrb4-gyxmq-nx67d-wmbky-k6xyt-byhmw-tr5ct-vsxu4-nuv2g-6rr65-aae")
.unwrap();
let contract_id = ID::from(1);
let next_token_id = ContractStorage::total_supply();
assert_eq!(next_token_id, Nat::from(0));
let token_1 = mock_token(next_token_id, 1);
let contract = Contract {
id: contract_id.clone(),
r#type: did::dilazionato::ContractType::Financing,
seller,
buyers: vec![Principal::anonymous()],
tokens: vec![token_1.id.clone()],
expiration: "2040-06-01".to_string(),
initial_value: 100,
is_signed: false,
value: 100,
currency: "EUR".to_string(),
properties: vec![(
"Rome".to_string(),
dip721::GenericValue::TextContent("Rome".to_string()),
)],
};

assert!(ContractStorage::insert_contract(contract.clone(), vec![token_1.clone()]).is_ok());
assert_eq!(ContractStorage::total_supply(), 1);

// create new tokens
let token_2 = mock_token(next_token_id + 1, 1);
assert!(
ContractStorage::add_tokens_to_contract(&contract.id, vec![token_2], alice()).is_err()
);
}
}

0 comments on commit 69f4e1d

Please sign in to comment.