Smart Contract
MockOracle
A.d2580caf2ef07c2f.MockOracle
1import FungibleToken from 0x9a0766d93b6608b7
2
3import DeFiActions from 0x0b11b1848a8aa2c0
4
5///
6/// THIS CONTRACT IS A MOCK AND IS NOT INTENDED FOR USE IN PRODUCTION
7/// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
8///
9access(all) contract MockOracle {
10
11 /// token price denominated in USD
12 access(self) let mockedPrices: {Type: UFix64}
13 /// the token type in which prices are denominated
14 access(self) let unitOfAccount: Type
15 /// bps up or down by which current price moves when bumpPrice is called
16 access(self) let bumpVariance: UInt16
17
18 access(all) struct PriceOracle : DeFiActions.PriceOracle {
19 access(contract) var uniqueID: DeFiActions.UniqueIdentifier?
20
21 init() {
22 self.uniqueID = nil
23 }
24 /// Returns the asset type serving as the price basis - e.g. USD in FLOW/USD
25 access(all) view fun unitOfAccount(): Type {
26 return MockOracle.unitOfAccount
27 }
28
29 /// Returns the latest price data for a given asset denominated in unitOfAccount()
30 access(all) fun price(ofToken: Type): UFix64? {
31 if ofToken == self.unitOfAccount() {
32 return 1.0
33 }
34 return MockOracle.mockedPrices[ofToken]
35 }
36 access(all) fun getComponentInfo(): DeFiActions.ComponentInfo {
37 return DeFiActions.ComponentInfo(
38 type: self.getType(),
39 id: self.id(),
40 innerComponents: []
41 )
42 }
43 access(contract) view fun copyID(): DeFiActions.UniqueIdentifier? {
44 return self.uniqueID
45 }
46 access(contract) fun setID(_ id: DeFiActions.UniqueIdentifier?) {
47 self.uniqueID = id
48 }
49 }
50
51 // resets the price of the token within 0-bumpVariance (bps) of the current price
52 // allows for mocked data to have variability
53 access(all) fun bumpPrice(forToken: Type) {
54 if forToken == self.unitOfAccount {
55 return
56 }
57 let current = self.mockedPrices[forToken]
58 ?? panic("MockOracle does not have a price set for token \(forToken.identifier)")
59 let sign = revertibleRandom<UInt8>(modulo: 2) // 0 - down | 1 - up
60 let variance = self.convertToBPS(revertibleRandom<UInt16>(modulo: self.bumpVariance)) // bps up or down
61 if sign == 0 {
62 self.mockedPrices[forToken] = current - (current * variance)
63 } else {
64 self.mockedPrices[forToken] = current + (current * variance)
65 }
66 }
67
68 access(all) fun setPrice(forToken: Type, price: UFix64) {
69 self.mockedPrices[forToken] = price
70 }
71
72 access(self) view fun convertToBPS(_ variance: UInt16): UFix64 {
73 var res = UFix64(variance)
74 for i in InclusiveRange(0, 3) {
75 res = res / 10.0
76 }
77 return res
78 }
79
80 init(unitOfAccountIdentifier: String) {
81 self.mockedPrices = {}
82 // e.g. vault.getType().identifier == 'A.0ae53cb6e3f42a79.FlowToken.Vault'
83 self.unitOfAccount = CompositeType(unitOfAccountIdentifier) ?? panic("Invalid unitOfAccountIdentifier \(unitOfAccountIdentifier)")
84 self.bumpVariance = 100 // 0.1% variance
85 }
86}
87