@layerzerolabs/protocol-stellar-v2 0.2.122 → 0.2.124
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/endpoint-v2/src/tests/endpoint_v2/pay_messaging_fees.rs +7 -1
- package/endpoint-v2/src/tests/endpoint_v2/quote.rs +2 -2
- package/endpoint-v2/src/tests/endpoint_v2/ttl_config.rs +4 -1
- package/endpoint-v2/src/tests/endpoint_v2/verifiable.rs +0 -1
- package/endpoint-v2/src/tests/message_lib_manager/require_receive_lib_for_eid.rs +9 -3
- package/endpoint-v2/src/tests/message_lib_manager/require_send_lib_for_eid.rs +6 -2
- package/endpoint-v2/src/tests/message_lib_manager/require_supported_eid.rs +6 -2
- package/endpoint-v2/src/tests/messaging_channel/clear_payload.rs +1 -4
- package/endpoint-v2/src/tests/messaging_channel/inbound.rs +1 -4
- package/endpoint-v2/src/tests/messaging_channel/mod.rs +1 -1
- package/endpoint-v2/src/tests/messaging_channel/nilify.rs +3 -12
- package/endpoint-v2/src/tests/messaging_channel/pending_inbound_nonces.rs +0 -1
- package/endpoint-v2/src/tests/messaging_composer/lz_compose_alert.rs +1 -0
- package/message-libs/uln-302/src/tests/send_uln302/send.rs +20 -4
- package/message-libs/uln-302/src/tests/uln302/get_app_receive_uln_config.rs +2 -2
- package/package.json +8 -8
- package/rustfmt.toml +8 -11
- package/upgrader/src/tests/mod.rs +1 -1
- package/workers/dvn/src/tests/auth.rs +12 -60
- package/workers/executor/src/auth.rs +3 -8
- package/workers/executor/src/storage.rs +1 -1
- package/workers/executor/src/tests/auth.rs +6 -1
- package/workers/executor/src/tests/executor.rs +5 -5
- package/workers/executor/src/tests/setup.rs +1 -2
- package/workers/executor-fee-lib/src/tests/executor_fee_lib.rs +5 -5
- package/workers/executor-fee-lib/src/tests/executor_option.rs +2 -2
- package/workers/executor-helper/src/executor_helper.rs +0 -1
- package/workers/executor-helper/src/tests/executor_helper.rs +0 -1
- package/workers/price-feed/src/tests/price_feed.rs +11 -11
- package/workers/worker/src/tests/worker.rs +27 -27
- package/docs/error-spec.md +0 -55
- package/docs/layerzero-v2-on-stellar.md +0 -511
- package/docs/oapp-guide.md +0 -5
- package/docs/oft-guide.md +0 -5
|
@@ -13,7 +13,7 @@ fn test_constructor_sets_owner_and_price_updater() {
|
|
|
13
13
|
let setup = TestSetup::new();
|
|
14
14
|
|
|
15
15
|
assert_eq!(setup.client.owner(), Some(setup.owner.clone()));
|
|
16
|
-
|
|
16
|
+
assert!(setup.client.is_price_updater(&setup.price_updater));
|
|
17
17
|
}
|
|
18
18
|
|
|
19
19
|
#[test]
|
|
@@ -91,7 +91,7 @@ fn test_estimate_fee_by_eid_default_model() {
|
|
|
91
91
|
// = (16_500_000_000_000 * 1e20) / 1e20
|
|
92
92
|
// = 16_500_000_000_000
|
|
93
93
|
|
|
94
|
-
assert_eq!(estimate.total_gas_fee,
|
|
94
|
+
assert_eq!(estimate.total_gas_fee, 16_500_000_000_000_i128);
|
|
95
95
|
assert_eq!(estimate.price_ratio, price.price_ratio);
|
|
96
96
|
assert_eq!(estimate.price_ratio_denominator, 10u128.pow(20));
|
|
97
97
|
assert_eq!(estimate.native_price_usd, 0);
|
|
@@ -214,7 +214,7 @@ fn test_estimate_fee_by_eid_arbitrum_model_hardcoded_eid() {
|
|
|
214
214
|
// = 34_306 * 10_000_000
|
|
215
215
|
// = 343_060_000_000
|
|
216
216
|
|
|
217
|
-
assert_eq!(estimate.total_gas_fee,
|
|
217
|
+
assert_eq!(estimate.total_gas_fee, 343_060_000_000_i128);
|
|
218
218
|
|
|
219
219
|
assert_eq!(estimate.price_ratio, arb_price.price_ratio);
|
|
220
220
|
}
|
|
@@ -237,7 +237,7 @@ fn test_estimate_fee_by_eid_arbitrum_model_hardcoded_eid_10143() {
|
|
|
237
237
|
setup.mock_auth(&fee_lib, "estimate_fee_by_eid", (&fee_lib, 10143u32, 1000u32, 500u128));
|
|
238
238
|
let estimate = setup.client.estimate_fee_by_eid(&fee_lib, &10143, &1000, &500);
|
|
239
239
|
|
|
240
|
-
assert_eq!(estimate.total_gas_fee,
|
|
240
|
+
assert_eq!(estimate.total_gas_fee, 343_060_000_000_i128);
|
|
241
241
|
assert_eq!(estimate.price_ratio, arb_price.price_ratio);
|
|
242
242
|
}
|
|
243
243
|
|
|
@@ -299,7 +299,7 @@ fn test_estimate_fee_by_eid_arbitrum_model_configured_eid() {
|
|
|
299
299
|
let estimate = setup.client.estimate_fee_by_eid(&fee_lib, &200, &1000, &500);
|
|
300
300
|
|
|
301
301
|
// Should use Arbitrum model (same expected fee as the hardcoded Arbitrum test)
|
|
302
|
-
assert_eq!(estimate.total_gas_fee,
|
|
302
|
+
assert_eq!(estimate.total_gas_fee, 343_060_000_000_i128);
|
|
303
303
|
assert_eq!(estimate.price_ratio, arb_price.price_ratio);
|
|
304
304
|
}
|
|
305
305
|
|
|
@@ -342,7 +342,7 @@ fn test_estimate_fee_by_eid_optimism_model_hardcoded_eid() {
|
|
|
342
342
|
// = 7_235_492_071_308 + 36_813_447_000
|
|
343
343
|
// = 7_272_305_518_308
|
|
344
344
|
|
|
345
|
-
assert_eq!(estimate.total_gas_fee,
|
|
345
|
+
assert_eq!(estimate.total_gas_fee, 7_272_305_518_308_i128);
|
|
346
346
|
assert_eq!(estimate.price_ratio, op_price.price_ratio);
|
|
347
347
|
}
|
|
348
348
|
|
|
@@ -368,7 +368,7 @@ fn test_estimate_fee_by_eid_optimism_model_goerli() {
|
|
|
368
368
|
|
|
369
369
|
// Deterministic expected fee (Optimism model):
|
|
370
370
|
// L1 uses Ethereum Goerli (10121) with +3188 overhead, L2 uses Optimism Goerli (10132).
|
|
371
|
-
assert_eq!(estimate.total_gas_fee,
|
|
371
|
+
assert_eq!(estimate.total_gas_fee, 7_272_305_518_308_i128);
|
|
372
372
|
assert_eq!(estimate.price_ratio, op_price.price_ratio);
|
|
373
373
|
}
|
|
374
374
|
#[test]
|
|
@@ -402,7 +402,7 @@ fn test_estimate_fee_by_eid_optimism_model_configured_eid() {
|
|
|
402
402
|
assert_eq!(estimate_300.total_gas_fee, estimate_111.total_gas_fee);
|
|
403
403
|
assert_eq!(estimate_300.price_ratio, estimate_111.price_ratio);
|
|
404
404
|
assert_eq!(estimate_300.price_ratio, op_price.price_ratio);
|
|
405
|
-
assert_eq!(estimate_300.total_gas_fee,
|
|
405
|
+
assert_eq!(estimate_300.total_gas_fee, 7_272_305_518_308_i128);
|
|
406
406
|
}
|
|
407
407
|
|
|
408
408
|
#[test]
|
|
@@ -511,12 +511,12 @@ fn test_set_price_updater_add_and_remove() {
|
|
|
511
511
|
// Add new price updater
|
|
512
512
|
setup.mock_owner_auth("set_price_updater", (&new_updater, true));
|
|
513
513
|
setup.client.set_price_updater(&new_updater, &true);
|
|
514
|
-
|
|
514
|
+
assert!(setup.client.is_price_updater(&new_updater));
|
|
515
515
|
|
|
516
516
|
// Remove price updater
|
|
517
517
|
setup.mock_owner_auth("set_price_updater", (&new_updater, false));
|
|
518
518
|
setup.client.set_price_updater(&new_updater, &false);
|
|
519
|
-
|
|
519
|
+
assert!(!setup.client.is_price_updater(&new_updater));
|
|
520
520
|
}
|
|
521
521
|
|
|
522
522
|
#[test]
|
|
@@ -806,7 +806,7 @@ fn test_is_price_updater_returns_false_for_unknown_address() {
|
|
|
806
806
|
let setup = TestSetup::new();
|
|
807
807
|
let unknown = Address::generate(&setup.env);
|
|
808
808
|
|
|
809
|
-
|
|
809
|
+
assert!(!setup.client.is_price_updater(&unknown));
|
|
810
810
|
}
|
|
811
811
|
|
|
812
812
|
// =============================================================================
|
|
@@ -27,12 +27,12 @@ fn test_set_paused_toggles_state() {
|
|
|
27
27
|
setup.mock_owner_auth("set_paused", (true,));
|
|
28
28
|
setup.client.set_paused(&true);
|
|
29
29
|
assert_eq_event(&setup.env, &setup.contract_id, Paused { pauser: setup.owner.clone() });
|
|
30
|
-
|
|
30
|
+
assert!(setup.client.paused());
|
|
31
31
|
|
|
32
32
|
setup.mock_owner_auth("set_paused", (false,));
|
|
33
33
|
setup.client.set_paused(&false);
|
|
34
34
|
assert_eq_event(&setup.env, &setup.contract_id, Unpaused { unpauser: setup.owner.clone() });
|
|
35
|
-
|
|
35
|
+
assert!(!setup.client.paused());
|
|
36
36
|
}
|
|
37
37
|
|
|
38
38
|
// allowlist
|
|
@@ -68,22 +68,22 @@ fn test_allowlist_remove_decrements_size_and_restores_default_acl() {
|
|
|
68
68
|
let oapp_b = Address::generate(&setup.env);
|
|
69
69
|
|
|
70
70
|
// Add allowlist entry => allowlist becomes non-empty; non-allowlisted is denied
|
|
71
|
-
|
|
71
|
+
assert!(!setup.client.is_on_allowlist(&oapp_a));
|
|
72
72
|
setup.mock_owner_auth("set_allowlist", (&oapp_a, true));
|
|
73
73
|
setup.client.set_allowlist(&oapp_a, &true);
|
|
74
74
|
assert_eq_event(&setup.env, &setup.contract_id, SetAllowlist { oapp: oapp_a.clone(), allowed: true });
|
|
75
|
-
|
|
75
|
+
assert!(setup.client.is_on_allowlist(&oapp_a));
|
|
76
76
|
assert_eq!(setup.client.allowlist_size(), 1);
|
|
77
|
-
|
|
78
|
-
|
|
77
|
+
assert!(setup.client.has_acl(&oapp_a));
|
|
78
|
+
assert!(!setup.client.has_acl(&oapp_b));
|
|
79
79
|
|
|
80
80
|
// Remove last allowlist entry => allowlist empty; default allows all (unless denylisted)
|
|
81
81
|
setup.mock_owner_auth("set_allowlist", (&oapp_a, false));
|
|
82
82
|
setup.client.set_allowlist(&oapp_a, &false);
|
|
83
83
|
assert_eq_event(&setup.env, &setup.contract_id, SetAllowlist { oapp: oapp_a.clone(), allowed: false });
|
|
84
|
-
|
|
84
|
+
assert!(!setup.client.is_on_allowlist(&oapp_a));
|
|
85
85
|
assert_eq!(setup.client.allowlist_size(), 0);
|
|
86
|
-
|
|
86
|
+
assert!(setup.client.has_acl(&oapp_b));
|
|
87
87
|
}
|
|
88
88
|
|
|
89
89
|
// denylist
|
|
@@ -129,7 +129,7 @@ fn test_message_lib_add_remove_and_errors() {
|
|
|
129
129
|
&setup.contract_id,
|
|
130
130
|
SetSupportedMessageLib { message_lib: new_lib.clone(), supported: true },
|
|
131
131
|
);
|
|
132
|
-
|
|
132
|
+
assert!(setup.client.is_supported_message_lib(&new_lib));
|
|
133
133
|
|
|
134
134
|
// Remove it
|
|
135
135
|
setup.mock_owner_auth("set_supported_message_lib", (&new_lib, false));
|
|
@@ -139,10 +139,10 @@ fn test_message_lib_add_remove_and_errors() {
|
|
|
139
139
|
&setup.contract_id,
|
|
140
140
|
SetSupportedMessageLib { message_lib: new_lib.clone(), supported: false },
|
|
141
141
|
);
|
|
142
|
-
|
|
142
|
+
assert!(!setup.client.is_supported_message_lib(&new_lib));
|
|
143
143
|
|
|
144
144
|
// Existing is still supported
|
|
145
|
-
|
|
145
|
+
assert!(setup.client.is_supported_message_lib(&existing));
|
|
146
146
|
}
|
|
147
147
|
|
|
148
148
|
#[test]
|
|
@@ -245,41 +245,41 @@ fn test_acl_allowlist_denylist_precedence() {
|
|
|
245
245
|
let oapp_b = Address::generate(&setup.env);
|
|
246
246
|
|
|
247
247
|
// Empty allowlist => allowed unless denylisted
|
|
248
|
-
|
|
248
|
+
assert!(setup.client.has_acl(&oapp_a));
|
|
249
249
|
|
|
250
250
|
// Denylist overrides everything
|
|
251
|
-
|
|
251
|
+
assert!(!setup.client.is_on_denylist(&oapp_a));
|
|
252
252
|
setup.mock_owner_auth("set_denylist", (&oapp_a, true));
|
|
253
253
|
setup.client.set_denylist(&oapp_a, &true);
|
|
254
254
|
assert_eq_event(&setup.env, &setup.contract_id, SetDenylist { oapp: oapp_a.clone(), denied: true });
|
|
255
|
-
|
|
256
|
-
|
|
255
|
+
assert!(setup.client.is_on_denylist(&oapp_a));
|
|
256
|
+
assert!(!setup.client.has_acl(&oapp_a));
|
|
257
257
|
|
|
258
258
|
// Remove from denylist => allowed again (since allowlist is empty)
|
|
259
259
|
setup.mock_owner_auth("set_denylist", (&oapp_a, false));
|
|
260
260
|
setup.client.set_denylist(&oapp_a, &false);
|
|
261
261
|
assert_eq_event(&setup.env, &setup.contract_id, SetDenylist { oapp: oapp_a.clone(), denied: false });
|
|
262
|
-
|
|
263
|
-
|
|
262
|
+
assert!(!setup.client.is_on_denylist(&oapp_a));
|
|
263
|
+
assert!(setup.client.has_acl(&oapp_a));
|
|
264
264
|
|
|
265
265
|
// Add allowlist entry => allowlist becomes non-empty; non-allowlisted is denied
|
|
266
266
|
setup.mock_owner_auth("set_allowlist", (&oapp_a, true));
|
|
267
267
|
setup.client.set_allowlist(&oapp_a, &true);
|
|
268
268
|
assert_eq!(setup.client.allowlist_size(), 1);
|
|
269
|
-
|
|
270
|
-
|
|
269
|
+
assert!(setup.client.has_acl(&oapp_a));
|
|
270
|
+
assert!(!setup.client.has_acl(&oapp_b));
|
|
271
271
|
|
|
272
272
|
// Denylist must override allowlist even for the same OApp.
|
|
273
273
|
setup.mock_owner_auth("set_denylist", (&oapp_a, true));
|
|
274
274
|
setup.client.set_denylist(&oapp_a, &true);
|
|
275
275
|
assert_eq_event(&setup.env, &setup.contract_id, SetDenylist { oapp: oapp_a.clone(), denied: true });
|
|
276
|
-
|
|
276
|
+
assert!(!setup.client.has_acl(&oapp_a));
|
|
277
277
|
|
|
278
278
|
// Removing from denylist should restore allowlist effect.
|
|
279
279
|
setup.mock_owner_auth("set_denylist", (&oapp_a, false));
|
|
280
280
|
setup.client.set_denylist(&oapp_a, &false);
|
|
281
281
|
assert_eq_event(&setup.env, &setup.contract_id, SetDenylist { oapp: oapp_a.clone(), denied: false });
|
|
282
|
-
|
|
282
|
+
assert!(setup.client.has_acl(&oapp_a));
|
|
283
283
|
}
|
|
284
284
|
|
|
285
285
|
// uninitialized getters (BareWorker)
|
|
@@ -369,7 +369,7 @@ fn test_init_worker_can_reinitialize() {
|
|
|
369
369
|
fn test_init_worker_sets_config_and_defaults() {
|
|
370
370
|
let setup = TestSetup::new();
|
|
371
371
|
|
|
372
|
-
|
|
372
|
+
assert!(!setup.client.paused());
|
|
373
373
|
assert_eq!(setup.client.admins(), setup.admins);
|
|
374
374
|
assert_eq!(setup.client.message_libs(), setup.message_libs);
|
|
375
375
|
assert_eq!(setup.client.price_feed(), Some(setup.price_feed));
|
|
@@ -379,7 +379,7 @@ fn test_init_worker_sets_config_and_defaults() {
|
|
|
379
379
|
assert_eq!(setup.client.allowlist_size(), 0);
|
|
380
380
|
|
|
381
381
|
let lib = setup.message_libs.get(0).unwrap();
|
|
382
|
-
|
|
382
|
+
assert!(setup.client.is_supported_message_lib(&lib));
|
|
383
383
|
}
|
|
384
384
|
|
|
385
385
|
// admin management (admins list)
|
|
@@ -392,12 +392,12 @@ fn test_admin_management_by_owner_adds_and_removes_admin() {
|
|
|
392
392
|
setup.mock_owner_auth("set_admin", (&new_admin, true));
|
|
393
393
|
setup.client.set_admin(&new_admin, &true);
|
|
394
394
|
assert_eq_event(&setup.env, &setup.contract_id, SetAdmin { admin: new_admin.clone(), active: true });
|
|
395
|
-
|
|
395
|
+
assert!(setup.client.is_admin(&new_admin));
|
|
396
396
|
|
|
397
397
|
setup.mock_owner_auth("set_admin", (&new_admin, false));
|
|
398
398
|
setup.client.set_admin(&new_admin, &false);
|
|
399
399
|
assert_eq_event(&setup.env, &setup.contract_id, SetAdmin { admin: new_admin.clone(), active: false });
|
|
400
|
-
|
|
400
|
+
assert!(!setup.client.is_admin(&new_admin));
|
|
401
401
|
}
|
|
402
402
|
|
|
403
403
|
#[test]
|
|
@@ -454,7 +454,7 @@ fn test_admin_management_can_remove_last_admin() {
|
|
|
454
454
|
|
|
455
455
|
// Removing the last admin is now allowed
|
|
456
456
|
client.set_admin(&only_admin, &false);
|
|
457
|
-
|
|
457
|
+
assert!(!client.is_admin(&only_admin));
|
|
458
458
|
assert_eq!(client.admins().len(), 0);
|
|
459
459
|
}
|
|
460
460
|
|
|
@@ -467,7 +467,7 @@ fn test_admin_management_by_admin_can_add_admin() {
|
|
|
467
467
|
setup.mock_auth(&caller, "set_admin_by_admin_for_test", (&caller, &new_admin, true));
|
|
468
468
|
setup.client.set_admin_by_admin_for_test(&caller, &new_admin, &true);
|
|
469
469
|
assert_eq_event(&setup.env, &setup.contract_id, SetAdmin { admin: new_admin.clone(), active: true });
|
|
470
|
-
|
|
470
|
+
assert!(setup.client.is_admin(&new_admin));
|
|
471
471
|
}
|
|
472
472
|
|
|
473
473
|
#[test]
|
package/docs/error-spec.md
DELETED
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
# Stellar LayerZero Protocol - Error Code Specification
|
|
2
|
-
|
|
3
|
-
This document defines the error code allocation strategy for the Stellar LayerZero contracts.
|
|
4
|
-
|
|
5
|
-
## Purpose
|
|
6
|
-
|
|
7
|
-
Each library has a unique error code range to:
|
|
8
|
-
|
|
9
|
-
- **Prevent collisions**: Avoid error code conflicts between different libraries
|
|
10
|
-
- **Enable traceability**: Quickly identify which library an error originated from based on its code
|
|
11
|
-
- **Simplify debugging**: Error codes are globally unique, making it easier to track and diagnose issues
|
|
12
|
-
|
|
13
|
-
## Allocation Rules
|
|
14
|
-
|
|
15
|
-
- **Contract-specific errors**: Each contract uses auto-incrementing error codes starting from 1. These are local to the contract and do not need global uniqueness since the contract address provides context.
|
|
16
|
-
- **Library errors**: Libraries that are shared across multiple contracts use reserved ranges (1000+) to ensure global uniqueness.
|
|
17
|
-
- **Library allocation**: Each library is allocated a 100-unit block (e.g., 1000-1099, 1100-1199). Total errors in one library should not exceed 100.
|
|
18
|
-
- **Sub-range allocation**: Each error type within a library is allocated a 10-unit block. If an error type exceeds 10 errors, it extends into the next block but the following error type should start at the next 10-unit boundary.
|
|
19
|
-
- **Auto-increment**: Within each error enum, values auto-increment from the starting value.
|
|
20
|
-
|
|
21
|
-
## Error Code Ranges
|
|
22
|
-
|
|
23
|
-
### Contract-Specific Errors (1-999)
|
|
24
|
-
|
|
25
|
-
Contract-specific errors auto-increment from 1 and are scoped to each contract.
|
|
26
|
-
|
|
27
|
-
| Contract | Location |
|
|
28
|
-
| ----------------- | --------------------------------------------------------------------- |
|
|
29
|
-
| EndpointV2 | `endpoint-v2/src/errors.rs` |
|
|
30
|
-
| ULN302 | `message-libs/uln-302/src/errors.rs` |
|
|
31
|
-
| Treasury | `message-libs/treasury/src/errors.rs` |
|
|
32
|
-
| SimpleMessageLib | `message-libs/simple-message-lib/src/errors.rs` |
|
|
33
|
-
| DVN | `workers/dvn/src/errors.rs` |
|
|
34
|
-
| Executor | `workers/executor/src/errors.rs` |
|
|
35
|
-
| DVN Fee Lib | `workers/dvn-fee-lib/src/errors.rs` |
|
|
36
|
-
| Executor Fee Lib | `workers/executor-fee-lib/src/errors.rs` |
|
|
37
|
-
| Price Feed | `workers/price-feed/src/errors.rs` |
|
|
38
|
-
| LayerZero Views | `layerzero-views/src/errors.rs` |
|
|
39
|
-
| Counter (example) | `apps/project-types/omni-counter-app/contracts/stellar/src/errors.rs` |
|
|
40
|
-
|
|
41
|
-
### Library Errors (1000+)
|
|
42
|
-
|
|
43
|
-
Libraries shared across contracts use reserved ranges for global uniqueness.
|
|
44
|
-
|
|
45
|
-
| Range | Category | Library | Location |
|
|
46
|
-
| --------- | ------------ | ------------------ | ----------------------------------------------------------- |
|
|
47
|
-
| 1000-1099 | Protocol Lib | utils | `contracts/common/utils/stellar/common-utils/src/errors.rs` |
|
|
48
|
-
| 1100-1199 | Protocol Lib | message-lib-common | `message-libs/message-lib-common/src/errors.rs` |
|
|
49
|
-
| 1200-1299 | Protocol Lib | worker | `workers/worker/src/errors.rs` |
|
|
50
|
-
| 1300-1999 | Protocol Lib | (reserved) | Future protocol libs |
|
|
51
|
-
| 2000-2099 | OApp Lib | oapp | `apps/oapp-app/contracts/stellar/contracts/src/errors.rs` |
|
|
52
|
-
| 2100-2999 | OApp Lib | (reserved) | Future OApp libs |
|
|
53
|
-
| 3000-3099 | OFT Lib | oft-core | `apps/oft-app/contracts/stellar/oft-core/src/errors.rs` |
|
|
54
|
-
| 3100-3199 | OFT Lib | oft (extensions) | `apps/oft-app/contracts/stellar/oft/src/extensions/` |
|
|
55
|
-
| 3200-3999 | OFT Lib | (reserved) | Future OFT libs |
|