What will be the mint process in a smart contract on neo3.
We have to take into account that there may be dynamic calls and that the contract can be malicious and make transactions reusing our signature, I think it is important to define the methodology to follow during a process.
This could help https://github.com/neo-project/neo/issues/544#issuecomment-509706398
A possible solution is deny, transfer, and allow only transferFrom
I think we can solve it without transferFrom, and its better, because tokens with transferFrom will have multiple solutions if desired.
We have multiple solutions in fact, just need to choose one as "standard".
Ok, here it goes a solution to it, without transferFrom:
User (ContractMe) wants to mint 2000 tokens on ContractToken, by attaching 200 NEO (ContractNEO):
Transaction Script (ContractInvoke)
System.Call ContractNEO "transfer" ContractMe ContractToken 200
System.Call ContractToken "mint" ContractMe
Witnesses
| scripthash | scope type | scope | description |
-------------------------------------------------------------------------------------------------------------------
| ContractMe | CallingScript | ContractInvokeHash | (i.e, only when EntryScriptHash = CallingScriptHash
Simple as that. In this case, we don't need multiple scripts, just a single one.
What happens is:
(1) ContractInvoke will be the caller of ContractNeo, so ContractNeo will have access to ContractMe witness (allowing 200 NEO to be transferred).
(1.1) If ContractToken tries to invoke ContractNeo, or any other Contract, neither of them will have the same CallingScript (just the same EntryScript), so ContractNEO is protected from all external accesses.
(2) ContractNeo will generate a notification, informing transfer ContractMe ContractToken 200.
(3) ContractToken will see it, and hide it (see hiding notifications). Why? Because user could double-call it. Another solution to this is use InvocationCounter, and only mint on InvocationCounter = 1. Both work, but I still prefer Notification Hiding solution (easier to understand in my opinion). Notifications are so much trusted as the contracts themselves they belong to.
======
What happens if ContractToken didn't expect this input (expired ICO, etc)?
ContractToken should execute a refund operation, by Call ContractNeo ContractToken ContractMe 200. This transfer should be authorized, even without witness, by considering the CallingScript an authorized witness. So, a "good approach" for validating witnesses on applications now is: Runtime.CheckWitness(user) OR user==CallingScriptHash. This authorizes the caller to do whatever it wants with its funds. To simplify user experience, perhaps CallingScriptHash should always be an authorized witness (we can discuss this).
======
How will wallets implement these features?
Currently, all features called "attach NEO" (or "attach GAS"), can be transformed into a System.Call ContractNeo "transfer" ... and attach a CallingScript scoped witness. Tokens would work in the same way: ContractToken "transfer" Me Other xx, require a CallingScript scoped witness.
Other types of witnesses will depend on specific applications, and to be honest, it's probably better to actually see them, before we proceed adding more functionalities.
Using manifest: one general possibility is to allow a specific contract to have your witness (ExecutingScriptHash = TargetContract) or allowing a group of contracts to use it (ExecutingScriptGroup = TargetGroup), but again, it will depend on applications.
@igormcoelho Yes, we need Scope and scope type signatures :)
@shargon do you need anything else besides scoped signatures? If not, can we close this?
We only need scoped signatures (to do), and read notifications (done)
Most helpful comment
Ok, here it goes a solution to it, without
transferFrom:User (
ContractMe) wants to mint 2000 tokens onContractToken, by attaching 200 NEO (ContractNEO):Transaction Script (
ContractInvoke)Witnesses
Simple as that. In this case, we don't need multiple scripts, just a single one.
What happens is:
(1)
ContractInvokewill be the caller of ContractNeo, so ContractNeo will have access to ContractMe witness (allowing 200 NEO to be transferred).(1.1) If ContractToken tries to invoke ContractNeo, or any other Contract, neither of them will have the same CallingScript (just the same EntryScript), so ContractNEO is protected from all external accesses.
(2) ContractNeo will generate a notification, informing
transfer ContractMe ContractToken 200.(3) ContractToken will see it, and hide it (see hiding notifications). Why? Because user could double-call it. Another solution to this is use InvocationCounter, and only mint on InvocationCounter = 1. Both work, but I still prefer Notification Hiding solution (easier to understand in my opinion). Notifications are so much trusted as the contracts themselves they belong to.
======
What happens if ContractToken didn't expect this input (expired ICO, etc)?
ContractToken should execute a refund operation, by
Call ContractNeo ContractToken ContractMe 200. This transfer should be authorized, even without witness, by considering the CallingScript an authorized witness. So, a "good approach" for validating witnesses on applications now is:Runtime.CheckWitness(user) OR user==CallingScriptHash. This authorizes the caller to do whatever it wants with its funds. To simplify user experience, perhaps CallingScriptHash should always be an authorized witness (we can discuss this).======
How will wallets implement these features?
Currently, all features called "attach NEO" (or "attach GAS"), can be transformed into a
System.Call ContractNeo "transfer" ...and attach a CallingScript scoped witness. Tokens would work in the same way:ContractToken "transfer" Me Other xx, require a CallingScript scoped witness.Other types of witnesses will depend on specific applications, and to be honest, it's probably better to actually see them, before we proceed adding more functionalities.
Using manifest: one general possibility is to allow a specific contract to have your witness (
ExecutingScriptHash = TargetContract) or allowing a group of contracts to use it (ExecutingScriptGroup = TargetGroup), but again, it will depend on applications.