Skip to content

Commit 4e020fa

Browse files
author
Paruyr Gevorgyan
committed
Applied review comments from ben-review session OpenST#1
1 parent 42d28de commit 4e020fa

10 files changed

Lines changed: 268 additions & 68 deletions

File tree

contracts/PriceOracleInterface.sol

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,8 +46,16 @@ interface PriceOracleInterface {
4646
returns (bytes3);
4747

4848
/**
49-
* @notice Returns an amount of the quote currency needed to purchase
50-
* one unit of the base currency.
49+
* @notice Returns quote currency decimals.
50+
*/
51+
function decimals()
52+
external
53+
view
54+
returns (uint8);
55+
56+
/**
57+
* @notice Returns an amount of the quote currency (see decimals()) needed
58+
* to purchase one unit of the base currency.
5159
*
5260
* @dev Function throws an exception if the price is invalid, for example,
5361
* was not set, or became outdated, etc.

contracts/PricerRule.sol

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,11 @@ contract PricerRule is Organized {
7070
*/
7171
uint256 public conversionRateDecimalsFromBaseCurrencyToToken;
7272

73+
/**
74+
* @dev Required decimals for price oracles.
75+
*/
76+
uint8 public requiredPriceOracleDecimals;
77+
7378
/**
7479
* @dev Token rules address of the economy.
7580
*/
@@ -111,6 +116,7 @@ contract PricerRule is Organized {
111116
* to the token.
112117
* @param _conversionRateDecimals The conversion rate's decimals from the
113118
* economy base currency to the token.
119+
* @param _requiredPriceOracleDecimals Required decimals for price oracles.
114120
* @param _tokenRules The economy token rules address.
115121
*/
116122
constructor(
@@ -119,6 +125,7 @@ contract PricerRule is Organized {
119125
bytes3 _baseCurrencyCode,
120126
uint256 _conversionRate,
121127
uint8 _conversionRateDecimals,
128+
uint8 _requiredPriceOracleDecimals,
122129
address _tokenRules
123130
)
124131
Organized(_organization)
@@ -149,6 +156,8 @@ contract PricerRule is Organized {
149156

150157
conversionRateDecimalsFromBaseCurrencyToToken = _conversionRateDecimals;
151158

159+
requiredPriceOracleDecimals = _requiredPriceOracleDecimals;
160+
152161
tokenRules = TokenRules(_tokenRules);
153162
}
154163

@@ -189,10 +198,19 @@ contract PricerRule is Organized {
189198
"'to' and 'amount' transfer arrays' lengths are not equal."
190199
);
191200

201+
if (_toList.length == 0) {
202+
return;
203+
}
204+
192205
uint256 baseCurrencyCurrentPrice = baseCurrencyPrice(
193206
_payCurrencyCode
194207
);
195208

209+
require(
210+
baseCurrencyCurrentPrice != 0,
211+
"Base currency price in pay currency is 0."
212+
);
213+
196214
require(
197215
isPriceInRange(
198216
_baseCurrencyIntendedPrice,
@@ -206,7 +224,7 @@ contract PricerRule is Organized {
206224

207225
for(uint256 i = 0; i < _amountList.length; ++i) {
208226
convertedAmounts[i] = convertPayCurrencyToToken(
209-
_baseCurrencyIntendedPrice,
227+
baseCurrencyCurrentPrice,
210228
_amountList[i]
211229
);
212230
}
@@ -228,6 +246,8 @@ contract PricerRule is Organized {
228246
* equal to the economy base currency code specified in this
229247
* contract constructor.
230248
* - The proposed price oracle does not exist.
249+
* - The proposed price oracle decimals number is equal to
250+
* the contract required price oracle decimals number.
231251
*
232252
* @param _priceOracle The proposed price oracle.
233253
*/
@@ -242,6 +262,11 @@ contract PricerRule is Organized {
242262
"Price oracle address is null."
243263
);
244264

265+
require(
266+
_priceOracle.decimals() == requiredPriceOracleDecimals,
267+
"Price oracle decimals number is difference from the required one."
268+
);
269+
245270
bytes3 payCurrencyCode = _priceOracle.quoteCurrency();
246271

247272
require(

contracts/TokenHolder.sol

Lines changed: 47 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -45,21 +45,35 @@ contract TokenHolder {
4545
address _sessionKey
4646
);
4747

48+
/**
49+
* @dev Rule's hash is calculated by:
50+
* keccak256(
51+
* abi.encodePacked(
52+
* to, // rule's address
53+
* keccak(data), // data is rule's payload
54+
* nonce, // non-used nonce for the specific session key
55+
* v, r, s // signature
56+
* )
57+
* )
58+
*/
4859
event RuleExecuted(
49-
address indexed _to,
50-
bytes4 _functionSelector,
51-
address _sessionKey,
52-
uint256 _nonce,
53-
bytes32 _messageHash,
60+
bytes32 _ruleHash,
5461
bool _status
5562
);
5663

64+
/**
65+
* @dev Redemption's hash is calculated by:
66+
* keccak256(
67+
* abi.encodePacked(
68+
* to, // cogateway's address
69+
* keccak(data), // data is cogateway::redeem function's payload
70+
* nonce, // non-used nonce for the specific session key
71+
* v, r, s // signature
72+
* )
73+
* )
74+
*/
5775
event RedeemExecuted(
58-
address indexed _to,
59-
bytes4 _functionSelector,
60-
address _sessionKey,
61-
uint256 _nonce,
62-
bytes32 _messageHash,
76+
bytes32 _redemptionHash,
6377
bool _status
6478
);
6579

@@ -349,14 +363,19 @@ contract TokenHolder {
349363

350364
TokenRules(tokenRules).disallowTransfers();
351365

352-
bytes4 functionSelector = bytesToBytes4(_data);
366+
bytes32 ruleHash = keccak256(
367+
abi.encodePacked(
368+
_to,
369+
keccak256(_data),
370+
_nonce,
371+
_v,
372+
_r,
373+
_s
374+
)
375+
);
353376

354377
emit RuleExecuted(
355-
_to,
356-
functionSelector,
357-
sessionKey,
358-
_nonce,
359-
messageHash,
378+
ruleHash,
360379
executionStatus_
361380
);
362381
}
@@ -406,15 +425,21 @@ contract TokenHolder {
406425
// solium-disable-next-line security/no-call-value
407426
(executionStatus_, returnData) = _to.call.value(msg.value)(_data);
408427

409-
410428
token.approve(_to, 0);
411429

430+
bytes32 redemptionHash = keccak256(
431+
abi.encodePacked(
432+
_to,
433+
keccak256(_data),
434+
_nonce,
435+
_v,
436+
_r,
437+
_s
438+
)
439+
);
440+
412441
emit RedeemExecuted(
413-
_to,
414-
functionSelector,
415-
sessionKey,
416-
_nonce,
417-
messageHash,
442+
redemptionHash,
418443
executionStatus_
419444
);
420445
}

contracts/test_doubles/unit_tests/pricer_rule/PriceOracleFake.sol

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,12 +28,15 @@ contract PriceOracleFake is PriceOracleInterface {
2828

2929
uint256 expirationHeight;
3030

31+
uint8 quoteCurrencyDecimals;
32+
3133

3234
/* Special */
3335

3436
constructor(
3537
bytes3 _baseCurrencyCode,
3638
bytes3 _quoteCurrencyCode,
39+
uint8 _quoteCurrencyDecimals,
3740
uint256 _initialPrice,
3841
uint256 _expirationHeight
3942
)
@@ -53,6 +56,8 @@ contract PriceOracleFake is PriceOracleInterface {
5356

5457
quoteCurrencyCode = _quoteCurrencyCode;
5558

59+
quoteCurrencyDecimals = _quoteCurrencyDecimals;
60+
5661
setPrice(_initialPrice, _expirationHeight);
5762
}
5863

@@ -85,6 +90,17 @@ contract PriceOracleFake is PriceOracleInterface {
8590
return quoteCurrencyCode;
8691
}
8792

93+
/**
94+
* @notice Returns quote currency decimals.
95+
*/
96+
function decimals()
97+
external
98+
view
99+
returns(uint8)
100+
{
101+
return quoteCurrencyDecimals;
102+
}
103+
88104
/**
89105
* @notice Returns an amount of the quote currency needed to purchase
90106
* one unit of the base currency.
@@ -117,8 +133,6 @@ contract PriceOracleFake is PriceOracleInterface {
117133
)
118134
public
119135
{
120-
require(_price != 0, "Price is 0.");
121-
122136
require(
123137
_expirationHeight > block.number,
124138
"Price expiration height is lte to the current block height."

test/pricer_rule/add_price_oracle.js

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,11 +58,38 @@ contract('PricerRule::add_price_oracle', async () => {
5858
);
5959
});
6060

61+
it('Reverts as the proposed price oracle decimals number is invalid.', async () => {
62+
const {
63+
organizationWorker,
64+
baseCurrencyCode,
65+
requiredPriceOracleDecimals,
66+
pricerRule,
67+
} = await PricerRuleUtils.createTokenEconomy(accountProvider);
68+
69+
const priceOracle = await PriceOracleFake.new(
70+
web3.utils.stringToHex(baseCurrencyCode),
71+
web3.utils.stringToHex('BTC'),
72+
requiredPriceOracleDecimals + 1,
73+
1, // price oracle initial price
74+
(await web3.eth.getBlockNumber()) + 10000, // expiration height
75+
);
76+
77+
await Utils.expectRevert(
78+
pricerRule.addPriceOracle(
79+
priceOracle.address,
80+
{ from: organizationWorker },
81+
),
82+
'Should revert as the proposed price oracle decimals number is invalid.',
83+
'Price oracle decimals number is difference from the required one.',
84+
);
85+
});
86+
6187
it('Reverts as the proposed price oracle base currency code does not '
6288
+ 'match with pricer base currency.', async () => {
6389
const {
6490
organizationWorker,
6591
baseCurrencyCode,
92+
requiredPriceOracleDecimals,
6693
pricerRule,
6794
quoteCurrencyCode,
6895
} = await PricerRuleUtils.createTokenEconomy(accountProvider);
@@ -78,6 +105,7 @@ contract('PricerRule::add_price_oracle', async () => {
78105
const priceOracle = await PriceOracleFake.new(
79106
web3.utils.stringToHex(anotherBaseCurrencyCode),
80107
web3.utils.stringToHex(quoteCurrencyCode),
108+
requiredPriceOracleDecimals,
81109
100, // initial price
82110
(await web3.eth.getBlockNumber()) + 10000, // expiration height
83111
);
@@ -97,6 +125,7 @@ contract('PricerRule::add_price_oracle', async () => {
97125
const {
98126
organizationWorker,
99127
baseCurrencyCode,
128+
requiredPriceOracleDecimals,
100129
pricerRule,
101130
priceOracle,
102131
quoteCurrencyCode,
@@ -110,6 +139,7 @@ contract('PricerRule::add_price_oracle', async () => {
110139
const priceOracle2 = await PriceOracleFake.new(
111140
web3.utils.stringToHex(baseCurrencyCode),
112141
web3.utils.stringToHex(quoteCurrencyCode),
142+
requiredPriceOracleDecimals,
113143
100, // initial price
114144
(await web3.eth.getBlockNumber()) + 10000, // expiration height
115145
);
@@ -140,7 +170,6 @@ contract('PricerRule::add_price_oracle', async () => {
140170
{ from: organizationWorker },
141171
);
142172

143-
144173
const events = Event.decodeTransactionResponse(
145174
response,
146175
);

test/pricer_rule/constructor.js

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ contract('PricerRule::constructor', async () => {
3535
web3.utils.stringToHex('OST'), // base currency code
3636
1, // conversion rate
3737
0, // conversion rate decimals
38+
0, // price oracles required decimals number
3839
accountProvider.get(), // token rules
3940
),
4041
'Should revert as the economy token address is null.',
@@ -54,6 +55,7 @@ contract('PricerRule::constructor', async () => {
5455
web3.utils.stringToHex(''), // base currency code
5556
1, // conversion rate
5657
0, // conversion rate decimals
58+
0, // price oracles required decimals number
5759
accountProvider.get(), // token rules
5860
),
5961
'Should revert as the base currency code is null.',
@@ -73,6 +75,7 @@ contract('PricerRule::constructor', async () => {
7375
web3.utils.stringToHex('OST'), // base currency code
7476
0, // conversion rate
7577
0, // conversion rate decimals
78+
0, // price oracles required decimals number
7679
accountProvider.get(), // token rules
7780
),
7881
'Should revert as the conversion rate from the base currency to the token is 0.',
@@ -92,6 +95,7 @@ contract('PricerRule::constructor', async () => {
9295
web3.utils.stringToHex('OST'), // base currency code
9396
1, // conversion rate
9497
0, // conversion rate decimals
98+
0, // price oracles required decimals number
9599
Utils.NULL_ADDRESS, // token rules
96100
),
97101
'Should revert as token rules is null.',
@@ -116,6 +120,7 @@ contract('PricerRule::constructor', async () => {
116120
web3.utils.stringToHex('OST'), // base currency code
117121
10, // conversion rate
118122
1, // conversion rate decimals
123+
2, // price oracles required decimals number
119124
tokenRules, // token rules
120125
);
121126

@@ -147,6 +152,10 @@ contract('PricerRule::constructor', async () => {
147152
(await pricerRule.conversionRateDecimalsFromBaseCurrencyToToken.call()).eqn(1),
148153
);
149154

155+
assert.isOk(
156+
(await pricerRule.requiredPriceOracleDecimals.call()).eqn(2),
157+
);
158+
150159
assert.strictEqual(
151160
(await pricerRule.tokenRules.call()),
152161
tokenRules,

0 commit comments

Comments
 (0)