@@ -28,9 +28,6 @@ pub struct SwitchboardDecimal {
28
28
29
29
#[ derive( BorshDeserialize , BorshSerialize , Serialize , Deserialize ) ]
30
30
pub struct PriceEntry {
31
- // pub price: U128, // Last reported price
32
- // pub decimals: u16, // Amount of decimals (e.g. if 2, 100 = 1.00)
33
- // pub last_update: Timestamp, // Time of report
34
31
pub result : SwitchboardDecimal ,
35
32
pub num_success : u32 ,
36
33
pub num_error : u32 ,
@@ -39,12 +36,11 @@ pub struct PriceEntry {
39
36
40
37
#[ derive( BorshDeserialize , BorshSerialize , Serialize , Deserialize ) ]
41
38
pub struct SwitchboarIx {
42
- pub address : Vec < u8 > ,
39
+ pub address : Vec < u8 > , // This feed address reference a specific price feed, see https://app.switchboard.xyz
43
40
pub payer : Vec < u8 > ,
44
41
}
45
42
46
-
47
- // Interface of the Switchboard price oracle
43
+ // Interface of the Switchboard feed parser
48
44
#[ near_sdk:: ext_contract( sb_contract) ]
49
45
trait Switchboard {
50
46
fn aggregator_read ( ix : SwitchboarIx ) -> Promise < PriceEntry > ;
@@ -53,8 +49,9 @@ trait Switchboard {
53
49
54
50
///
55
51
/// This contract
56
- /// - oracle_account_id: should be a valid FPO oracle account ID
57
- /// - provider_account_id: should be a valid FPO provider account ID
52
+ /// - feed_parser: should be a valid Switchboard feed parser
53
+ /// - feed_address: should be a valid NEAR/USD price feed
54
+ /// - feed_payer: pays for feeds not sponsored by Switchboard
58
55
/// - owner_id: only the owner can edit the contract state values above (default = deployer)
59
56
#[ near_bindgen]
60
57
#[ derive( Default , BorshDeserialize , BorshSerialize ) ]
@@ -105,7 +102,7 @@ impl ConversionProxy {
105
102
/// - `payment_reference`: used for indexing and matching the payment with a request
106
103
/// - `payment_address`: `amount` in `currency` of NEAR will be paid to this address
107
104
/// - `amount`: in `currency` with 2 decimals (eg. 1000 is 10.00)
108
- /// - `currency`: ticker, most likely fiat (eg. 'USD')
105
+ /// - `currency`: ticker, only "USD" implemented for now
109
106
/// - `fee_payment_address`: `fee_amount` in `currency` of NEAR will be paid to this address
110
107
/// - `fee_amount`: in `currency`
111
108
/// - `max_rate_timespan`: in nanoseconds, the maximum validity for the oracle rate response (or 0 if none)
@@ -126,11 +123,11 @@ impl ConversionProxy {
126
123
env:: prepaid_gas( ) ,
127
124
MIN_GAS
128
125
) ;
126
+ assert_eq ! ( currency, "USD" , "Only payments denominated in USD are implemented for now" ) ;
129
127
130
128
let reference_vec: Vec < u8 > = hex:: decode ( payment_reference. replace ( "0x" , "" ) )
131
129
. expect ( "Payment reference value error" ) ;
132
130
assert_eq ! ( reference_vec. len( ) , 8 , "Incorrect payment reference length" ) ;
133
- assert_eq ! ( currency, "USD" , "Only payments denominated in USD are implemented for now" ) ;
134
131
135
132
let get_rate = sb_contract:: aggregator_read ( SwitchboarIx { address : self . feed_address . clone ( ) , payer : self . feed_payer . clone ( ) } ,
136
133
& self . feed_parser ,
@@ -156,7 +153,7 @@ impl ConversionProxy {
156
153
#[ init]
157
154
pub fn new ( feed_parser : AccountId , feed_address : Vec < u8 > ) -> Self {
158
155
let owner_id = env:: signer_account_id ( ) ;
159
- let feed_payer = bs58 :: decode ( owner_id . clone ( ) ) . into_vec ( ) . expect ( "Could not decode owner" ) ;
156
+ let feed_payer = env :: signer_account_pk ( ) ;
160
157
Self {
161
158
feed_parser,
162
159
feed_address,
@@ -178,19 +175,23 @@ impl ConversionProxy {
178
175
return self . feed_parser . clone ( ) ;
179
176
}
180
177
181
- pub fn set_feed_address ( & mut self , oracle : Vec < u8 > ) {
178
+ pub fn set_feed_address ( & mut self , feed_address : String ) {
182
179
let signer_id = env:: predecessor_account_id ( ) ;
183
180
if self . owner_id == signer_id {
184
- self . feed_address = oracle ;
181
+ self . feed_address = bs58 :: decode ( feed_address ) . into_vec ( ) . expect ( "Wrong feed address format" ) ;
185
182
} else {
186
183
panic ! ( "ERR_PERMISSION" ) ;
187
184
}
188
185
}
189
-
186
+
190
187
pub fn get_feed_address ( & self ) -> Vec < u8 > {
191
188
return self . feed_address . clone ( ) ;
192
189
}
193
190
191
+ pub fn get_encoded_feed_address ( & self ) -> String {
192
+ return bs58:: encode ( self . feed_address . clone ( ) ) . into_string ( ) ;
193
+ }
194
+
194
195
pub fn set_owner ( & mut self , owner : ValidAccountId ) {
195
196
let signer_id = env:: predecessor_account_id ( ) ;
196
197
if self . owner_id == signer_id {
@@ -199,6 +200,36 @@ impl ConversionProxy {
199
200
panic ! ( "ERR_PERMISSION" ) ;
200
201
}
201
202
}
203
+ pub fn set_feed_payer ( & mut self ) {
204
+ let signer_id = env:: predecessor_account_id ( ) ;
205
+ println ! ( "signer_id: {}" , signer_id) ;
206
+ if self . owner_id == signer_id {
207
+ let feed_payer = env:: signer_account_pk ( ) ;
208
+ let vec_length = feed_payer. len ( ) ;
209
+ println ! ( "feed_payer: {}, len: {}" , feed_payer. clone( ) . into_iter( ) . map( |c| c. to_string( ) ) . collect:: <Vec <String >>( ) . join( "," ) , vec_length) ;
210
+ if vec_length == 32 {
211
+ self . feed_payer = env:: signer_account_pk ( ) ;
212
+ return ;
213
+ }
214
+ // For some reason the VM prepends a 0 in front of the 32-long vector
215
+ if vec_length > 32 {
216
+ log ! ( "Trimming the feed_payer pk to fit length 32 from length {}" , vec_length) ;
217
+ self . feed_payer = feed_payer[ vec_length-32 ..] . to_vec ( ) ;
218
+ return
219
+ }
220
+ panic ! ( "ERR_OWNER_PK_LENGTH" ) ;
221
+ } else {
222
+ panic ! ( "ERR_PERMISSION" ) ;
223
+ }
224
+ }
225
+
226
+ pub fn get_feed_payer ( & self ) -> Vec < u8 > {
227
+ return self . feed_payer . clone ( ) ;
228
+ }
229
+
230
+ pub fn get_encoded_feed_payer ( & self ) -> String {
231
+ return bs58:: encode ( self . feed_payer . clone ( ) ) . into_string ( ) ;
232
+ }
202
233
203
234
#[ private]
204
235
pub fn on_transfer_with_reference (
@@ -356,7 +387,7 @@ mod tests {
356
387
VMContext {
357
388
current_account_id : predecessor_account_id. clone ( ) ,
358
389
signer_account_id : predecessor_account_id. clone ( ) ,
359
- signer_account_pk : vec ! [ 0 , 1 , 2 ] ,
390
+ signer_account_pk : vec ! [ 0 , 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 ] ,
360
391
predecessor_account_id,
361
392
input : vec ! [ ] ,
362
393
block_index : 1 ,
@@ -447,6 +478,26 @@ mod tests {
447
478
) ;
448
479
}
449
480
481
+ #[ test]
482
+ #[ should_panic( expected = r#"Only payments denominated in USD are implemented for now"# ) ]
483
+ fn transfer_with_wrong_currency ( ) {
484
+ let context = get_context ( alice_account ( ) , ntoy ( 100 ) , 10u64 . pow ( 14 ) , false ) ;
485
+ testing_env ! ( context) ;
486
+ let mut contract = ConversionProxy :: default ( ) ;
487
+ let payment_reference = "0x11223344556677" . to_string ( ) ;
488
+ let currency = "HKD" . to_string ( ) ;
489
+ let ( to, amount, fee_address, fee_amount, max_rate_timespan) = default_values ( ) ;
490
+ contract. transfer_with_reference (
491
+ payment_reference,
492
+ to,
493
+ amount,
494
+ currency,
495
+ fee_address,
496
+ fee_amount,
497
+ max_rate_timespan,
498
+ ) ;
499
+ }
500
+
450
501
#[ test]
451
502
fn transfer_with_reference ( ) {
452
503
let context = get_context ( alice_account ( ) , ntoy ( 1 ) , 10u64 . pow ( 14 ) , false ) ;
@@ -473,7 +524,7 @@ mod tests {
473
524
testing_env ! ( context) ;
474
525
let mut contract = ConversionProxy :: default ( ) ;
475
526
let ( _to, _amount, _fee_address, _fee_amount, _max_rate_timespan) = default_values ( ) ;
476
- contract. set_feed_address ( bs58 :: decode ( "HeS3xrDqHA2CSHTmN9osstz8vbXfgh2mzzzzzzzzzzzz" ) . into_vec ( ) . expect ( "WRONG TEST FEED ADDRESS FORMAT" ) ) ;
527
+ contract. set_feed_address ( "HeS3xrDqHA2CSHTmN9osstz8vbXfgh2mzzzzzzzzzzzz" . into ( ) ) ;
477
528
}
478
529
479
530
#[ test]
@@ -483,7 +534,27 @@ mod tests {
483
534
let context = get_context ( owner, ntoy ( 1 ) , 10u64 . pow ( 14 ) , false ) ;
484
535
testing_env ! ( context) ;
485
536
let ( _to, _amount, _fee_address, _fee_amount, _max_rate_timespan) = default_values ( ) ;
486
- contract. set_feed_address ( bs58:: decode ( "HeS3xrDqHA2CSHTmN9osstz8vbXfgh2mzzzzzzzzzzzz" ) . into_vec ( ) . expect ( "WRONG TEST FEED ADDRESS FORMAT" ) ) ;
537
+ contract. set_feed_address ( "HeS3xrDqHA2CSHTmN9osstz8vbXfgh2mzzzzzzzzzzzz" . into ( ) ) ;
538
+ }
539
+
540
+ #[ test]
541
+ #[ should_panic( expected = r#"ERR_PERMISSION"# ) ]
542
+ fn admin_feed_payer_no_permission ( ) {
543
+ let context = get_context ( alice_account ( ) , ntoy ( 1 ) , 10u64 . pow ( 14 ) , false ) ;
544
+ testing_env ! ( context) ;
545
+ let mut contract = ConversionProxy :: default ( ) ;
546
+ let ( _to, _amount, _fee_address, _fee_amount, _max_rate_timespan) = default_values ( ) ;
547
+ contract. set_feed_payer ( ) ;
548
+ }
549
+
550
+ #[ test]
551
+ fn admin_feed_payer ( ) {
552
+ let owner = ConversionProxy :: default ( ) . owner_id ;
553
+ let mut contract = ConversionProxy :: default ( ) ;
554
+ let context = get_context ( owner, ntoy ( 1 ) , 10u64 . pow ( 14 ) , false ) ;
555
+ testing_env ! ( context) ;
556
+ let ( _to, _amount, _fee_address, _fee_amount, _max_rate_timespan) = default_values ( ) ;
557
+ contract. set_feed_payer ( ) ;
487
558
}
488
559
489
560
#[ test]
0 commit comments