Proxy
This example shows how you can use the implementation of proxy to to implement proxy pattern for upgradeable contracts.
Disclaimer
Delegate calls were marked as a possible attack vector in ink! Therefore the Proxy
pattern will not work within OpenBrush until this is reimplemented in ink! 4.
You can use this tutorial for general understanding of Proxy
pattern.
Step 1: Import default implementation
With default Cargo.toml
,
you need to enable corresponding features, embed modules data structures and implement them via #[openbrush::implementation]
macro
as described in that section.
The main traits are Ownable
and Proxy
.
Step 2: Define constructor
Define the constructor where you initialize the owner with the contract initiator and passing code hash of the logic layer.
impl Contract {
#[ink(constructor)]
pub fn new(forward_to: Hash) -> Self {
let mut instance = Self::default();
let caller = Self::env().caller();
instance._init_with_forward_to(forward_to);
instance._init_with_owner(caller);
instance
}
}
Step 3: Define forward function
Define the forward function to make delegate calls of upgradeable contract through proxy contract.
#![cfg_attr(not(feature = "std"), no_std, no_main)]
#[openbrush::implementation(Proxy, Ownable)]
#[openbrush::contract]
pub mod proxy {
use openbrush::traits::Storage;
#[ink(storage)]
#[derive(Default, Storage)]
pub struct Contract {
#[storage_field]
proxy: proxy::Data,
#[storage_field]
ownable: ownable::Data,
}
impl Contract {
#[ink(constructor)]
pub fn new(forward_to: Hash) -> Self {
let mut instance = Self::default();
proxy::Internal::_init_with_forward_to(&mut instance, forward_to);
ownable::Internal::_init_with_owner(&mut instance, Self::env().caller());
instance
}
#[ink(message, payable, selector = _)]
pub fn forward(&self) {
proxy::Internal::_fallback(self)
}
}
}
You can check an example of the usage of Proxy.