Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Updating multisig wallet contract to sails version #511

Merged
merged 2 commits into from
Nov 13, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 14 additions & 13 deletions contracts/Cargo.lock

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

3 changes: 0 additions & 3 deletions contracts/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ members = [
"concert/wasm",
"galactic-express/wasm",
"multisig-wallet",
"multisig-wallet/state",
"oracle",
"oracle/state",
"oracle/randomness",
Expand Down Expand Up @@ -70,8 +69,6 @@ tamagotchi-battle-state.path = "tamagotchi-battle/state"
battleship-io.path = "battleship/io"
car-races-io.path = "car-races/io"
multi-token-io.path = "multi-token/io"
multisig-wallet-io.path = "multisig-wallet/io"
ping-io.path = "ping/io"
rmrk-catalog-io.path = "rmrk/catalog/io"
rmrk-io.path = "rmrk/io"
rmrk-resource-io.path = "rmrk/resource/io"
Expand Down
2 changes: 2 additions & 0 deletions contracts/multisig-wallet/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
target/
.binpath
21 changes: 13 additions & 8 deletions contracts/multisig-wallet/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,22 @@
name = "multisig-wallet"
version.workspace = true
edition.workspace = true
publish.workspace = true
license.workspace = true

[dependencies]
gstd.workspace = true
multisig-wallet-io.workspace = true
primitive-types.workspace = true
multisig-wallet-app = { path = "app" }

[build-dependencies]
multisig-wallet-app = { path = "app" }
sails-rs = { workspace = true, features = ["wasm-builder"] }
sails-idl-gen.workspace = true

[dev-dependencies]
gstd.workspace = true
multisig-wallet = { path = ".", features = ["wasm-binary"] }
multisig-wallet-client = { path = "client" }
sails-rs = { workspace = true, features = ["gtest"] }
tokio = { workspace = true, features = ["rt", "macros"] }
gtest.workspace = true

[build-dependencies]
multisig-wallet-io.workspace = true
gear-wasm-builder.workspace = true
[features]
wasm-binary = []
13 changes: 8 additions & 5 deletions contracts/multisig-wallet/README.md
Original file line number Diff line number Diff line change
@@ -1,16 +1,19 @@
[![Open in Gitpod](https://img.shields.io/badge/Open_in-Gitpod-white?logo=gitpod)](https://gitpod.io/#FOLDER=multisig-wallet/https://github.com/gear-foundation/dapps)
[![Docs](https://img.shields.io/github/actions/workflow/status/gear-foundation/dapps/contracts.yml?logo=rust&label=docs)](https://dapps.gear.rs/multisig_wallet_io)
## The **Multisig-Wallet** program

A detailed description of the project can be found on the [wiki](https://wiki.vara.network/docs/examples/DeFi/multisig-wallet).

⚙️ **Note**: The project code is developed using the [Sails](https://github.com/gear-tech/sails) framework.

# [Multisig wallet](https://wiki.gear-tech.io/docs/examples/DeFi/multisig-wallet)

### 🏗️ Building

```sh
cargo b -r -p "multisig-wallet*"
cargo b -r -p "multisig-wallet"
```

### ✅ Testing

Run all tests:
```sh
cargo t -r -p "multisig-wallet*"
cargo t -r -p "multisig-wallet"
```
8 changes: 8 additions & 0 deletions contracts/multisig-wallet/app/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
[package]
name = "multisig-wallet-app"
version.workspace = true
edition.workspace = true
license.workspace = true

[dependencies]
sails-rs.workspace = true
207 changes: 207 additions & 0 deletions contracts/multisig-wallet/app/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,207 @@
#![no_std]

use core::cmp::min;
use sails_rs::gstd::msg;
use sails_rs::prelude::*;
mod utils;
use utils::*;

static mut STORAGE: Option<MultisigWallet> = None;

struct MultisigWalletService(());

#[derive(Debug, Encode, Decode, TypeInfo)]
#[codec(crate = sails_rs::scale_codec)]
#[scale_info(crate = sails_rs::scale_info)]
pub enum Event {
Confirmation {
sender: ActorId,
transaction_id: U256,
},
Revocation {
sender: ActorId,
transaction_id: U256,
},
Submission {
transaction_id: U256,
},
Execution {
transaction_id: U256,
},
OwnerAddition {
owner: ActorId,
},
OwnerRemoval {
owner: ActorId,
},
OwnerReplace {
old_owner: ActorId,
new_owner: ActorId,
},
RequirementChange(U256),
}

impl MultisigWalletService {
pub fn new() -> Self {
Self(())
}
pub fn get_mut(&mut self) -> &'static mut MultisigWallet {
unsafe { STORAGE.as_mut().expect("Storage is not initialized") }
}
pub fn get(&self) -> &'static MultisigWallet {
unsafe { STORAGE.as_ref().expect("Storage is not initialized") }
}
}

#[sails_rs::service(events = Event)]
impl MultisigWalletService {
fn init(owners: Vec<ActorId>, required: u32) -> Self {
let owners_count = owners.len();

validate_requirement(owners_count, required);

let mut wallet = MultisigWallet::default();

for owner in &owners {
if wallet.owners.contains(owner) {
panic!("The same owner contained twice")
} else {
wallet.owners.insert(*owner);
}
}

wallet.required = required;

unsafe { STORAGE = Some(wallet) };
Self(())
}

pub fn add_owner(&mut self, owner: ActorId) {
let wallet = self.get_mut();
wallet.validate_only_wallet();
wallet.validate_owner_doesnt_exist(&owner);
validate_requirement(wallet.owners.len() + 1, wallet.required);
wallet.owners.insert(owner);
self.notify_on(Event::OwnerAddition { owner })
.expect("Notification Error");
}
pub fn remove_owner(&mut self, owner: ActorId) {
let wallet = self.get_mut();
wallet.validate_only_wallet();
wallet.validate_owner_exists(&owner);
let next_owners_count = wallet.owners.len() - 1;
validate_requirement(
next_owners_count,
min(next_owners_count as u32, wallet.required),
);

wallet.owners.remove(&owner);

if (next_owners_count as u32) < wallet.required {
wallet.change_requirement(next_owners_count as _);
self.notify_on(Event::RequirementChange(next_owners_count.into()))
.expect("Notification Error");
}
self.notify_on(Event::OwnerRemoval { owner })
.expect("Notification Error");
}

pub fn replace_owner(&mut self, old_owner: ActorId, new_owner: ActorId) {
let wallet = self.get_mut();
wallet.validate_only_wallet();
wallet.validate_owner_exists(&old_owner);
wallet.validate_owner_doesnt_exist(&new_owner);

wallet.owners.insert(new_owner);
wallet.owners.remove(&old_owner);

self.notify_on(Event::OwnerReplace {
old_owner,
new_owner,
})
.expect("Notification Error");
}
pub fn change_required_confirmations_count(&mut self, count: u32) {
let wallet = self.get_mut();
wallet.change_requirement(count);
self.notify_on(Event::RequirementChange(count.into()))
.expect("Notification Error");
}

pub fn submit_transaction(
&mut self,
destination: ActorId,
data: Vec<u8>,
value: u128,
description: Option<String>,
) {
let wallet = self.get_mut();
let msg_source = msg::source();
let transaction_id = wallet.add_transaction(&destination, data, value, description);
wallet.confirm_transaction(&transaction_id, msg_source);

self.notify_on(Event::Submission { transaction_id })
.expect("Notification Error");
}
pub fn confirm_transaction(&mut self, transaction_id: U256) {
let wallet = self.get_mut();
let msg_source = msg::source();
wallet.confirm_transaction(&transaction_id, msg_source);
self.notify_on(Event::Confirmation {
sender: msg_source,
transaction_id,
})
.expect("Notification Error");
}
pub fn revoke_confirmation(&mut self, transaction_id: U256) {
let wallet = self.get_mut();
let msg_source = msg::source();

wallet.validate_owner_exists(&msg_source);
wallet.validate_confirmed(&transaction_id, &msg_source);
wallet.validate_not_executed(&transaction_id);

wallet
.confirmations
.entry(transaction_id)
.or_default()
.remove(&msg_source);

self.notify_on(Event::Revocation {
sender: msg_source,
transaction_id,
})
.expect("Notification Error");
}
pub fn execute_transaction(&mut self, transaction_id: U256) {
let wallet = self.get_mut();
let completion = || {
self.notify_on(Event::Execution { transaction_id })
.expect("Notification Error");
};

wallet.execute_transaction(&transaction_id, Some(completion));
}

// Service's query
pub fn get_state(&self) -> State {
self.get().clone().into()
}
}

pub struct MultisigWalletProgram(());

#[allow(clippy::new_without_default)]
#[sails_rs::program]
impl MultisigWalletProgram {
// Program's constructor
pub fn new(owners: Vec<ActorId>, required: u32) -> Self {
MultisigWalletService::init(owners, required);
Self(())
}

// Exposed service
pub fn multisig_wallet(&self) -> MultisigWalletService {
MultisigWalletService::new()
}
}
Loading