tests: example rust contracts moved from warp-wasm-templates
This commit is contained in:
19
crates/pst/contract/implementation/Cargo.toml
Normal file
19
crates/pst/contract/implementation/Cargo.toml
Normal file
@@ -0,0 +1,19 @@
|
||||
[package]
|
||||
name = "warp_pst_implementation"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[lib]
|
||||
crate-type = ["cdylib"]
|
||||
|
||||
[dependencies]
|
||||
console_error_panic_hook = "0.1.7"
|
||||
warp_pst = { path = "../definition" }
|
||||
warp-contracts = { version = "0.1.2", features = ["debug"], path = "../../../warp-contracts" }
|
||||
wasm-bindgen = "=0.2.84"
|
||||
wasm-bindgen-futures = "=0.4.34"
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
serde-wasm-bindgen = "=0.5.0"
|
||||
async-recursion = "1.0.0"
|
||||
async-trait = "0.1.56"
|
||||
tokio-test = "0.4.2"
|
||||
20
crates/pst/contract/implementation/src/actions/balance.rs
Normal file
20
crates/pst/contract/implementation/src/actions/balance.rs
Normal file
@@ -0,0 +1,20 @@
|
||||
use super::ViewActionable;
|
||||
use warp_pst::{
|
||||
action::{Balance, PstBalanceResult, PstViewResponse::BalanceResult, PstViewResult},
|
||||
error::PstError::*,
|
||||
state::PstState,
|
||||
};
|
||||
|
||||
impl ViewActionable for Balance {
|
||||
fn action(self, _caller: String, state: &PstState) -> PstViewResult {
|
||||
if !state.balances.contains_key(&self.target) {
|
||||
return PstViewResult::ContractError(WalletHasNoBalanceDefined(self.target));
|
||||
}
|
||||
let balance_response = PstBalanceResult {
|
||||
balance: *state.balances.get(&self.target).unwrap(),
|
||||
ticker: state.ticker.clone(),
|
||||
target: self.target,
|
||||
};
|
||||
PstViewResult::Success(BalanceResult(balance_response))
|
||||
}
|
||||
}
|
||||
23
crates/pst/contract/implementation/src/actions/evolve.rs
Normal file
23
crates/pst/contract/implementation/src/actions/evolve.rs
Normal file
@@ -0,0 +1,23 @@
|
||||
use super::WriteActionable;
|
||||
use warp_contracts::js_imports::Transaction;
|
||||
use warp_pst::{
|
||||
action::{Evolve, PstWriteResult},
|
||||
error::PstError::*,
|
||||
state::PstState,
|
||||
};
|
||||
|
||||
impl WriteActionable for Evolve {
|
||||
fn action(self, _caller: String, mut state: PstState) -> PstWriteResult {
|
||||
match state.can_evolve {
|
||||
Some(true) => {
|
||||
if state.owner == Transaction::owner() {
|
||||
state.evolve = Option::from(self.value);
|
||||
PstWriteResult::Success(state)
|
||||
} else {
|
||||
PstWriteResult::ContractError(OnlyOwnerCanEvolve)
|
||||
}
|
||||
}
|
||||
_ => PstWriteResult::ContractError(EvolveNotAllowed),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
use super::AsyncWriteActionable;
|
||||
use async_trait::async_trait;
|
||||
use warp_contracts::{foreign_call::read_foreign_contract_state, js_imports::log};
|
||||
use warp_pst::{
|
||||
action::{ForeignRead, PstWriteResult},
|
||||
error::PstError::*,
|
||||
state::PstState,
|
||||
};
|
||||
|
||||
#[async_trait(?Send)]
|
||||
impl AsyncWriteActionable for ForeignRead {
|
||||
async fn action(self, _caller: String, mut state: PstState) -> PstWriteResult {
|
||||
if self.contract_tx_id == "bad_contract" {
|
||||
return PstWriteResult::ContractError(IDontLikeThisContract);
|
||||
}
|
||||
let foreign_contract_state: PstState =
|
||||
match read_foreign_contract_state(&self.contract_tx_id).await {
|
||||
Ok(s) => s,
|
||||
Err(e) => return PstWriteResult::RuntimeError(e),
|
||||
};
|
||||
// Some dummy logic - just for the sake of the integration test
|
||||
if foreign_contract_state.ticker == "FOREIGN_PST" {
|
||||
log("Adding to tokens");
|
||||
for val in state.balances.values_mut() {
|
||||
*val += 1000;
|
||||
}
|
||||
}
|
||||
|
||||
PstWriteResult::Success(state)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
use super::AsyncViewActionable;
|
||||
use async_trait::async_trait;
|
||||
use serde::Serialize;
|
||||
use warp_contracts::{foreign_call::view_foreign_contract_state, handler_result::ViewResult::*};
|
||||
use warp_pst::{
|
||||
action::{
|
||||
ForeignView, PstBalanceResult, PstForeignViewResult, PstViewResponse::*, PstViewResult,
|
||||
},
|
||||
state::PstState,
|
||||
};
|
||||
|
||||
#[derive(Serialize, Debug)]
|
||||
struct BalanceInput {
|
||||
function: String,
|
||||
target: String,
|
||||
}
|
||||
|
||||
#[async_trait(?Send)]
|
||||
impl AsyncViewActionable for ForeignView {
|
||||
async fn action(self, _caller: String, _state: &PstState) -> PstViewResult {
|
||||
let foreign_contract_state = view_foreign_contract_state(
|
||||
&self.contract_tx_id,
|
||||
BalanceInput {
|
||||
target: self.target,
|
||||
function: "balance".to_string(),
|
||||
},
|
||||
)
|
||||
.await;
|
||||
match foreign_contract_state {
|
||||
Success(PstBalanceResult {
|
||||
balance,
|
||||
ticker,
|
||||
target,
|
||||
}) => Success(ForeignViewResult(PstForeignViewResult {
|
||||
balance,
|
||||
ticker,
|
||||
target,
|
||||
})),
|
||||
ContractError(e) => ContractError(e),
|
||||
RuntimeError(e) => RuntimeError(e),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
use super::AsyncWriteActionable;
|
||||
use async_trait::async_trait;
|
||||
use serde::Serialize;
|
||||
use warp_contracts::{foreign_call::write_foreign_contract, handler_result::WriteResult::*};
|
||||
use warp_pst::{
|
||||
action::{ForeignWrite, PstWriteResult},
|
||||
error::PstError,
|
||||
state::PstState,
|
||||
};
|
||||
|
||||
#[derive(Serialize)]
|
||||
struct Input {
|
||||
function: String,
|
||||
qty: u64,
|
||||
target: String,
|
||||
}
|
||||
|
||||
#[async_trait(?Send)]
|
||||
impl AsyncWriteActionable for ForeignWrite {
|
||||
async fn action(self, _caller: String, state: PstState) -> PstWriteResult {
|
||||
match write_foreign_contract::<Input, PstError>(
|
||||
&self.contract_tx_id,
|
||||
Input {
|
||||
function: "transfer".to_string(),
|
||||
qty: self.qty,
|
||||
target: self.target,
|
||||
},
|
||||
)
|
||||
.await
|
||||
{
|
||||
Success(_) => Success(state),
|
||||
ContractError(e) => ContractError(e),
|
||||
RuntimeError(e) => RuntimeError(e),
|
||||
}
|
||||
}
|
||||
}
|
||||
28
crates/pst/contract/implementation/src/actions/kv_get.rs
Normal file
28
crates/pst/contract/implementation/src/actions/kv_get.rs
Normal file
@@ -0,0 +1,28 @@
|
||||
use super::AsyncViewActionable;
|
||||
use async_trait::async_trait;
|
||||
use warp_contracts::{handler_result::ViewResult::*, kv_operations::kv_get};
|
||||
use warp_pst::{
|
||||
action::{KvGet, PstKvGetResult, PstViewResponse, PstViewResult},
|
||||
state::PstState,
|
||||
};
|
||||
|
||||
#[async_trait(?Send)]
|
||||
impl AsyncViewActionable for KvGet {
|
||||
async fn action(self, _caller: String, _state: &PstState) -> PstViewResult {
|
||||
match kv_get(&self.key).await {
|
||||
Success(a) => {
|
||||
PstViewResult::Success(PstViewResponse::KvGetResult(PstKvGetResult {
|
||||
key: self.key,
|
||||
value: a,
|
||||
}))
|
||||
}
|
||||
ContractError(_) => {
|
||||
PstViewResult::Success(PstViewResponse::KvGetResult(PstKvGetResult {
|
||||
key: self.key,
|
||||
value: "".to_owned(),
|
||||
}))
|
||||
},
|
||||
RuntimeError(e) => RuntimeError(e),
|
||||
}
|
||||
}
|
||||
}
|
||||
24
crates/pst/contract/implementation/src/actions/kv_put.rs
Normal file
24
crates/pst/contract/implementation/src/actions/kv_put.rs
Normal file
@@ -0,0 +1,24 @@
|
||||
use super::AsyncWriteActionable;
|
||||
use async_trait::async_trait;
|
||||
use warp_contracts::{
|
||||
js_imports::{log, Transaction},
|
||||
kv_operations::kv_put,
|
||||
};
|
||||
use warp_pst::{
|
||||
action::{KvPut, PstWriteResult},
|
||||
state::PstState,
|
||||
};
|
||||
|
||||
#[async_trait(?Send)]
|
||||
impl AsyncWriteActionable for KvPut {
|
||||
async fn action(self, caller: String, state: PstState) -> PstWriteResult {
|
||||
let owner = Transaction::owner();
|
||||
log(&format!("caller {caller}"));
|
||||
log(&format!("Transaction owner {owner}"));
|
||||
|
||||
match kv_put(&self.key, &self.value).await {
|
||||
Err(e) => PstWriteResult::RuntimeError(e),
|
||||
Ok(_) => PstWriteResult::Success(state),
|
||||
}
|
||||
}
|
||||
}
|
||||
36
crates/pst/contract/implementation/src/actions/mod.rs
Normal file
36
crates/pst/contract/implementation/src/actions/mod.rs
Normal file
@@ -0,0 +1,36 @@
|
||||
use async_trait::async_trait;
|
||||
use warp_pst::{action::{PstViewResult, PstWriteResult}, state::PstState};
|
||||
|
||||
pub mod balance;
|
||||
pub mod evolve;
|
||||
pub mod foreign_read;
|
||||
pub mod foreign_view;
|
||||
pub mod foreign_write;
|
||||
pub mod kv_get;
|
||||
pub mod kv_put;
|
||||
pub mod transfer;
|
||||
|
||||
pub use balance::*;
|
||||
pub use evolve::*;
|
||||
pub use foreign_read::*;
|
||||
pub use foreign_view::*;
|
||||
pub use foreign_write::*;
|
||||
pub use transfer::*;
|
||||
|
||||
pub trait ViewActionable {
|
||||
fn action(self, caller: String, state: &PstState) -> PstViewResult;
|
||||
}
|
||||
|
||||
#[async_trait(?Send)]
|
||||
pub trait AsyncViewActionable {
|
||||
async fn action(self, caller: String, state: &PstState) -> PstViewResult;
|
||||
}
|
||||
|
||||
pub trait WriteActionable {
|
||||
fn action(self, caller: String, state: PstState) -> PstWriteResult;
|
||||
}
|
||||
|
||||
#[async_trait(?Send)]
|
||||
pub trait AsyncWriteActionable {
|
||||
async fn action(self, caller: String, state: PstState) -> PstWriteResult;
|
||||
}
|
||||
36
crates/pst/contract/implementation/src/actions/transfer.rs
Normal file
36
crates/pst/contract/implementation/src/actions/transfer.rs
Normal file
@@ -0,0 +1,36 @@
|
||||
use super::WriteActionable;
|
||||
use warp_contracts::js_imports::{log, SmartWeave, Transaction};
|
||||
use warp_pst::{
|
||||
action::{PstWriteResult, Transfer},
|
||||
error::PstError::*,
|
||||
state::PstState,
|
||||
};
|
||||
|
||||
impl WriteActionable for Transfer {
|
||||
fn action(self, _caller: String, mut state: PstState) -> PstWriteResult {
|
||||
log(("caller ".to_owned() + &SmartWeave::caller()).as_str());
|
||||
log(("Transaction owner ".to_owned() + &Transaction::owner()).as_str());
|
||||
|
||||
if self.qty == 0 {
|
||||
return PstWriteResult::ContractError(TransferAmountMustBeHigherThanZero);
|
||||
}
|
||||
|
||||
let caller = Transaction::owner();
|
||||
let balances = &mut state.balances;
|
||||
|
||||
// Checking if caller has enough funds
|
||||
let caller_balance = *balances.get(&caller).unwrap_or(&0);
|
||||
if caller_balance < self.qty {
|
||||
return PstWriteResult::ContractError(CallerBalanceNotEnough(caller_balance));
|
||||
}
|
||||
|
||||
// Update caller balance
|
||||
balances.insert(caller, caller_balance - self.qty);
|
||||
|
||||
// Update target balance
|
||||
let target_balance = *balances.get(&self.target).unwrap_or(&0);
|
||||
balances.insert(self.target, target_balance + self.qty);
|
||||
|
||||
PstWriteResult::Success(state)
|
||||
}
|
||||
}
|
||||
55
crates/pst/contract/implementation/src/contract.rs
Normal file
55
crates/pst/contract/implementation/src/contract.rs
Normal file
@@ -0,0 +1,55 @@
|
||||
use warp_pst::{
|
||||
action::{Action, PstWriteResult, PstViewResult},
|
||||
state::PstState,
|
||||
};
|
||||
use wasm_bindgen::prelude::wasm_bindgen;
|
||||
|
||||
use crate::actions::*;
|
||||
use warp_contracts::{js_imports::*, warp_contract};
|
||||
|
||||
#[warp_contract(write)]
|
||||
pub async fn handle_write(state: PstState, action: Action) -> PstWriteResult {
|
||||
console_error_panic_hook::set_once();
|
||||
let effective_caller = SmartWeave::caller();
|
||||
|
||||
//Example of accessing functions imported from js:
|
||||
log("log from contract");
|
||||
log(&("Transaction::id()".to_owned() + &Transaction::id()));
|
||||
log(&("Transaction::owner()".to_owned() + &Transaction::owner()));
|
||||
log(&("Transaction::target()".to_owned() + &Transaction::target()));
|
||||
|
||||
log(&("Block::height()".to_owned() + &Block::height().to_string()));
|
||||
log(&("Block::indep_hash()".to_owned() + &Block::indep_hash()));
|
||||
log(&("Block::timestamp()".to_owned() + &Block::timestamp().to_string()));
|
||||
|
||||
log(&("Contract::id()".to_owned() + &Contract::id()));
|
||||
log(&("Contract::owner()".to_owned() + &Contract::owner()));
|
||||
|
||||
log(&("SmartWeave::caller()".to_owned() + &SmartWeave::caller()));
|
||||
|
||||
// for vrf-compatible interactions
|
||||
log(&("Vrf::value()".to_owned() + &Vrf::value()));
|
||||
log(&("Vrf::randomInt(7)".to_owned() + &Vrf::randomInt(7).to_string()));
|
||||
|
||||
match action {
|
||||
Action::Transfer(action) => action.action(effective_caller, state),
|
||||
Action::Evolve(action) => action.action(effective_caller, state),
|
||||
Action::ForeignRead(action) => action.action(effective_caller, state).await,
|
||||
Action::ForeignWrite(action) => action.action(effective_caller, state).await,
|
||||
Action::KvPut(action) => action.action(effective_caller, state).await,
|
||||
_ => PstWriteResult::RuntimeError("invalid method for write".to_owned()),
|
||||
}
|
||||
}
|
||||
|
||||
#[warp_contract(view)]
|
||||
pub async fn handle_view(state: &PstState, action: Action) -> PstViewResult {
|
||||
console_error_panic_hook::set_once();
|
||||
let effective_caller = SmartWeave::caller();
|
||||
|
||||
match action {
|
||||
Action::Balance(action) => action.action(effective_caller, state),
|
||||
Action::ForeignView(action) => action.action(effective_caller, state).await,
|
||||
Action::KvGet(action) => action.action(effective_caller, state).await,
|
||||
_ => PstViewResult::RuntimeError("invalid method for view".to_owned()),
|
||||
}
|
||||
}
|
||||
2
crates/pst/contract/implementation/src/lib.rs
Normal file
2
crates/pst/contract/implementation/src/lib.rs
Normal file
@@ -0,0 +1,2 @@
|
||||
mod actions;
|
||||
mod contract;
|
||||
Reference in New Issue
Block a user