Skip to content

Commit

Permalink
feat: deploy proxy contract on context creation (#943)
Browse files Browse the repository at this point in the history
Co-authored-by: alenmestrov <[email protected]>
  • Loading branch information
xilosada and alenmestrov authored Nov 8, 2024
1 parent fc62560 commit 58503df
Show file tree
Hide file tree
Showing 14 changed files with 596 additions and 54 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

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

4 changes: 2 additions & 2 deletions contracts/context-config/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ license.workspace = true
crate-type = ["rlib", "cdylib"]

[dependencies]
near-sdk.workspace = true

near-sdk = { workspace = true, features = ["unstable"] }
hex.workspace = true
calimero-context-config = { path = "../../crates/context/config" }

[dev-dependencies]
Expand Down
12 changes: 9 additions & 3 deletions contracts/context-config/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,8 @@

use calimero_context_config::types::{Application, ContextId, ContextIdentity};
use calimero_context_config::Timestamp;
use near_sdk::store::{IterableMap, IterableSet};
use near_sdk::{near, BorshStorageKey};

use near_sdk::store::{IterableMap, IterableSet, LazyOption};
use near_sdk::{near, AccountId, BorshStorageKey};
mod guard;
mod mutate;
mod query;
Expand All @@ -23,6 +22,8 @@ const DEFAULT_VALIDITY_THRESHOLD_MS: Timestamp = 10_000;
pub struct ContextConfigs {
contexts: IterableMap<ContextId, Context>,
config: Config,
proxy_code: LazyOption<Vec<u8>>,
next_proxy_id: u64,
}

#[derive(Debug)]
Expand All @@ -36,6 +37,7 @@ struct Config {
struct Context {
pub application: Guard<Application<'static>>,
pub members: Guard<IterableSet<ContextIdentity>>,
pub proxy: Guard<AccountId>,
}

#[derive(Copy, Clone, Debug, BorshStorageKey)]
Expand All @@ -44,6 +46,7 @@ enum Prefix {
Contexts,
Members(ContextId),
Privileges(PrivilegeScope),
ProxyCode,
}

#[derive(Copy, Clone, Debug)]
Expand All @@ -57,6 +60,7 @@ enum PrivilegeScope {
enum ContextPrivilegeScope {
Application,
MemberList,
Proxy,
}

impl Default for ContextConfigs {
Expand All @@ -66,6 +70,8 @@ impl Default for ContextConfigs {
config: Config {
validity_threshold_ms: DEFAULT_VALIDITY_THRESHOLD_MS,
},
proxy_code: LazyOption::new(Prefix::ProxyCode, None),
next_proxy_id: 0,
}
}
}
Expand Down
128 changes: 125 additions & 3 deletions contracts/context-config/src/mutate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,11 @@ use calimero_context_config::types::{
Application, Capability, ContextId, ContextIdentity, Signed, SignerId,
};
use calimero_context_config::{ContextRequest, ContextRequestKind, Request, RequestKind};
use near_sdk::serde_json::{self, json};
use near_sdk::store::IterableSet;
use near_sdk::{env, near, require};
use near_sdk::{
env, near, require, AccountId, Gas, NearToken, Promise, PromiseError, PromiseResult,
};

use super::{
parse_input, Context, ContextConfigs, ContextConfigsExt, ContextPrivilegeScope, Guard, Prefix,
Expand All @@ -15,6 +18,7 @@ use super::{

#[near]
impl ContextConfigs {
#[payable]
pub fn mutate(&mut self) {
parse_input!(request: Signed<Request<'_>>);

Expand Down Expand Up @@ -53,6 +57,9 @@ impl ContextConfigs {
ContextRequestKind::Revoke { capabilities } => {
self.revoke(&request.signer_id, context_id, capabilities.into_owned());
}
ContextRequestKind::UpdateProxyContract => {
self.update_proxy_contract(&request.signer_id, context_id);
}
},
}
}
Expand All @@ -65,7 +72,7 @@ impl ContextConfigs {
context_id: Repr<ContextId>,
author_id: Repr<ContextIdentity>,
application: Application<'_>,
) {
) -> Promise {
require!(
signer_id.as_bytes() == context_id.as_bytes(),
"context addition must be signed by the context itself"
Expand All @@ -74,6 +81,13 @@ impl ContextConfigs {
let mut members = IterableSet::new(Prefix::Members(*context_id));
let _ = members.insert(*author_id);

// Create incremental account ID
let account_id: AccountId = format!("{}.{}", self.next_proxy_id, env::current_account_id())
.parse()
.expect("invalid account ID");

self.next_proxy_id += 1;

let context = Context {
application: Guard::new(
Prefix::Privileges(PrivilegeScope::Context(
Expand All @@ -97,13 +111,23 @@ impl ContextConfigs {
author_id.rt().expect("infallible conversion"),
members,
),
proxy: Guard::new(
Prefix::Privileges(PrivilegeScope::Context(
*context_id,
ContextPrivilegeScope::Proxy,
)),
author_id.rt().expect("infallible conversion"),
account_id.clone(),
),
};

if self.contexts.insert(*context_id, context).is_some() {
env::panic_str("context already exists");
}

env::log_str(&format!("Context `{context_id}` added"));
// Initiate proxy contract deployment with a callback for when it completes
self.deploy_proxy_contract(context_id, account_id)
.then(Self::ext(env::current_account_id()).add_context_callback(context_id))
}

fn update_application(
Expand Down Expand Up @@ -276,4 +300,102 @@ impl ContextConfigs {
));
}
}

pub fn deploy_proxy_contract(
&mut self,
context_id: Repr<ContextId>,
account_id: AccountId,
) -> Promise {
// Deploy and initialize the proxy contract
Promise::new(account_id.clone())
.create_account()
.transfer(env::attached_deposit())
.deploy_contract(self.proxy_code.get().clone().unwrap())
.function_call(
"init".to_owned(),
serde_json::to_vec(&json!({
"context_id": context_id,
"context_config_account_id": env::current_account_id()
}))
.unwrap(),
NearToken::from_near(0),
Gas::from_tgas(30),
)
.then(Self::ext(env::current_account_id()).proxy_deployment_callback())
}

fn update_proxy_contract(
&mut self,
signer_id: &SignerId,
context_id: Repr<ContextId>,
) -> Promise {
// Get the context and verify proxy contract exists
let context = self
.contexts
.get_mut(&context_id)
.expect("context does not exist");

let proxy_account_id = context
.proxy
.get(signer_id)
.expect("unable to update contract")
.get_mut();

let new_code = self.proxy_code.get().clone().unwrap();

// Call the update method on the proxy contract
Promise::new(proxy_account_id.clone())
.function_call(
"update_contract".to_owned(),
new_code,
NearToken::from_near(0),
Gas::from_tgas(100),
)
.then(Self::ext(env::current_account_id()).update_proxy_callback())
}
}

#[near]
impl ContextConfigs {
pub fn proxy_deployment_callback(
&mut self,
#[callback_result] call_result: Result<(), PromiseError>,
) {
if let Err(e) = call_result {
panic!("Failed to deploy proxy contract: {:?}", e);
}
}

pub fn add_context_callback(&mut self, context_id: Repr<ContextId>) {
require!(
env::promise_results_count() == 1,
"Expected 1 promise result"
);

match env::promise_result(0) {
PromiseResult::Successful(_) => {
env::log_str(&format!("Context `{context_id}` added"));
}
_ => {
panic!("Failed to deploy proxy contract for context");
}
}
}

#[private]
#[handle_result]
pub fn update_contract_callback(&mut self) -> Result<(), &'static str> {
require!(
env::promise_results_count() == 1,
"Expected 1 promise result"
);

match env::promise_result(0) {
PromiseResult::Successful(_) => {
env::log_str("Successfully updated proxy contract code");
Ok(())
}
_ => Err("Failed to update proxy contract code"),
}
}
}
11 changes: 10 additions & 1 deletion contracts/context-config/src/query.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use calimero_context_config::repr::{Repr, ReprTransmute};
use calimero_context_config::types::{
Application, Capability, ContextId, ContextIdentity, Revision, SignerId,
};
use near_sdk::near;
use near_sdk::{near, AccountId};

use super::{ContextConfigs, ContextConfigsExt};

Expand All @@ -28,6 +28,15 @@ impl ContextConfigs {
context.application.revision()
}

pub fn proxy_contract(&self, context_id: Repr<ContextId>) -> AccountId {
let context = self
.contexts
.get(&context_id)
.expect("context does not exist");

context.proxy.clone()
}

pub fn members(
&self,
context_id: Repr<ContextId>,
Expand Down
11 changes: 11 additions & 0 deletions contracts/context-config/src/sys.rs
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,17 @@ impl ContextConfigs {
env::log_str(&format!("Migrating context `{}`", Repr::new(*context_id)));
}
}

#[private]
pub fn update_proxy_callback(&mut self) {
env::log_str("Successfully updated proxy contract");
}

#[private]
pub fn set_proxy_code(&mut self) {
self.proxy_code
.set(Some(env::input().expect("Expected proxy code").to_vec()));
}
}

impl ContextConfigs {
Expand Down
Loading

0 comments on commit 58503df

Please sign in to comment.