Skip to content

Commit

Permalink
feat: add mock dapp multi
Browse files Browse the repository at this point in the history
  • Loading branch information
bishalbikram committed May 8, 2024
1 parent 4ad1074 commit d00f276
Show file tree
Hide file tree
Showing 15 changed files with 497 additions and 3 deletions.
9 changes: 9 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

9 changes: 9 additions & 0 deletions contracts/soroban/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,7 @@
extern crate std;

mod xcall {
soroban_sdk::contractimport!(
file = "../../target/wasm32-unknown-unknown/release/xcall.optimized.wasm"
);
soroban_sdk::contractimport!(file = "../../target/wasm32-unknown-unknown/release/xcall.wasm");
}

use crate::{
Expand Down
17 changes: 17 additions & 0 deletions contracts/soroban/contracts/mock-dapp-multi/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
[package]
name = "mock-dapp-multi"
version = "0.0.0"
edition = "2021"
publish = false

[lib]
crate-type = ["cdylib"]
doctest = false

[dependencies]
soroban-sdk = { workspace = true, features = ["alloc"] }
soroban-rlp = { path = "../../libs/soroban-rlp" }
xcall = { path = "../xcall" }

[dev-dependencies]
soroban-sdk = { workspace = true, features = ["testutils"] }
146 changes: 146 additions & 0 deletions contracts/soroban/contracts/mock-dapp-multi/src/contract.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
use soroban_rlp::decoder;
use soroban_sdk::{
bytes, contract, contractimpl, panic_with_error, Address, Bytes, Env, String, Vec,
};

use xcall::{
messages::{
call_message::CallMessage, call_message_persisted::CallMessagePersisted,
call_message_rollback::CallMessageWithRollback, envelope::Envelope, AnyMessage,
},
types::{message::MessageType, network_address::NetworkAddress},
};

use crate::{errors::ContractError, types::Connection};

#[contract]
pub struct MockDapp;

#[contractimpl]
impl MockDapp {
pub fn init(env: Env, xcall_address: Address) -> Result<(), ContractError> {
let sn = u128::default();
Self::store_sn_no(&env, &sn);
Self::store_xcall_address(&env, &xcall_address);

Ok(())
}

pub fn send_call_message(
env: Env,
to: NetworkAddress,
data: Bytes,
msg_type: u32,
rollback: Option<Bytes>,
fee: u128,
) -> Result<(), ContractError> {
let network_id = to.nid(&env);
let message = Self::process_message(msg_type, data, rollback)?;
let (sources, destinations) = Self::get_network_connections(&env, network_id)?;

let envelope = Envelope {
message,
sources,
destinations,
};

let xcall_address = Self::get_xcall_address(&env)?;
Self::xcall_send_call(&env, &to, &envelope, &fee, &xcall_address);

Ok(())
}

pub fn handle_call_message(
env: Env,
sender: Address,
from: NetworkAddress,
data: Bytes,
_protocols: Option<Vec<String>>,
) {
let (nid, account) = from.parse_network_address(&env);
if sender.to_string() == account {
return;
}

let msg_data = decoder::decode_string(&env, data);
if msg_data == String::from_str(&env, "rollback") {
panic_with_error!(&env, ContractError::RevertFromDapp)
} else {
if msg_data == String::from_str(&env, "reply-response") {
let message = AnyMessage::CallMessage(CallMessage {
data: bytes!(&env, 0xabc),
});

let xcall_address = Self::get_xcall_address(&env).ok();
if xcall_address.is_none() {
panic_with_error!(&env, ContractError::Uninitialized)
}

let (sources, destinations) = Self::get_network_connections(&env, nid)
.unwrap_or_else(|error| panic_with_error!(&env, error));

let envelope = Envelope {
message,
sources,
destinations,
};
Self::xcall_send_call(&env, &from, &envelope, &100_u128, &xcall_address.unwrap());
}
}
}

pub fn add_connection(
env: Env,
src_endpoint: String,
dst_endpoint: String,
network_id: String,
) {
Self::add_new_connection(
&env,
network_id,
Connection::new(src_endpoint, dst_endpoint),
)
}

pub fn get_sequence(env: Env) -> Result<u128, ContractError> {
Self::get_sn(&env)
}

fn process_message(
message_type: u32,
data: Bytes,
rollback: Option<Bytes>,
) -> Result<AnyMessage, ContractError> {
let msg_type: MessageType = message_type.into();

let message = if msg_type == MessageType::CallMessagePersisted {
AnyMessage::CallMessagePersisted(CallMessagePersisted { data })
} else if msg_type == MessageType::CallMessageWithRollback {
if let Some(rollback) = rollback {
AnyMessage::CallMessageWithRollback(CallMessageWithRollback { data, rollback })
} else {
return Err(ContractError::InvalidRollbackMessage);
}
} else {
AnyMessage::CallMessage(CallMessage { data })
};

Ok(message)
}

fn get_network_connections(
env: &Env,
network_id: String,
) -> Result<(Vec<String>, Vec<String>), ContractError> {
let connections = Self::get_connections(&env, network_id)?;

let mut sources = Vec::new(&env);
let mut destinations = Vec::new(&env);
for conn in connections {
sources.push_back(conn.src_endpoint);
destinations.push_back(conn.dst_endpoint);
}

Ok((sources, destinations))
}
}
13 changes: 13 additions & 0 deletions contracts/soroban/contracts/mock-dapp-multi/src/errors.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
use soroban_sdk::contracterror;

#[contracterror]
#[derive(Clone, Copy, PartialEq, Eq, Debug, PartialOrd, Ord)]
#[repr(u32)]
pub enum ContractError {
OnlyAdmin = 1,
Uninitialized = 2,
AlreadyInitialized = 3,
ConnectionNotFound = 4,
InvalidRollbackMessage = 5,
RevertFromDapp = 6,
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
use soroban_sdk::{contractclient, Address, Env};

use crate::errors::ContractError;
use xcall::{messages::envelope::Envelope, types::network_address::NetworkAddress};

#[contractclient(name = "XcallClient")]
pub trait IXcall {
fn send_call(
env: Env,
envelope: Envelope,
to: NetworkAddress,
fee: u128,
sender: Address,
) -> Result<u128, ContractError>;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
pub mod interface_xcall;
10 changes: 10 additions & 0 deletions contracts/soroban/contracts/mock-dapp-multi/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#![no_std]

pub mod contract;
pub mod errors;
pub mod interfaces;
pub mod state;
pub mod types;
pub mod xcall;

mod test;
83 changes: 83 additions & 0 deletions contracts/soroban/contracts/mock-dapp-multi/src/state.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
use soroban_sdk::{Address, Bytes, Env, String, Vec};

use crate::errors::ContractError;
use crate::{
contract::MockDapp,
types::{Connection, StorageKey},
};

impl MockDapp {
pub fn is_initialized(e: &Env) -> Result<(), ContractError> {
let initialized = e.storage().instance().has(&StorageKey::XcallAddress);
if initialized {
Err(ContractError::AlreadyInitialized)
} else {
Ok(())
}
}

pub fn store_xcall_address(e: &Env, address: &Address) {
e.storage()
.instance()
.set(&StorageKey::XcallAddress, address);
}

pub fn store_sn_no(e: &Env, sn: &u128) {
e.storage().instance().set(&StorageKey::Sn, sn)
}

pub fn store_rollback(e: &Env, sn: &u128, bytes: &Bytes) {
e.storage()
.instance()
.set(&StorageKey::Rollback(*sn), bytes)
}

pub fn add_new_connection(e: &Env, network_id: String, conn: Connection) {
let mut connections: Vec<Connection> = e
.storage()
.instance()
.get(&StorageKey::Connections(network_id.clone()))
.unwrap_or(Vec::new(&e));

connections.push_back(conn);
e.storage()
.instance()
.set(&StorageKey::Connections(network_id), &connections);
}

pub fn get_connections(e: &Env, network_id: String) -> Result<Vec<Connection>, ContractError> {
if let Some(connections) = e
.storage()
.instance()
.get(&StorageKey::Connections(network_id))
{
Ok(connections)
} else {
Err(ContractError::ConnectionNotFound)
}
}

pub fn get_xcall_address(e: &Env) -> Result<Address, ContractError> {
if let Some(xcall) = e.storage().instance().get(&StorageKey::XcallAddress) {
Ok(xcall)
} else {
Err(ContractError::Uninitialized)
}
}

pub fn get_sn(e: &Env) -> Result<u128, ContractError> {
if let Some(sn) = e.storage().instance().get(&StorageKey::Sn) {
Ok(sn)
} else {
Err(ContractError::Uninitialized)
}
}

pub fn get_next_sn(e: &Env) -> Result<u128, ContractError> {
let mut sn = Self::get_sn(&e)?;
sn += 1;
e.storage().instance().set(&StorageKey::Sn, &sn);

Ok(sn)
}
}
4 changes: 4 additions & 0 deletions contracts/soroban/contracts/mock-dapp-multi/src/test.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
#![cfg(test)]

mod contract;
pub mod setup;
Loading

0 comments on commit d00f276

Please sign in to comment.