Skip to content

Commit 0ac1bd3

Browse files
committed
feat!: Claimable trait for all contracts with no coreriff macro
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)
1 parent 66f810d commit 0ac1bd3

File tree

6 files changed

+121
-23
lines changed

6 files changed

+121
-23
lines changed

contracts/smartdeploy/src/error.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,4 +22,10 @@ pub enum Error {
2222

2323
/// Failed to initialize contract
2424
InitFailed = 7,
25+
26+
/// Failed to redeploy a deployed contract with no coreriff macro
27+
RedeployDeployedFailed = 8,
28+
29+
/// Contract doesn't have owner, impossible to perform the operation
30+
NoOwnerSet = 9,
2531
}

contracts/smartdeploy/src/lib.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
use loam_sdk::{soroban_contract, soroban_sdk};
33
use loam_sdk_core_riff::{owner::Owner, CoreRiff};
44
use registry::{
5-
contract::ContractRegistry, wasm::WasmRegistry, Deployable, DevDeployable, Publishable,
5+
contract::ContractRegistry, wasm::WasmRegistry, Deployable, DevDeployable, Publishable, Claimable,
66
};
77

88
pub mod error;
@@ -25,6 +25,10 @@ impl Deployable for Contract {
2525
type Impl = ContractRegistry;
2626
}
2727

28+
impl Claimable for Contract {
29+
type Impl = ContractRegistry;
30+
}
31+
2832
impl DevDeployable for Contract {
2933
type Impl = ContractRegistry;
3034
}

contracts/smartdeploy/src/registry.rs

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -52,9 +52,6 @@ pub trait IsPublishable {
5252

5353
#[riff]
5454
pub trait IsDeployable {
55-
/// Claim a contract id of an already deployed contract
56-
fn claim_deployed_contract(&mut self, deployed_name: soroban_sdk::String, id: soroban_sdk::Address) -> Result<(), Error>;
57-
5855
/// Deploys a new published contract returning the deployed contract's id.
5956
/// If no salt provided it will use the current sequence number.
6057
fn deploy(
@@ -81,6 +78,31 @@ pub trait IsDeployable {
8178
) -> Result<soroban_sdk::Vec<(soroban_sdk::String, soroban_sdk::Address)>, Error>;
8279
}
8380

81+
#[riff]
82+
pub trait IsClaimable {
83+
/// Claim a contract id of an already deployed contract
84+
fn claim_already_deployed_contract(
85+
&mut self,
86+
deployed_name: soroban_sdk::String,
87+
id: soroban_sdk::Address,
88+
owner: soroban_sdk::Address,
89+
) -> Result<(), Error>;
90+
91+
/// Get the owner of a claimed deployed contract
92+
fn get_claimed_owner(
93+
&self,
94+
deployed_name: soroban_sdk::String
95+
) -> Result<Option<soroban_sdk::Address>, Error>;
96+
97+
/// Redeploy a claimed deployed contract to a new wasm. Defaults: use redeploy from coreriff
98+
fn redeploy_claimed_contract(
99+
&self,
100+
binary_name: Option<soroban_sdk::String>,
101+
version: Option<Version>,
102+
deployed_name: soroban_sdk::String,
103+
redeploy_fn: Option<(soroban_sdk::Symbol, soroban_sdk::Vec<soroban_sdk::Val>)>,
104+
) -> Result<(), Error>;
105+
}
84106

85107
#[riff]
86108
pub trait IsDevDeployable {

contracts/smartdeploy/src/registry/contract.rs

Lines changed: 79 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,10 @@ use crate::{
1010
util::{hash_string, MAX_BUMP},
1111
version::Version,
1212
Contract,
13+
WasmRegistry,
1314
};
1415

15-
use crate::WasmRegistry;
16-
17-
use super::{IsDeployable, IsDevDeployable};
16+
use super::{IsClaimable, IsDeployable, IsDevDeployable};
1817

1918
loam_sdk::import_contract!(core_riff);
2019

@@ -25,9 +24,29 @@ loam_sdk::import_contract!(core_riff);
2524
// loam_sdk::soroban_sdk::contractimport!(file = "../../target/loam/core_riff.wasm",);
2625
// }
2726

27+
#[contracttype(export = false)]
28+
pub struct ContractRegistry(pub Map<String, ContractType>);
2829

2930
#[contracttype(export = false)]
30-
pub struct ContractRegistry(pub Map<String, Address>);
31+
#[derive(Clone)]
32+
pub enum ContractType {
33+
ContractById(Address),
34+
ContractByIdAndOwner(Address, Address),
35+
}
36+
37+
impl ContractType {
38+
pub fn contract_id(&self) -> &Address {
39+
match self {
40+
Self::ContractById(id) | Self::ContractByIdAndOwner(id, _) => id,
41+
}
42+
}
43+
pub fn owner(&self) -> Option<&Address> {
44+
match self {
45+
Self::ContractByIdAndOwner(_, owner) => Some(owner),
46+
Self::ContractById(_) => None,
47+
}
48+
}
49+
}
3150

3251
impl Default for ContractRegistry {
3352
fn default() -> Self {
@@ -52,13 +71,6 @@ impl Lazy for ContractRegistry {
5271
}
5372

5473
impl IsDeployable for ContractRegistry {
55-
fn claim_deployed_contract(&mut self, deployed_name: String, id: Address) -> Result<(), Error> {
56-
if self.0.contains_key(deployed_name.clone()) {
57-
return Err(Error::AlreadyClaimed);
58-
}
59-
self.0.set(deployed_name, id);
60-
Ok(())
61-
}
6274
fn deploy(
6375
&mut self,
6476
contract_name: String,
@@ -79,7 +91,7 @@ impl IsDeployable for ContractRegistry {
7991
if let Some((init_fn, args)) = init {
8092
let _ = env().invoke_contract::<Val>(&address, &init_fn, args);
8193
}
82-
self.0.set(deployed_name.clone(), address.clone());
94+
self.0.set(deployed_name.clone(), ContractType::ContractById(address.clone()));
8395

8496
// Publish a deploy event
8597
let version = version.map_or_else(
@@ -107,6 +119,7 @@ impl IsDeployable for ContractRegistry {
107119
self.0
108120
.get(deployed_name)
109121
.ok_or(Error::NoSuchContractDeployed)
122+
.map(|contract| contract.contract_id().clone())
110123
}
111124

112125
fn list_deployed_contracts(
@@ -121,12 +134,60 @@ impl IsDeployable for ContractRegistry {
121134
.take(limit.unwrap_or_else(|| self.0.len()) as usize);
122135
let mut res = vec![env()];
123136
for item in items {
124-
res.push_back(item);
137+
res.push_back((item.0, item.1.contract_id().clone()));
125138
}
126139
Ok(res)
127140
}
128141
}
129142

143+
impl IsClaimable for ContractRegistry {
144+
fn claim_already_deployed_contract(
145+
&mut self,
146+
deployed_name: soroban_sdk::String,
147+
id: soroban_sdk::Address,
148+
owner: soroban_sdk::Address,
149+
) -> Result<(), Error> {
150+
owner.require_auth();
151+
if self.0.contains_key(deployed_name.clone()) {
152+
return Err(Error::AlreadyClaimed);
153+
}
154+
self.0.set(deployed_name, ContractType::ContractByIdAndOwner(id, owner));
155+
Ok(())
156+
}
157+
158+
fn get_claimed_owner(
159+
&self,
160+
deployed_name: soroban_sdk::String
161+
) -> Result<Option<Address>, Error> {
162+
self.0
163+
.get(deployed_name)
164+
.ok_or(Error::NoSuchContractDeployed)
165+
.map(|contract| contract.owner().cloned())
166+
}
167+
168+
fn redeploy_claimed_contract(
169+
&self,
170+
binary_name: Option<soroban_sdk::String>,
171+
version: Option<Version>,
172+
deployed_name: soroban_sdk::String,
173+
redeploy_fn: Option<(soroban_sdk::Symbol, soroban_sdk::Vec<soroban_sdk::Val>)>,
174+
) -> Result<(), Error> {
175+
self.get_claimed_owner(deployed_name.clone())?
176+
.ok_or(Error::NoOwnerSet)?
177+
.require_auth();
178+
let contract_id = self.fetch_contract_id(deployed_name)?;
179+
if let Some(binary_name) = binary_name {
180+
let hash = Contract::fetch_hash(binary_name, version)?;
181+
env().deployer().update_current_contract_wasm(hash);
182+
} else if let Some((fn_name, args)) = redeploy_fn {
183+
let _ = env().invoke_contract::<Val>(&contract_id, &fn_name, args);
184+
} else {
185+
return Err(Error::RedeployDeployedFailed);
186+
}
187+
Ok(())
188+
}
189+
}
190+
130191
fn deploy_and_init(
131192
owner: &Address,
132193
salt: BytesN<32>,
@@ -152,14 +213,15 @@ impl IsDevDeployable for ContractRegistry {
152213
wasm: soroban_sdk::Bytes,
153214
) -> Result<soroban_sdk::Address, Error> {
154215
let wasm_hash = env().deployer().upload_contract_wasm(wasm);
155-
if let Some(address) = self.0.get(name.clone()) {
156-
let contract = core_riff::Client::new(env(), &address);
216+
if let Some(contract_state) = self.0.get(name.clone()) {
217+
let address = contract_state.contract_id();
218+
let contract = core_riff::Client::new(env(), address);
157219
contract.redeploy(&wasm_hash);
158-
return Ok(address);
220+
return Ok(address.clone());
159221
}
160222
let salt = hash_string(&name);
161223
let id = deploy_and_init(&owner, salt, wasm_hash)?;
162-
self.0.set(name, id.clone());
224+
self.0.set(name, ContractType::ContractById(id.clone()));
163225
Ok(id)
164226
}
165227
}

deploy.sh

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ echo $ID
4949
if test "$FILE_HASH" = ""; then
5050
just publish smartdeploy
5151
just claim_self
52+
just set_owner default
5253
fi
5354

5455
if test "$SOROBAN_NETWORK" = "testnet"; then

justfile

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -75,8 +75,11 @@ setup_default:
7575
@./deploy.sh
7676

7777
[private]
78-
@claim_self:
79-
just smartdeploy claim_deployed_contract --deployed_name smartdeploy --id {{ id }}
78+
@claim_self owner='default':
79+
just smartdeploy claim_already_deployed_contract --deployed_name smartdeploy --id {{ id }} --owner {{owner}}
80+
81+
@set_owner owner:
82+
@just smartdeploy_raw -- owner_set --new_owner {{ owner }}
8083

8184
[private]
8285
@install_self:

0 commit comments

Comments
 (0)