-
Notifications
You must be signed in to change notification settings - Fork 1k
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
Invoke contracts' payable method on asset Transfers #2012
Conversation
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.
neo-project/proposals#108 is good one actually, it can simplify things for contracts like NeoFS mainnet contract and the one from #1573 where some deposit is being made, it allows to make it in the most natural way, by transferring tokens to the contract address.
|
||
// React to transfer event | ||
|
||
if (eventName == "Transfer") |
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.
|
||
var contract = Snapshot.Contracts.TryGet(new UInt160(to)); | ||
if (contract == null) return; | ||
if (!contract.Payable) throw new InvalidOperationException("Not payable 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.
One can say that this should be checked by the contract. Though if we're to make sure this is a valid transfer event, maybe it's worth enforcing it here.
|
||
// Call _fallback method | ||
|
||
CallContractInternal(contract, method, new Array(ReferenceCounter) |
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.
BTW, this can also prevent some unexpected transfers, like NeoFS contract is happy to accept some GAS, but if you're to throw any NEO at it --- it doesn't know how to handle that, so the contract can check what is being transferred to it and reject things it doesn't expect.
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, you can filter with your own code.
|
||
// Validate | ||
|
||
var method = contract.Manifest.Abi.GetMethod("_onPaymentReceived"); |
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.
May happen re-entrancy attack?
Nep5A.Transfer -> `_onPaymentReceived` -> NepA.Transfer .......?
Then the user's asset can be transfered
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.
Of course, the users need to be aware and use invocation counter or decrease the balance before send the notification
I think that if necessary, it should be called by the contract, not by the system. |
If so, then
|
I mean, the NEP-5 contract is obliged to call the |
Then, we need to remove the '_' because it will be called by the contract, and it can be called manually so it's untrustable, you need to check the notifications. |
Yeah, contract-driven invocation is problematic too: contracts can skip it, it can be invoked from somewhere else, receiver has to check for notifications. Better have it done by the system. |
You don't need to read the notifications. The caller is the asset id. The value can be passed as a parameter. And you must trust the NEP-5 contract, because the notification is sent by the caller too. |
But it's still a different level of guarantees. Contract can just not invoke the method while the system can be trusted to always do that. You're probably concerned with notification parsing required for this, but I think we need it anyway for #1879. And performance-wise that's what we're always doing in neo-go by default (batteries included, no plugins for us), it is visible in the profiler, but I think it's affordable. |
That it's true, and usually this method only will check the caller and throw an exception, if you want to do more logic you can check the notifications |
There is another problem with non-system invocations: manifested contract's permissions/trusts. The call might get blocked and at the same time we can't predict in the NEP-5 contract what other contracts can be called on transfer, so with this scheme all NEP-5 will need to have "*/*" permissions which makes permission system not very useful. Invocation by the system doesn't have this problem. |
Indeed. But the actual use of permissions is actually for dynamic sharding. But if the system calls the target contract, this will also destroy the sharding. |
Yeah, that's true (hi, #546). And I don't see any simple solution for that. Callback execution could probably be moved into some other post-transaction-execution context that would be somehow tied to the transaction execution and could affect it (make it fail if it fails), but that would be very complicated and fragile. |
Or maybe there is one. At least allowing for #546 and not considering real storage sharding (maybe NeoFS is a better example of how storage sharding is to be done when needed). One thing we're currently missing for #546 is manifests for entry scripts, they're free to call anything and it's a problem. But instead of adding full-blown manifests (or just permissions) to them (that would most of the time contain just one entry for the contract being called by the script) we can provide a list of contracts allowed to execute within the context of this transaction (not exactly an "execution plan", but something reminiscent). This way we can leave permissions/trusts for security purposes and let execution parallelization be solved by using these lists. And these lists are easily obtained during test invocations that won't be restricted. I don't expect these lists to be big (and again, to tackle #546 some additional in-transaction data is needed anyway), so it shouldn't be a problem from size perspective. And it all can be done as an experimental attribute for the start. So we can use system-induced invocations for |
In fact they only need |
For me, only NEO/GAS can invoke |
NEP11 about NFT, also has |
Well, we can get back a little to https://cryptoslate.com/this-user-lost-1m-of-top-defi-coin-aave-aave-by-accident-heres-why/ that triggered this PR. Does it solve this problem? Should we ignore this problem?
That's exactly why we need #1883 (with #1879, of course), this logic should only be used for verified NEP-5 and NEP-11 contracts. And other contracts can emit any kind of "transfer" events they want. |
There some other ways to solve it.
|
That's what we are doing in neo-project/proposals#124. |
Closed in favor of #2024 |
Related to https://cryptoslate.com/this-user-lost-1m-of-top-defi-coin-aave-aave-by-accident-heres-why/
Close neo-project/proposals#108