1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
#![cfg_attr(not(feature = "std"), no_std)]
use ink_lang as ink;
#[ink::contract]
mod delegator {
use accumulator::AccumulatorRef;
use adder::AdderRef;
use ink_storage::traits::{
PackedLayout,
SpreadLayout,
};
use subber::SubberRef;
/// Specifies the state of the `delegator` contract.
///
/// In `Adder` state the `delegator` contract will delegate to the `Adder` contract
/// and in `Subber` state will delegate to the `Subber` contract.
///
/// The initial state is `Adder`.
#[derive(
Debug,
Copy,
Clone,
PartialEq,
Eq,
scale::Encode,
scale::Decode,
SpreadLayout,
PackedLayout,
)]
#[cfg_attr(
feature = "std",
derive(::scale_info::TypeInfo, ::ink_storage::traits::StorageLayout)
)]
pub enum Which {
Adder,
Subber,
}
/// Delegates calls to an `adder` or `subber` contract to mutate
/// a value in an `accumulator` contract.
///
/// # Note
///
/// In order to instantiate the `delegator` smart contract we first
/// have to manually put the code of the `accumulator`, `adder`
/// and `subber` smart contracts, receive their code hashes from
/// the signalled events and put their code hash into our
/// `delegator` smart contract.
///
/// The `AccumulatorRef`, `AdderRef` and `SubberRef` are smart contract
/// reference types that have been automatically generated by ink!.
#[ink(storage)]
pub struct Delegator {
/// Says which of `adder` or `subber` is currently in use.
which: Which,
/// The `accumulator` smart contract.
accumulator: AccumulatorRef,
/// The `adder` smart contract.
adder: AdderRef,
/// The `subber` smart contract.
subber: SubberRef,
}
impl Delegator {
/// Instantiate a `delegator` contract with the given sub-contract codes.
#[ink(constructor)]
pub fn new(
init_value: i32,
version: u32,
accumulator_code_hash: Hash,
adder_code_hash: Hash,
subber_code_hash: Hash,
) -> Self {
let total_balance = Self::env().balance();
let salt = version.to_le_bytes();
let accumulator = AccumulatorRef::new(init_value)
.endowment(total_balance / 4)
.code_hash(accumulator_code_hash)
.salt_bytes(salt)
.instantiate()
.unwrap_or_else(|error| {
panic!(
"failed at instantiating the Accumulator contract: {:?}",
error
)
});
let adder = AdderRef::new(accumulator.clone())
.endowment(total_balance / 4)
.code_hash(adder_code_hash)
.salt_bytes(salt)
.instantiate()
.unwrap_or_else(|error| {
panic!("failed at instantiating the Adder contract: {:?}", error)
});
let subber = SubberRef::new(accumulator.clone())
.endowment(total_balance / 4)
.code_hash(subber_code_hash)
.salt_bytes(salt)
.instantiate()
.unwrap_or_else(|error| {
panic!("failed at instantiating the Subber contract: {:?}", error)
});
Self {
which: Which::Adder,
accumulator,
adder,
subber,
}
}
/// Returns the `accumulator` value.
#[ink(message)]
pub fn get(&self) -> i32 {
self.accumulator.get()
}
/// Delegates the call to either `Adder` or `Subber`.
#[ink(message)]
pub fn change(&mut self, by: i32) {
match self.which {
Which::Adder => self.adder.inc(by),
Which::Subber => self.subber.dec(by),
}
}
/// Switches the `delegator` contract.
#[ink(message)]
pub fn switch(&mut self) {
match self.which {
Which::Adder => {
self.which = Which::Subber;
}
Which::Subber => {
self.which = Which::Adder;
}
}
}
}
}