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.
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.
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.
anything to be worried about here wrt reentry?
There was a problem hiding this comment.
yes this smells like a re-entry attack
There was a problem hiding this comment.
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.
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.
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 |
|
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
WorldContextConsumerWorldContextConsumer/WorldContextProviderwith msgSender and msgValue