Skip to content

Commit 83bec1d

Browse files
committed
Tested onchain. Missing: deploy.sh updates
1 parent 69b29d9 commit 83bec1d

File tree

3 files changed

+111
-19
lines changed

3 files changed

+111
-19
lines changed

conversion_proxy/src/lib.rs

Lines changed: 88 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,6 @@ pub struct SwitchboardDecimal {
2828

2929
#[derive(BorshDeserialize, BorshSerialize, Serialize, Deserialize)]
3030
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
3431
pub result: SwitchboardDecimal,
3532
pub num_success: u32,
3633
pub num_error: u32,
@@ -39,12 +36,11 @@ pub struct PriceEntry {
3936

4037
#[derive(BorshDeserialize, BorshSerialize, Serialize, Deserialize)]
4138
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
4340
pub payer: Vec<u8>,
4441
}
4542

46-
47-
// Interface of the Switchboard price oracle
43+
// Interface of the Switchboard feed parser
4844
#[near_sdk::ext_contract(sb_contract)]
4945
trait Switchboard {
5046
fn aggregator_read(ix: SwitchboarIx) -> Promise<PriceEntry>;
@@ -53,8 +49,9 @@ trait Switchboard {
5349

5450
///
5551
/// 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
5855
/// - owner_id: only the owner can edit the contract state values above (default = deployer)
5956
#[near_bindgen]
6057
#[derive(Default, BorshDeserialize, BorshSerialize)]
@@ -105,7 +102,7 @@ impl ConversionProxy {
105102
/// - `payment_reference`: used for indexing and matching the payment with a request
106103
/// - `payment_address`: `amount` in `currency` of NEAR will be paid to this address
107104
/// - `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
109106
/// - `fee_payment_address`: `fee_amount` in `currency` of NEAR will be paid to this address
110107
/// - `fee_amount`: in `currency`
111108
/// - `max_rate_timespan`: in nanoseconds, the maximum validity for the oracle rate response (or 0 if none)
@@ -126,11 +123,11 @@ impl ConversionProxy {
126123
env::prepaid_gas(),
127124
MIN_GAS
128125
);
126+
assert_eq!(currency, "USD", "Only payments denominated in USD are implemented for now");
129127

130128
let reference_vec: Vec<u8> = hex::decode(payment_reference.replace("0x", ""))
131129
.expect("Payment reference value error");
132130
assert_eq!(reference_vec.len(), 8, "Incorrect payment reference length");
133-
assert_eq!(currency, "USD", "Only payments denominated in USD are implemented for now");
134131

135132
let get_rate = sb_contract::aggregator_read(SwitchboarIx {address: self.feed_address.clone(), payer: self.feed_payer.clone()},
136133
&self.feed_parser,
@@ -156,7 +153,7 @@ impl ConversionProxy {
156153
#[init]
157154
pub fn new(feed_parser: AccountId, feed_address: Vec<u8>) -> Self {
158155
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();
160157
Self {
161158
feed_parser,
162159
feed_address,
@@ -178,19 +175,23 @@ impl ConversionProxy {
178175
return self.feed_parser.clone();
179176
}
180177

181-
pub fn set_feed_address(&mut self, oracle: Vec<u8>) {
178+
pub fn set_feed_address(&mut self, feed_address: String) {
182179
let signer_id = env::predecessor_account_id();
183180
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");
185182
} else {
186183
panic!("ERR_PERMISSION");
187184
}
188185
}
189-
186+
190187
pub fn get_feed_address(&self) -> Vec<u8> {
191188
return self.feed_address.clone();
192189
}
193190

191+
pub fn get_encoded_feed_address(&self) -> String {
192+
return bs58::encode(self.feed_address.clone()).into_string();
193+
}
194+
194195
pub fn set_owner(&mut self, owner: ValidAccountId) {
195196
let signer_id = env::predecessor_account_id();
196197
if self.owner_id == signer_id {
@@ -199,6 +200,36 @@ impl ConversionProxy {
199200
panic!("ERR_PERMISSION");
200201
}
201202
}
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+
}
202233

203234
#[private]
204235
pub fn on_transfer_with_reference(
@@ -356,7 +387,7 @@ mod tests {
356387
VMContext {
357388
current_account_id: predecessor_account_id.clone(),
358389
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],
360391
predecessor_account_id,
361392
input: vec![],
362393
block_index: 1,
@@ -447,6 +478,26 @@ mod tests {
447478
);
448479
}
449480

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+
450501
#[test]
451502
fn transfer_with_reference() {
452503
let context = get_context(alice_account(), ntoy(1), 10u64.pow(14), false);
@@ -473,7 +524,7 @@ mod tests {
473524
testing_env!(context);
474525
let mut contract = ConversionProxy::default();
475526
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());
477528
}
478529

479530
#[test]
@@ -483,7 +534,27 @@ mod tests {
483534
let context = get_context(owner, ntoy(1), 10u64.pow(14), false);
484535
testing_env!(context);
485536
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();
487558
}
488559

489560
#[test]

mocks/src/switchboard_feed_parser_mock.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,8 @@ mod tests {
8888
}
8989
#[test]
9090
fn aggregator_read() {
91+
let disp_vec = bs58::decode("E81iAUr7RPDUksAFtZxn7curbUVRy1Gps6sr6JnQALHx").into_vec().expect("!!").into_iter().map(|c| c.to_string()).collect::<Vec<String>>().join(",");
92+
println!("RESULT: {}", disp_vec);
9193
let context = get_context("alice.near".to_string(), to_yocto("1"), 10u64.pow(14), true);
9294
testing_env!(context);
9395
let contract = SwitchboardFeedParser::default();
@@ -97,14 +99,15 @@ mod tests {
9799
}) {
98100
assert_eq!(result.result.mantissa, i128::from(1234000));
99101
assert_eq!(result.result.scale, 6);
100-
// TODO
101102
} else {
102103
panic!("NEAR/USD mock returned None")
103104
}
104105
}
105106
#[test]
106107
#[should_panic(expected = r#"InvalidAggregator"#)]
107108
fn missing_aggregator_read() {
109+
let disp_vec = bs58::decode("E81iAUr7RPDUksAFtZxn7curbUVRy1Gps6sr6JnQALHx").into_vec().expect("!!").into_iter().map(|c| c.to_string()).collect::<Vec<String>>().join(",");
110+
println!("RESULT: {}", disp_vec);
108111
let context = get_context("alice.near".to_string(), to_yocto("1"), 10u64.pow(14), true);
109112
testing_env!(context);
110113
let contract = SwitchboardFeedParser::default();

tests/sim/conversion_proxy.rs

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,24 @@ fn test_transfer_with_invalid_reference_length() {
169169

170170
#[test]
171171
fn test_transfer_with_wrong_currency() {
172+
let working_vec = bs58::encode([252, 166, 196, 242, 159, 139, 89, 47, 230, 78, 243, 185, 185, 188, 150, 219, 165, 68, 131, 5, 216, 42, 120, 26, 26, 142, 133, 0, 111, 235, 63, 18]).into_string();
173+
println!("WORKING VEC: {}", working_vec.clone());
174+
let vec = bs58::decode( working_vec.clone()).into_vec().expect("!!");
175+
let disp_vec = vec.clone().into_iter().map(|c| c.to_string()).collect::<Vec<String>>().join("','");
176+
println!("RESULT WORKING VEC: ['{}']", disp_vec.clone());
177+
178+
let vec = bs58::decode("E81iAUr7RPDUksAFtZxn7curbUVRy1Gps6sr6JnQALHx").into_vec().expect("!!");
179+
let disp_vec1 = vec.clone().into_iter().map(|c| c.to_string()).collect::<Vec<String>>().join("','");
180+
// println!("RESULT feed-payer: [{}] {}", disp_vec.clone(), vec.len());
181+
182+
let vec = bs58::decode("7igqhpGQ8xPpyjQ4gMHhXRvtZcrKSGJkdKDJYBiPQgcb").into_vec().expect("!!");
183+
let disp_vec2 = vec.clone().into_iter().map(|c| c.to_string()).collect::<Vec<String>>().join("','");
184+
println!("RESULT \"feed-address\":['{}'],\"payer\":['{}']", disp_vec2.clone(), disp_vec1.clone());
185+
186+
let vec = &bs58::decode("7igqhpGQ8xPpyjQ4gMHhXRvtZcrKSGJkdKDJYBiPQgcb").into_vec().expect("!!")[1..];
187+
let disp_vec2 = vec.clone().into_iter().map(|c| c.to_string()).collect::<Vec<String>>().join("','");
188+
println!("SLICE \"feed-address\":['{}'],\"length\":['{}']", disp_vec2.clone(), vec.len());
189+
172190
let (alice, bob, builder, proxy) = init();
173191
let transfer_amount = to_yocto("100");
174192
let payment_address = bob.account_id().try_into().unwrap();
@@ -188,7 +206,7 @@ fn test_transfer_with_wrong_currency() {
188206
),
189207
deposit = transfer_amount
190208
);
191-
assert_one_promise_error(result, "Only payments denominated in USD are implemented for now");
209+
assert_one_promise_error(result, &disp_vec);
192210
}
193211

194212
#[test]

0 commit comments

Comments
 (0)