Skip to content

Commit

Permalink
Merge pull request #69 from comit-network/negative-tests
Browse files Browse the repository at this point in the history
Test that loan cannot be repaid with wrong amount/asset/address
  • Loading branch information
luckysori authored Aug 13, 2021
2 parents f3b3389 + f7080c5 commit faf653e
Show file tree
Hide file tree
Showing 2 changed files with 296 additions and 0 deletions.
3 changes: 3 additions & 0 deletions src/loan.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@ use std::future::Future;
use std::str::FromStr;
use std::time::SystemTime;

#[cfg(test)]
mod negative_tests;

/// Secret key used to produce a signature which proves that an
/// input's witness stack contains transaction data equivalent to the
/// transaction which includes the input itself.
Expand Down
293 changes: 293 additions & 0 deletions src/loan/negative_tests.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,293 @@
use elements::confidential::{Asset, AssetBlindingFactor, ValueBlindingFactor};
use elements::secp256k1_zkp::{SecretKey, SECP256K1};
use elements::{
Address, AddressParams, AssetId, AssetIssuance, OutPoint, Script, Transaction, TxIn,
TxInWitness, TxOut, TxOutSecrets,
};
use rand::{CryptoRng, RngCore, SeedableRng};
use rand_chacha::ChaChaRng;

use super::{make_keypair, Chain, CollateralContract};

#[tokio::test]
async fn wrong_loan_repayment_amount() {
let mut rng = ChaChaRng::seed_from_u64(0);

let (
mut repayment_tx,
collateral_contract,
collateral_output,
expected_asset,
expected_address,
expected_amount,
borrower_sk,
) = prepare_loan_repayment_tx(&mut rng);

let wrong_amount = expected_amount - 5_000;
add_repayment_output(
&mut rng,
&mut repayment_tx,
wrong_amount,
expected_address,
expected_asset,
);

collateral_contract
.satisfy_loan_repayment(
&mut repayment_tx,
collateral_output.value,
0,
|message| async move { Ok(SECP256K1.sign(&message, &borrower_sk)) },
)
.await
.expect_err("could spend collateral with wrong repayment amount");
}

#[tokio::test]
async fn wrong_loan_repayment_address() {
let mut rng = ChaChaRng::seed_from_u64(0);

let (
mut repayment_tx,
collateral_contract,
collateral_output,
expected_asset,
_expected_address,
expected_amount,
borrower_sk,
) = prepare_loan_repayment_tx(&mut rng);

let wrong_address = {
let (_wrong_sk, wrong_pk) = make_keypair(&mut rng);
let (_wrong_blinding_sk, wrong_blinding_pk) = make_keypair(&mut rng);

Address::p2pkh(
&wrong_pk,
Some(wrong_blinding_pk.key),
&AddressParams::ELEMENTS,
)
};
add_repayment_output(
&mut rng,
&mut repayment_tx,
expected_amount,
wrong_address,
expected_asset,
);

collateral_contract
.satisfy_loan_repayment(
&mut repayment_tx,
collateral_output.value,
0,
|message| async move { Ok(SECP256K1.sign(&message, &borrower_sk)) },
)
.await
.expect_err("could spend collateral with wrong repayment address");
}

#[tokio::test]
async fn wrong_loan_repayment_asset() {
let mut rng = ChaChaRng::seed_from_u64(0);

let (
mut repayment_tx,
collateral_contract,
collateral_output,
_expected_asset,
expected_address,
expected_amount,
borrower_sk,
) = prepare_loan_repayment_tx(&mut rng);

let wrong_asset = "600c9579b066bd69632dbbf0686610d02a46295494d14071b2f569e3a2553795"
.parse()
.unwrap();
add_repayment_output(
&mut rng,
&mut repayment_tx,
expected_amount,
expected_address,
wrong_asset,
);

collateral_contract
.satisfy_loan_repayment(
&mut repayment_tx,
collateral_output.value,
0,
|message| async move { Ok(SECP256K1.sign(&message, &borrower_sk)) },
)
.await
.expect_err("could spend collateral with wrong repayment asset");
}

#[tokio::test]
async fn wrong_loan_repayment_signer() {
let mut rng = ChaChaRng::seed_from_u64(0);

let (
mut repayment_tx,
collateral_contract,
collateral_output,
expected_asset,
expected_address,
expected_amount,
_borrower_sk,
) = prepare_loan_repayment_tx(&mut rng);

add_repayment_output(
&mut rng,
&mut repayment_tx,
expected_amount,
expected_address,
expected_asset,
);

let (wrong_signing_sk, _) = make_keypair(&mut rng);
collateral_contract
.satisfy_loan_repayment(
&mut repayment_tx,
collateral_output.value,
0,
|message| async move { Ok(SECP256K1.sign(&message, &wrong_signing_sk)) },
)
.await
.expect_err("could spend collateral with wrong signature");
}

fn prepare_loan_repayment_tx<R>(
rng: &mut R,
) -> (
Transaction,
CollateralContract,
TxOut,
AssetId,
Address,
u64,
SecretKey,
)
where
R: RngCore + CryptoRng,
{
let collateral_asset_id = "0c5d451941f37b801d04c46920f2bc5bbd3986e5f56cb56c6b17bedc655e9fc6"
.parse()
.unwrap();
let principal_asset_id = "6b397062b69411b554ec398ae3b25fdc54fab1805126786581a56a7746afbab2"
.parse()
.unwrap();

let (_oracle_sk, oracle_pk) = make_keypair(rng);
let (borrower_sk, borrower_pk) = make_keypair(rng);
let (_lender_sk, lender_pk) = make_keypair(rng);
let (_repayment_sk, repayment_pk) = make_keypair(rng);
let (repayment_blinding_sk, repayment_blinding_pk) = make_keypair(rng);
let repayment_address = Address::p2wpkh(
&repayment_pk,
Some(repayment_blinding_pk.key),
&AddressParams::ELEMENTS,
);
let collateral_amount = 100_000;
let repayment_amount = 20_000;
let (repayment_output, _repayment_abf, _repayment_vbf) = {
let input_abf = AssetBlindingFactor::new(rng);
let input_asset = Asset::new_confidential(SECP256K1, principal_asset_id, input_abf);
let input_amount = 0;
let input_vbf = ValueBlindingFactor::new(rng);
let input_secrets =
TxOutSecrets::new(principal_asset_id, input_abf, input_amount, input_vbf);
let inputs = [(input_asset, Some(&input_secrets))];

TxOut::new_not_last_confidential(
rng,
SECP256K1,
repayment_amount,
repayment_address.clone(),
principal_asset_id,
&inputs,
)
.unwrap()
};
let (_collateral_blinding_sk, collateral_blinding_pk) = make_keypair(rng);
let collateral_contract = CollateralContract::new(
borrower_pk,
lender_pk,
10,
(repayment_output, repayment_blinding_sk),
oracle_pk,
10_000,
0,
Chain::Elements,
)
.unwrap();
let (collateral_output, _collateral_abf, _collateral_vbf) = {
let input_abf = AssetBlindingFactor::new(rng);
let input_asset = Asset::new_confidential(SECP256K1, collateral_asset_id, input_abf);
let input_amount = 1_000_000;
let input_vbf = ValueBlindingFactor::new(rng);
let input_secrets =
TxOutSecrets::new(collateral_asset_id, input_abf, input_amount, input_vbf);
let inputs = [(input_asset, Some(&input_secrets))];
TxOut::new_not_last_confidential(
rng,
SECP256K1,
collateral_amount,
collateral_contract.blinded_address(collateral_blinding_pk.key),
collateral_asset_id,
&inputs,
)
.unwrap()
};

let repayment_tx = Transaction {
version: 2,
lock_time: 0,
input: vec![TxIn {
previous_output: OutPoint {
txid: "e867486a7df31bece8cf85b27f30d9eaa7d1a9393da018ab614b39daf3042693"
.parse()
.unwrap(),
vout: 0,
},
is_pegin: false,
has_issuance: false,
script_sig: Script::new(),
sequence: 0,
asset_issuance: AssetIssuance::default(),
witness: TxInWitness::default(),
}],
output: Vec::new(),
};

(
repayment_tx,
collateral_contract,
collateral_output,
principal_asset_id,
repayment_address,
repayment_amount,
borrower_sk,
)
}

fn add_repayment_output<R>(
rng: &mut R,
tx: &mut Transaction,
amount: u64,
address: Address,
asset: AssetId,
) where
R: RngCore + CryptoRng,
{
let (repayment_output, _repayment_abf, _repayment_vbf) = {
let input_abf = AssetBlindingFactor::new(rng);
let input_asset = Asset::new_confidential(SECP256K1, asset, input_abf);
let input_amount = 0;
let input_vbf = ValueBlindingFactor::new(rng);
let input_secrets = TxOutSecrets::new(asset, input_abf, input_amount, input_vbf);
let inputs = [(input_asset, Some(&input_secrets))];

TxOut::new_not_last_confidential(rng, SECP256K1, amount, address, asset, &inputs).unwrap()
};
tx.output.push(repayment_output);
}

0 comments on commit faf653e

Please sign in to comment.