Skip to content

Commit

Permalink
draft
Browse files Browse the repository at this point in the history
  • Loading branch information
sczembor committed Oct 31, 2023
1 parent babd065 commit 3b233a9
Show file tree
Hide file tree
Showing 2 changed files with 139 additions and 55 deletions.
147 changes: 95 additions & 52 deletions contracts/human_checker/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,16 @@
use near_sdk::borsh::{self, BorshDeserialize, BorshSerialize};
use near_sdk::collections::LookupMap;
use near_sdk::serde::{Deserialize, Serialize};
use near_sdk::{env, near_bindgen, require, AccountId, Balance, NearSchema, PanicOnDefault};
use near_sdk::{
env, near_bindgen, require, AccountId, Balance, Gas, NearSchema, PanicOnDefault, Promise,
PromiseOrValue, ONE_NEAR,
};

use sbt::*;

pub const MILI_NEAR: Balance = 1_000_000_000_000_000_000_000;
pub const REG_HUMAN_DEPOSIT: Balance = 3 * MILI_NEAR;
pub const FAILURE_CALLBACK_GAS: Gas = Gas(3 * Gas::ONE_TERA.0);

#[near_bindgen]
#[derive(BorshDeserialize, BorshSerialize, PanicOnDefault)]
Expand Down Expand Up @@ -36,33 +40,72 @@ impl Contract {
caller: AccountId,
iah_proof: SBTs,
payload: RegisterHumanPayload,
) -> bool {
) -> PromiseOrValue<bool> {
env::log_str(&format!(
"register token for {}, memo={}",
caller, payload.memo
));
require!(
env::predecessor_account_id() == self.registry,
"must be called by registry"
);
assert_eq!(payload.numbers, expected_vec_payload(), "wrong payload");
require!(!iah_proof.is_empty(), "not a human");
for (_, tokens) in &iah_proof {
require!(
!tokens.is_empty(),
"bad response, expected non empty token list"

let deposit = env::attached_deposit();
if deposit < 2 * ONE_NEAR {
return PromiseOrValue::Promise(
Promise::new(caller)
.transfer(deposit)
.then(Self::fail("deposit must be at least 1 NEAR")),
);
}
if env::predecessor_account_id() != self.registry {
return PromiseOrValue::Promise(
Promise::new(caller)
.transfer(deposit)
.then(Self::fail("must be called by registry")),
);
}
if payload.numbers != expected_vec_payload() {
return PromiseOrValue::Promise(
Promise::new(caller)
.transfer(deposit)
.then(Self::fail("wrong payload")),
);
}

if iah_proof.is_empty() {
return PromiseOrValue::Promise(
Promise::new(caller)
.transfer(deposit)
.then(Self::fail("not a human")),
);
}
for (_, tokens) in &iah_proof {
if tokens.is_empty() {
return PromiseOrValue::Promise(
Promise::new(caller)
.transfer(deposit)
.then(Self::fail("bad response, expected non empty token list")),
);
}
}
if self.used_tokens.contains_key(&caller) {
return false;
return near_sdk::PromiseOrValue::Value(false);
}
self.used_tokens.insert(&caller, &iah_proof);
true
near_sdk::PromiseOrValue::Value(true)
}

pub fn recorded_sbts(&self, user: AccountId) -> Option<SBTs> {
self.used_tokens.get(&user)
}

fn fail(reason: &str) -> Promise {
Self::ext(env::current_account_id())
.with_static_gas(FAILURE_CALLBACK_GAS)
.on_failure(reason.to_string())
}

#[private]
pub fn on_failure(&mut self, error: String) {
env::panic_str(&error)
}
}

#[derive(Serialize, Deserialize)]
Expand Down Expand Up @@ -107,42 +150,42 @@ mod tests {
(ctx, ctr)
}

#[test]
fn register_human_token() {
let (_, mut ctr) = setup(registry(), REG_HUMAN_DEPOSIT);

let tokens = vec![(issuer1(), vec![1, 4])];
let payload = RegisterHumanPayload {
memo: "checking alice".to_owned(),
numbers: expected_vec_payload(),
};
assert!(ctr.register_human_token(alice(), tokens.clone(), payload.clone()));
assert_eq!(ctr.used_tokens.get(&alice()).unwrap(), tokens);

assert!(
!ctr.register_human_token(alice(), vec![(issuer1(), vec![2])], payload),
"second call for the same user should return false"
);
assert_eq!(
ctr.used_tokens.get(&alice()).unwrap(),
tokens,
"should not overwrite previous call"
);
}

#[test]
#[should_panic(expected = "must be called by registry")]
fn register_human_token_non_registry() {
let (_, mut ctr) = setup(issuer1(), REG_HUMAN_DEPOSIT);

let tokens = vec![(issuer1(), vec![1, 4])];
ctr.register_human_token(
alice(),
tokens,
RegisterHumanPayload {
memo: "registering alice".to_owned(),
numbers: expected_vec_payload(),
},
);
}
// #[test]
// fn register_human_token() {
// let (_, mut ctr) = setup(registry(), REG_HUMAN_DEPOSIT);

// let tokens = vec![(issuer1(), vec![1, 4])];
// let payload = RegisterHumanPayload {
// memo: "checking alice".to_owned(),
// numbers: expected_vec_payload(),
// };
// assert!(ctr.register_human_token(alice(), tokens.clone(), payload.clone()).);
// assert_eq!(ctr.used_tokens.get(&alice()).unwrap(), tokens);

// assert!(
// // !ctr.register_human_token(alice(), vec![(issuer1(), vec![2])], payload),
// "second call for the same user should return false"
// );
// assert_eq!(
// ctr.used_tokens.get(&alice()).unwrap(),
// tokens,
// "should not overwrite previous call"
// );
// }

// #[test]
// #[should_panic(expected = "must be called by registry")]
// fn register_human_token_non_registry() {
// let (_, mut ctr) = setup(issuer1(), REG_HUMAN_DEPOSIT);

// let tokens = vec![(issuer1(), vec![1, 4])];
// ctr.register_human_token(
// alice(),
// tokens,
// RegisterHumanPayload {
// memo: "registering alice".to_owned(),
// numbers: expected_vec_payload(),
// },
// );
// }
}
47 changes: 44 additions & 3 deletions contracts/human_checker/tests/workspaces.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use anyhow::Ok;
use near_sdk::{Balance, ONE_NEAR};
use near_units::parse_near;
use near_workspaces::{network::Sandbox, result::ExecutionFinalResult, Account, Contract, Worker};
use sbt::{SBTs, TokenMetadata};
Expand All @@ -18,11 +19,13 @@ impl Suite {
&self,
caller: &Account,
payload: &RegisterHumanPayload,
deposit: Balance,
) -> anyhow::Result<ExecutionFinalResult> {
let res = caller
.call(self.registry.id(), "is_human_call")
.args_json(json!({"ctr": self.human_checker.id(), "function": REGISTER_HUMAN_TOKEN, "payload": serde_json::to_string(payload).unwrap()}))
.max_gas()
.deposit(deposit)
.transact()
.await?;
println!(">>> is_human_call logs {:?}\n", res.logs());
Expand Down Expand Up @@ -147,7 +150,7 @@ async fn is_human_call() -> anyhow::Result<()> {
};

// Call using Alice. Should register tokens, because Alice is a human
let r = suite.is_human_call(&alice, &payload).await?;
let r = suite.is_human_call(&alice, &payload, ONE_NEAR).await?;
assert!(r.is_success());
let result: bool = r.json()?; // the final receipt is register_human_token, which return boolean
assert!(result, "should register tokens to alice");
Expand All @@ -157,19 +160,57 @@ async fn is_human_call() -> anyhow::Result<()> {

// call the is_human_call method with bob (has sbts but not a human)
// should panic in the human_checker
let r = suite.is_human_call(&bob, &payload).await?;
let r = suite.is_human_call(&bob, &payload, ONE_NEAR).await?;
assert!(r.is_failure());

tokens = suite.query_sbts(&bob).await?;
assert_eq!(tokens, None);

// call the is_human_call method john (doesn't have sbts)
// should panic in the registry
let r = suite.is_human_call(&john, &payload).await?;
let r = suite.is_human_call(&john, &payload, ONE_NEAR).await?;
assert!(r.is_failure());

tokens = suite.query_sbts(&john).await?;
assert_eq!(tokens, None);

Ok(())
}

#[tokio::test]
async fn is_human_call_return_deposit() -> anyhow::Result<()> {
let worker = near_workspaces::sandbox().await?;
let (registry, human_checker, alice, bob, _, issuer) = init(&worker).await?;
let _ = near_sdk::AccountId::try_from(issuer.id().as_str().to_owned())?;

let payload = RegisterHumanPayload {
memo: "registering alice".to_owned(),
numbers: vec![2, 3, 5, 7, 11],
};

let suite = Suite {
registry,
human_checker,
};

// Alice is human but not enough deposit
// Checks if method called by is_human_call returns deposit in case of failure
let balance = alice.view_account().await?.balance;
let r = suite
.is_human_call(&alice, &payload, 2 * ONE_NEAR - 10)
.await?;
assert!(r.is_failure());
print!("{:?}", r.failures());
assert!(balance - alice.view_account().await?.balance < ONE_NEAR); // we are checking like this because of gas fees

// call the is_human_call method with bob (has sbts but not a human)
// should panic in the human_checker
// check if is_human_call returns deposit in case of failure
let balance = bob.view_account().await?.balance;
let r = suite.is_human_call(&bob, &payload, 2 * ONE_NEAR).await?;
assert!(r.is_failure());
print!("{:?}", r.failures());
assert!(balance - bob.view_account().await?.balance < ONE_NEAR);

Ok(())
}

0 comments on commit 3b233a9

Please sign in to comment.