Skip to content

Commit

Permalink
feat!: Claimable trait for all contracts with no coreriff macro
Browse files Browse the repository at this point in the history
Possibility to claim/ import a contract to SmartDeploy which hasn't been deployed with the smartdeploy-cli. We keep the notion of ownership and redeployment.

Add an admin/ owner to the smartdeploy contract (justfile)
  • Loading branch information
asanson1404 committed Feb 5, 2024
1 parent 76a8d23 commit 51db61a
Show file tree
Hide file tree
Showing 6 changed files with 123 additions and 23 deletions.
6 changes: 6 additions & 0 deletions contracts/smartdeploy/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,10 @@ pub enum Error {

/// Failed to initialize contract
InitFailed = 7,

/// Failed to redeploy a deployed contract with no coreriff macro
RedeployDeployedFailed = 8,

/// Contract doesn't have owner, impossible to perform the operation
NoOwnerSet = 9,
}
6 changes: 5 additions & 1 deletion contracts/smartdeploy/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
use loam_sdk::{soroban_contract, soroban_sdk};
use loam_sdk_core_riff::{owner::Owner, CoreRiff};
use registry::{
contract::ContractRegistry, wasm::WasmRegistry, Deployable, DevDeployable, Publishable,
contract::ContractRegistry, wasm::WasmRegistry, Deployable, DevDeployable, Publishable, Claimable,
};

pub mod error;
Expand All @@ -24,6 +24,10 @@ impl Deployable for Contract {
type Impl = ContractRegistry;
}

impl Claimable for Contract {
type Impl = ContractRegistry;
}

impl DevDeployable for Contract {
type Impl = ContractRegistry;
}
Expand Down
28 changes: 25 additions & 3 deletions contracts/smartdeploy/src/registry.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,9 +52,6 @@ pub trait IsPublishable {

#[riff]
pub trait IsDeployable {
/// Claim a contract id of an already deployed contract
fn claim_deployed_contract(&mut self, deployed_name: soroban_sdk::String, id: soroban_sdk::Address) -> Result<(), Error>;

/// Deploys a new published contract returning the deployed contract's id.
/// If no salt provided it will use the current sequence number.
fn deploy(
Expand All @@ -81,6 +78,31 @@ pub trait IsDeployable {
) -> Result<soroban_sdk::Vec<(soroban_sdk::String, soroban_sdk::Address)>, Error>;
}

#[riff]
pub trait IsClaimable {
/// Claim a contract id of an already deployed contract
fn claim_already_deployed_contract(
&mut self,
deployed_name: soroban_sdk::String,
id: soroban_sdk::Address,
owner: soroban_sdk::Address,
) -> Result<(), Error>;

/// Get the owner of a claimed deployed contract
fn get_claimed_owner(
&self,
deployed_name: soroban_sdk::String
) -> Result<Option<soroban_sdk::Address>, Error>;

/// Redeploy a claimed deployed contract to a new wasm. Defaults: use redeploy from coreriff
fn redeploy_claimed_contract(
&self,
binary_name: Option<soroban_sdk::String>,
version: Option<Version>,
deployed_name: soroban_sdk::String,
redeploy_fn: Option<(soroban_sdk::Symbol, soroban_sdk::Vec<soroban_sdk::Val>)>,
) -> Result<(), Error>;
}

#[riff]
pub trait IsDevDeployable {
Expand Down
98 changes: 81 additions & 17 deletions contracts/smartdeploy/src/registry/contract.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,10 @@ use crate::{
util::{hash_string, MAX_BUMP},
version::Version,
Contract,
WasmRegistry,
};

use crate::WasmRegistry;

use super::{IsDeployable, IsDevDeployable};
use super::{IsClaimable, IsDeployable, IsDevDeployable};

loam_sdk::import_contract!(core_riff);

Expand All @@ -32,9 +31,29 @@ pub struct DeployEventData {
deployer: Address,
contract_id: Address,
}
#[contracttype(export = false)]
pub struct ContractRegistry(pub Map<String, ContractState>);

#[contracttype(export = false)]
pub struct ContractRegistry(pub Map<String, Address>);
#[derive(Clone)]
pub enum ContractState {
ContractId(Address),
Owner(Address, Address)
}

impl ContractState {
pub fn contract_id(&self) -> &Address {
match self {
Self::ContractId(id) | Self::Owner(id, _) => id,
}
}
pub fn owner(&self) -> Option<&Address> {
match self {
Self::Owner(_, owner) => Some(owner),
Self::ContractId(_) => None
}
}
}

impl Default for ContractRegistry {
fn default() -> Self {
Expand All @@ -59,13 +78,6 @@ impl Lazy for ContractRegistry {
}

impl IsDeployable for ContractRegistry {
fn claim_deployed_contract(&mut self, deployed_name: String, id: Address) -> Result<(), Error> {
if self.0.contains_key(deployed_name.clone()) {
return Err(Error::AlreadyClaimed);
}
self.0.set(deployed_name, id);
Ok(())
}
fn deploy(
&mut self,
contract_name: String,
Expand All @@ -86,7 +98,7 @@ impl IsDeployable for ContractRegistry {
if let Some((init_fn, args)) = init {
let _ = env().invoke_contract::<Val>(&address, &init_fn, args);
}
self.0.set(deployed_name.clone(), address.clone());
self.0.set(deployed_name.clone(), ContractState::ContractId(address.clone()));

// Publish a deploy event
let version = version.map_or_else(
Expand All @@ -112,6 +124,7 @@ impl IsDeployable for ContractRegistry {
self.0
.get(deployed_name)
.ok_or(Error::NoSuchContractDeployed)
.map(|contract| contract.contract_id().clone())
}

fn list_deployed_contracts(
Expand All @@ -126,12 +139,62 @@ impl IsDeployable for ContractRegistry {
.take(limit.unwrap_or_else(|| self.0.len()) as usize);
let mut res = vec![env()];
for item in items {
res.push_back(item);
res.push_back((item.0, item.1.contract_id().clone()));
}
Ok(res)
}
}

impl IsClaimable for ContractRegistry {
fn claim_already_deployed_contract(
&mut self,
deployed_name: soroban_sdk::String,
id: soroban_sdk::Address,
owner: soroban_sdk::Address,
) -> Result<(), Error> {
owner.require_auth();
if self.0.contains_key(deployed_name.clone()) {
return Err(Error::AlreadyClaimed);
}
self.0.set(deployed_name, ContractState::Owner(id, owner));
Ok(())
}

fn get_claimed_owner(
&self,
deployed_name: soroban_sdk::String
) -> Result<Option<Address>, Error> {
self
.0
.get(deployed_name)
.ok_or(Error::NoSuchContractDeployed)
.map(|contract| contract.owner().cloned())
}

fn redeploy_claimed_contract(
&self,
binary_name: Option<soroban_sdk::String>,
version: Option<Version>,
deployed_name: soroban_sdk::String,
redeploy_fn: Option<(soroban_sdk::Symbol, soroban_sdk::Vec<soroban_sdk::Val>)>,
) -> Result<(), Error> {
self
.get_claimed_owner(deployed_name.clone())?
.ok_or(Error::NoOwnerSet)?
.require_auth();
let contract_id = self.fetch_contract_id(deployed_name)?;
if let Some(binary_name) = binary_name {
let hash = Contract::fetch_hash(binary_name, version)?;
env().deployer().update_current_contract_wasm(hash);
} else if let Some((fn_name, args)) = redeploy_fn {
let _ = env().invoke_contract::<Val>(&contract_id, &fn_name, args);
} else {
return Err(Error::RedeployDeployedFailed);
}
Ok(())
}
}

fn deploy_and_init(
owner: &Address,
salt: BytesN<32>,
Expand All @@ -157,14 +220,15 @@ impl IsDevDeployable for ContractRegistry {
wasm: soroban_sdk::Bytes,
) -> Result<soroban_sdk::Address, Error> {
let wasm_hash = env().deployer().upload_contract_wasm(wasm);
if let Some(address) = self.0.get(name.clone()) {
let contract = core_riff::Client::new(env(), &address);
if let Some(contract_state) = self.0.get(name.clone()) {
let address = contract_state.contract_id();
let contract = core_riff::Client::new(env(), address);
contract.redeploy(&wasm_hash);
return Ok(address);
return Ok(address.clone());
}
let salt = hash_string(&name);
let id = deploy_and_init(&owner, salt, wasm_hash)?;
self.0.set(name, id.clone());
self.0.set(name, ContractState::ContractId(id.clone()));
Ok(id)
}
}
1 change: 1 addition & 0 deletions deploy.sh
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ echo $ID
if test "$FILE_HASH" = ""; then
just publish smartdeploy
just claim_self
just set_owner default
fi

if test "$SOROBAN_NETWORK" = "testnet"; then
Expand Down
7 changes: 5 additions & 2 deletions justfile
Original file line number Diff line number Diff line change
Expand Up @@ -75,8 +75,11 @@ setup_default:
@./deploy.sh

[private]
@claim_self:
just smartdeploy claim_deployed_contract --deployed_name smartdeploy --id {{ id }}
@claim_self owner='default':
just smartdeploy claim_already_deployed_contract --deployed_name smartdeploy --id {{ id }} --owner {{owner}}

@set_owner owner:
@just smartdeploy_raw -- owner_set --new_owner {{ owner }}

[private]
@install_self:
Expand Down

0 comments on commit 51db61a

Please sign in to comment.