@layerzerolabs/protocol-stellar-v2 0.2.18 → 0.2.20
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.turbo/turbo-build.log +303 -253
- package/.turbo/turbo-lint.log +66 -65
- package/.turbo/turbo-test.log +1312 -1282
- package/Cargo.lock +21 -8
- package/Cargo.toml +2 -0
- package/contracts/ERROR_SPEC.md +9 -2
- package/contracts/common-macros/src/contract_ttl.rs +18 -7
- package/contracts/common-macros/src/lib.rs +4 -4
- package/contracts/common-macros/src/tests/contract_ttl.rs +1 -1
- package/contracts/common-macros/src/tests/snapshots/common_macros__tests__contract_ttl__snapshot_generated_contractimpl_code.snap +2 -1
- package/contracts/common-macros/src/tests/snapshots/common_macros__tests__upgradeable__snapshot_generated_upgradeable_code.snap +7 -12
- package/contracts/common-macros/src/upgradeable.rs +15 -21
- package/contracts/message-libs/uln-302/src/events.rs +4 -0
- package/contracts/message-libs/uln-302/src/send_uln.rs +23 -7
- package/contracts/message-libs/uln-302/src/tests/send_uln302/send.rs +38 -64
- package/contracts/oapps/counter/Cargo.toml +1 -0
- package/contracts/oapps/counter/integration_tests/setup_uln.rs +1 -1
- package/contracts/oapps/oapp/src/oapp_receiver.rs +1 -1
- package/contracts/oapps/oapp/src/tests/test_oapp_core.rs +113 -65
- package/contracts/oapps/oapp/src/tests/test_oapp_options_type3.rs +111 -82
- package/contracts/oapps/oapp/src/tests/test_oapp_receiver.rs +293 -65
- package/contracts/oapps/oapp/src/tests/test_oapp_sender.rs +331 -56
- package/contracts/oapps/oft/Cargo.toml +10 -7
- package/contracts/oapps/{oft-std → oft}/integration-tests/extensions/test_oft_fee.rs +3 -4
- package/contracts/oapps/{oft-std → oft}/integration-tests/extensions/test_pausable.rs +2 -3
- package/contracts/oapps/{oft-std → oft}/integration-tests/extensions/test_rate_limiter.rs +1 -1
- package/contracts/oapps/oft/integration-tests/mod.rs +1 -1
- package/contracts/oapps/oft/integration-tests/setup.rs +28 -127
- package/contracts/oapps/oft/integration-tests/utils.rs +254 -21
- package/contracts/oapps/oft/src/extensions/oft_fee.rs +23 -8
- package/contracts/oapps/oft/src/extensions/pausable.rs +19 -4
- package/contracts/oapps/oft/src/extensions/rate_limiter.rs +52 -28
- package/contracts/oapps/oft/src/lib.rs +10 -14
- package/contracts/oapps/oft/src/oft.rs +143 -193
- package/contracts/oapps/oft/src/oft_types/lock_unlock.rs +9 -11
- package/contracts/oapps/oft/src/oft_types/mint_burn.rs +12 -14
- package/contracts/oapps/oft/src/oft_types/mod.rs +13 -0
- package/contracts/oapps/{oft-std → oft-core}/Cargo.toml +6 -4
- package/contracts/oapps/{oft-std → oft-core}/integration-tests/mod.rs +1 -1
- package/contracts/oapps/{oft-std → oft-core}/integration-tests/setup.rs +126 -29
- package/contracts/oapps/{oft → oft-core}/integration-tests/test_with_sml.rs +3 -3
- package/contracts/oapps/oft-core/integration-tests/utils.rs +201 -0
- package/contracts/oapps/oft-core/src/lib.rs +18 -0
- package/contracts/oapps/oft-core/src/oft_core.rs +479 -0
- package/contracts/oapps/{oft → oft-core}/src/tests/mod.rs +0 -2
- package/contracts/oapps/{oft → oft-core}/src/tests/test_lz_receive.rs +7 -7
- package/contracts/oapps/{oft → oft-core}/src/tests/test_oft_msg_codec.rs +4 -4
- package/contracts/oapps/{oft → oft-core}/src/tests/test_resolve_address.rs +3 -3
- package/contracts/oapps/{oft → oft-core}/src/tests/test_utils.rs +46 -27
- package/contracts/oapps/{oft → oft-core}/src/utils.rs +1 -1
- package/contracts/upgrader/src/lib.rs +30 -57
- package/contracts/upgrader/src/tests/test_data/test_upgradeable_contract1.wasm +0 -0
- package/contracts/upgrader/src/tests/test_data/test_upgradeable_contract2.wasm +0 -0
- package/contracts/upgrader/src/tests/test_upgrader.rs +44 -35
- package/contracts/utils/src/buffer_reader.rs +1 -0
- package/contracts/utils/src/errors.rs +8 -2
- package/contracts/utils/src/ownable.rs +125 -3
- package/contracts/utils/src/tests/option_ext.rs +1 -1
- package/contracts/utils/src/tests/ownable.rs +445 -7
- package/contracts/utils/src/tests/ttl_configurable.rs +2 -2
- package/contracts/utils/src/tests/upgradeable.rs +372 -175
- package/contracts/utils/src/ttl_configurable.rs +3 -3
- package/contracts/utils/src/upgradeable.rs +48 -23
- package/contracts/workers/dvn/Cargo.toml +1 -0
- package/contracts/workers/dvn/src/auth.rs +12 -42
- package/contracts/workers/dvn/src/dvn.rs +16 -31
- package/contracts/workers/dvn/src/errors.rs +0 -1
- package/contracts/workers/dvn/src/interfaces/dvn.rs +35 -0
- package/contracts/workers/dvn/src/lib.rs +4 -3
- package/contracts/workers/dvn/src/tests/auth.rs +1 -1
- package/contracts/workers/dvn/src/tests/dvn.rs +19 -15
- package/contracts/workers/dvn/src/tests/multisig/set_threshold.rs +2 -4
- package/contracts/workers/dvn/src/tests/multisig/verify_signatures.rs +1 -3
- package/contracts/workers/dvn/src/tests/setup.rs +5 -9
- package/contracts/workers/dvn-fee-lib/Cargo.toml +1 -1
- package/contracts/workers/dvn-fee-lib/src/dvn_fee_lib.rs +3 -5
- package/contracts/workers/dvn-fee-lib/src/tests/dvn_fee_lib.rs +2 -3
- package/contracts/workers/executor/Cargo.toml +1 -0
- package/contracts/workers/executor/src/executor.rs +15 -26
- package/contracts/workers/executor-fee-lib/Cargo.toml +2 -1
- package/contracts/workers/executor-fee-lib/src/executor_fee_lib.rs +63 -5
- package/contracts/workers/executor-fee-lib/src/executor_option.rs +28 -1
- package/contracts/workers/executor-fee-lib/src/lib.rs +3 -0
- package/contracts/workers/executor-fee-lib/src/tests/executor_fee_lib.rs +701 -0
- package/contracts/workers/executor-fee-lib/src/tests/executor_option.rs +370 -0
- package/contracts/workers/executor-fee-lib/src/tests/mod.rs +4 -0
- package/contracts/workers/executor-fee-lib/src/tests/setup.rs +60 -0
- package/contracts/workers/executor-helper/src/lib.rs +3 -0
- package/contracts/workers/executor-helper/src/tests/executor_helper.rs +184 -0
- package/contracts/workers/executor-helper/src/tests/mod.rs +2 -0
- package/contracts/workers/executor-helper/src/tests/setup.rs +366 -0
- package/contracts/workers/fee-lib-interfaces/Cargo.toml +14 -0
- package/contracts/workers/{worker/src/interfaces/mod.rs → fee-lib-interfaces/src/lib.rs} +4 -3
- package/contracts/workers/price-feed/Cargo.toml +2 -1
- package/contracts/workers/price-feed/src/events.rs +1 -1
- package/contracts/workers/price-feed/src/lib.rs +3 -0
- package/contracts/workers/price-feed/src/price_feed.rs +6 -12
- package/contracts/workers/price-feed/src/storage.rs +1 -1
- package/contracts/workers/price-feed/src/tests/mod.rs +2 -0
- package/contracts/workers/price-feed/src/tests/price_feed.rs +869 -0
- package/contracts/workers/price-feed/src/tests/setup.rs +70 -0
- package/contracts/workers/price-feed/src/types.rs +1 -1
- package/contracts/workers/worker/src/errors.rs +0 -3
- package/contracts/workers/worker/src/lib.rs +0 -2
- package/contracts/workers/worker/src/storage.rs +32 -29
- package/contracts/workers/worker/src/tests/setup.rs +1 -7
- package/contracts/workers/worker/src/tests/worker.rs +50 -42
- package/contracts/workers/worker/src/worker.rs +49 -58
- package/package.json +4 -5
- package/sdk/.turbo/turbo-test.log +229 -217
- package/sdk/dist/generated/bml.d.ts +39 -1
- package/sdk/dist/generated/bml.js +33 -8
- package/sdk/dist/generated/counter.d.ts +131 -3
- package/sdk/dist/generated/counter.js +41 -10
- package/sdk/dist/generated/dvn.d.ts +431 -362
- package/sdk/dist/generated/dvn.js +80 -55
- package/sdk/dist/generated/dvn_fee_lib.d.ts +327 -251
- package/sdk/dist/generated/dvn_fee_lib.js +55 -57
- package/sdk/dist/generated/endpoint.d.ts +131 -3
- package/sdk/dist/generated/endpoint.js +41 -10
- package/sdk/dist/generated/executor.d.ts +503 -339
- package/sdk/dist/generated/executor.js +80 -48
- package/sdk/dist/generated/executor_fee_lib.d.ts +395 -319
- package/sdk/dist/generated/executor_fee_lib.js +54 -56
- package/sdk/dist/generated/executor_helper.d.ts +53 -187
- package/sdk/dist/generated/executor_helper.js +47 -29
- package/sdk/dist/generated/layerzero_view.d.ts +1271 -0
- package/sdk/dist/generated/layerzero_view.js +294 -0
- package/sdk/dist/generated/oft.d.ts +1851 -0
- package/sdk/dist/generated/oft.js +347 -0
- package/sdk/dist/generated/price_feed.d.ts +329 -253
- package/sdk/dist/generated/price_feed.js +55 -57
- package/sdk/dist/generated/sml.d.ts +131 -3
- package/sdk/dist/generated/sml.js +41 -10
- package/sdk/dist/generated/treasury.d.ts +131 -3
- package/sdk/dist/generated/treasury.js +41 -10
- package/sdk/dist/generated/uln302.d.ts +131 -3
- package/sdk/dist/generated/uln302.js +43 -12
- package/sdk/dist/generated/upgrader.d.ts +201 -15
- package/sdk/dist/generated/upgrader.js +99 -1
- package/sdk/dist/index.d.ts +2 -2
- package/sdk/dist/index.js +3 -3
- package/sdk/package.json +3 -2
- package/sdk/src/index.ts +3 -3
- package/sdk/test/oft-sml.test.ts +20 -20
- package/sdk/test/upgrader.test.ts +2 -3
- package/sdk/turbo.json +8 -0
- package/tools/ts-bindings-gen/Cargo.toml +2 -0
- package/tools/ts-bindings-gen/src/main.rs +53 -5
- package/turbo.json +0 -2
- package/contracts/oapps/oft/src/interfaces/mint_burn_token.rs +0 -23
- package/contracts/oapps/oft/src/interfaces/mod.rs +0 -3
- package/contracts/oapps/oft/src/oft_impl.rs +0 -201
- package/contracts/oapps/oft/src/tests/extensions/mod.rs +0 -11
- package/contracts/oapps/oft/src/tests/extensions/setup.rs +0 -917
- package/contracts/oapps/oft/src/tests/extensions/test_oft_fee.rs +0 -751
- package/contracts/oapps/oft/src/tests/extensions/test_pausable.rs +0 -434
- package/contracts/oapps/oft/src/tests/extensions/test_rate_limiter.rs +0 -1080
- package/contracts/oapps/oft-std/integration-tests/utils.rs +0 -427
- package/contracts/oapps/oft-std/src/lib.rs +0 -16
- package/contracts/oapps/oft-std/src/oft.rs +0 -174
- package/sdk/dist/generated/oft_std.d.ts +0 -1722
- package/sdk/dist/generated/oft_std.js +0 -316
- package/sdk/dist/wasm/blocked-message-lib.d.ts +0 -1
- package/sdk/dist/wasm/blocked-message-lib.js +0 -2
- package/sdk/dist/wasm/counter.d.ts +0 -1
- package/sdk/dist/wasm/counter.js +0 -2
- package/sdk/dist/wasm/dvn-fee-lib.d.ts +0 -1
- package/sdk/dist/wasm/dvn-fee-lib.js +0 -2
- package/sdk/dist/wasm/dvn.d.ts +0 -1
- package/sdk/dist/wasm/dvn.js +0 -2
- package/sdk/dist/wasm/endpoint-v2.d.ts +0 -1
- package/sdk/dist/wasm/endpoint-v2.js +0 -2
- package/sdk/dist/wasm/executor-fee-lib.d.ts +0 -1
- package/sdk/dist/wasm/executor-fee-lib.js +0 -2
- package/sdk/dist/wasm/executor-helper.d.ts +0 -1
- package/sdk/dist/wasm/executor-helper.js +0 -2
- package/sdk/dist/wasm/executor.d.ts +0 -1
- package/sdk/dist/wasm/executor.js +0 -2
- package/sdk/dist/wasm/layerzero-views.d.ts +0 -1
- package/sdk/dist/wasm/layerzero-views.js +0 -2
- package/sdk/dist/wasm/oft-std.d.ts +0 -1
- package/sdk/dist/wasm/oft-std.js +0 -2
- package/sdk/dist/wasm/price-feed.d.ts +0 -1
- package/sdk/dist/wasm/price-feed.js +0 -2
- package/sdk/dist/wasm/simple-message-lib.d.ts +0 -1
- package/sdk/dist/wasm/simple-message-lib.js +0 -2
- package/sdk/dist/wasm/treasury.d.ts +0 -1
- package/sdk/dist/wasm/treasury.js +0 -2
- package/sdk/dist/wasm/uln302.d.ts +0 -1
- package/sdk/dist/wasm/uln302.js +0 -2
- package/sdk/dist/wasm/upgrader.d.ts +0 -1
- package/sdk/dist/wasm/upgrader.js +0 -2
- package/sdk/dist/wasm.d.ts +0 -15
- package/sdk/dist/wasm.js +0 -15
- /package/contracts/oapps/{oft-std → oft}/integration-tests/extensions/mod.rs +0 -0
- /package/contracts/oapps/{oft → oft-core}/src/codec/mod.rs +0 -0
- /package/contracts/oapps/{oft → oft-core}/src/codec/oft_compose_msg_codec.rs +0 -0
- /package/contracts/oapps/{oft → oft-core}/src/codec/oft_msg_codec.rs +0 -0
- /package/contracts/oapps/{oft → oft-core}/src/errors.rs +0 -0
- /package/contracts/oapps/{oft → oft-core}/src/events.rs +0 -0
- /package/contracts/oapps/{oft → oft-core}/src/storage.rs +0 -0
- /package/contracts/oapps/{oft → oft-core}/src/tests/test_decimals.rs +0 -0
- /package/contracts/oapps/{oft → oft-core}/src/tests/test_oft_compose_msg_codec.rs +0 -0
- /package/contracts/oapps/{oft → oft-core}/src/tests/test_oft_version.rs +0 -0
- /package/contracts/oapps/{oft → oft-core}/src/tests/test_quote_oft.rs +0 -0
- /package/contracts/oapps/{oft → oft-core}/src/tests/test_quote_send.rs +0 -0
- /package/contracts/oapps/{oft → oft-core}/src/tests/test_send.rs +0 -0
- /package/contracts/oapps/{oft → oft-core}/src/tests/test_token.rs +0 -0
- /package/contracts/oapps/{oft → oft-core}/src/types.rs +0 -0
- /package/contracts/workers/{worker/src/interfaces → fee-lib-interfaces/src}/dvn_fee_lib.rs +0 -0
- /package/contracts/workers/{worker/src/interfaces → fee-lib-interfaces/src}/executor_fee_lib.rs +0 -0
- /package/contracts/workers/{worker/src/interfaces → fee-lib-interfaces/src}/price_feed.rs +0 -0
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
use crate::{
|
|
6
6
|
codec::oft_msg_codec::OFTMessage,
|
|
7
|
-
|
|
7
|
+
oft_core::OFTClient,
|
|
8
8
|
types::{OFTReceipt, SendParam},
|
|
9
9
|
};
|
|
10
10
|
use endpoint_v2::{LayerZeroReceiverClient, MessagingFee, MessagingParams, MessagingReceipt, Origin};
|
|
@@ -104,15 +104,21 @@ pub fn create_origin(src_eid: u32, sender: &BytesN<32>, nonce: u64) -> Origin {
|
|
|
104
104
|
// ==================== Test OFT Contracts ====================
|
|
105
105
|
|
|
106
106
|
mod test_mint_burn_oft {
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
use crate::types::OFTReceipt;
|
|
107
|
+
use crate::{
|
|
108
|
+
self as oft_core,
|
|
109
|
+
oft_core::{lz_receive, OFTCore, OFTInternal},
|
|
110
|
+
types::OFTReceipt,
|
|
111
|
+
};
|
|
113
112
|
use endpoint_v2::Origin;
|
|
114
113
|
use oapp::oapp_receiver::LzReceiveInternal;
|
|
115
|
-
use soroban_sdk::{contractimpl, Address, Bytes, BytesN, Env};
|
|
114
|
+
use soroban_sdk::{contractclient, contractimpl, Address, Bytes, BytesN, Env};
|
|
115
|
+
|
|
116
|
+
#[contractclient(name = "MintBurnTokenClient")]
|
|
117
|
+
#[allow(dead_code)]
|
|
118
|
+
trait MintBurnToken {
|
|
119
|
+
fn mint(env: Env, to: Address, amount: i128);
|
|
120
|
+
fn burn(env: Env, from: Address, amount: i128);
|
|
121
|
+
}
|
|
116
122
|
|
|
117
123
|
#[oapp_macros::oapp]
|
|
118
124
|
pub struct TestMintBurnOFT;
|
|
@@ -127,12 +133,12 @@ mod test_mint_burn_oft {
|
|
|
127
133
|
delegate: &Option<Address>,
|
|
128
134
|
shared_decimals: u32,
|
|
129
135
|
) {
|
|
130
|
-
|
|
136
|
+
Self::__initialize_oft(env, owner, token, endpoint, delegate, shared_decimals)
|
|
131
137
|
}
|
|
132
138
|
}
|
|
133
139
|
|
|
134
140
|
#[contractimpl(contracttrait)]
|
|
135
|
-
impl
|
|
141
|
+
impl OFTCore for TestMintBurnOFT {}
|
|
136
142
|
|
|
137
143
|
impl LzReceiveInternal for TestMintBurnOFT {
|
|
138
144
|
fn __lz_receive(
|
|
@@ -144,32 +150,36 @@ mod test_mint_burn_oft {
|
|
|
144
150
|
executor: &Address,
|
|
145
151
|
value: i128,
|
|
146
152
|
) {
|
|
147
|
-
|
|
153
|
+
lz_receive::<Self>(env, executor, origin, guid, message, extra_data, value)
|
|
148
154
|
}
|
|
149
155
|
}
|
|
150
156
|
|
|
151
157
|
impl OFTInternal for TestMintBurnOFT {
|
|
152
158
|
fn __debit(env: &Env, sender: &Address, amount_ld: i128, min_amount_ld: i128, dst_eid: u32) -> OFTReceipt {
|
|
153
|
-
|
|
159
|
+
// Inline mint_burn::debit implementation
|
|
160
|
+
let receipt = Self::__debit_view(env, amount_ld, min_amount_ld, dst_eid);
|
|
161
|
+
MintBurnTokenClient::new(env, &Self::token(env)).burn(sender, &receipt.amount_received_ld);
|
|
162
|
+
receipt
|
|
154
163
|
}
|
|
155
164
|
|
|
156
|
-
fn __credit(env: &Env, to: &Address, amount_ld: i128,
|
|
157
|
-
|
|
165
|
+
fn __credit(env: &Env, to: &Address, amount_ld: i128, _src_eid: u32) -> i128 {
|
|
166
|
+
// Inline mint_burn::credit implementation
|
|
167
|
+
MintBurnTokenClient::new(env, &Self::token(env)).mint(to, &amount_ld);
|
|
168
|
+
amount_ld
|
|
158
169
|
}
|
|
159
170
|
}
|
|
160
171
|
}
|
|
161
172
|
pub use test_mint_burn_oft::TestMintBurnOFT;
|
|
162
173
|
|
|
163
174
|
mod test_lock_unlock_oft {
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
use crate::types::OFTReceipt;
|
|
175
|
+
use crate::{
|
|
176
|
+
self as oft_core,
|
|
177
|
+
oft_core::{lz_receive, OFTCore, OFTInternal},
|
|
178
|
+
types::OFTReceipt,
|
|
179
|
+
};
|
|
170
180
|
use endpoint_v2::Origin;
|
|
171
181
|
use oapp::oapp_receiver::{LzReceiveInternal, OAppReceiver};
|
|
172
|
-
use soroban_sdk::{contractimpl, Address, Bytes, BytesN, Env};
|
|
182
|
+
use soroban_sdk::{contractimpl, token::TokenClient, Address, Bytes, BytesN, Env};
|
|
173
183
|
|
|
174
184
|
#[oapp_macros::oapp(custom = [receiver])]
|
|
175
185
|
pub struct TestLockUnlockOFT;
|
|
@@ -184,12 +194,12 @@ mod test_lock_unlock_oft {
|
|
|
184
194
|
delegate: &Option<Address>,
|
|
185
195
|
shared_decimals: u32,
|
|
186
196
|
) {
|
|
187
|
-
|
|
197
|
+
Self::__initialize_oft(env, owner, token, endpoint, delegate, shared_decimals)
|
|
188
198
|
}
|
|
189
199
|
}
|
|
190
200
|
|
|
191
201
|
#[contractimpl(contracttrait)]
|
|
192
|
-
impl
|
|
202
|
+
impl OFTCore for TestLockUnlockOFT {}
|
|
193
203
|
|
|
194
204
|
impl LzReceiveInternal for TestLockUnlockOFT {
|
|
195
205
|
fn __lz_receive(
|
|
@@ -201,7 +211,7 @@ mod test_lock_unlock_oft {
|
|
|
201
211
|
executor: &Address,
|
|
202
212
|
value: i128,
|
|
203
213
|
) {
|
|
204
|
-
|
|
214
|
+
lz_receive::<Self>(env, executor, origin, guid, message, extra_data, value)
|
|
205
215
|
}
|
|
206
216
|
}
|
|
207
217
|
|
|
@@ -211,11 +221,20 @@ mod test_lock_unlock_oft {
|
|
|
211
221
|
|
|
212
222
|
impl OFTInternal for TestLockUnlockOFT {
|
|
213
223
|
fn __debit(env: &Env, sender: &Address, amount_ld: i128, min_amount_ld: i128, dst_eid: u32) -> OFTReceipt {
|
|
214
|
-
|
|
224
|
+
// Inline lock_unlock::debit implementation
|
|
225
|
+
let receipt: OFTReceipt = Self::__debit_view(env, amount_ld, min_amount_ld, dst_eid);
|
|
226
|
+
TokenClient::new(env, &Self::token(env)).transfer(
|
|
227
|
+
sender,
|
|
228
|
+
env.current_contract_address(),
|
|
229
|
+
&receipt.amount_received_ld,
|
|
230
|
+
);
|
|
231
|
+
receipt
|
|
215
232
|
}
|
|
216
233
|
|
|
217
|
-
fn __credit(env: &Env, to: &Address, amount_ld: i128,
|
|
218
|
-
|
|
234
|
+
fn __credit(env: &Env, to: &Address, amount_ld: i128, _src_eid: u32) -> i128 {
|
|
235
|
+
// Inline lock_unlock::credit implementation
|
|
236
|
+
TokenClient::new(env, &Self::token(env)).transfer(&env.current_contract_address(), to, &amount_ld);
|
|
237
|
+
amount_ld
|
|
219
238
|
}
|
|
220
239
|
}
|
|
221
240
|
}
|
|
@@ -38,7 +38,7 @@ pub fn remove_dust(amount_ld: i128, conversion_rate: i128) -> i128 {
|
|
|
38
38
|
///
|
|
39
39
|
/// # Returns
|
|
40
40
|
/// A 32-byte payload (contract ID hash or Ed25519 public key)
|
|
41
|
-
pub fn
|
|
41
|
+
pub fn address_payload(address: &Address) -> BytesN<32> {
|
|
42
42
|
match address.to_payload().unwrap() {
|
|
43
43
|
AddressPayload::ContractIdHash(payload) => payload,
|
|
44
44
|
AddressPayload::AccountIdPublicKeyEd25519(payload) => payload,
|
|
@@ -2,45 +2,25 @@
|
|
|
2
2
|
|
|
3
3
|
//! # Upgrader Contract
|
|
4
4
|
//!
|
|
5
|
-
//! A stateless utility contract for performing upgrade and migrate operations
|
|
6
|
-
//!
|
|
7
|
-
//! This contract provides a convenient way to upgrade other contracts, especially useful for
|
|
8
|
-
//! performing upgrade+migrate atomically in a single transaction.
|
|
5
|
+
//! A stateless utility contract for performing atomic upgrade and migrate operations
|
|
6
|
+
//! on contracts implementing the [`Upgradeable`](utils::upgradeable::Upgradeable) trait.
|
|
9
7
|
//!
|
|
10
8
|
//! ## Security Model
|
|
11
9
|
//!
|
|
12
|
-
//! The Upgrader is
|
|
13
|
-
//!
|
|
14
|
-
//!
|
|
10
|
+
//! The Upgrader is permissionless - anyone can call it, but security is enforced by the
|
|
11
|
+
//! target contract's authorization checks. The target contract's `#[only_auth]` guard
|
|
12
|
+
//! ensures only its authorizer can successfully upgrade it.
|
|
15
13
|
//!
|
|
16
14
|
//! ## Usage
|
|
17
15
|
//!
|
|
18
|
-
//! Deploy this contract once, then anyone can use it to upgrade contracts they own.
|
|
19
|
-
//!
|
|
20
16
|
//! ```ignore
|
|
21
|
-
//! // Deploy upgrader (no initialization needed)
|
|
22
|
-
//! let upgrader_id = env.register(Upgrader, ());
|
|
23
17
|
//! let upgrader = UpgraderClient::new(&env, &upgrader_id);
|
|
24
|
-
//!
|
|
25
|
-
//!
|
|
26
|
-
//! upgrader.upgrade(&target_contract, &new_wasm_hash);
|
|
27
|
-
//!
|
|
28
|
-
//! // Or upgrade and migrate in one transaction
|
|
29
|
-
//! let migration_data = vec![&env, val1, val2];
|
|
30
|
-
//! upgrader.upgrade_and_migrate(&target_contract, &new_wasm_hash, migration_data);
|
|
18
|
+
//! let migration_data = my_data.to_xdr(&env);
|
|
19
|
+
//! upgrader.upgrade_and_migrate(&target_contract, &new_wasm_hash, &migration_data);
|
|
31
20
|
//! ```
|
|
32
21
|
|
|
33
|
-
use soroban_sdk::{contract,
|
|
34
|
-
|
|
35
|
-
/// Symbol for the migrate function call
|
|
36
|
-
pub const MIGRATE: Symbol = symbol_short!("migrate");
|
|
37
|
-
|
|
38
|
-
/// Trait representing an upgradeable contract's interface
|
|
39
|
-
#[contractclient(name = "UpgradeableContractClient")]
|
|
40
|
-
pub trait UpgradeableContract {
|
|
41
|
-
/// Upgrades the contract to new WASM bytecode
|
|
42
|
-
fn upgrade(env: &Env, new_wasm_hash: BytesN<32>);
|
|
43
|
-
}
|
|
22
|
+
use soroban_sdk::{contract, contractimpl, xdr::ToXdr, Address, Bytes, BytesN, Env};
|
|
23
|
+
use utils::upgradeable::UpgradeableClient;
|
|
44
24
|
|
|
45
25
|
/// Upgrader contract for managing upgrades of other contracts.
|
|
46
26
|
///
|
|
@@ -51,46 +31,39 @@ pub struct Upgrader;
|
|
|
51
31
|
|
|
52
32
|
#[contractimpl]
|
|
53
33
|
impl Upgrader {
|
|
54
|
-
///
|
|
34
|
+
/// Upgrades a target contract without custom migration data.
|
|
35
|
+
///
|
|
36
|
+
/// This is a convenience wrapper that calls `upgrade_and_migrate` with empty migration data.
|
|
37
|
+
///
|
|
38
|
+
/// # Arguments
|
|
39
|
+
/// * `contract_address` - The address of the contract to upgrade
|
|
40
|
+
/// * `wasm_hash` - The hash of the new WASM bytecode
|
|
41
|
+
pub fn upgrade(env: &Env, contract_address: &Address, wasm_hash: &BytesN<32>) {
|
|
42
|
+
Self::upgrade_and_migrate(env, contract_address, wasm_hash, &().to_xdr(env));
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/// Upgrades a target contract and runs its migration in a single transaction.
|
|
55
46
|
///
|
|
56
47
|
/// The caller must be authorized as the authorizer of the target contract.
|
|
57
48
|
/// This is enforced by the target contract's `#[only_auth]` check.
|
|
58
49
|
///
|
|
59
|
-
/// This is useful for atomic upgrades where you want to ensure the migration
|
|
60
|
-
/// happens immediately after the upgrade, or the entire operation fails.
|
|
61
|
-
///
|
|
62
50
|
/// # Arguments
|
|
63
51
|
/// * `contract_address` - The address of the contract to upgrade
|
|
64
52
|
/// * `wasm_hash` - The hash of the new WASM bytecode
|
|
65
|
-
/// * `migration_data` -
|
|
66
|
-
///
|
|
53
|
+
/// * `migration_data` - XDR-encoded bytes to pass to the migrate function.
|
|
54
|
+
/// Use `value.to_xdr(&env)` to encode the target contract's MigrationData type.
|
|
67
55
|
///
|
|
68
56
|
/// # Example
|
|
69
57
|
/// ```ignore
|
|
70
|
-
///
|
|
71
|
-
///
|
|
72
|
-
/// &env,
|
|
73
|
-
/// 42u32.into_val(&env),
|
|
74
|
-
/// true.into_val(&env),
|
|
75
|
-
/// ];
|
|
76
|
-
/// upgrader.upgrade_and_migrate(&contract_addr, &wasm_hash, migration_data);
|
|
58
|
+
/// let migration_data = my_data.to_xdr(&env);
|
|
59
|
+
/// upgrader.upgrade_and_migrate(&contract_addr, &wasm_hash, &migration_data);
|
|
77
60
|
/// ```
|
|
78
|
-
pub fn upgrade_and_migrate(
|
|
79
|
-
env
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
migration_data: Vec<soroban_sdk::Val>,
|
|
83
|
-
) {
|
|
84
|
-
let contract_client = UpgradeableContractClient::new(env, contract_address);
|
|
85
|
-
|
|
86
|
-
// First upgrade the contract
|
|
87
|
-
contract_client.upgrade(&wasm_hash);
|
|
88
|
-
|
|
89
|
-
// Then call migrate with the provided data
|
|
90
|
-
// We use invoke_contract because the migration data type is unknown to this contract
|
|
91
|
-
env.invoke_contract::<()>(contract_address, &MIGRATE, migration_data);
|
|
61
|
+
pub fn upgrade_and_migrate(env: &Env, contract_address: &Address, wasm_hash: &BytesN<32>, migration_data: &Bytes) {
|
|
62
|
+
let client = UpgradeableClient::new(env, contract_address);
|
|
63
|
+
client.upgrade(wasm_hash);
|
|
64
|
+
client.migrate(migration_data);
|
|
92
65
|
}
|
|
93
66
|
}
|
|
94
67
|
|
|
95
68
|
#[cfg(test)]
|
|
96
|
-
mod tests;
|
|
69
|
+
mod tests;
|
|
Binary file
|
|
Binary file
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
extern crate std;
|
|
2
2
|
|
|
3
|
-
use soroban_sdk::{contractclient, testutils::Address as _, Address, BytesN, Env
|
|
3
|
+
use soroban_sdk::{contractclient, testutils::Address as _, xdr::ToXdr, Address, BytesN, Env};
|
|
4
4
|
|
|
5
5
|
use crate::{Upgrader, UpgraderClient};
|
|
6
6
|
|
|
@@ -17,16 +17,20 @@ trait TestUpgradeableContract2 {
|
|
|
17
17
|
}
|
|
18
18
|
|
|
19
19
|
mod contract_v1 {
|
|
20
|
-
|
|
21
|
-
// #[upgradeable]
|
|
22
|
-
// #[ownable]
|
|
23
|
-
// pub struct TestUpgradeableContract;
|
|
20
|
+
//#![no_std]
|
|
24
21
|
|
|
25
|
-
//
|
|
26
|
-
//
|
|
22
|
+
// use soroban_sdk::{contractimpl, Env, Symbol, Address, contractclient};
|
|
23
|
+
// use utils::{ upgradeable::UpgradeableInternal};
|
|
24
|
+
// use common_macros::lz_contract;
|
|
27
25
|
|
|
28
|
-
//
|
|
29
|
-
//
|
|
26
|
+
// #[lz_contract(upgradeable)]
|
|
27
|
+
// pub struct DummyContract;
|
|
28
|
+
|
|
29
|
+
// impl UpgradeableInternal for DummyContract {
|
|
30
|
+
// type MigrationData = u32;
|
|
31
|
+
|
|
32
|
+
// fn __migrate(env: &Env, migration_data: &Self::MigrationData) {
|
|
33
|
+
// env.storage().instance().set(&Symbol::new(env, "counter2"), migration_data);
|
|
30
34
|
// }
|
|
31
35
|
// }
|
|
32
36
|
|
|
@@ -35,34 +39,37 @@ mod contract_v1 {
|
|
|
35
39
|
// fn counter(env: &Env) -> u32;
|
|
36
40
|
// }
|
|
37
41
|
|
|
38
|
-
// #[
|
|
39
|
-
// impl TestUpgradeable for
|
|
42
|
+
// #[contractimpl]
|
|
43
|
+
// impl TestUpgradeable for DummyContract {
|
|
40
44
|
// fn counter(env: &Env) -> u32 {
|
|
41
45
|
// env.storage().instance().get(&Symbol::new(env, "counter")).unwrap_or(0)
|
|
42
46
|
// }
|
|
43
47
|
// }
|
|
44
48
|
|
|
45
|
-
// #[
|
|
46
|
-
// impl
|
|
49
|
+
// #[contractimpl]
|
|
50
|
+
// impl DummyContract {
|
|
47
51
|
// pub fn __constructor(env: &Env, owner: &Address) {
|
|
48
52
|
// Self::init_owner(env, owner);
|
|
49
53
|
// env.storage().instance().set(&Symbol::new(env, "counter"), &1_u32);
|
|
50
54
|
// }
|
|
51
55
|
// }
|
|
52
|
-
use super::MigrationData;
|
|
53
56
|
soroban_sdk::contractimport!(file = "./src/tests/test_data/test_upgradeable_contract1.wasm");
|
|
54
57
|
}
|
|
55
58
|
mod contract_v2 {
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
//
|
|
59
|
-
//
|
|
59
|
+
//#![no_std]
|
|
60
|
+
|
|
61
|
+
// use soroban_sdk::{contractimpl, Env, Symbol, Address, contractclient};
|
|
62
|
+
// use utils::{ upgradeable::UpgradeableInternal};
|
|
63
|
+
// use common_macros::lz_contract;
|
|
64
|
+
|
|
65
|
+
// #[lz_contract(upgradeable)]
|
|
66
|
+
// pub struct DummyContract;
|
|
60
67
|
|
|
61
|
-
// impl UpgradeableInternal for
|
|
62
|
-
// type MigrationData =
|
|
68
|
+
// impl UpgradeableInternal for DummyContract {
|
|
69
|
+
// type MigrationData = u32;
|
|
63
70
|
|
|
64
|
-
// fn
|
|
65
|
-
// env.storage().instance().set(&Symbol::new(env, "counter2"),
|
|
71
|
+
// fn __migrate(env: &Env, migration_data: &Self::MigrationData) {
|
|
72
|
+
// env.storage().instance().set(&Symbol::new(env, "counter2"), migration_data);
|
|
66
73
|
// }
|
|
67
74
|
// }
|
|
68
75
|
|
|
@@ -72,8 +79,8 @@ mod contract_v2 {
|
|
|
72
79
|
// fn counter2(env: &Env) -> u32;
|
|
73
80
|
// }
|
|
74
81
|
|
|
75
|
-
// #[
|
|
76
|
-
// impl TestUpgradeable for
|
|
82
|
+
// #[contractimpl]
|
|
83
|
+
// impl TestUpgradeable for DummyContract {
|
|
77
84
|
// fn counter(env: &Env) -> u32 {
|
|
78
85
|
// env.storage().instance().get(&Symbol::new(env, "counter")).unwrap_or(0)
|
|
79
86
|
// }
|
|
@@ -82,7 +89,14 @@ mod contract_v2 {
|
|
|
82
89
|
// env.storage().instance().get(&Symbol::new(env, "counter2")).unwrap_or(0)
|
|
83
90
|
// }
|
|
84
91
|
// }
|
|
85
|
-
|
|
92
|
+
|
|
93
|
+
// #[contractimpl]
|
|
94
|
+
// impl DummyContract {
|
|
95
|
+
// pub fn __constructor(env: &Env, owner: &Address) {
|
|
96
|
+
// Self::init_owner(env, owner);
|
|
97
|
+
// env.storage().instance().set(&Symbol::new(env, "counter"), &1_u32);
|
|
98
|
+
// }
|
|
99
|
+
// }
|
|
86
100
|
soroban_sdk::contractimport!(file = "./src/tests/test_data/test_upgradeable_contract2.wasm");
|
|
87
101
|
}
|
|
88
102
|
|
|
@@ -90,9 +104,6 @@ fn install_new_wasm(e: &Env) -> BytesN<32> {
|
|
|
90
104
|
e.deployer().upload_contract_wasm(contract_v2::WASM)
|
|
91
105
|
}
|
|
92
106
|
|
|
93
|
-
#[allow(dead_code)]
|
|
94
|
-
type MigrationData = ();
|
|
95
|
-
|
|
96
107
|
#[test]
|
|
97
108
|
fn test_upgrade_with_upgrader() {
|
|
98
109
|
let e = Env::default();
|
|
@@ -107,14 +118,12 @@ fn test_upgrade_with_upgrader() {
|
|
|
107
118
|
let upgrader_client = UpgraderClient::new(&e, &upgrader);
|
|
108
119
|
|
|
109
120
|
let new_wasm_hash = install_new_wasm(&e);
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
&soroban_sdk::vec![&e, ().try_into_val(&e).unwrap()],
|
|
115
|
-
);
|
|
121
|
+
let counter_value = 2_u32;
|
|
122
|
+
// Encode migration data as XDR bytes
|
|
123
|
+
let migration_data = counter_value.to_xdr(&e);
|
|
124
|
+
upgrader_client.upgrade_and_migrate(&contract_id, &new_wasm_hash, &migration_data);
|
|
116
125
|
|
|
117
126
|
let client_v2 = TestUpgradeableContractClient2::new(&e, &contract_id);
|
|
118
127
|
|
|
119
|
-
assert_eq!(client_v2.counter2(),
|
|
128
|
+
assert_eq!(client_v2.counter2(), counter_value);
|
|
120
129
|
}
|
|
@@ -27,8 +27,12 @@ pub enum TtlConfigurableError {
|
|
|
27
27
|
/// OwnableError: 1030-1039
|
|
28
28
|
#[contract_error]
|
|
29
29
|
pub enum OwnableError {
|
|
30
|
-
|
|
30
|
+
InvalidPendingOwner = 1030,
|
|
31
|
+
InvalidTtl,
|
|
32
|
+
NoPendingTransfer,
|
|
33
|
+
OwnerAlreadySet,
|
|
31
34
|
OwnerNotSet,
|
|
35
|
+
TransferInProgress,
|
|
32
36
|
}
|
|
33
37
|
|
|
34
38
|
/// BytesExtError: 1040-1049
|
|
@@ -40,7 +44,9 @@ pub enum BytesExtError {
|
|
|
40
44
|
/// UpgradeableError: 1050-1059
|
|
41
45
|
#[contract_error]
|
|
42
46
|
pub enum UpgradeableError {
|
|
43
|
-
|
|
47
|
+
InvalidMigrationData = 1050,
|
|
48
|
+
MigrationNotAllowed,
|
|
49
|
+
UpgradesFrozen,
|
|
44
50
|
}
|
|
45
51
|
|
|
46
52
|
/// MultisigError: 1060-1069
|
|
@@ -6,7 +6,7 @@ use soroban_sdk::{assert_with_error, contractevent, Address, Env};
|
|
|
6
6
|
// Ownable events
|
|
7
7
|
// ===========================================================================
|
|
8
8
|
|
|
9
|
-
/// Event emitted when ownership is transferred.
|
|
9
|
+
/// Event emitted when ownership is transferred (both single-step and two-step completion).
|
|
10
10
|
#[contractevent]
|
|
11
11
|
#[derive(Clone, Debug, Eq, PartialEq)]
|
|
12
12
|
pub struct OwnershipTransferred {
|
|
@@ -14,6 +14,15 @@ pub struct OwnershipTransferred {
|
|
|
14
14
|
pub new_owner: Address,
|
|
15
15
|
}
|
|
16
16
|
|
|
17
|
+
/// Event emitted when a 2-step ownership transfer is proposed.
|
|
18
|
+
#[contractevent]
|
|
19
|
+
#[derive(Clone, Debug, Eq, PartialEq)]
|
|
20
|
+
pub struct OwnershipTransferring {
|
|
21
|
+
pub old_owner: Address,
|
|
22
|
+
pub new_owner: Address,
|
|
23
|
+
pub ttl: u32,
|
|
24
|
+
}
|
|
25
|
+
|
|
17
26
|
/// Event emitted when ownership is renounced.
|
|
18
27
|
#[contractevent]
|
|
19
28
|
#[derive(Clone, Debug, Eq, PartialEq)]
|
|
@@ -30,6 +39,10 @@ pub struct OwnershipRenounced {
|
|
|
30
39
|
pub enum OwnableStorage {
|
|
31
40
|
#[instance(Address)]
|
|
32
41
|
Owner,
|
|
42
|
+
/// Pending owner for 2-step transfer. Stored in temporary storage with TTL -
|
|
43
|
+
/// automatically expires if not accepted in time.
|
|
44
|
+
#[temporary(Address)]
|
|
45
|
+
PendingOwner,
|
|
33
46
|
}
|
|
34
47
|
|
|
35
48
|
// ===========================================================================
|
|
@@ -40,23 +53,126 @@ pub enum OwnableStorage {
|
|
|
40
53
|
///
|
|
41
54
|
/// Extends `Auth` to provide owner-based authorization. The `Auth::authorizer()`
|
|
42
55
|
/// implementation should return the owner address for Ownable contracts.
|
|
56
|
+
///
|
|
57
|
+
/// Supports both single-step and two-step ownership transfer:
|
|
58
|
+
/// - Single-step: `transfer_ownership` - Immediate transfer (use with caution)
|
|
59
|
+
/// - Two-step: `propose_ownership_transfer` + `accept_ownership` - Safer, requires new owner to accept
|
|
43
60
|
#[contract_trait]
|
|
44
61
|
pub trait Ownable: Sized + Auth {
|
|
62
|
+
// ===========================================================================
|
|
63
|
+
// View functions
|
|
64
|
+
// ===========================================================================
|
|
65
|
+
|
|
45
66
|
/// Returns the current owner address, or None if no owner is set.
|
|
46
67
|
fn owner(env: &Env) -> Option<Address> {
|
|
47
68
|
OwnableStorage::owner(env)
|
|
48
69
|
}
|
|
49
70
|
|
|
50
|
-
///
|
|
71
|
+
/// Returns the pending owner address for 2-step transfer, or None if no transfer is pending.
|
|
72
|
+
fn pending_owner(env: &Env) -> Option<Address> {
|
|
73
|
+
OwnableStorage::pending_owner(env)
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// ===========================================================================
|
|
77
|
+
// Single-step transfer (immediate)
|
|
78
|
+
// ===========================================================================
|
|
79
|
+
|
|
80
|
+
/// Transfers ownership immediately to a new address.
|
|
81
|
+
///
|
|
82
|
+
/// Use with caution - if you transfer to a wrong address, ownership is lost forever.
|
|
83
|
+
/// Consider using `propose_ownership_transfer` instead.
|
|
84
|
+
///
|
|
85
|
+
/// # Panics
|
|
86
|
+
/// - `OwnerNotSet` if no owner is currently set
|
|
87
|
+
/// - `TransferInProgress` if a 2-step transfer is in progress
|
|
51
88
|
fn transfer_ownership(env: &Env, new_owner: &Address) {
|
|
52
89
|
let old_owner = enforce_owner_auth::<Self>(env);
|
|
90
|
+
assert_no_pending_transfer::<Self>(env);
|
|
91
|
+
|
|
53
92
|
OwnableStorage::set_owner(env, new_owner);
|
|
54
93
|
OwnershipTransferred { old_owner, new_owner: new_owner.clone() }.publish(env);
|
|
55
94
|
}
|
|
56
95
|
|
|
57
|
-
|
|
96
|
+
// ===========================================================================
|
|
97
|
+
// Two-step transfer (safer)
|
|
98
|
+
// ===========================================================================
|
|
99
|
+
|
|
100
|
+
/// Proposes an ownership transfer to a new address.
|
|
101
|
+
///
|
|
102
|
+
/// The new owner must call `accept_ownership()` within `ttl` ledgers
|
|
103
|
+
/// to complete the transfer. The pending transfer will automatically expire after.
|
|
104
|
+
///
|
|
105
|
+
/// # Arguments
|
|
106
|
+
/// - `new_owner` - The proposed new owner
|
|
107
|
+
/// - `ttl` - Number of ledgers the new owner has to accept.
|
|
108
|
+
/// Use `0` to cancel a pending transfer (new_owner must match pending).
|
|
109
|
+
///
|
|
110
|
+
/// # Panics
|
|
111
|
+
/// - `OwnerNotSet` if no owner is currently set
|
|
112
|
+
/// - `NoPendingTransfer` when cancelling and no pending transfer exists
|
|
113
|
+
/// - `InvalidTtl` if ttl exceeds max TTL
|
|
114
|
+
/// - `InvalidPendingOwner` when cancelling with wrong new_owner address
|
|
115
|
+
fn propose_ownership_transfer(env: &Env, new_owner: &Address, ttl: u32) {
|
|
116
|
+
let old_owner = enforce_owner_auth::<Self>(env);
|
|
117
|
+
|
|
118
|
+
// Cancel case: ttl == 0
|
|
119
|
+
if ttl == 0 {
|
|
120
|
+
let pending = Self::pending_owner(env).unwrap_or_panic(env, OwnableError::NoPendingTransfer);
|
|
121
|
+
|
|
122
|
+
// Verify new_owner matches pending (prevents accidental cancellation)
|
|
123
|
+
assert_with_error!(env, pending == *new_owner, OwnableError::InvalidPendingOwner);
|
|
124
|
+
|
|
125
|
+
OwnableStorage::remove_pending_owner(env);
|
|
126
|
+
return;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
// Initiate case: validate ttl
|
|
130
|
+
assert_with_error!(env, ttl <= env.storage().max_ttl(), OwnableError::InvalidTtl);
|
|
131
|
+
|
|
132
|
+
// Store pending owner with TTL
|
|
133
|
+
OwnableStorage::set_pending_owner(env, new_owner);
|
|
134
|
+
OwnableStorage::extend_pending_owner_ttl(env, ttl, ttl);
|
|
135
|
+
|
|
136
|
+
OwnershipTransferring { old_owner, new_owner: new_owner.clone(), ttl }.publish(env);
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/// Accepts a pending 2-step ownership transfer.
|
|
140
|
+
///
|
|
141
|
+
/// Must be called by the pending owner before the TTL expires.
|
|
142
|
+
///
|
|
143
|
+
/// # Panics
|
|
144
|
+
/// - `NoPendingTransfer` if there is no pending transfer (or it expired)
|
|
145
|
+
fn accept_ownership(env: &Env) {
|
|
146
|
+
let new_owner = Self::pending_owner(env).unwrap_or_panic(env, OwnableError::NoPendingTransfer);
|
|
147
|
+
|
|
148
|
+
// Require authorization from the pending owner
|
|
149
|
+
new_owner.require_auth();
|
|
150
|
+
|
|
151
|
+
// Safe to unwrap: owner must exist if pending_owner exists because:
|
|
152
|
+
// 1. pending_owner can only be set via propose_ownership_transfer, which requires owner auth
|
|
153
|
+
// 2. renounce_ownership is blocked while a 2-step transfer is in progress
|
|
154
|
+
let old_owner = OwnableStorage::owner(env).unwrap();
|
|
155
|
+
|
|
156
|
+
// Transfer ownership
|
|
157
|
+
OwnableStorage::remove_pending_owner(env);
|
|
158
|
+
OwnableStorage::set_owner(env, &new_owner);
|
|
159
|
+
|
|
160
|
+
OwnershipTransferred { old_owner, new_owner }.publish(env);
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
// ===========================================================================
|
|
164
|
+
// Renounce
|
|
165
|
+
// ===========================================================================
|
|
166
|
+
|
|
167
|
+
/// Permanently renounces ownership.
|
|
168
|
+
///
|
|
169
|
+
/// # Panics
|
|
170
|
+
/// - `OwnerNotSet` if no owner is currently set
|
|
171
|
+
/// - `TransferInProgress` if a 2-step transfer is in progress (cancel it first)
|
|
58
172
|
fn renounce_ownership(env: &Env) {
|
|
59
173
|
let old_owner = enforce_owner_auth::<Self>(env);
|
|
174
|
+
assert_no_pending_transfer::<Self>(env);
|
|
175
|
+
|
|
60
176
|
OwnableStorage::remove_owner(env);
|
|
61
177
|
OwnershipRenounced { old_owner }.publish(env);
|
|
62
178
|
}
|
|
@@ -86,3 +202,9 @@ pub fn enforce_owner_auth<T: Ownable>(env: &Env) -> Address {
|
|
|
86
202
|
pub fn require_owner_auth<T: Ownable>(env: &Env) {
|
|
87
203
|
let _ = enforce_owner_auth::<T>(env);
|
|
88
204
|
}
|
|
205
|
+
|
|
206
|
+
/// Asserts that no 2-step ownership transfer is in progress.
|
|
207
|
+
/// Panics with `TransferInProgress` if a pending transfer exists.
|
|
208
|
+
fn assert_no_pending_transfer<T: Ownable>(env: &Env) {
|
|
209
|
+
assert_with_error!(env, T::pending_owner(env).is_none(), OwnableError::TransferInProgress);
|
|
210
|
+
}
|
|
@@ -10,7 +10,7 @@ fn unwrap_or_panic_some_returns_value() {
|
|
|
10
10
|
|
|
11
11
|
#[test]
|
|
12
12
|
fn unwrap_or_panic_none_panics_with_error() {
|
|
13
|
-
const EXPECTED: &str = "Error(Contract, #
|
|
13
|
+
const EXPECTED: &str = "Error(Contract, #1034)"; // OwnerNotSet
|
|
14
14
|
assert_panics_contains("none unwrap_or_panic", EXPECTED, || {
|
|
15
15
|
let env = Env::default();
|
|
16
16
|
let _got: u32 = None::<u32>.unwrap_or_panic(&env, OwnableError::OwnerNotSet);
|