pub use crate::{
diamond,
ownable,
traits::{
diamond::*,
ownable::*,
},
};
pub use diamond::Internal as _;
pub use ownable::Internal as _;
use ink::{
env::call::{
ExecutionInput,
Selector as InkSelector,
},
prelude::vec::Vec,
primitives::Clear,
storage::traits::{
AutoStorableHint,
ManualKey,
Storable,
StorableHint,
},
};
use openbrush::{
modifiers,
storage::Mapping,
traits::{
Hash,
OccupiedStorage,
Storage,
},
};
pub const STORAGE_KEY: u32 = openbrush::storage_unique_key!(Data);
#[derive(Default, Debug)]
#[openbrush::upgradeable_storage(STORAGE_KEY)]
pub struct Data<D = ()>
where
D: Storable
+ StorableHint<ManualKey<913099263>>
+ AutoStorableHint<ManualKey<1826024066, ManualKey<{ STORAGE_KEY }>>, Type = D>,
{
pub selector_to_hash: Mapping<Selector, Hash>,
pub hash_to_selectors: Mapping<Hash, Vec<Selector>>,
pub handler: D,
}
impl<D, T> Diamond for T
where
D: DiamondCut,
D: Storable
+ StorableHint<ManualKey<913099263>>
+ AutoStorableHint<ManualKey<1826024066, ManualKey<{ STORAGE_KEY }>>, Type = D>,
T: Storage<ownable::Data>,
T: Storage<Data<D>>,
T: OccupiedStorage<STORAGE_KEY, WithData = Data<D>>,
{
#[modifiers(ownable::only_owner)]
default fn diamond_cut(&mut self, diamond_cut: Vec<FacetCut>, init: Option<InitCall>) -> Result<(), DiamondError> {
self._diamond_cut(diamond_cut, init)
}
}
pub trait Internal {
fn _emit_diamond_cut_event(&self, diamond_cut: &Vec<FacetCut>, init: &Option<InitCall>);
fn _diamond_cut(&mut self, diamond_cut: Vec<FacetCut>, init: Option<InitCall>) -> Result<(), DiamondError>;
fn _diamond_cut_facet(&mut self, facet_cut: &FacetCut) -> Result<(), DiamondError>;
fn _fallback(&self) -> !;
fn _init_call(&self, call: InitCall) -> !;
fn _remove_facet(&mut self, code_hash: Hash);
fn _remove_selectors(&mut self, facet_cut: &FacetCut);
}
impl<D, T> Internal for T
where
D: DiamondCut,
D: Storable
+ StorableHint<ManualKey<913099263>>
+ AutoStorableHint<ManualKey<1826024066, ManualKey<{ STORAGE_KEY }>>, Type = D>,
T: Storage<Data<D>>,
T: OccupiedStorage<STORAGE_KEY, WithData = Data<D>>,
{
default fn _emit_diamond_cut_event(&self, _diamond_cut: &Vec<FacetCut>, _init: &Option<InitCall>) {}
default fn _diamond_cut(&mut self, diamond_cut: Vec<FacetCut>, init: Option<InitCall>) -> Result<(), DiamondError> {
for facet_cut in diamond_cut.iter() {
self._diamond_cut_facet(facet_cut)?;
}
self._emit_diamond_cut_event(&diamond_cut, &init);
if init.is_some() {
self.flush();
self._init_call(init.unwrap());
}
Ok(())
}
default fn _diamond_cut_facet(&mut self, facet_cut: &FacetCut) -> Result<(), DiamondError> {
let code_hash = facet_cut.hash;
if code_hash.is_clear() {
return Err(DiamondError::EmptyCodeHash)
}
if facet_cut.selectors.is_empty() {
self._remove_facet(code_hash);
} else {
for selector in facet_cut.selectors.iter() {
let selector_hash = self.data().selector_to_hash.get(&selector);
if selector_hash.and_then(|hash| Some(hash == code_hash)).unwrap_or(false) {
continue
} else if selector_hash.is_some() {
return Err(DiamondError::ReplaceExisting(selector_hash.unwrap()))
} else {
self.data().selector_to_hash.insert(&selector, &code_hash);
}
}
if self.data().hash_to_selectors.get(&code_hash).is_none() {
self.data().handler.on_add_facet(code_hash);
}
self._remove_selectors(facet_cut);
self.data().hash_to_selectors.insert(&code_hash, &facet_cut.selectors);
}
Ok(())
}
default fn _fallback(&self) -> ! {
let selector = ink::env::decode_input::<Selector>().unwrap_or_else(|_| panic!("Calldata error"));
let delegate_code = self.data().selector_to_hash.get(&selector);
if delegate_code.is_none() {
panic!("Function is not registered");
}
ink::env::call::build_call::<ink::env::DefaultEnvironment>()
.delegate(delegate_code.unwrap())
.call_flags(
ink::env::CallFlags::default()
.set_forward_input(true)
.set_tail_call(true),
)
.try_invoke()
.unwrap_or_else(|err| panic!("delegate call to {:?} failed due to {:?}", delegate_code, err))
.unwrap_or_else(|err| panic!("delegate call to {:?} failed due to {:?}", delegate_code, err));
unreachable!("the _fallback call will never return since `tail_call` was set");
}
default fn _init_call(&self, call: InitCall) -> ! {
ink::env::call::build_call::<ink::env::DefaultEnvironment>()
.delegate(call.hash)
.exec_input(ExecutionInput::new(InkSelector::new(call.selector)).push_arg(call.input))
.call_flags(ink::env::CallFlags::default()
.set_tail_call(true))
.returns::<()>()
.try_invoke()
.unwrap_or_else(|err| panic!("init call failed due to {:?}", err))
.unwrap_or_else(|err| panic!("init call failed due to {:?}", err));
unreachable!("the _init_call call will never return since `tail_call` was set");
}
default fn _remove_facet(&mut self, code_hash: Hash) {
let vec = self.data().hash_to_selectors.get(&code_hash).unwrap();
vec.iter().for_each(|old_selector| {
self.data().selector_to_hash.remove(&old_selector);
});
self.data().hash_to_selectors.remove(&code_hash);
self.data().handler.on_remove_facet(code_hash);
}
default fn _remove_selectors(&mut self, facet_cut: &FacetCut) {
let selectors = self
.data()
.hash_to_selectors
.get(&facet_cut.hash)
.unwrap_or(Vec::<Selector>::new());
for selector in selectors.iter() {
if !facet_cut.selectors.contains(&selector) {
self.data().selector_to_hash.remove(&selector);
}
}
}
}
pub trait DiamondCut {
fn on_add_facet(&mut self, code_hash: Hash);
fn on_remove_facet(&mut self, code_hash: Hash);
}
impl DiamondCut for () {
#[inline(always)]
fn on_add_facet(&mut self, _code_hash: Hash) {}
#[inline(always)]
fn on_remove_facet(&mut self, _code_hash: Hash) {}
}