diff --git a/docs/tutorials/chains/tezos_testnet.md b/docs/tutorials/chains/tezos_testnet.md index 930dda238..02ae39f9c 100644 --- a/docs/tutorials/chains/tezos_testnet.md +++ b/docs/tutorials/chains/tezos_testnet.md @@ -30,36 +30,24 @@ However, it is also possible to configure the transaction signing service using > **NOTE**: The default option is not secure and is mainly used for development and demo purposes. Therefore, for the production, use the selected KMS.\ The full list can be found [here](https://github.com/ecadlabs/signatory#backend-kmshsm-support-status). -## Create a `tezosconnect.yml` config file - -In order to connect to the Tezos testnet, you will need to set a few configuration options for the tezosconnect blockchain connector. Create a text file called `tezosconnect.yml` with the following contents: - -```yml -connector: - blockchain: - rpc: https://ghostnet.ecadinfra.com - network: ghostnet - signatory: http://127.0.0.1:6732 # tx signing service address -``` - -For this tutorial, we will assume this file is saved at `~/Desktop/tezosconnect.yml`. If your path is different, you will need to adjust the path in the next command below. - ## Creating a new stack To create a local FireFly development stack and connect it to the Tezos Ghostnet testnet, we will use command line flags to customize the following settings: - Create a new Tezos based stack named `tezos` with `1` member - Disable `multiparty` mode. We are going to be using this FireFly node as a Web3 gateway, and we don't need to communicate with a consortium here -- Merge the custom config created above with the generated `tezosconnect.yml` config file +- See the list of Tezos [public RPC nodes](https://tezostaquito.io/docs/rpc_nodes/) and select an HTTPS RPC node. To do this, run the following command: ``` ff init tezos dev 1 \ --multiparty=false \ - --connector-config ~/Desktop/tezosonnect.yml + --remote-node-url ``` +> **NOTE**: The public RPC nodes may have limitations or may not support all FF required RPC endpoints. Therefore it's not recommended to use ones for production and you may need to run own node or use third-party vendors. + ## Start the stack Now you should be able to start your stack by running: @@ -106,4 +94,8 @@ You should be able to go lookup your account on [TzStats for the Ghostnet testne On the **Transfers** tab from you account page you will see the actual transfer of the XTZ from the faucet. -![TzStats](images/tezos_explorer.png) \ No newline at end of file +![TzStats](images/tezos_explorer.png) + +## Use the public testnet + +Now that you have everything set up, you can follow one of the other FireFly guides such as [Custom Smart Contracts](../custom_contracts/tezos.md). For detailed instructions on deploying a custom smart contract to Tezos, please see the [Tezos docs](https://docs.tezos.com/smart-contracts/deploying) for instructions using various tools. \ No newline at end of file diff --git a/docs/tutorials/custom_contracts/images/simple_storage_swagger.png b/docs/tutorials/custom_contracts/images/simple_storage_swagger.png index e5f7e9c45..1d49237f2 100644 Binary files a/docs/tutorials/custom_contracts/images/simple_storage_swagger.png and b/docs/tutorials/custom_contracts/images/simple_storage_swagger.png differ diff --git a/docs/tutorials/custom_contracts/images/tezos_contract_deployment.png b/docs/tutorials/custom_contracts/images/tezos_contract_deployment.png index d9d952de2..5f17421e4 100644 Binary files a/docs/tutorials/custom_contracts/images/tezos_contract_deployment.png and b/docs/tutorials/custom_contracts/images/tezos_contract_deployment.png differ diff --git a/docs/tutorials/custom_contracts/images/tezos_contract_deployment2.png b/docs/tutorials/custom_contracts/images/tezos_contract_deployment2.png index a75e1725c..8b84d1794 100644 Binary files a/docs/tutorials/custom_contracts/images/tezos_contract_deployment2.png and b/docs/tutorials/custom_contracts/images/tezos_contract_deployment2.png differ diff --git a/docs/tutorials/custom_contracts/tezos.md b/docs/tutorials/custom_contracts/tezos.md index 01754366d..eb5a297c3 100644 --- a/docs/tutorials/custom_contracts/tezos.md +++ b/docs/tutorials/custom_contracts/tezos.md @@ -38,22 +38,34 @@ import smartpy as sp @sp.module def main(): + # Declares a new contract class SimpleStorage(sp.Contract): + # Storage. Persists in between transactions def __init__(self, value): - self.data.storedValue = value + self.data.x = value + # Allows the stored integer to be changed @sp.entrypoint - def replace(self, params): - self.data.storedValue = params.value + def set(self, params): + self.data.x = params.value + + # Returns the currently stored integer + @sp.onchain_view() + def get(self): + return self.data.x @sp.add_test(name="SimpleStorage") def test(): - c1 = main.SimpleStorage(12) + # Initialize the contract + c = main.SimpleStorage(12) + + # Create a test scenario and run some test cases scenario = sp.test_scenario(main) scenario.h1("SimpleStorage") - scenario += c1 - c1.replace(value=15) - scenario.verify(c1.data.storedValue == 15) + scenario += c + c.set(value=15) + scenario.verify(c.data.x == 15) + scenario.verify(scenario.compute(c.get()) == 15) ``` ## Contract deployment @@ -71,7 +83,7 @@ To deploy the contract, we will use [SmartPy IDE](https://smartpy.io/ide). ![ContractDeployment](images/tezos_contract_deployment.png) ![ContractDeployment2](images/tezos_contract_deployment2.png) -Here we can see that our new contract address is `KT1D254HTPKq5GZNVcF73XBinG9BLybHqu8s`. This is the address that we will reference in the rest of this guide. +Here we can see that our new contract address is `KT1ED4gj2xZnp8318yxa5NpvyvW15pqe4yFg`. This is the address that we will reference in the rest of this guide. ## The FireFly Interface Format @@ -342,7 +354,7 @@ We will use the FFI JSON constructed above and `POST` that to the `/contracts/in "description": "", "methods": [ { - "name": "replace", + "name": "set", "pathname": "", "description": "", "params": [ @@ -358,6 +370,13 @@ We will use the FFI JSON constructed above and `POST` that to the `/contracts/in } ], "returns": [] + }, + { + "name": "get", + "pathname": "", + "description": "", + "params": [], + "returns": [] } ], "events": [] @@ -368,34 +387,44 @@ We will use the FFI JSON constructed above and `POST` that to the `/contracts/in ```json { - "id": "c655704a-f0e2-4aa3-adbb-c7bf3280cdc2", - "namespace": "default", - "name": "simplestorage", - "description": "", - "version": "v1.0.0", - "methods": [ - { - "id": "6f707105-d8b5-4808-a864-51475086608d", - "interface": "c655704a-f0e2-4aa3-adbb-c7bf3280cdc2", - "name": "replace", - "namespace": "default", - "pathname": "replace", - "description": "", - "params": [ + "id": "f9e34787-e634-46cd-af47-b52c537404ff", + "namespace": "default", + "name": "simplestorage", + "description": "", + "version": "v1.0.0", + "methods": [ + { + "id": "78f13a7f-7b85-47c3-bf51-346a9858c027", + "interface": "f9e34787-e634-46cd-af47-b52c537404ff", + "name": "set", + "namespace": "default", + "pathname": "set", + "description": "", + "params": [ + { + "name": "newValue", + "schema": { + "type": "integer", + "details": { + "type": "integer", + "internalType": "integer" + } + } + } + ], + "returns": [] + }, { - "name": "newValue", - "schema": { - "type": "integer", - "details": { - "type": "integer", - "internalType": "integer" - } - } + "id": "ee864e25-c3f7-42d3-aefd-a82f753e9002", + "interface": "f9e34787-e634-46cd-af47-b52c537404ff", + "name": "get", + "namespace": "tezos", + "pathname": "get", + "description": "", + "params": [], + "returns": [] } - ], - "returns": [] - } - ] + ] } ``` @@ -424,10 +453,10 @@ We need to copy the `id` field we got in the response from the previous step to { "name": "simple-storage", "interface": { - "id": "c655704a-f0e2-4aa3-adbb-c7bf3280cdc2" + "id": "f9e34787-e634-46cd-af47-b52c537404ff" }, "location": { - "address": "KT1D254HTPKq5GZNVcF73XBinG9BLybHqu8s" + "address": "KT1ED4gj2xZnp8318yxa5NpvyvW15pqe4yFg" } } ``` @@ -439,10 +468,10 @@ We need to copy the `id` field we got in the response from the previous step to "id": "af09de97-741d-4f61-8d30-4db5e7460f76", "namespace": "default", "interface": { - "id": "c655704a-f0e2-4aa3-adbb-c7bf3280cdc2" + "id": "f9e34787-e634-46cd-af47-b52c537404ff" }, "location": { - "address": "KT1D254HTPKq5GZNVcF73XBinG9BLybHqu8s" + "address": "KT1ED4gj2xZnp8318yxa5NpvyvW15pqe4yFg" }, "name": "simple-storage", "urls": { @@ -460,167 +489,51 @@ You'll notice in the response body that there are a couple of URLs near the bott ## Invoke the smart contract -Now that we've got everything set up, it's time to use our smart contract! We're going to make a `POST` request to the `invoke/replace` endpoint to set the integer value on-chain. Let's set it to the value of `3` right now. +Now that we've got everything set up, it's time to use our smart contract! We're going to make a `POST` request to the `invoke/set` endpoint to set the integer value on-chain. Let's set it to the value of `3` right now. ### Request -`POST` `http://localhost:5000/api/v1/namespaces/default/apis/simple-storage/invoke/replace` +`POST` `http://localhost:5000/api/v1/namespaces/default/apis/simple-storage/invoke/set` ```json { "input": { "newValue": 3 - }, - "key": "tz1cuFw1E2Mn2bVS8q8d7QoCb6FXC18JivSp" + } } ``` -> **NOTE**: The `key` field (optional) is the tezos account's address, which is used to sign blockchain transactions.\ -See more at [transaction signing service set up](../chains/tezos_testnet.md#signatory). - ### Response ```json { - "id": "cb38a538-7093-4150-8a80-6097a666df82", - "namespace": "default", - "tx": "5860befb-9f76-4aa0-a67c-55718b2c46d6", + "id": "87c7ee1b-33d1-46e2-b3f5-8566c14367cf", "type": "blockchain_invoke", "status": "Pending", - "plugin": "tezos", - "input": { - "input": { - "newValue": 3 - }, - "interface": "c655704a-f0e2-4aa3-adbb-c7bf3280cdc2", - "key": "tz1cuFw1E2Mn2bVS8q8d7QoCb6FXC18JivSp", - "location": { - "address": "KT1D254HTPKq5GZNVcF73XBinG9BLybHqu8s" - }, - "method": { - "description": "", - "id": "6f707105-d8b5-4808-a864-51475086608d", - "interface": "c655704a-f0e2-4aa3-adbb-c7bf3280cdc2", - "name": "replace", - "namespace": "default", - "params": [ - { - "name": "newValue", - "schema": { - "details": { - "internalType": "integer", - "type": "integer" - }, - "type": "integer" - } - } - ], - "pathname": "replace", - "returns": [] - }, - "methodPath": "replace", - "options": null, - "type": "invoke" - }, - "created": "2023-09-27T09:12:24.033724927Z", - "updated": "2023-09-27T09:12:24.033724927Z" + "..." } ``` -You'll notice that we got an ID back with status `Pending`, and that's expected due to the asynchronous programming model of working with custom onchain logic in FireFly. After a while, let's see the result of our operation. +You'll notice that we got an ID back with status `Pending`, and that's expected due to the asynchronous programming model of working with smart contracts in FireFly. To see what the value is now, we can query the smart contract. -## Get the operation result +## Query the current value -To see the result of the operation, call `/operations` endpoint with the operation ID from the previous step. +To make a read-only request to the blockchain to check the current value of the stored integer, we can make a `POST` to the `query/get` endpoint. ### Request -`GET` `http://localhost:5000/api/v1/operations/cb38a538-7093-4150-8a80-6097a666df82?fetchstatus=true` +`POST` `http://localhost:5000/api/v1/namespaces/default/apis/simple-storage/query/get` + +```json +{} +``` ### Response ```json { - "id": "cb38a538-7093-4150-8a80-6097a666df82", - "namespace": "default", - "tx": "5860befb-9f76-4aa0-a67c-55718b2c46d6", - "type": "blockchain_invoke", - "status": "Succeeded", - "plugin": "tezos", - "input": { - "input": { - "newValue": 3 - }, - "interface": "c655704a-f0e2-4aa3-adbb-c7bf3280cdc2", - "key": "tz1cuFw1E2Mn2bVS8q8d7QoCb6FXC18JivSp", - "location": { - "address": "KT1D254HTPKq5GZNVcF73XBinG9BLybHqu8s" - }, - "method": { - "description": "", - "id": "6f707105-d8b5-4808-a864-51475086608d", - "interface": "c655704a-f0e2-4aa3-adbb-c7bf3280cdc2", - "name": "replace", - "namespace": "default", - "params": [ - { - "name": "newValue", - "schema": { - "details": { - "internalType": "integer", - "type": "integer" - }, - "type": "integer" - } - } - ], - "pathname": "replace", - "returns": [] - }, - "methodPath": "replace", - "options": null, - "type": "invoke" - }, - "output": { - "contractLocation": { - "address": "KT1D254HTPKq5GZNVcF73XBinG9BLybHqu8s" - }, - "headers": { - "requestId": "default:cb38a538-7093-4150-8a80-6097a666df82", - "type": "TransactionSuccess" - }, - "protocolId": "PtNairobiyssHuh87hEhfVBGCVrK3WnS8Z2FT4ymB5tAa4r1nQf", - "transactionHash": "opMjGX58akxboipsxMcTv5yc5M4Y2ZCGktos4E26zgEpgtHop7g" - }, - "detail": { - "receipt": { - "blockHash": "BLy9BdEjBvHvhYkt8tR4wTQzHagCUmweh8K8uM6X5gXzPLbCmzP", - "blockNumber": "4012016", - "contractLocation": { - "address": "KT1D254HTPKq5GZNVcF73XBinG9BLybHqu8s" - }, - "extraInfo": [ - { - "consumedGas": "1279", - "contractAddress": "KT1D254HTPKq5GZNVcF73XBinG9BLybHqu8s", - "counter": "18602183", - "errorMessage": null, - "fee": "404", - "from": "tz1cuFw1E2Mn2bVS8q8d7QoCb6FXC18JivSp", - "gasLimit": "1380", - "paidStorageSizeDiff": "0", - "status": "applied", - "storage": "3", - "to": "KT1D254HTPKq5GZNVcF73XBinG9BLybHqu8s" - } - ], - "protocolId": "PtNairobiyssHuh87hEhfVBGCVrK3WnS8Z2FT4ymB5tAa4r1nQf", - "success": true, - "transactionIndex": "0" - }, - "status": "Succeeded" - } + "3" } ``` -Here we can see `detail.receipt.extraInfo.storage` section, which displays the latest state of the contract storage state after invoking the operation and that the value of the `storage` variable was changed to `3`. +> **NOTE:** Some contracts may have queries that require input parameters. That's why the query endpoint is a `POST`, rather than a `GET` so that parameters can be passed as JSON in the request body. This particular function does not have any parameters, so we just pass an empty JSON object. \ No newline at end of file