This document provides an overview of advanced NEO smart contracts. It begins with an agenda for the workshop and questions about transaction experience. It then discusses how NEO verifies transactions using witness scripts and unspent outputs. Details are given on transaction structure, types, and attributes. Best practices are outlined around constraining invocation scripts, guarding dynamic invokes, prefixing storage keys, validating inputs, and protecting users. The presentation encourages following Switcheo for an upcoming API development competition.
4. #SwitchtoSwitcheo
Workshop Agenda
1. How Does NEO Verify Transactions?
2. How To Make Withdrawals From A Smart Contract?
3. NEO Smart Contracts Best Practices
4. Questions and Answers (Q&A)
5. Demo (If there is time)
6. #SwitchtoSwitcheo
How Does NEO Verify Transactions?
CheckWitness(t_from)
What is “witness”? And are we actually “checking” for here?
https://github.com/kentarohorie/simple-neo-token-sample/blob/1a38e50/yourcoin/nep5.py#L58
To find out, we need to understand:
• NEO’s transaction structure, and
• “unspent outputs” or “UTXOs” (this type of model is inherited from Bitcoin)
Recall this code from the lecture in the Transfer operation:
8. #SwitchtoSwitcheo
NEO Transaction Types
You can find the full list of transaction “types”:
https://github.com/neo-project/neo/blob/master/neo/Core/TransactionType.cs
ContractTransaction
Normal NEO & GAS transfers
InvocationTransaction
Invokes some operations
in the NEO VM using the
given script
2 Most Common Types:
9. #SwitchtoSwitcheo
NEO Transaction Attributes
Full list of transaction attribute types or “usages” here:
https://github.com/neo-project/docs/blob/master/en-us/sc/reference/fw/dotnet/neo/TransactionAttribute/Usage.md
General Usages Specific Usages
• Doesn’t change transaction
execution
• For general uses like logging
transaction purpose as a
record, or adding data for
deployed smart contracts to
read from
• e.g.: Data “Hash”, or “Remarks”
• Causes transaction to be
verified or executed differently
• e.g: “Additional Witness” or
“Script” (0x20), etc.
• Will look at one, read docs for
info on the others
10. #SwitchtoSwitcheo
NEO Inputs & Outputs
{
inputs: [{
txid: “0xa…”,
index: 0,
address: A,
amount: 5,
}, {
txid: “0xb…”,
index: 0,
address: B,
amount: 7,
}],
outputs: [{
address: C,
amount: 12
}],
attributes: [{
usage: 0x20, // Script
data: <addr D>],
}
Transaction
must be
witnessed by
A+B+D
Address A
+5
Address B
+7
Address C
12
https://bitcoin.org/en/developer-guide#block-chain
12. #SwitchtoSwitcheo
NEO Script
• This is only for transactions of Invocation type.
• The script is directly executed by the VM
• So it is actually just a series of opcodes and data
{
…,
“script”:“020bf1920…”,
…
}
13. #SwitchtoSwitcheo
OpCode Hex Explanation
PUSH20 0x20 Pushes the next 20 bytes onto the stack
<from> 0x11fg876d..
Push the “from” address for an NEP-5 transfer
operation
PUSH3 0x53 Pushes the number ‘3' onto the stack
0x11fg876d..
0x225ab73..
0x3356765..
3
… … … … … … … … … … … …
PACK 0xC1
Pops N from stack and combines the next N items into an
array
PUSHBYTES8 0x08 Pushes the next 8 bytes onto the stack
“transfer” 0x7472616e73666572
the operation string as bytes in this case it is the
“transfer” operation for NEP-5
APPCALL 0x67
Reads the next 20 bytes and invokes the corresponding
deployed contract with Application Trigger.
<scriptHash> 0xa12cde… The hash of the deployed smart contract to invoke
So transaction will have: { …, “script”:“020bf1920…” }
0x11 0x22 0x3
0x7472616..
Stack
https://github.com/neo-project/neo-vm/blob/master/src/neo-vm/OpCode.cs
Script example for a standard entrypoint: Main(string operation, params object[] args)
NEO Script
14. #SwitchtoSwitcheo
Verification of Smart Contracts
Verify([mempool]) VerifyScripts(IVerifiable) GetScriptHashesForVerifying()
https://github.com/neo-project/neo/blob/
23bbe9b/neo/Core/Transaction.cs#L330
https://github.com/neo-project/neo/blob/
23bbe9b/neo/Core/Helper.cs#L46
https://github.com/neo-project/neo/blob/
23bbe9b/neo/Core/Transaction.cs#L227
Check Double Spend,
etc..
Get hashes that must match
Verification Scripts
(found in “scripts”)
Get hashes of inputs
Add data (hash) in
transaction attribute
0x20 (usage “Script”
a.k.a. “Additional
Witness”)
This is useful if you
want to ensure
Verification runs on a
deployed contract, but
are not using inputs
from a smart contract
Hashes each VerificationScript
and compares hashes in order.
Fails if any missing or does
not match.
Executes Invocation Script
+ Verification Script.
Fails if hash mismatch, or
does not return true
Pass!
15. #SwitchtoSwitcheo
Verification of Smart Contracts
https://github.com/neo-project/neo/blob/23bbe9b/neo/Core/Helper.cs#L61
How to run custom verification on deployed contracts?
Write custom verification logic in Trigger
User can leave VerificationScript empty if deployed
contract needs to be a witness
16. #SwitchtoSwitcheo
Dangers of Sending from Custom Smart Contracts
Jack’s Available Balance:
5 NEO
Jack’s
Transaction
A
5 NEO
To Jack
*State cannot be changed
during verification
5 NEO
To Jack
Jack’s
Transaction
B
5 NEO
To Jack
Jack’s
Transaction
C
5 NEO
To Jack
Jack’s
Transaction
D
> Change
Jack’s Balance
0 - 5 = ???
> Change
Jack’s Balance
5 - 5 = 0 NEO
VERIFICATION
APPLICATION
17. #SwitchtoSwitcheo
VERIFICATION
APPLICATION
*State cannot be changed
during verification
5 NEO
Jack’s
Transaction
A
5 NEO
Jack’s
Transaction
B
5 NEO
Jack’s
Transaction
C
5 NEO
Jack’s
Transaction
D
Jack’s Available Balance:
5 NEO
> Not enough balance,
do nothing
> Check & Change
Jack’s Balance
0 NEO < 5 NEO
> Reserve Output
to Jack
> Check & Change
Jack’s Balance
5 - 5 = 0 NEO
Dangers of Sending from Custom Smart Contracts
19. #SwitchtoSwitcheo
Examples for Sending from Custom Smart Contracts
Some example implementations and references:
Switcheo Exchange (live): https://github.com/ConjurTech/switcheo/blob/v2/switcheo/BrokerContract.cs
NeoResearch (prototype): https://github.com/NeoResearch/nep-distributed-payments/blob/master/workingPrototype.cs
Neon Exchange (whitepaper): https://neonexchange.org/pdfs/whitepaper_v1.pdf
20. #SwitchtoSwitcheo
Dangers Of Using Verification Trigger
Witness can be used in other contracts!
Withdrawing NEO!
Runtime.CheckWitness(MyContractScriptHash)
will be true.
So “transfer” from “My Contract” to ANYONE
will also pass!
My Contract
RPX Token
*My Contract has 1000 RPX tokens
*Transaction’s script is an
“AppCall" to “RPX Token"
instead of “My Contract”!
Withdrawal checks pass
so contract returns true
VERIFICATION
APPLICATION
21. #SwitchtoSwitcheo
Best Practices - Constrain Invocation Script
*My Contract has 1000 RPX tokensVERIFICATION
https://github.com/ConjurTech/switcheo/blob/v2/switcheo/BrokerContract.cs#L198
22. Best Practices - Guard When Doing Dynamic Invoke
My Contract ATK Token RPX Token
1000 RPX
100 ATK
transfer transfer
fr: SC
to: A
amt: 100 ATK
fr: SC
to: A
amt: 1000 RPX
Attacker
withdraw
fr: SC
to: A
amt: 100 ATK
https://github.com/neo-project/proposals/pull/44/files#diff-e5a1452ea0de8fa24b9c328151e94affR90
NEP-5
23. #SwitchtoSwitcheo
Best Practices - Prefix All Storage Keys
https://github.com/kentarohorie/simple-neo-token-sample/blob/1a38e50/yourcoin/nep5.py#L151
-> When t_spender is an empty byte array, approval_key is
the same format as balanceOf key!
https://github.com/kentarohorie/simple-neo-token-sample/blob/1a38e50/yourcoin/nep5.py#L29
->> Value of balance can be changed wrongly!
24. #SwitchtoSwitcheo
Best Practices - Prefix All Storage Keys
https://github.com/ConjurTech/switcheo/blob/v2/switcheo/BrokerContract.cs
Storage keys should be prefixed by unique, non-overlapping bytes
for different types of data
25. #SwitchtoSwitcheo
Best Practices - Validate All User Inputs
Validate ALL inputs from users, and constrain them to the minimum set of formats
• Length of both t_owner and t_spender should be constrained to 20 as
addresses are 20 bytes long
• Reduce flows and set of inputs to test or check against
• Acts as additional guard against accidental “key collision”
26. #SwitchtoSwitcheo
Best Practices - Protect Users Whenever Possible
Don’t assume honest clients will always send in valid inputs!
• Don’t let user lose assets or “burn” tokens accidentally through malformed script
or transaction
• Never ignore receiving of system assets if possible, in case of accidental sends
• Always handle received system assets by moving to an internal user balance and let
users withdraw it later
• When encountering invalid state or input during smart contract execution, revert
whole script by throwing Exceptions, see link
28. #SwitchtoSwitcheo
V2 Launch - API Development Competition
Switcheo is holding an API Development
Contest for our upcoming V2 launch!
Prizes include:
1,000,000 SWTH Tokens,
Customised Switcheo Ledger Nano S’s,
and various Switcheo Merch!
Follow us for more details!