Skip to content

Commit

Permalink
Merge pull request #79 from neo-project/dev
Browse files Browse the repository at this point in the history
master < dev
  • Loading branch information
apisit authored Aug 17, 2023
2 parents 4f28fd0 + ec8bce4 commit 2d1be1d
Show file tree
Hide file tree
Showing 10 changed files with 102 additions and 49 deletions.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
Expand Up @@ -44,9 +44,18 @@ Create a new folder for your project and open it in VS Code, then create a file
Press `Ctrl+Shift+P` to open the Command Palette and type `Python: Create Environment`, select `Venv`, your Python
version, select the `requirements.txt` file, and press `Ok`, so that the virtual environment can be created.

If you have a Python file open, you can check the lower right corner of VS Code to verify that the virtual environment
is active, and it's using Python 3.
Create a new terminal by pressing `Ctrl+Shift+P` and typing `Terminal: Create New Terminal`. You should see `(.venv)`
at the beginning of the terminal line. You'll only be able to compile your contract if the virtual environment is
active.

> Note: if you are using a powershell terminal you might get an error stating that
> the `Activate.ps1 cannot be loaded because running scripts is disabled on this system`, you can just use a cmd
> terminal instead by clicking on the **** icon on right side of the **+** symbol on the terminal tab and selecting
> `Command Prompt`. If everything is alright you should see `(.venv)` at the beginning of the terminal line.
> ![Activating CMD on Terminal](./assets/terminal-cmd.png)
Also, if you have a Python file open, you can check the lower right corner of VS Code to verify that the virtual environment
is active, and it's using Python 3.
![Venv active on Python file](./assets/venv-active.png)

## 3. Create the Coin contract file
Expand All @@ -70,13 +79,6 @@ Open the VS Code terminal and run the following command to compile the contract:
neo3-boa compile coin.py --debug
```

> Note: if you are using a powershell terminal you might get an error before executing the command above stating that
> the `Activate.ps1 cannot be loaded because running scripts is disabled on this system`, you can just use a cmd
> terminal instead by clicking on the **** icon on right side of the **+** symbol on the terminal tab and selecting
> `Command Prompt`. If everything is alright you should see `(.venv)` at the beginning of the terminal line, and then
> you can execute the code above.
> ![Activating CMD on Terminal](./assets/terminal-cmd.png)
Be sure to include the `--debug` flag to generate the debug information required by the Neo Blockchain Toolkit.

If the compilation is successful, you should see 3 new files:
Expand All @@ -90,6 +92,7 @@ generated by the compiler alongside the nef.

Click on the `.nef` or `.manifest.json` generated file and press `Ctrl+Shift+D` to open the Run and Debug panel.
Click on `create a launch.json file` and select `Neo Contract` as the environment.
![Creating a debug launch file](./assets/create-launch-json.png)

This will generate a `.vscode/launch.json` file inside the project folder. Open the file and replace the `operation`
field value with `totalSupply`:
Expand All @@ -103,17 +106,21 @@ field value with `totalSupply`:
...
```

Next, press `F5` to start debugging. The Neo Blockchain Toolkit will automatically deploy the contract and invoke the
`totalSupply` method in a test environment.
Next, press `F5` to start debugging. The Neo Blockchain Toolkit will simulate a contract deploy so that you can invoke the
`totalSupply` method in a test environment. This environment will not be persisted after the debug session ends. So, if
you want to test a method that changes the contract storage, you will need to deploy the contract to a local neo-express
instance or the testnet.

Debugging the `totalSupply` method will not be very useful, but it's a good way to test if your environment is working
properly. After debugging, you should get a message on the debug console showing the GAS consumed and the return value of the method.

## 6. Contract Initialization

To test some methods that we will implement, having some data on the storage will be important. So we will save some
information on the storage when the contract is deployed.

Neo has some methods that are automatically called by the Virtual Machine, for example, there is the `_deploy` method
that is called whenever a contract is deployed or updated, and is often used in all kinds of smart contracts. This can
be useful to set up some information on the storage.
that is called whenever a contract is deployed or updated, and is often used in all kinds of smart contracts.

### _deploy

Expand All @@ -125,6 +132,7 @@ is to have the owner as the key and the quantity of tokens they own as the value

```python
# update coin.py adding the following code:
from typing import Any
from boa3.builtin.contract import Nep17TransferEvent
from boa3.builtin.interop import runtime, storage
from boa3.builtin.interop.blockchain import Transaction
Expand All @@ -137,7 +145,8 @@ def _deploy(data: Any, update: bool):
container: Transaction = runtime.script_container
storage.put(container.sender, total_supply())

# trigger the Transfer event to notify that the tokens were minted, check out the `NEP-17 Event` section below for more details
# trigger the Transfer event to notify that the tokens were minted, it's a NEP-17 requirement
# check out more about NEP-17 events here: https://github.com/neo-project/proposals/blob/master/nep-17.mediawiki#events
Nep17TransferEvent(None, container.sender, total_supply())
```

Expand All @@ -164,11 +173,31 @@ When writting methods that will be used by other contracts or users, you need to
The `safe` parameter indicates that when calling the method it won't change the contract storage and can be safely
called by other contracts or users.

If you want to run one of the new methods that will be added, you need to recompile the smart contract using
Neo3-boa again and change the operation in the `.vscode/launch.json` file to the name of the method you want to run.

Strings returned by the contract are shown as a hex string by default, that's why if you try to run the test by just
changing the operation to `symbol`, the return is `434f494e` instead of `COIN`. But you can add the
[`"return-types"`](https://github.com/neo-project/neo-debugger/blob/master/docs/debug-config-reference.md#return-types)
configuration to cast it into a legible string.

```json
...
"invocation": {
"operation": "symbol",
"args": []
},
"return-types": [
"string",
],
...
```

### decimals

Returns the number of decimals used by the token.
This is used to provide decimal precision when displaying token balances because Neo doesn't support floating types as
they are often unreliable. In this example, we will return **2**.
they are often unreliable. In this example, we will return **2**, but in a real situation you'd want a bigger decimal number.

```python
# update coin.py adding the following code:
Expand All @@ -184,7 +213,7 @@ Returns the total supply of the token. We already implemented this method before
2 decimals, we need to multiply the supply by 10 ** 2.

```python
# update coin.py adding the following code:
# update coin.py by overwriting the total_supply method with the following code:

@public(name='totalSupply', safe=True)
def total_supply() -> int:
Expand Down Expand Up @@ -217,6 +246,21 @@ def balance_of(account: UInt160) -> int:
return type_helper.to_int(amount_in_bytes)
```

To run methods that require parameters, you need to add the parameters to the `args` list in the `.vscode/launch.json`
file. For example, to run the `balanceOf` method, you need to add the address you want to check the balance of.
Since we didn't define [a signer](https://github.com/neo-project/neo-debugger/blob/master/docs/debug-config-reference.md#signers),
the account that will deploy the smart contract is `0x0000000000000000000000000000000000000000` and that is the
only account that will have a balance that is not zero.

```json
...
"invocation": {
"operation": "balanceOf",
"args": [ "0x0000000000000000000000000000000000000000" ]
},
...
```

### transfer

Transfers a number of tokens from the sender to the specified address, passing an optional data parameter.
Expand All @@ -227,7 +271,6 @@ of peculiarities detailed in the comments in the code below.
```python
# update coin.py adding the following code:

from typing import Any
from boa3.builtin.interop import blockchain, contract

@public
Expand Down Expand Up @@ -255,7 +298,8 @@ def transfer(from_address: UInt160, to_address: UInt160, amount: int, data: Any)
storage.put(from_address, type_helper.to_bytes(tokens_sender - amount))
storage.put(to_address, type_helper.to_bytes(tokens_receiver + amount))

# if the method succeeds, it must fire the Transfer event (more details in the next section)
# if the method succeeds, it must fire the Transfer event
# check out more details here: https://github.com/neo-project/proposals/blob/master/nep-17.mediawiki#transfer-1
Nep17TransferEvent(from_address, to_address, amount)
# if the to_address is a smart contract, it must call the onNEP17Payment
if blockchain.get_contract(to_address) is not None:
Expand All @@ -266,34 +310,37 @@ def transfer(from_address: UInt160, to_address: UInt160, amount: int, data: Any)

Since the `transfer` method changes values on the storage, it can not be flagged as `safe`.

## 8. NEP-17 Event

The NEP-17 standard defines a single event called `Transfer` that must be triggered when a transfer occurs.
You can use the `Nep17TransferEvent` from Neo3-boa or create your own event with `CreateNewEvent`.
The `transfer` method is the most complex method of the NEP-17 standard. It's the method you should debug the most.
However, to reach the end of the function and return `True`, you need to pass through the `check_witness` function.
So, you can either add a [signer](https://github.com/neo-project/neo-debugger/blob/master/docs/debug-config-reference.md#signers)
when invoking or add a [runtime property](https://github.com/neo-project/neo-debugger/blob/master/docs/debug-config-reference.md#runtime)
to always return `True` when doing a `check_witness`.

In this example, we use this event twice: when minting all the tokens at the deploy and whenever a transfer operation occurs.
In the example below, we are transfering 5.00 tokens from the `0x00000...` address to the `0x99999...` address.

```python
# update coin.py adding the following code:
from boa3.builtin.compile_time import CreateNewEvent

on_nep17_transfer = CreateNewEvent(
[
('from', Union[UInt160, None]),
('to', Union[UInt160, None]),
('amount', int),
],
'Transfer'
)

# to trigger the event, just call it by passing the parameters
# using the already implemented Event:
Nep17TransferEvent(from_address, to_address, amount)
# using the newly created Event:
on_nep17_transfer(from_address, to_address, amount)
```json
...
"invocation": {
"operation": "transfer",
"args": [
"0x0000000000000000000000000000000000000000",
"0x9999999999999999999999999999999999999999",
500,
null
]
},
"runtime": {
"witnesses": {
"check-result": true
}
}
...
```

## 9. NEP-17 Callbacks
Since the debugger is just simulating an invocation, the changes made to the storage won't persist after the debug
session has ended. So, trying to check the balance of the `0x99999...` address later will not return `500`.

## 8. NEP-17 Callbacks

The NEP-17 standard defines a single callback called `onNEP17Payment` that must be called if the recipient is a contract.
This callback is used to notify the recipient that it has received tokens. It's up to the recipient to implement this
Expand All @@ -308,10 +355,11 @@ def on_nep17_payment(from_address: UInt160, amount: int, data: Any):
abort() # in this example, the smart contract is rejecting all transfers made to it
```

## 10. Manifest Metadata
## 9. Manifest Metadata

Neo3-boa allows you to define the contract metadata using the `metadata` decorator. This information is used to generate
the contract manifest file.
the contract manifest file. You can check the `coin.manifest.json` before and after adding the method to see the changes
made into the file.

In our example, we will define the contract name and the supported standards, but you can add any information you want
to. We are also adding permissions to allow our contract to call the `onNEP17Payment` method. The compiler automatically
Expand All @@ -329,11 +377,16 @@ def manifest_metadata() -> NeoMetadata:
return meta
```

## 11. Other examples
## 10. Other examples

Check out this [simple NEP-17](https://github.com/CityOfZion/neo3-boa/blob/v1.0.0/boa3_test/examples/simple_nep17.py)
example to see a smart contract that is as simple as the one in this example, but is more cohesive and uses some more
features in its implementation.

Also, check out this [more complex NEP-17](https://github.com/CityOfZion/neo3-boa/blob/v1.0.0/boa3_test/examples/nep17.py)
example to examine a smart contract that can also mint and burn tokens.

## 11. What's next

To test your smart contract in a more realist environment, you might want to create a private network with neo-express
and deploy your smart contract into it, or deploy your smart contract into a testnet.
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ sidebar: true

<div align="center" style={{ padding: '0% 25% 0% 25%' }}>
<img src="/tooling/neow3j.png" alt="neow3j" width="75%" style={{ padding: '0% 0% 5% 0%' }}/>
<h1> <a href="https://github.com/neow3j/neow3j">neow3j</a> <sub><small>v3.20.1</small></sub></h1>
<h1> <a href="https://github.com/neow3j/neow3j">neow3j</a> <sub><small>v3.20.2</small></sub></h1>
</div>

Neow3j is a development toolkit that provides easy and reliable tools to build Neo dApps and Smart Contracts using the
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ sidebar: true

<div align="center" style={{ padding: '0% 25% 0% 25%' }}>
<img src="/tooling/neow3j.png" alt="neow3j" width="75%" style={{ padding: '0% 0% 5% 0%' }}/>
<h1> <a href="https://github.com/neow3j/neow3j">neow3j</a> <sub><small>v3.20.1</small></sub></h1>
<h1> <a href="https://github.com/neow3j/neow3j">neow3j</a> <sub><small>v3.20.2</small></sub></h1>
</div>

Neow3j is a development toolkit that provides easy and reliable tools to build Neo dApps and Smart Contracts using the
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ sidebar: true

<div align="center" style={{ padding: '0% 25% 0% 25%' }}>
<img src="/tooling/neow3j.png" alt="neow3j" width="75%" style={{ padding: '0% 0% 5% 0%' }}/>
<h1> <a href="https://github.com/neow3j/neow3j">neow3j</a> <sub><small>v3.20.1</small></sub></h1>
<h1> <a href="https://github.com/neow3j/neow3j">neow3j</a> <sub><small>v3.20.2</small></sub></h1>
</div>

## 1. Introduction
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ sidebar: true

<div align="center" style={{ padding: '0% 25% 0% 25%' }}>
<img src="/tooling/neow3j.png" alt="neow3j" width="75%" style={{ padding: '0% 0% 5% 0%' }}/>
<h1> <a href="https://github.com/neow3j/neow3j">neow3j</a> <sub><small>v3.20.1</small></sub></h1>
<h1> <a href="https://github.com/neow3j/neow3j">neow3j</a> <sub><small>v3.20.2</small></sub></h1>
</div>

## 1. Introduction
Expand Down

0 comments on commit 2d1be1d

Please sign in to comment.