-
Notifications
You must be signed in to change notification settings - Fork 196
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
feat(world): add Balance table and BalanceTransferSystem #1425
Conversation
🦋 Changeset detectedLatest commit: 7ffde62 The changes in this PR will be included in the next version bump. This PR includes changesets to release 28 packages
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
|
||
// Update the balances | ||
Balances.set(fromNamespace, balance - amount); | ||
payable(toAddress).transfer(amount); |
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 don't know the "why" but I've seen folks prefer this approach over the above:
(bool success, ) = toAddress.call{value: amount}("");
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.
good catch! probably because of the 2300 gas limit of transfer
(see https://twitter.com/obatirou/status/1697167795077698038 and https://medium.com/coinmonks/solidity-transfer-vs-send-vs-call-function-64c92cfc878a)
bytes16 namespace = resourceSelector.getNamespace(); | ||
uint256 currentBalance = Balances.get(namespace); | ||
Balances.set(namespace, currentBalance + value); | ||
} |
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.
anything to be worried about here wrt reentry?
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 this smells like a re-entry attack
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.
Can you elaborate how a reentry attack would work here?
This is a utility that is used by call
, callFrom
and the World's fallback function, in each case just passing the msg.value
to the SystemCall
util. If the contract that's called in here would call one of these entry points again, it would still only pass that new call's msg.value
to the function.
I think we need to update the balance table value before calling the system, because the system might want to transfer the balance somewhere else in this call.
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 an expert on this, reentry + managing balances/funds just makes me nervous and so wanted to make sure we've considered it.
I think the important thing is that the balance transfer happens before any code that can be called/overridden/injected by malicious actors? In this case, requireAccess
is the only thing I can see but it doesn't make any external calls, so I think it's fine?
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, requireAccess
only checks an internal table.
Agree this is definitely a critical part of the system that we should be extra careful with and should also point this out as a focus area in the audit.
|
you can never prevent someone from sending eth to a contract, a contract can always self destruct and send value and not trigger your fallback |
Calling systems directly is not intended, but I don't think we should protect against it. As long as systems don't hold state it doesn't matter by who they're called since they will read/write on their caller by default. And there might be some advanced custom use cases where systems are limited to one World or do hold some internal state and the developers have some method for updating the internal state by calling them directly.
Whoever has root access can theoretically withdraw everything by deploying a new root system to transfer all the world contract's balance out, but it's basically a rug pull and not intended (we can't prevent it though). In the ideal world namespaces can only manage their own balances, which is the case once root namespace access is burned.
Right now the world can receive ETH without being attributed to any namespace via its |
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.
Are there ways for funds to get into the world without triggering receive
?
If so, do we want some way for the root namespace owner to withdraw address(world).balance - totalOfCurrentBalances
as a safety/backstop?
Yes it is possible to not trigger receive (see my comment on selfdestruct)
…On Tue, Sep 12, 2023 at 12:51 PM Kevin Ingersoll ***@***.***> wrote:
***@***.**** approved this pull request.
Are there ways for funds to get into the world without triggering receive?
If so, do we want some way for the root namespace owner to withdraw address(world).balance
- totalOfCurrentBalances?
—
Reply to this email directly, view it on GitHub
<#1425 (review)>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/AFBYUK4RYXLHZLD2QBF6KVDX2BEFRANCNFSM6AAAAAA4QIWAQQ>
.
You are receiving this because your review was requested.Message ID:
***@***.***>
|
I'd say because it requires real effort to send balance to the world without triggering For anyone with root access to the World it's still possible to withdraw all balance from the World (with or without adjusting the |
How so? |
Root systems are delegatecalled and therefore can access the world state directly (including the World contract's balance) |
Fixes #1283
TODO
WorldContextConsumer
WorldContextConsumer
/WorldContextProvider
with msgSender and msgValue