-
Notifications
You must be signed in to change notification settings - Fork 45
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
ServiceRegistry (without parameter reconfiguration) #1116
Conversation
Codecov Report
@@ Coverage Diff @@
## master #1116 +/- ##
=========================================
Coverage ? 80.96%
=========================================
Files ? 21
Lines ? 1408
Branches ? 178
=========================================
Hits ? 1140
Misses ? 228
Partials ? 40
Continue to review full report at Codecov.
|
Codecov Report
@@ Coverage Diff @@
## master #1116 +/- ##
==========================================
+ Coverage 81% 81.14% +0.13%
==========================================
Files 21 21
Lines 1411 1432 +21
Branches 179 186 +7
==========================================
+ Hits 1143 1162 +19
- Misses 228 229 +1
- Partials 40 41 +1
Continue to review full report at Codecov.
|
aa61897
to
0c98616
Compare
0afaadb
to
d4aa7e8
Compare
4140515
to
1983528
Compare
8182ef4
to
2a6831d
Compare
require(now >= release_at); | ||
require(balance > 0); | ||
require(token.transfer(_to, balance)); | ||
return true; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why does this function have a return value? It always returns true if it does not fail on a require.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think currently it's safer to always return a boolean (even when it's always true), and always check the return value.
Solidity compiler doesn't warn when we forget to check the return value of a function call, so sticking with "always check return values" is a safe convention to follow.
I'll document this in the contribution guide.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've written this in CONTRIBUTING.md
.
@@ -3,49 +3,167 @@ pragma solidity 0.5.4; | |||
import "raiden/Token.sol"; | |||
import "raiden/Utils.sol"; | |||
|
|||
contract Deposit { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why is this it's own contract? Couldn't you also model this as a struct inside the ServiceRegistry
contract?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, everything could be in ServiceRegistry
and that would be gas-efficient.
The current choice follows security-in-depth. Even if ServiceRegistry
is compromized, the deposits made earlier would not be affected.
Is this conceptual security worth more than the additional gas? I don't know for sure, but the deposits are rarer and bigger than usual Raiden transfers.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That argument makes sense to me, but I don't have much experience. The question was aimed at understanding the trade-off better!
withdrawer = _withdrawer; | ||
} | ||
|
||
// In order to make a deposit, transfer the ERC20 token into this contract. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is it possible to forbid this behaviour and only allow deposits with a deposit
function, where one could check the token?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unfortunately, contracts cannot refuse incoming ERC20 tokens.
In the beginning, I had a deposit()
function, but it did nothing useful. So I removed it.
|
||
// @param _token_for_registration The address of the ERC20 token contract that services use for registration fees | ||
constructor(address _token_for_registration) public { | ||
constructor(address _token_for_registration, uint256 _initial_price) public { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should min_price
be settable as well?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This follows in the next PR. min_price
, 6/5
bumping ratio and 200 days
will be configurable.
// Check against overflow. | ||
require(valid_till < valid_till + 180 days); | ||
valid_till = valid_till + 180 days; | ||
assert(valid_till > service_valid_till[msg.sender]); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure about low-level differences, but why do you use assert
here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Because I know the assert is always true. So I use assert
and then the SMT solver in solc
tries to find a counterexample.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To say it in a different way: assert
should only fail for bugs in the contract, require
is for all other cases.
require(token.transfer(address(depo), amount)); | ||
|
||
// Fire event | ||
emit RegisteredService(msg.sender, valid_till, amount, depo); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Above you write that all functions should return true
, so this one as well?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I believe so. I'll add return true
.
require(bytes(new_url).length != 0, "new url is empty string"); | ||
if (bytes(urls[msg.sender]).length == 0) { | ||
service_addresses.push(msg.sender); | ||
} | ||
urls[msg.sender] = new_url; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same here, should this return true
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's also true.
and the new value is small enough. ``` >>> A = 200 >>> X = 2 ** 60 - 1 >>> P = 24 * (A ** 4) >>> Q = P + 24*(A**3)*X + 12*(A**2)*(X**2) + 4*A*(X**3) + X**4 >>> Q < (2 ** 256 - 1) True ```
// We are here trying to approximate some exponential decay. | ||
// exp(- X / A) where | ||
// X is the number of seconds since the last price change | ||
// A is the decay constant (A = 200 days correspnods to 0.5% decrease per day) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
s/correspnods/corresponds
uint256 P = 24 * (A ** 4); | ||
uint256 Q = P + 24*(A**3)*X + 12*(A**2)*(X**2) + 4*A*(X**3) + X**4; | ||
|
||
uint256 price = _set_price * P / Q; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Once you make A
configurable, you might have to check for an overflow here as well.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, the next PR will contain lots of those checks. I hope nobody needs the price decaying over billions of years.
def test_deposit_contract( | ||
get_deposit_contract: Callable, custom_token: Contract, get_accounts: Callable | ||
) -> None: | ||
(A,) = get_accounts(1) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: You don't need braces here
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I like it without the braces, but it's with the braces everywhere in the codebase. For now I just follow the local convention.
amount of deposits required for a service registration.
require() statements.
because it `selfdestruct()`s.
This is a part of #1087 .
Getting and Extending the Membership
There is always a deposit amount for six-month of membership.
The Change of Deposit Amounts
Terms of the Deposits
The deposit is held until the six months period.