NEP | Title | Author | Status | DiscussionsTo | Type | Category | Version | Created | Updated |
---|---|---|---|---|---|---|---|---|---|
418 |
Remove attached_deposit view panic |
Austin Abell <[email protected]> |
Final |
Standards Track |
Tools |
1.0.0 |
18-Oct-2022 |
27-Jan-2023 |
This proposal is to switch the behavior of the attached_deposit
host function on the runtime from panicking in view contexts to returning 0. This results in a better devX because instead of having to configure an assertion that there was no attached deposit to a function call only for transactions and not view calls, which is impossible because you can send a transaction to any method, you could just apply this assertion without the runtime aborting in view contexts.
This will allow contract SDK frameworks to add the attached_deposit == 0
assertion for every function on a contract by default. This behavior matches the Solidity/Eth payable modifier and will ensure that funds aren't sent accidentally to a contract in more cases than currently possible.
This can't be done at a contract level because there is no way of checking if a function call is within view context to call attached_deposit
conditionally. This means that there is no way of restricting the sending of funds to functions intended to be view only because the abort from within attached_deposit
can't be caught and ignored from inside the contract.
Initial discussion: https://near.zulipchat.com/#narrow/stream/295306-pagoda.2Fcontract-runtime/topic/attached_deposit.20view.20error
The rationale for assigning 0u128
to the pointer (u64
) passed into attached_deposit
is that it's the least breaking change.
The alternative of returning some special value, say u128::MAX
, is that it would cause some unintended side effects for view calls using the attached_deposit
. For example, if attached_deposit
is called within a function, older versions of a contract that do not check the special value will return a result assuming that the attached deposit is u128::MAX
. This is not a large concern since it would just be a view call, but it might be a bad UX in some edge cases, where returning 0 wouldn't be an issue.
The error inside attached_deposit
for view calls will be removed, and for all view calls, 0u128
will be set at the pointer passed in.
Currently, the implementation for attached_deposit
is as follows:
pub fn attached_deposit(&mut self, balance_ptr: u64) -> Result<()> {
self.gas_counter.pay_base(base)?;
if self.context.is_view() {
return Err(HostError::ProhibitedInView {
method_name: "attached_deposit".to_string(),
}
.into());
}
self.memory_set_u128(balance_ptr, self.context.attached_deposit)
}
Which would just remove the check for is_view
to no longer throw an error:
pub fn attached_deposit(&mut self, balance_ptr: u64) -> Result<()> {
self.gas_counter.pay_base(base)?;
self.memory_set_u128(balance_ptr, self.context.attached_deposit)
}
This assumes that in all cases, self.context.attached_deposit
is set to 0 in all cases. This can be asserted, or just to be safe, can check if self.context.is_view()
and set 0u128
explicitly.
This won't have any implications outside of view calls, so this will not affect anything that is persisted on-chain. This only affects view calls. This can only have a negative side effect if a contract is under the assumption that attached_deposit
will panic in view contexts. The possibility that this is done and has some value connected with a view call result off-chain seems extremely unlikely.
This has a breaking change of the functionality of attached_deposit
and affects the behavior of some function calls in view contexts if they use attached_deposit
and no other prohibited host functions.
- The Rust SDK, as well as other SDKs, can add the
attached_deposit() == 0
check by default to all methods for safety of use. - Potentially, other host functions can be allowed where reasonable values can be inferred. For example,
prepaid_gas
,used_gas
could return 0.
The initial version of NEP-418 was approved by Tools Working Group members on January 19, 2023 (meeting recording).
- This will allow contract SDK frameworks to add the
attached_deposit == 0
assertion for every function on a contract by default. - This behavior matches the Solidity/Eth payable modifier and will ensure that funds aren't sent accidentally to a contract in more cases than currently possible.
- Given that there is no way of checking if a function call is within view context to call
attached_deposit
conditionally, this NEP only changes a small surface of the API instead of introducing a new host function.
# | Concern | Resolution | Status |
---|---|---|---|
1 | Proposal potentially triggers the protocol version change | It does not trigger the protocol version change. Current update could be considered a client-breaking change update. | Resolved |
2 | The contract can assume that attached_deposit will panic in view contexts. |
The possibility that this is done and has some value connected with a view call result off-chain seems extremely unlikely. | Won't Fix |
3 | Can we assume that in all view calls, the attached_deposit in the VMContext always zero? |
Yes, there is no way to set attached_deposit in view calls context |
Resolved |
Copyright and related rights waived via CC0.