diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md index 2f5bb384..5403e3c1 100644 --- a/CONTRIBUTORS.md +++ b/CONTRIBUTORS.md @@ -2,6 +2,9 @@ Special thanks for all the people who had helped this project so far: -- +- +- + +More details [here](https://github.com/massalabs/station-massa-wallet/graphs/contributors). For more information, please refer to our [CONTRIBUTING](CONTRIBUTING.md) guide. diff --git a/README.md b/README.md index a434438b..b523e2cb 100644 --- a/README.md +++ b/README.md @@ -4,6 +4,13 @@ This is the MassaStation plugin that implements the Massa wallet features. +## Add a token in the wallet + +As a developer, you can add a token in the wallet by following these steps: + +- Open a pull request in the ui-kit to add the icon [here](https://github.com/massalabs/ui-kit/tree/main/src/components/Icons/Svg/FT) and add a line [here](https://github.com/massalabs/ui-kit/blob/main/src/components/Icons/Svg/FT/tokenIcons.tsx#L100) +- Open a pull request in this repository to add the token [here](https://github.com/massalabs/station-massa-wallet/blob/4aa5d5b7885d5d5227724f5114de99c409701a6e/pkg/assets/default_assets.go#L121) and update the ui-kit with `npm update @massalabs/react-ui-kit` + ## Developer guide This section helps developer getting started. @@ -73,6 +80,4 @@ MassaStation can detect the plugin and launch it. ### Postman collection -You will find a postman collection in the `/api` directory. - -Before testing this API, you must initialize the `baseURL` variable to <127.0.0.1:8080>. +You can import the swagger file `api/walletApi-V0.yml` into Postman to test the API. diff --git a/api/WalletPluginPostmanCollection.json b/api/WalletPluginPostmanCollection.json deleted file mode 100644 index 687b9794..00000000 --- a/api/WalletPluginPostmanCollection.json +++ /dev/null @@ -1,2704 +0,0 @@ -{ - "info": { - "_postman_id": "62478e0f-3dd1-42fd-89ab-98ae7979e35b", - "name": "Wallet plugin", - "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json", - "_exporter_id": "7885963" - }, - "item": [ - { - "name": "api Account Create", - "request": { - "method": "POST", - "header": [ - { - "key": "Content-Type", - "value": "application/json" - }, - { - "key": "Accept", - "value": "application/json" - } - ], - "url": { - "raw": "http://{{baseURL}}/api/accounts/{{nickname}}", - "protocol": "http", - "host": [ - "{{baseURL}}" - ], - "path": [ - "api", - "accounts", - "{{nickname}}" - ] - } - }, - "response": [ - { - "name": "api Account Create", - "originalRequest": { - "method": "POST", - "header": [ - { - "key": "Content-Type", - "value": "application/json" - }, - { - "key": "Accept", - "value": "application/json" - } - ], - "body": { - "mode": "raw", - "raw": "{\n \"nickname\": \"{{nickname}}\"\n}", - "options": { - "raw": { - "language": "json" - } - } - }, - "url": { - "raw": "http://{{baseURL}}/api/accounts", - "protocol": "http", - "host": [ - "{{baseURL}}" - ], - "path": [ - "api", - "accounts" - ] - } - }, - "status": "OK", - "code": 200, - "_postman_previewlanguage": "json", - "header": [ - { - "key": "Content-Type", - "value": "application/json" - }, - { - "key": "Vary", - "value": "Origin" - }, - { - "key": "Date", - "value": "Fri, 28 Apr 2023 14:08:01 GMT" - }, - { - "key": "Content-Length", - "value": "204" - }, - { - "key": "Connection", - "value": "close" - } - ], - "cookie": [], - "body": "{\n \"address\": \"AU...\",\n \"keyPair\": {\n \"nonce\": \"\",\n \"privateKey\": \"\",\n \"publicKey\": \"P...\",\n \"salt\": \"\"\n },\n \"nickname\": \"created\"\n}" - }, - { - "name": "Bad request.", - "originalRequest": { - "method": "POST", - "header": [], - "body": { - "mode": "raw", - "raw": "{\n \"nickname\": \"tempor in laboris\",\n \"password\": \"non ea Ut\"\n}", - "options": { - "raw": { - "language": "json" - } - } - }, - "url": { - "raw": "{{baseUrl}}/api/accounts", - "host": [ - "{{baseUrl}}" - ], - "path": [ - "api", - "accounts" - ] - } - }, - "status": "Bad Request", - "code": 400, - "_postman_previewlanguage": "json", - "header": [ - { - "key": "Content-Type", - "value": "application/json" - } - ], - "cookie": [], - "body": "{\n \"code\": \"tempor eiusmod quis\",\n \"message\": \"nulla proident culpa E\"\n}" - }, - { - "name": "Unprocessable Entity - syntax is correct, but the server was unable to process the contained instructions.", - "originalRequest": { - "method": "POST", - "header": [], - "body": { - "mode": "raw", - "raw": "{\n \"nickname\": \"tempor in laboris\",\n \"password\": \"non ea Ut\"\n}", - "options": { - "raw": { - "language": "json" - } - } - }, - "url": { - "raw": "{{baseUrl}}/api/accounts", - "host": [ - "{{baseUrl}}" - ], - "path": [ - "api", - "accounts" - ] - } - }, - "status": "Unprocessable Entity (WebDAV) (RFC 4918)", - "code": 422, - "_postman_previewlanguage": "json", - "header": [ - { - "key": "Content-Type", - "value": "application/json" - } - ], - "cookie": [], - "body": "{\n \"code\": \"tempor eiusmod quis\",\n \"message\": \"nulla proident culpa E\"\n}" - }, - { - "name": "Internal Server Error - The server has encountered a situation it does not know how to handle.", - "originalRequest": { - "method": "POST", - "header": [], - "body": { - "mode": "raw", - "raw": "{\n \"nickname\": \"tempor in laboris\",\n \"password\": \"non ea Ut\"\n}", - "options": { - "raw": { - "language": "json" - } - } - }, - "url": { - "raw": "{{baseUrl}}/api/accounts", - "host": [ - "{{baseUrl}}" - ], - "path": [ - "api", - "accounts" - ] - } - }, - "status": "Internal Server Error", - "code": 500, - "_postman_previewlanguage": "json", - "header": [ - { - "key": "Content-Type", - "value": "application/json" - } - ], - "cookie": [], - "body": "{\n \"code\": \"tempor eiusmod quis\",\n \"message\": \"nulla proident culpa E\"\n}" - } - ] - }, - { - "name": "api Account List", - "request": { - "method": "GET", - "header": [ - { - "key": "Accept", - "value": "application/json" - } - ], - "url": { - "raw": "http://{{baseURL}}/api/accounts", - "protocol": "http", - "host": [ - "{{baseURL}}" - ], - "path": [ - "api", - "accounts" - ] - } - }, - "response": [ - { - "name": "api Account List", - "originalRequest": { - "method": "GET", - "header": [ - { - "key": "Accept", - "value": "application/json" - } - ], - "url": { - "raw": "http://{{baseURL}}/api/accounts", - "protocol": "http", - "host": [ - "{{baseURL}}" - ], - "path": [ - "api", - "accounts" - ] - } - }, - "status": "OK", - "code": 200, - "_postman_previewlanguage": "json", - "header": [ - { - "key": "Content-Type", - "value": "application/json" - }, - { - "key": "Vary", - "value": "Origin" - }, - { - "key": "Date", - "value": "Fri, 28 Apr 2023 14:08:47 GMT" - }, - { - "key": "Content-Length", - "value": "155" - }, - { - "key": "Connection", - "value": "close" - } - ], - "cookie": [], - "body": "[\n {\n \"address\": \"AU...\",\n \"keyPair\": {\n \"nonce\": \"\",\n \"privateKey\": \"\",\n \"publicKey\": \"\",\n \"salt\": \"\"\n },\n \"nickname\": \"created\"\n }\n]" - }, - { - "name": "Bad request.", - "originalRequest": { - "method": "GET", - "header": [], - "url": { - "raw": "{{baseUrl}}/api/accounts", - "host": [ - "{{baseUrl}}" - ], - "path": [ - "api", - "accounts" - ] - } - }, - "status": "Bad Request", - "code": 400, - "_postman_previewlanguage": "json", - "header": [ - { - "key": "Content-Type", - "value": "application/json" - } - ], - "cookie": [], - "body": "{\n \"code\": \"dolore eiusmod in cillum velit\",\n \"message\": \"do anim volupt\"\n}" - }, - { - "name": "Internal Server Error - The server has encountered a situation it does not know how to handle.", - "originalRequest": { - "method": "GET", - "header": [], - "url": { - "raw": "{{baseUrl}}/api/accounts", - "host": [ - "{{baseUrl}}" - ], - "path": [ - "api", - "accounts" - ] - } - }, - "status": "Internal Server Error", - "code": 500, - "_postman_previewlanguage": "json", - "header": [ - { - "key": "Content-Type", - "value": "application/json" - } - ], - "cookie": [], - "body": "{\n \"code\": \"dolore eiusmod in cillum velit\",\n \"message\": \"do anim volupt\"\n}" - } - ] - }, - { - "name": "api Account import", - "request": { - "method": "PUT", - "header": [ - { - "key": "Accept", - "value": "application/json" - } - ], - "url": { - "raw": "http://{{baseURL}}/api/accounts", - "protocol": "http", - "host": [ - "{{baseURL}}" - ], - "path": [ - "api", - "accounts" - ] - } - }, - "response": [ - { - "name": "api Account import", - "originalRequest": { - "method": "PUT", - "header": [ - { - "key": "Accept", - "value": "application/json" - } - ], - "url": { - "raw": "http://{{baseURL}}/api/accounts", - "protocol": "http", - "host": [ - "{{baseURL}}" - ], - "path": [ - "api", - "accounts" - ] - } - }, - "status": "OK", - "code": 200, - "_postman_previewlanguage": "json", - "header": [ - { - "key": "Content-Type", - "value": "application/json" - }, - { - "key": "Vary", - "value": "Origin" - }, - { - "key": "Date", - "value": "Wed, 10 May 2023 08:18:36 GMT" - }, - { - "key": "Content-Length", - "value": "211" - }, - { - "key": "Connection", - "value": "close" - } - ], - "cookie": [], - "body": "{\n \"address\": \"AU12irbDfYNwyZRbnpBrfCBPCxrktp8f8riK2sQddWbzQ3g43G7bb\",\n \"balance\": \"249997889273803581\",\n \"candidateBalance\": \"249997891762038957\",\n \"keyPair\": {\n \"nonce\": \"\",\n \"privateKey\": \"\",\n \"publicKey\": \"P1kKfgrCveVnosUkxTzaBw5cf9f2cbTvK3R5Ssb2Pf76au8xwmH\",\n \"salt\": \"\"\n },\n \"nickname\": \"buildnet\"\n}" - }, - { - "name": "Bad request.", - "originalRequest": { - "method": "GET", - "header": [], - "url": { - "raw": "{{baseUrl}}/api/accounts", - "host": [ - "{{baseUrl}}" - ], - "path": [ - "api", - "accounts" - ] - } - }, - "status": "Bad Request", - "code": 400, - "_postman_previewlanguage": "json", - "header": [ - { - "key": "Content-Type", - "value": "application/json" - } - ], - "cookie": [], - "body": "{\n \"code\": \"dolore eiusmod in cillum velit\",\n \"message\": \"do anim volupt\"\n}" - }, - { - "name": "Internal Server Error - The server has encountered a situation it does not know how to handle.", - "originalRequest": { - "method": "GET", - "header": [], - "url": { - "raw": "{{baseUrl}}/api/accounts", - "host": [ - "{{baseUrl}}" - ], - "path": [ - "api", - "accounts" - ] - } - }, - "status": "Internal Server Error", - "code": 500, - "_postman_previewlanguage": "json", - "header": [ - { - "key": "Content-Type", - "value": "application/json" - } - ], - "cookie": [], - "body": "{\n \"code\": \"dolore eiusmod in cillum velit\",\n \"message\": \"do anim volupt\"\n}" - } - ] - }, - { - "name": "api Account Get", - "request": { - "method": "GET", - "header": [], - "url": { - "raw": "{{baseURL}}/api/accounts/{{nickname}}", - "host": [ - "{{baseURL}}" - ], - "path": [ - "api", - "accounts", - "{{nickname}}" - ] - } - }, - "response": [ - { - "name": "api Account Get", - "originalRequest": { - "method": "GET", - "header": [], - "url": { - "raw": "{{baseURL}}/api/accounts/{{nickname}}", - "host": [ - "{{baseURL}}" - ], - "path": [ - "api", - "accounts", - "{{nickname}}" - ] - } - }, - "status": "OK", - "code": 200, - "_postman_previewlanguage": "json", - "header": [ - { - "key": "Content-Type", - "value": "application/json" - }, - { - "key": "Vary", - "value": "Origin" - }, - { - "key": "Date", - "value": "Fri, 28 Apr 2023 14:09:08 GMT" - }, - { - "key": "Content-Length", - "value": "153" - }, - { - "key": "Connection", - "value": "close" - } - ], - "cookie": [], - "body": "{\n \"address\": \"AU...\",\n \"keyPair\": {\n \"nonce\": \"\",\n \"privateKey\": \"\",\n \"publicKey\": \"\",\n \"salt\": \"\"\n },\n \"nickname\": \"created\"\n}" - }, - { - "name": "Bad request.", - "originalRequest": { - "method": "GET", - "header": [], - "url": { - "raw": "{{baseUrl}}/api/accounts/:nickname", - "host": [ - "{{baseUrl}}" - ], - "path": [ - "api", - "accounts", - ":nickname" - ], - "variable": [ - { - "key": "nickname", - "value": "mollit ma", - "description": "(Required) Wallet's short name." - } - ] - } - }, - "status": "Bad Request", - "code": 400, - "_postman_previewlanguage": "json", - "header": [ - { - "key": "Content-Type", - "value": "application/json" - } - ], - "cookie": [], - "body": "{\n \"code\": \"dolore eiusmod in cillum velit\",\n \"message\": \"do anim volupt\"\n}" - }, - { - "name": "api Account Get Not Found", - "originalRequest": { - "method": "GET", - "header": [], - "url": { - "raw": "{{baseURL}}/api/accounts/{{nickname}}", - "host": [ - "{{baseURL}}" - ], - "path": [ - "api", - "accounts", - "{{nickname}}" - ] - } - }, - "status": "Not Found", - "code": 404, - "_postman_previewlanguage": "json", - "header": [ - { - "key": "Content-Type", - "value": "application/json" - }, - { - "key": "Vary", - "value": "Origin" - }, - { - "key": "Date", - "value": "Tue, 02 May 2023 13:43:53 GMT" - }, - { - "key": "Content-Length", - "value": "64" - }, - { - "key": "Connection", - "value": "close" - } - ], - "cookie": [], - "body": "{\n \"code\": \"Wallet-0009\",\n \"message\": \"account '{{nicknam'not found\"\n}" - }, - { - "name": "Internal Server Error - The server has encountered a situation it does not know how to handle.", - "originalRequest": { - "method": "GET", - "header": [], - "url": { - "raw": "{{baseUrl}}/api/accounts/:nickname", - "host": [ - "{{baseUrl}}" - ], - "path": [ - "api", - "accounts", - ":nickname" - ], - "variable": [ - { - "key": "nickname", - "value": "mollit ma", - "description": "(Required) Wallet's short name." - } - ] - } - }, - "status": "Internal Server Error", - "code": 500, - "_postman_previewlanguage": "json", - "header": [ - { - "key": "Content-Type", - "value": "application/json" - } - ], - "cookie": [], - "body": "{\n \"code\": \"dolore eiusmod in cillum velit\",\n \"message\": \"do anim volupt\"\n}" - } - ] - }, - { - "name": "api Account Backup", - "request": { - "method": "POST", - "header": [], - "url": { - "raw": "{{baseURL}}/api/accounts/{{nickname}}/backup", - "host": [ - "{{baseURL}}" - ], - "path": [ - "api", - "accounts", - "{{nickname}}", - "backup" - ] - } - }, - "response": [ - { - "name": "api Account Get", - "originalRequest": { - "method": "GET", - "header": [], - "url": { - "raw": "{{baseURL}}/api/accounts/{{nickname}}", - "host": [ - "{{baseURL}}" - ], - "path": [ - "api", - "accounts", - "{{nickname}}" - ] - } - }, - "status": "OK", - "code": 200, - "_postman_previewlanguage": "json", - "header": [ - { - "key": "Content-Type", - "value": "application/json" - }, - { - "key": "Vary", - "value": "Origin" - }, - { - "key": "Date", - "value": "Fri, 28 Apr 2023 14:09:08 GMT" - }, - { - "key": "Content-Length", - "value": "153" - }, - { - "key": "Connection", - "value": "close" - } - ], - "cookie": [], - "body": "{\n \"address\": \"AU...\",\n \"keyPair\": {\n \"nonce\": \"\",\n \"privateKey\": \"\",\n \"publicKey\": \"\",\n \"salt\": \"\"\n },\n \"nickname\": \"created\"\n}" - }, - { - "name": "Bad request.", - "originalRequest": { - "method": "GET", - "header": [], - "url": { - "raw": "{{baseUrl}}/api/accounts/:nickname", - "host": [ - "{{baseUrl}}" - ], - "path": [ - "api", - "accounts", - ":nickname" - ], - "variable": [ - { - "key": "nickname", - "value": "mollit ma", - "description": "(Required) Wallet's short name." - } - ] - } - }, - "status": "Bad Request", - "code": 400, - "_postman_previewlanguage": "json", - "header": [ - { - "key": "Content-Type", - "value": "application/json" - } - ], - "cookie": [], - "body": "{\n \"code\": \"dolore eiusmod in cillum velit\",\n \"message\": \"do anim volupt\"\n}" - }, - { - "name": "api Account Get Not Found", - "originalRequest": { - "method": "GET", - "header": [], - "url": { - "raw": "{{baseURL}}/api/accounts/{{nickname}}", - "host": [ - "{{baseURL}}" - ], - "path": [ - "api", - "accounts", - "{{nickname}}" - ] - } - }, - "status": "Not Found", - "code": 404, - "_postman_previewlanguage": "json", - "header": [ - { - "key": "Content-Type", - "value": "application/json" - }, - { - "key": "Vary", - "value": "Origin" - }, - { - "key": "Date", - "value": "Tue, 02 May 2023 13:43:53 GMT" - }, - { - "key": "Content-Length", - "value": "64" - }, - { - "key": "Connection", - "value": "close" - } - ], - "cookie": [], - "body": "{\n \"code\": \"Wallet-0009\",\n \"message\": \"account '{{nicknam'not found\"\n}" - }, - { - "name": "Internal Server Error - The server has encountered a situation it does not know how to handle.", - "originalRequest": { - "method": "GET", - "header": [], - "url": { - "raw": "{{baseUrl}}/api/accounts/:nickname", - "host": [ - "{{baseUrl}}" - ], - "path": [ - "api", - "accounts", - ":nickname" - ], - "variable": [ - { - "key": "nickname", - "value": "mollit ma", - "description": "(Required) Wallet's short name." - } - ] - } - }, - "status": "Internal Server Error", - "code": 500, - "_postman_previewlanguage": "json", - "header": [ - { - "key": "Content-Type", - "value": "application/json" - } - ], - "cookie": [], - "body": "{\n \"code\": \"dolore eiusmod in cillum velit\",\n \"message\": \"do anim volupt\"\n}" - } - ] - }, - { - "name": "api Account Get decrytped", - "request": { - "method": "GET", - "header": [], - "url": { - "raw": "{{baseURL}}/api/accounts/{{nickname}}?ciphered=false", - "host": [ - "{{baseURL}}" - ], - "path": [ - "api", - "accounts", - "{{nickname}}" - ], - "query": [ - { - "key": "ciphered", - "value": "false" - } - ] - } - }, - "response": [ - { - "name": "api Account Get decrytped", - "originalRequest": { - "method": "GET", - "header": [], - "url": { - "raw": "{{baseURL}}/api/accounts/{{nickname}}?ciphered=false", - "host": [ - "{{baseURL}}" - ], - "path": [ - "api", - "accounts", - "{{nickname}}" - ], - "query": [ - { - "key": "ciphered", - "value": "false" - } - ] - } - }, - "status": "OK", - "code": 200, - "_postman_previewlanguage": "json", - "header": [ - { - "key": "Content-Type", - "value": "application/json" - }, - { - "key": "Vary", - "value": "Origin" - }, - { - "key": "Date", - "value": "Fri, 28 Apr 2023 14:10:10 GMT" - }, - { - "key": "Content-Length", - "value": "307" - }, - { - "key": "Connection", - "value": "close" - } - ], - "cookie": [], - "body": "{\n \"address\": \"AU...\",\n \"keyPair\": {\n \"nonce\": \"...\",\n \"privateKey\": \"S...\",\n \"publicKey\": \"P...\",\n \"salt\": \"...\"\n },\n \"nickname\": \"created\"\n}" - }, - { - "name": "Bad request.", - "originalRequest": { - "method": "GET", - "header": [], - "url": { - "raw": "{{baseUrl}}/api/accounts/:nickname", - "host": [ - "{{baseUrl}}" - ], - "path": [ - "api", - "accounts", - ":nickname" - ], - "variable": [ - { - "key": "nickname", - "value": "mollit ma", - "description": "(Required) Wallet's short name." - } - ] - } - }, - "status": "Not Found", - "code": 404, - "_postman_previewlanguage": "json", - "header": [ - { - "key": "Content-Type", - "value": "application/json" - } - ], - "cookie": [], - "body": "{\n \"code\": \"dolore eiusmod in cillum velit\",\n \"message\": \"do anim volupt\"\n}" - }, - { - "name": "api Account Get Unauthorized", - "originalRequest": { - "method": "GET", - "header": [], - "url": { - "raw": "{{baseURL}}/api/accounts/{{nickname}}?ciphered=false", - "host": [ - "{{baseURL}}" - ], - "path": [ - "api", - "accounts", - "{{nickname}}" - ], - "query": [ - { - "key": "ciphered", - "value": "false" - } - ] - } - }, - "status": "Unauthorized", - "code": 401, - "_postman_previewlanguage": "json", - "header": [ - { - "key": "Content-Type", - "value": "application/json" - }, - { - "key": "Vary", - "value": "Origin" - }, - { - "key": "Date", - "value": "Tue, 02 May 2023 13:44:18 GMT" - }, - { - "key": "Content-Length", - "value": "62" - }, - { - "key": "Connection", - "value": "close" - } - ], - "cookie": [], - "body": "{\n \"code\": \"Wallet-0009\",\n \"message\": \"Unable to unprotect wallet\"\n}" - }, - { - "name": "Unprocessable Entity - syntax is correct, but the server was unable to process the contained instructions.", - "originalRequest": { - "method": "GET", - "header": [], - "url": { - "raw": "{{baseUrl}}/api/accounts/:nickname", - "host": [ - "{{baseUrl}}" - ], - "path": [ - "api", - "accounts", - ":nickname" - ], - "variable": [ - { - "key": "nickname", - "value": "mollit ma", - "description": "(Required) Wallet's short name." - } - ] - } - }, - "status": "Unprocessable Entity (WebDAV) (RFC 4918)", - "code": 422, - "_postman_previewlanguage": "json", - "header": [ - { - "key": "Content-Type", - "value": "application/json" - } - ], - "cookie": [], - "body": "{\n \"code\": \"dolore eiusmod in cillum velit\",\n \"message\": \"do anim volupt\"\n}" - }, - { - "name": "Internal Server Error - The server has encountered a situation it does not know how to handle.", - "originalRequest": { - "method": "GET", - "header": [], - "url": { - "raw": "{{baseUrl}}/api/accounts/:nickname", - "host": [ - "{{baseUrl}}" - ], - "path": [ - "api", - "accounts", - ":nickname" - ], - "variable": [ - { - "key": "nickname", - "value": "mollit ma", - "description": "(Required) Wallet's short name." - } - ] - } - }, - "status": "Internal Server Error", - "code": 500, - "_postman_previewlanguage": "json", - "header": [ - { - "key": "Content-Type", - "value": "application/json" - } - ], - "cookie": [], - "body": "{\n \"code\": \"dolore eiusmod in cillum velit\",\n \"message\": \"do anim volupt\"\n}" - } - ] - }, - { - "name": "api Account Export File", - "request": { - "method": "GET", - "header": [ - { - "key": "Accept", - "value": "application/json" - } - ], - "url": { - "raw": "{{baseURL}}/api/accounts/{{nickname}}/exportFile", - "host": [ - "{{baseURL}}" - ], - "path": [ - "api", - "accounts", - "{{nickname}}", - "exportFile" - ] - } - }, - "response": [ - { - "name": "Download the file", - "originalRequest": { - "method": "GET", - "header": [ - { - "key": "Accept", - "value": "application/json" - } - ], - "url": { - "raw": "{{baseURL}}/api/accounts/export/file/{{nickname}}", - "host": [ - "{{baseURL}}" - ], - "path": [ - "api", - "accounts", - "export", - "file", - "{{nickname}}" - ] - } - }, - "status": "OK", - "code": 200, - "_postman_previewlanguage": "raw", - "header": [ - { - "key": "Content-Disposition", - "value": "attachment; filename=\"wallet_created.yml\"" - }, - { - "key": "Content-Type", - "value": "application/octet-stream" - }, - { - "key": "Vary", - "value": "Origin" - }, - { - "key": "Date", - "value": "Mon, 24 Apr 2023 12:52:52 GMT" - }, - { - "key": "Connection", - "value": "close" - }, - { - "key": "Transfer-Encoding", - "value": "chunked" - } - ], - "cookie": [], - "body": "Version: 0\nNickname: created\nAddress: AU...\nSalt: [248, ...]\nNonce: [19, ...]\nCipheredData: [166, ...]\nPublicKey: [25, ...]\n" - }, - { - "name": "Bad request.", - "originalRequest": { - "method": "GET", - "header": [], - "url": { - "raw": "{{baseUrl}}/api/accounts/:nickname", - "host": [ - "{{baseUrl}}" - ], - "path": [ - "api", - "accounts", - ":nickname" - ], - "variable": [ - { - "key": "nickname", - "value": "mollit ma", - "description": "(Required) Wallet's short name." - } - ] - } - }, - "status": "Bad Request", - "code": 400, - "_postman_previewlanguage": "json", - "header": [ - { - "key": "Content-Type", - "value": "application/json" - } - ], - "cookie": [], - "body": "{\n \"code\": \"dolore eiusmod in cillum velit\",\n \"message\": \"do anim volupt\"\n}" - }, - { - "name": "Unprocessable Entity - syntax is correct, but the server was unable to process the contained instructions.", - "originalRequest": { - "method": "GET", - "header": [], - "url": { - "raw": "{{baseUrl}}/api/accounts/:nickname", - "host": [ - "{{baseUrl}}" - ], - "path": [ - "api", - "accounts", - ":nickname" - ], - "variable": [ - { - "key": "nickname", - "value": "mollit ma", - "description": "(Required) Wallet's short name." - } - ] - } - }, - "status": "Unprocessable Entity (WebDAV) (RFC 4918)", - "code": 422, - "_postman_previewlanguage": "json", - "header": [ - { - "key": "Content-Type", - "value": "application/json" - } - ], - "cookie": [], - "body": "{\n \"code\": \"dolore eiusmod in cillum velit\",\n \"message\": \"do anim volupt\"\n}" - }, - { - "name": "Internal Server Error - The server has encountered a situation it does not know how to handle.", - "originalRequest": { - "method": "GET", - "header": [], - "url": { - "raw": "{{baseUrl}}/api/accounts/:nickname", - "host": [ - "{{baseUrl}}" - ], - "path": [ - "api", - "accounts", - ":nickname" - ], - "variable": [ - { - "key": "nickname", - "value": "mollit ma", - "description": "(Required) Wallet's short name." - } - ] - } - }, - "status": "Internal Server Error", - "code": 500, - "_postman_previewlanguage": "json", - "header": [ - { - "key": "Content-Type", - "value": "application/json" - } - ], - "cookie": [], - "body": "{\n \"code\": \"dolore eiusmod in cillum velit\",\n \"message\": \"do anim volupt\"\n}" - } - ] - }, - { - "name": "api Account Sign", - "request": { - "method": "POST", - "header": [ - { - "key": "Content-Type", - "value": "application/json" - }, - { - "key": "Accept", - "value": "application/json" - } - ], - "body": { - "mode": "raw", - "raw": "{\"operation\":\"MjIzM3QyNHQ=\"}", - "options": { - "raw": { - "language": "json" - } - } - }, - "url": { - "raw": "{{baseURL}}/api/accounts/{{nickname}}/sign", - "host": [ - "{{baseURL}}" - ], - "path": [ - "api", - "accounts", - "{{nickname}}", - "sign" - ] - } - }, - "response": [ - { - "name": "Signature.", - "originalRequest": { - "method": "POST", - "header": [], - "body": { - "mode": "raw", - "raw": "{\n \"operation\": \"labore Lorem nostrud culpa\"\n}", - "options": { - "raw": { - "language": "json" - } - } - }, - "url": { - "raw": "{{baseUrl}}/api/accounts/:nickname/sign", - "host": [ - "{{baseUrl}}" - ], - "path": [ - "api", - "accounts", - ":nickname", - "sign" - ], - "variable": [ - { - "key": "nickname", - "value": "mollit ma", - "description": "(Required) Wallet's short name." - } - ] - } - }, - "status": "OK", - "code": 200, - "_postman_previewlanguage": "json", - "header": [ - { - "key": "Content-Type", - "value": "application/json" - } - ], - "cookie": [], - "body": "{\n \"signature\": \"veniam dolore ullamco commodo\",\n \"publicKey\": \"consectetur exercitation non\"\n}" - }, - { - "name": "Bad request.", - "originalRequest": { - "method": "POST", - "header": [], - "body": { - "mode": "raw", - "raw": "{\n \"operation\": \"labore Lorem nostrud culpa\"\n}", - "options": { - "raw": { - "language": "json" - } - } - }, - "url": { - "raw": "{{baseUrl}}/api/accounts/:nickname/sign", - "host": [ - "{{baseUrl}}" - ], - "path": [ - "api", - "accounts", - ":nickname", - "sign" - ], - "variable": [ - { - "key": "nickname", - "value": "mollit ma", - "description": "(Required) Wallet's short name." - } - ] - } - }, - "status": "Bad Request", - "code": 400, - "_postman_previewlanguage": "json", - "header": [ - { - "key": "Content-Type", - "value": "application/json" - } - ], - "cookie": [], - "body": "{\n \"code\": \"dolore eiusmod in cillum velit\",\n \"message\": \"do anim volupt\"\n}" - }, - { - "name": "api Account Sign Unauthorized", - "originalRequest": { - "method": "POST", - "header": [ - { - "key": "Content-Type", - "value": "application/json" - }, - { - "key": "Accept", - "value": "application/json" - } - ], - "body": { - "mode": "raw", - "raw": "{\"operation\":\"MjIzM3QyNHQ=\"}", - "options": { - "raw": { - "language": "json" - } - } - }, - "url": { - "raw": "{{baseURL}}/api/accounts/{{nickname}}/sign", - "host": [ - "{{baseURL}}" - ], - "path": [ - "api", - "accounts", - "{{nickname}}", - "sign" - ] - } - }, - "status": "Unauthorized", - "code": 401, - "_postman_previewlanguage": "json", - "header": [ - { - "key": "Content-Type", - "value": "application/json" - }, - { - "key": "Vary", - "value": "Origin" - }, - { - "key": "Date", - "value": "Tue, 02 May 2023 13:45:06 GMT" - }, - { - "key": "Content-Length", - "value": "62" - }, - { - "key": "Connection", - "value": "close" - } - ], - "cookie": [], - "body": "{\n \"code\": \"Wallet-0003\",\n \"message\": \"Unable to unprotect wallet\"\n}" - }, - { - "name": "Unprocessable Entity - syntax is correct, but the server was unable to process the contained instructions.", - "originalRequest": { - "method": "POST", - "header": [], - "body": { - "mode": "raw", - "raw": "{\n \"operation\": \"labore Lorem nostrud culpa\"\n}", - "options": { - "raw": { - "language": "json" - } - } - }, - "url": { - "raw": "{{baseUrl}}/api/accounts/:nickname/sign", - "host": [ - "{{baseUrl}}" - ], - "path": [ - "api", - "accounts", - ":nickname", - "sign" - ], - "variable": [ - { - "key": "nickname", - "value": "mollit ma", - "description": "(Required) Wallet's short name." - } - ] - } - }, - "status": "Unprocessable Entity (WebDAV) (RFC 4918)", - "code": 422, - "_postman_previewlanguage": "json", - "header": [ - { - "key": "Content-Type", - "value": "application/json" - } - ], - "cookie": [], - "body": "{\n \"code\": \"dolore eiusmod in cillum velit\",\n \"message\": \"do anim volupt\"\n}" - }, - { - "name": "Internal Server Error - The server has encountered a situation it does not know how to handle.", - "originalRequest": { - "method": "POST", - "header": [], - "body": { - "mode": "raw", - "raw": "{\n \"operation\": \"labore Lorem nostrud culpa\"\n}", - "options": { - "raw": { - "language": "json" - } - } - }, - "url": { - "raw": "{{baseUrl}}/api/accounts/:nickname/sign", - "host": [ - "{{baseUrl}}" - ], - "path": [ - "api", - "accounts", - ":nickname", - "sign" - ], - "variable": [ - { - "key": "nickname", - "value": "mollit ma", - "description": "(Required) Wallet's short name." - } - ] - } - }, - "status": "Internal Server Error", - "code": 500, - "_postman_previewlanguage": "json", - "header": [ - { - "key": "Content-Type", - "value": "application/json" - } - ], - "cookie": [], - "body": "{\n \"code\": \"dolore eiusmod in cillum velit\",\n \"message\": \"do anim volupt\"\n}" - } - ] - }, - { - "name": "api Account Sign New Batch", - "request": { - "method": "POST", - "header": [ - { - "key": "Content-Type", - "value": "application/json" - }, - { - "key": "Accept", - "value": "application/json" - } - ], - "body": { - "mode": "raw", - "raw": "{\"operation\":\"MjIzM3QyNHQ=\", \"batch\": true}", - "options": { - "raw": { - "language": "json" - } - } - }, - "url": { - "raw": "{{baseURL}}/api/accounts/{{nickname}}/sign", - "host": [ - "{{baseURL}}" - ], - "path": [ - "api", - "accounts", - "{{nickname}}", - "sign" - ] - } - }, - "response": [ - { - "name": "Signature and new correlationId", - "originalRequest": { - "method": "POST", - "header": [ - { - "key": "Content-Type", - "value": "application/json" - }, - { - "key": "Accept", - "value": "application/json" - } - ], - "body": { - "mode": "raw", - "raw": "{\"operation\":\"MjIzM3QyNHQ=\", \"batch\": true}", - "options": { - "raw": { - "language": "json" - } - } - }, - "url": { - "raw": "{{baseURL}}/api/accounts/{{nickname}}/sign", - "host": [ - "{{baseURL}}" - ], - "path": [ - "api", - "accounts", - "{{nickname}}", - "sign" - ] - } - }, - "status": "OK", - "code": 200, - "_postman_previewlanguage": "json", - "header": [ - { - "key": "Content-Type", - "value": "application/json" - }, - { - "key": "Vary", - "value": "Origin" - }, - { - "key": "Date", - "value": "Tue, 21 Mar 2023 10:56:02 GMT" - }, - { - "key": "Content-Length", - "value": "278" - }, - { - "key": "Connection", - "value": "close" - } - ], - "cookie": [], - "body": "{\n \"correlationId\": \"WUOeMbUxvOR/7w2x6jnvikrhg8UmFkvQk/LQHgXjvnOtFyFKISQuCI4zcn1cMahPuR8jUklkjMUoGZxi8ERncg==\",\n \"publicKey\": \"P1tU5s96f92RaNS59e4kGw9G7b7RbdKTNjFFeLaWTbWcd49U7wS\",\n \"signature\": \"viLLnIhGrBwr7+CgMr3j9zaotWL0eK1caCXgRIMZ8ogsXiEwUpjftXBQ9NGbbaWr5IXdP1ZbqWQ/i5l3eFZNAw==\"\n}" - }, - { - "name": "Bad request.", - "originalRequest": { - "method": "POST", - "header": [], - "body": { - "mode": "raw", - "raw": "{\n \"operation\": \"labore Lorem nostrud culpa\"\n}", - "options": { - "raw": { - "language": "json" - } - } - }, - "url": { - "raw": "{{baseUrl}}/api/accounts/:nickname/sign", - "host": [ - "{{baseUrl}}" - ], - "path": [ - "api", - "accounts", - ":nickname", - "sign" - ], - "variable": [ - { - "key": "nickname", - "value": "mollit ma", - "description": "(Required) Wallet's short name." - } - ] - } - }, - "status": "Bad Request", - "code": 400, - "_postman_previewlanguage": "json", - "header": [ - { - "key": "Content-Type", - "value": "application/json" - } - ], - "cookie": [], - "body": "{\n \"code\": \"dolore eiusmod in cillum velit\",\n \"message\": \"do anim volupt\"\n}" - }, - { - "name": "api Account Sign New Batch Unauthorized", - "originalRequest": { - "method": "POST", - "header": [ - { - "key": "Content-Type", - "value": "application/json" - }, - { - "key": "Accept", - "value": "application/json" - } - ], - "body": { - "mode": "raw", - "raw": "{\"operation\":\"MjIzM3QyNHQ=\", \"batch\": true}", - "options": { - "raw": { - "language": "json" - } - } - }, - "url": { - "raw": "{{baseURL}}/api/accounts/{{nickname}}/sign", - "host": [ - "{{baseURL}}" - ], - "path": [ - "api", - "accounts", - "{{nickname}}", - "sign" - ] - } - }, - "status": "Unauthorized", - "code": 401, - "_postman_previewlanguage": "json", - "header": [ - { - "key": "Content-Type", - "value": "application/json" - }, - { - "key": "Vary", - "value": "Origin" - }, - { - "key": "Date", - "value": "Tue, 02 May 2023 13:46:14 GMT" - }, - { - "key": "Content-Length", - "value": "62" - }, - { - "key": "Connection", - "value": "close" - } - ], - "cookie": [], - "body": "{\n \"code\": \"Wallet-0003\",\n \"message\": \"Unable to unprotect wallet\"\n}" - }, - { - "name": "Unprocessable Entity - syntax is correct, but the server was unable to process the contained instructions.", - "originalRequest": { - "method": "POST", - "header": [], - "body": { - "mode": "raw", - "raw": "{\n \"operation\": \"labore Lorem nostrud culpa\"\n}", - "options": { - "raw": { - "language": "json" - } - } - }, - "url": { - "raw": "{{baseUrl}}/api/accounts/:nickname/sign", - "host": [ - "{{baseUrl}}" - ], - "path": [ - "api", - "accounts", - ":nickname", - "sign" - ], - "variable": [ - { - "key": "nickname", - "value": "mollit ma", - "description": "(Required) Wallet's short name." - } - ] - } - }, - "status": "Unprocessable Entity (WebDAV) (RFC 4918)", - "code": 422, - "_postman_previewlanguage": "json", - "header": [ - { - "key": "Content-Type", - "value": "application/json" - } - ], - "cookie": [], - "body": "{\n \"code\": \"dolore eiusmod in cillum velit\",\n \"message\": \"do anim volupt\"\n}" - }, - { - "name": "Internal Server Error - The server has encountered a situation it does not know how to handle.", - "originalRequest": { - "method": "POST", - "header": [], - "body": { - "mode": "raw", - "raw": "{\n \"operation\": \"labore Lorem nostrud culpa\"\n}", - "options": { - "raw": { - "language": "json" - } - } - }, - "url": { - "raw": "{{baseUrl}}/api/accounts/:nickname/sign", - "host": [ - "{{baseUrl}}" - ], - "path": [ - "api", - "accounts", - ":nickname", - "sign" - ], - "variable": [ - { - "key": "nickname", - "value": "mollit ma", - "description": "(Required) Wallet's short name." - } - ] - } - }, - "status": "Internal Server Error", - "code": 500, - "_postman_previewlanguage": "json", - "header": [ - { - "key": "Content-Type", - "value": "application/json" - } - ], - "cookie": [], - "body": "{\n \"code\": \"dolore eiusmod in cillum velit\",\n \"message\": \"do anim volupt\"\n}" - } - ] - }, - { - "name": "api Account Sign Batch item", - "request": { - "method": "POST", - "header": [ - { - "key": "Content-Type", - "value": "application/json" - }, - { - "key": "Accept", - "value": "application/json" - } - ], - "body": { - "mode": "raw", - "raw": "{\"operation\":\"MjIzM3QyNHQ=\",\"correlationId\": \"orlpAN6KX+OKThTTEynHB3rkkDg426SRZiTlZ5Dxjr8yTYSbF7DrblbEe7sJQ9Ew2By5duBZSiR2xZ1HezB71w==\"}", - "options": { - "raw": { - "language": "json" - } - } - }, - "url": { - "raw": "{{baseURL}}/api/accounts/{{nickname}}/sign", - "host": [ - "{{baseURL}}" - ], - "path": [ - "api", - "accounts", - "{{nickname}}", - "sign" - ] - } - }, - "response": [ - { - "name": "Signature and correlation id", - "originalRequest": { - "method": "POST", - "header": [ - { - "key": "Content-Type", - "value": "application/json" - }, - { - "key": "Accept", - "value": "application/json" - } - ], - "body": { - "mode": "raw", - "raw": "{\"operation\":\"MjIzM3QyNHQ=\",\"correlationId\": \"u0xfG4EQEQIj3x/qiawTJMcD1irzKj2VONOBKQPXJ5QNGE+3ifZPmIk0gk/Mn9KeRLTIUhkykgfdBrZmHxIytg==\"}", - "options": { - "raw": { - "language": "json" - } - } - }, - "url": { - "raw": "{{baseURL}}/api/accounts/{{nickname}}/sign", - "host": [ - "{{baseURL}}" - ], - "path": [ - "api", - "accounts", - "{{nickname}}", - "sign" - ] - } - }, - "status": "OK", - "code": 200, - "_postman_previewlanguage": "json", - "header": [ - { - "key": "Content-Type", - "value": "application/json" - }, - { - "key": "Vary", - "value": "Origin" - }, - { - "key": "Date", - "value": "Tue, 21 Mar 2023 11:07:27 GMT" - }, - { - "key": "Content-Length", - "value": "278" - }, - { - "key": "Connection", - "value": "close" - } - ], - "cookie": [], - "body": "{\n \"correlationId\": \"u0xfG4EQEQIj3x/qiawTJMcD1irzKj2VONOBKQPXJ5QNGE+3ifZPmIk0gk/Mn9KeRLTIUhkykgfdBrZmHxIytg==\",\n \"publicKey\": \"P1tU5s96f92RaNS59e4kGw9G7b7RbdKTNjFFeLaWTbWcd49U7wS\",\n \"signature\": \"viLLnIhGrBwr7+CgMr3j9zaotWL0eK1caCXgRIMZ8ogsXiEwUpjftXBQ9NGbbaWr5IXdP1ZbqWQ/i5l3eFZNAw==\"\n}" - }, - { - "name": "Bad request.", - "originalRequest": { - "method": "POST", - "header": [], - "body": { - "mode": "raw", - "raw": "{\n \"operation\": \"labore Lorem nostrud culpa\"\n}", - "options": { - "raw": { - "language": "json" - } - } - }, - "url": { - "raw": "{{baseUrl}}/api/accounts/:nickname/sign", - "host": [ - "{{baseUrl}}" - ], - "path": [ - "api", - "accounts", - ":nickname", - "sign" - ], - "variable": [ - { - "key": "nickname", - "value": "mollit ma", - "description": "(Required) Wallet's short name." - } - ] - } - }, - "status": "Bad Request", - "code": 400, - "_postman_previewlanguage": "json", - "header": [ - { - "key": "Content-Type", - "value": "application/json" - } - ], - "cookie": [], - "body": "{\n \"code\": \"dolore eiusmod in cillum velit\",\n \"message\": \"do anim volupt\"\n}" - }, - { - "name": "Unprocessable Entity - syntax is correct, but the server was unable to process the contained instructions.", - "originalRequest": { - "method": "POST", - "header": [], - "body": { - "mode": "raw", - "raw": "{\n \"operation\": \"labore Lorem nostrud culpa\"\n}", - "options": { - "raw": { - "language": "json" - } - } - }, - "url": { - "raw": "{{baseUrl}}/api/accounts/:nickname/sign", - "host": [ - "{{baseUrl}}" - ], - "path": [ - "api", - "accounts", - ":nickname", - "sign" - ], - "variable": [ - { - "key": "nickname", - "value": "mollit ma", - "description": "(Required) Wallet's short name." - } - ] - } - }, - "status": "Unprocessable Entity (WebDAV) (RFC 4918)", - "code": 422, - "_postman_previewlanguage": "json", - "header": [ - { - "key": "Content-Type", - "value": "application/json" - } - ], - "cookie": [], - "body": "{\n \"code\": \"dolore eiusmod in cillum velit\",\n \"message\": \"do anim volupt\"\n}" - }, - { - "name": "Internal Server Error - The server has encountered a situation it does not know how to handle.", - "originalRequest": { - "method": "POST", - "header": [], - "body": { - "mode": "raw", - "raw": "{\n \"operation\": \"labore Lorem nostrud culpa\"\n}", - "options": { - "raw": { - "language": "json" - } - } - }, - "url": { - "raw": "{{baseUrl}}/api/accounts/:nickname/sign", - "host": [ - "{{baseUrl}}" - ], - "path": [ - "api", - "accounts", - ":nickname", - "sign" - ], - "variable": [ - { - "key": "nickname", - "value": "mollit ma", - "description": "(Required) Wallet's short name." - } - ] - } - }, - "status": "Internal Server Error", - "code": 500, - "_postman_previewlanguage": "json", - "header": [ - { - "key": "Content-Type", - "value": "application/json" - } - ], - "cookie": [], - "body": "{\n \"code\": \"dolore eiusmod in cillum velit\",\n \"message\": \"do anim volupt\"\n}" - } - ] - }, - { - "name": "api Account Delete", - "request": { - "method": "DELETE", - "header": [ - { - "key": "Accept", - "value": "application/json" - } - ], - "url": { - "raw": "{{baseURL}}/api/accounts/{{nickname}}", - "host": [ - "{{baseURL}}" - ], - "path": [ - "api", - "accounts", - "{{nickname}}" - ] - } - }, - "response": [ - { - "name": "api Account Delete", - "originalRequest": { - "method": "DELETE", - "header": [ - { - "key": "Accept", - "value": "application/json" - } - ], - "url": { - "raw": "{{baseURL}}/api/accounts/{{nickname}}", - "host": [ - "{{baseURL}}" - ], - "path": [ - "api", - "accounts", - "{{nickname}}" - ] - } - }, - "status": "No Content", - "code": 204, - "_postman_previewlanguage": "json", - "header": [ - { - "key": "Content-Type", - "value": "application/json" - }, - { - "key": "Vary", - "value": "Origin" - }, - { - "key": "Date", - "value": "Fri, 28 Apr 2023 14:12:46 GMT" - }, - { - "key": "Connection", - "value": "close" - } - ], - "cookie": [], - "body": "" - }, - { - "name": "Bad request.", - "originalRequest": { - "method": "DELETE", - "header": [], - "url": { - "raw": "{{baseUrl}}/api/accounts/:nickname", - "host": [ - "{{baseUrl}}" - ], - "path": [ - "api", - "accounts", - ":nickname" - ], - "variable": [ - { - "key": "nickname", - "value": "mollit ma", - "description": "(Required) Wallet's short name." - } - ] - } - }, - "status": "Not Found", - "code": 404, - "_postman_previewlanguage": "json", - "header": [ - { - "key": "Content-Type", - "value": "application/json" - } - ], - "cookie": [], - "body": "{\n \"code\": \"dolore eiusmod in cillum velit\",\n \"message\": \"do anim volupt\"\n}" - }, - { - "name": "Internal Server Error - The server has encountered a situation it does not know how to handle.", - "originalRequest": { - "method": "DELETE", - "header": [], - "url": { - "raw": "{{baseUrl}}/api/accounts/:nickname", - "host": [ - "{{baseUrl}}" - ], - "path": [ - "api", - "accounts", - ":nickname" - ], - "variable": [ - { - "key": "nickname", - "value": "mollit ma", - "description": "(Required) Wallet's short name." - } - ] - } - }, - "status": "Internal Server Error", - "code": 500, - "_postman_previewlanguage": "json", - "header": [ - { - "key": "Content-Type", - "value": "application/json" - } - ], - "cookie": [], - "body": "{\n \"code\": \"dolore eiusmod in cillum velit\",\n \"message\": \"do anim volupt\"\n}" - } - ] - }, - { - "name": "api Account Rename", - "request": { - "method": "PUT", - "header": [ - { - "key": "Accept", - "value": "application/json" - } - ], - "body": { - "mode": "raw", - "raw": "{\n \"newNickname\": \"{{nickname}}-modified\"\n}", - "options": { - "raw": { - "language": "json" - } - } - }, - "url": { - "raw": "{{baseURL}}/api/accounts/{{nickname}}", - "host": [ - "{{baseURL}}" - ], - "path": [ - "api", - "accounts", - "{{nickname}}" - ] - } - }, - "response": [ - { - "name": "api Account Updated", - "originalRequest": { - "method": "PUT", - "header": [ - { - "key": "Accept", - "value": "application/json" - } - ], - "body": { - "mode": "raw", - "raw": "{\n \"newNickname\": \"{{nickname}}-modified\"\n}", - "options": { - "raw": { - "language": "json" - } - } - }, - "url": { - "raw": "{{baseURL}}/api/accounts/{{nickname}}", - "host": [ - "{{baseURL}}" - ], - "path": [ - "api", - "accounts", - "{{nickname}}" - ] - } - }, - "status": "OK", - "code": 200, - "_postman_previewlanguage": "json", - "header": [ - { - "key": "Content-Type", - "value": "application/json" - }, - { - "key": "Vary", - "value": "Origin" - }, - { - "key": "Date", - "value": "Fri, 02 Jun 2023 22:27:02 GMT" - }, - { - "key": "Content-Length", - "value": "198" - }, - { - "key": "Connection", - "value": "close" - } - ], - "cookie": [], - "body": "{\n \"address\": \"AU1a3E3dzUWaVeaLSVm3Uk9jnWK53VnWBZRpYHt1xn9d1M6ctyKE\",\n \"balance\": \"0\",\n \"candidateBalance\": \"0\",\n \"keyPair\": {\n \"nonce\": \"\",\n \"privateKey\": \"\",\n \"publicKey\": \"\",\n \"salt\": \"\"\n },\n \"nickname\": \"created-modified\"\n}" - }, - { - "name": "Bad request.", - "originalRequest": { - "method": "DELETE", - "header": [], - "url": { - "raw": "{{baseUrl}}/api/accounts/:nickname", - "host": [ - "{{baseUrl}}" - ], - "path": [ - "api", - "accounts", - ":nickname" - ], - "variable": [ - { - "key": "nickname", - "value": "mollit ma", - "description": "(Required) Wallet's short name." - } - ] - } - }, - "status": "Not Found", - "code": 404, - "_postman_previewlanguage": "json", - "header": [ - { - "key": "Content-Type", - "value": "application/json" - } - ], - "cookie": [], - "body": "{\n \"code\": \"dolore eiusmod in cillum velit\",\n \"message\": \"do anim volupt\"\n}" - }, - { - "name": "Internal Server Error - The server has encountered a situation it does not know how to handle.", - "originalRequest": { - "method": "DELETE", - "header": [], - "url": { - "raw": "{{baseUrl}}/api/accounts/:nickname", - "host": [ - "{{baseUrl}}" - ], - "path": [ - "api", - "accounts", - ":nickname" - ], - "variable": [ - { - "key": "nickname", - "value": "mollit ma", - "description": "(Required) Wallet's short name." - } - ] - } - }, - "status": "Internal Server Error", - "code": 500, - "_postman_previewlanguage": "json", - "header": [ - { - "key": "Content-Type", - "value": "application/json" - } - ], - "cookie": [], - "body": "{\n \"code\": \"dolore eiusmod in cillum velit\",\n \"message\": \"do anim volupt\"\n}" - } - ] - }, - { - "name": "api Account Transfer", - "request": { - "method": "POST", - "header": [ - { - "key": "Content-Type", - "value": "application/json" - }, - { - "key": "Accept", - "value": "application/json" - } - ], - "body": { - "mode": "raw", - "raw": "{\n \"fee\": \"10\",\n \"amount\": \"10000000\",\n \"recipientAddress\": \"AU14nFDPZR5tCkw9Pap6P8Dux2RqAuV6HCee41YVz9ryAgxjH2dX\"\n}", - "options": { - "raw": { - "language": "json" - } - } - }, - "url": { - "raw": "{{baseURL}}/api/accounts/{{nickname}}/transfer", - "host": [ - "{{baseURL}}" - ], - "path": [ - "api", - "accounts", - "{{nickname}}", - "transfer" - ] - } - }, - "response": [ - { - "name": "Success", - "originalRequest": { - "method": "POST", - "header": [ - { - "key": "Content-Type", - "value": "application/json" - }, - { - "key": "Accept", - "value": "application/json" - } - ], - "body": { - "mode": "raw", - "raw": "{\n \"fee\": \"0\",\n \"amount\": \"1\",\n \"recipientAddress\": \"AU1eQkRhZZBa5VNc24fCejxgFDpe1FHChpwiUksQB9StNb3rWm6i\"\n}", - "options": { - "raw": { - "language": "json" - } - } - }, - "url": { - "raw": "{{baseURL}}/api/accounts/{{nickname}}/transfer", - "host": [ - "{{baseURL}}" - ], - "path": [ - "api", - "accounts", - "{{nickname}}", - "transfer" - ] - } - }, - "status": "OK", - "code": 200, - "_postman_previewlanguage": "json", - "header": [ - { - "key": "Content-Type", - "value": "application/json" - }, - { - "key": "Vary", - "value": "Origin" - }, - { - "key": "Date", - "value": "Tue, 09 May 2023 13:48:02 GMT" - }, - { - "key": "Content-Length", - "value": "70" - }, - { - "key": "Connection", - "value": "close" - } - ], - "cookie": [], - "body": "{\n \"operationId\": \"O1eqYCBbsjoGX4nPREkswxreXsymm7VquDEZVYhcBfi925PbwLz\"\n}" - }, - { - "name": "Bad request.", - "originalRequest": { - "method": "POST", - "header": [], - "body": { - "mode": "raw", - "raw": "{\n \"operation\": \"labore Lorem nostrud culpa\"\n}", - "options": { - "raw": { - "language": "json" - } - } - }, - "url": { - "raw": "{{baseUrl}}/api/accounts/:nickname/sign", - "host": [ - "{{baseUrl}}" - ], - "path": [ - "api", - "accounts", - ":nickname", - "sign" - ], - "variable": [ - { - "key": "nickname", - "value": "mollit ma", - "description": "(Required) Wallet's short name." - } - ] - } - }, - "status": "Bad Request", - "code": 400, - "_postman_previewlanguage": "json", - "header": [ - { - "key": "Content-Type", - "value": "application/json" - } - ], - "cookie": [], - "body": "{\n \"code\": \"dolore eiusmod in cillum velit\",\n \"message\": \"do anim volupt\"\n}" - }, - { - "name": "Unauthorized", - "originalRequest": { - "method": "POST", - "header": [ - { - "key": "Content-Type", - "value": "application/json" - }, - { - "key": "Accept", - "value": "application/json" - } - ], - "body": { - "mode": "raw", - "raw": "{\"operation\":\"MjIzM3QyNHQ=\"}", - "options": { - "raw": { - "language": "json" - } - } - }, - "url": { - "raw": "{{baseURL}}/api/accounts/{{nickname}}/sign", - "host": [ - "{{baseURL}}" - ], - "path": [ - "api", - "accounts", - "{{nickname}}", - "sign" - ] - } - }, - "status": "Unauthorized", - "code": 401, - "_postman_previewlanguage": "json", - "header": [ - { - "key": "Content-Type", - "value": "application/json" - }, - { - "key": "Vary", - "value": "Origin" - }, - { - "key": "Date", - "value": "Tue, 02 May 2023 13:45:06 GMT" - }, - { - "key": "Content-Length", - "value": "62" - }, - { - "key": "Connection", - "value": "close" - } - ], - "cookie": [], - "body": "{\n \"code\": \"Wallet-0003\",\n \"message\": \"Unable to unprotect wallet\"\n}" - }, - { - "name": "Internal Server Error - The server has encountered a situation it does not know how to handle.", - "originalRequest": { - "method": "POST", - "header": [], - "body": { - "mode": "raw", - "raw": "{\n \"operation\": \"labore Lorem nostrud culpa\"\n}", - "options": { - "raw": { - "language": "json" - } - } - }, - "url": { - "raw": "{{baseUrl}}/api/accounts/:nickname/sign", - "host": [ - "{{baseUrl}}" - ], - "path": [ - "api", - "accounts", - ":nickname", - "sign" - ], - "variable": [ - { - "key": "nickname", - "value": "mollit ma", - "description": "(Required) Wallet's short name." - } - ] - } - }, - "status": "Internal Server Error", - "code": 500, - "_postman_previewlanguage": "json", - "header": [ - { - "key": "Content-Type", - "value": "application/json" - } - ], - "cookie": [], - "body": "{\n \"code\": \"dolore eiusmod in cillum velit\",\n \"message\": \"do anim volupt\"\n}" - } - ] - } - ], - "event": [ - { - "listen": "prerequest", - "script": { - "type": "text/javascript", - "exec": [ - "" - ] - } - }, - { - "listen": "test", - "script": { - "type": "text/javascript", - "exec": [ - "" - ] - } - } - ], - "variable": [ - { - "key": "baseURL", - "value": "127.0.0.1:8080", - "type": "string" - }, - { - "key": "nickname", - "value": "created", - "type": "string" - }, - { - "key": "password", - "value": "1234", - "type": "string" - } - ] -} \ No newline at end of file diff --git a/api/server/models/asset_info.go b/api/server/models/asset_info.go index 0d5a8253..9696452a 100644 --- a/api/server/models/asset_info.go +++ b/api/server/models/asset_info.go @@ -22,6 +22,10 @@ type AssetInfo struct { // address Address string `json:"address,omitempty"` + // chain ID + // Minimum: 0 + ChainID *int64 `json:"chainID,omitempty"` + // decimals // Minimum: 0 Decimals *int64 `json:"decimals,omitempty"` @@ -37,6 +41,10 @@ type AssetInfo struct { func (m *AssetInfo) Validate(formats strfmt.Registry) error { var res []error + if err := m.validateChainID(formats); err != nil { + res = append(res, err) + } + if err := m.validateDecimals(formats); err != nil { res = append(res, err) } @@ -47,6 +55,18 @@ func (m *AssetInfo) Validate(formats strfmt.Registry) error { return nil } +func (m *AssetInfo) validateChainID(formats strfmt.Registry) error { + if swag.IsZero(m.ChainID) { // not required + return nil + } + + if err := validate.MinimumInt("chainID", "body", *m.ChainID, 0, false); err != nil { + return err + } + + return nil +} + func (m *AssetInfo) validateDecimals(formats strfmt.Registry) error { if swag.IsZero(m.Decimals) { // not required return nil diff --git a/api/server/restapi/embedded_spec.go b/api/server/restapi/embedded_spec.go index eacd466b..8d5345e0 100644 --- a/api/server/restapi/embedded_spec.go +++ b/api/server/restapi/embedded_spec.go @@ -868,6 +868,9 @@ func init() { "address": { "type": "string" }, + "chainID": { + "type": "integer" + }, "decimals": { "type": "integer" }, @@ -2047,6 +2050,10 @@ func init() { "address": { "type": "string" }, + "chainID": { + "type": "integer", + "minimum": 0 + }, "decimals": { "type": "integer", "minimum": 0 diff --git a/api/walletApi-V0.yml b/api/walletApi-V0.yml index c56663bb..78373fb6 100644 --- a/api/walletApi-V0.yml +++ b/api/walletApi-V0.yml @@ -745,6 +745,9 @@ definitions: decimals: type: integer minimum: 0 + chainID: + type: integer + minimum: 0 x-nullable: false AssetInfoWithBalance: allOf: diff --git a/internal/handler/wallet/add_asset.go b/internal/handler/wallet/add_asset.go index 10d27789..948c66c3 100644 --- a/internal/handler/wallet/add_asset.go +++ b/internal/handler/wallet/add_asset.go @@ -56,7 +56,7 @@ func (a *addAsset) Handle(params operations.AddAssetParams) middleware.Responder } // Add Asset and persist in JSON file. - if err := a.AssetsStore.AddAsset(params.Nickname, params.AssetAddress, *assetInfoFromSC); err != nil { + if err := a.AssetsStore.AddAsset(params.Nickname, *assetInfoFromSC); err != nil { // Return error occurred while persisting the asset errorMsg := "Failed to add the asset to the JSON file." return operations.NewAddAssetInternalServerError().WithPayload(&models.Error{Code: errorAddAssetJSON, Message: errorMsg}) diff --git a/internal/handler/wallet/get_all_assets.go b/internal/handler/wallet/get_all_assets.go index 8b7e0050..124b0f6b 100644 --- a/internal/handler/wallet/get_all_assets.go +++ b/internal/handler/wallet/get_all_assets.go @@ -3,6 +3,7 @@ package wallet import ( "fmt" "sort" + "sync" "github.com/go-openapi/runtime/middleware" "github.com/massalabs/station-massa-wallet/api/server/models" @@ -45,11 +46,16 @@ func (g *getAllAssets) Handle(params operations.GetAllAssetsParams) middleware.R assetsWithBalance = append(assetsWithBalance, massaAsset) - userAssetData, resp := g.getAssetsData(acc) - if resp != nil { - return resp + nodeInfo, err := network.GetNetworkInfo() + if err != nil { + operations.NewGetAllAssetsInternalServerError().WithPayload(&models.Error{ + Code: errorFetchAssetBalance, + Message: fmt.Sprintf("Failed to fetch network info: %s", err.Error()), + }) } + userAssetData := g.getAssetsData(acc, nodeInfo.ChainID) + assetsWithBalance = append(assetsWithBalance, userAssetData...) sort.Slice(assetsWithBalance, func(i, j int) bool { @@ -114,28 +120,47 @@ func (g *getAllAssets) getMASAsset(acc *account.Account) (*assets.AssetInfoWithB // getAssetsData fetches the balance and dollar value for each asset in the account. // If user has asset that are deployed on another network, it will not be included. -func (g *getAllAssets) getAssetsData(acc *account.Account) ([]*assets.AssetInfoWithBalances, middleware.Responder) { - assetsInfo := g.AssetsStore.All(acc.Nickname) +func (g *getAllAssets) getAssetsData(acc *account.Account, chainID int) []*assets.AssetInfoWithBalances { + assetsInfo := g.AssetsStore.All(acc.Nickname, chainID) assetsWithBalance := make([]*assets.AssetInfoWithBalances, 0) + var wg sync.WaitGroup + mu := &sync.Mutex{} + resultsCh := make(chan *assets.AssetInfoWithBalances) // Retrieve all assets from the selected nickname for _, asset := range assetsInfo { - // First, check if the asset exists in the network - if !g.massaClient.AssetExistInNetwork(asset.AssetInfo.Address) { - logger.Infof("Asset %s does not exist in the network", asset.AssetInfo.Address) - continue - } + wg.Add(1) + + go func(asset *assets.AssetInfoWithBalances) { + defer wg.Done() - // Fetch the balance for the current asset - balance, dollarValue := g.fetchAssetData(asset, acc) + if asset.AssetInfo.Address == "" { + return + } - asset.Balance = balance - asset.DollarValue = dollarValue - assetsWithBalance = append(assetsWithBalance, asset) + // Fetch the balance and dollar value of the current asset + balance, dollarValue := g.fetchAssetData(asset, acc) + + asset.Balance = balance + asset.DollarValue = dollarValue + + resultsCh <- asset + }(asset) + } + + go func() { + wg.Wait() + close(resultsCh) + }() + + for result := range resultsCh { + mu.Lock() + assetsWithBalance = append(assetsWithBalance, result) + mu.Unlock() } - return assetsWithBalance, nil + return assetsWithBalance } func (g *getAllAssets) fetchAssetData(asset *assets.AssetInfoWithBalances, acc *account.Account) (string, *float64) { @@ -177,22 +202,20 @@ func convertToModel(assetsWithBalance []*assets.AssetInfoWithBalances) []*models Decimals: asset.AssetInfo.Decimals, Name: asset.AssetInfo.Name, Symbol: asset.AssetInfo.Symbol, + ChainID: asset.AssetInfo.ChainID, + } + + newAsset := &models.AssetInfoWithBalance{ + AssetInfo: assetInfo, + Balance: asset.Balance, + IsDefault: asset.IsDefault, } - if asset.DollarValue == nil { - result = append(result, &models.AssetInfoWithBalance{ - AssetInfo: assetInfo, - Balance: asset.Balance, - IsDefault: asset.IsDefault, - }) - } else { - result = append(result, &models.AssetInfoWithBalance{ - AssetInfo: assetInfo, - Balance: asset.Balance, - DollarValue: fmt.Sprintf("%.2f", *asset.DollarValue), - IsDefault: asset.IsDefault, - }) + if asset.DollarValue != nil { + newAsset.DollarValue = fmt.Sprintf("%.2f", *asset.DollarValue) } + + result = append(result, newAsset) } return result diff --git a/internal/handler/wallet/get_all_assets_test.go b/internal/handler/wallet/get_all_assets_test.go index c86e8063..ee5b231b 100644 --- a/internal/handler/wallet/get_all_assets_test.go +++ b/internal/handler/wallet/get_all_assets_test.go @@ -4,10 +4,13 @@ import ( "encoding/json" "fmt" "net/http" + "os" "testing" "github.com/massalabs/station-massa-wallet/api/server/models" "github.com/massalabs/station-massa-wallet/api/server/restapi/operations" + "github.com/massalabs/station-massa-wallet/pkg/assets" + "github.com/massalabs/station-massa-wallet/pkg/network" "github.com/stretchr/testify/assert" ) @@ -23,7 +26,8 @@ func TestGetAllAssetsHandler(t *testing.T) { assetsWithBalance := getAssets(t, api, nickname) // Assert that assetsWithBalance contains the expected data - assert.Len(t, assetsWithBalance, 9, "the assets list should have 9 items") + counter := getExpectedAssetsCount(t) + assert.Len(t, assetsWithBalance, counter+1) // +1 for native MAS assert.Equal(t, "1000000", assetsWithBalance[0].Balance) assert.Equal(t, "Massa", assetsWithBalance[0].AssetInfo.Name) @@ -55,4 +59,24 @@ func assertAssetInfoWithBalanceEqual(t *testing.T, actual, expected *models.Asse assert.Equal(t, expected.AssetInfo.Name, actual.AssetInfo.Name) assert.Equal(t, expected.AssetInfo.Symbol, actual.AssetInfo.Symbol) assert.Equal(t, expected.AssetInfo.Decimals, actual.AssetInfo.Decimals) + assert.Equal(t, expected.AssetInfo.ChainID, actual.AssetInfo.ChainID) +} + +func getExpectedAssetsCount(t *testing.T) int { + tempDir, err := os.MkdirTemp(os.TempDir(), "*-wallet-dir") + assert.NoError(t, err) + nodeFetcher := network.NewNodeFetcher() + store, err := assets.NewAssetsStore(tempDir, nodeFetcher) + assert.NoError(t, err) + defaultAssets, err := store.Default() + assert.NoError(t, err) + counter := 0 + + for _, asset := range defaultAssets { + if asset.ChainID == 77658377 { + counter += 1 + } + } + + return counter } diff --git a/internal/handler/wallet/sign.go b/internal/handler/wallet/sign.go index 83976235..e2324722 100644 --- a/internal/handler/wallet/sign.go +++ b/internal/handler/wallet/sign.go @@ -129,7 +129,7 @@ func (w *walletSign) Handle(params operations.SignParams) middleware.Responder { } } - operation, msgToSign, err := prepareOperation(acc, fees, params.Body.Operation.String(), promptRequest.Data.(PromptRequestSignData).OperationType, *params.Body.ChainID) + operation, msgToSign, err := prepareOperation(acc, fees, params.Body.Operation.String(), *params.Body.ChainID) if err != nil { return newErrorResponse(err.Error(), errorSignDecodeOperation, http.StatusBadRequest) } @@ -203,7 +203,7 @@ func (w *walletSign) Success(acc *account.Account, signature []byte, correlation // prepareOperation prepares the operation to be signed. // Returns the modified operation (fees change) and the operation to be signed (with public key). // Returns an error if the operation cannot be decoded. -func prepareOperation(acc *account.Account, fees uint64, operationB64 string, operationType int, chainID int64) ([]byte, []byte, error) { +func prepareOperation(acc *account.Account, fees uint64, operationB64 string, chainID int64) ([]byte, []byte, error) { decodedMsg, _, expiry, err := sendoperation.DecodeMessage64(operationB64) if err != nil { return nil, nil, fmt.Errorf("failed to decode operation for preparing before signing: %w", err) @@ -254,7 +254,7 @@ func (w *walletSign) getPromptRequest(params operations.SignParams, acc *account data, err = getExecuteSCPromptData(decodedMsg) case callsc.OpType: - data, err = getCallSCPromptData(decodedMsg, acc) + data, err = getCallSCPromptData(decodedMsg) default: return nil, 0, fmt.Errorf("unhandled operation type: %d", opType) @@ -282,7 +282,7 @@ func (w *walletSign) getPromptRequest(params operations.SignParams, acc *account data.OperationType = int(opType) data.AllowFeeEdition = *params.AllowFeeEdition data.ChainID = chainID - data.Assets = convertAssetsToModel(w.AssetsStore.All(acc.Nickname)) + data.Assets = convertAssetsToModel(w.AssetsStore.All(acc.Nickname, int(chainID))) promptRequest := prompt.PromptRequest{ Action: walletapp.Sign, @@ -294,7 +294,6 @@ func (w *walletSign) getPromptRequest(params operations.SignParams, acc *account func getCallSCPromptData( decodedMsg []byte, - acc *account.Account, ) (PromptRequestSignData, error) { msg, err := callsc.DecodeMessage(decodedMsg) if err != nil { @@ -456,6 +455,7 @@ func convertAssetsToModel(assetsWithBalance []*assets.AssetInfoWithBalances) []m Decimals: asset.AssetInfo.Decimals, Name: asset.AssetInfo.Name, Symbol: asset.AssetInfo.Symbol, + ChainID: asset.AssetInfo.ChainID, } result = append(result, assetInfo) } diff --git a/internal/handler/wallet/sign_test.go b/internal/handler/wallet/sign_test.go index 2f8ac39d..1ccf12cc 100644 --- a/internal/handler/wallet/sign_test.go +++ b/internal/handler/wallet/sign_test.go @@ -44,7 +44,7 @@ func TestPrepareOperation(t *testing.T) { fees := uint64(1000) operationB64 := "AKT4CASAzuTNAqCNBgEAXBwUw39NBQYix8Ovph0TUiJuDDEnlFYUPgsbeMbrA4cLZm9yd2FyZEJ1cm7FAQDgfY7fLW7qpwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACoAAAAweGZDRERBRTI1MTAwNjIxYTViQzg4MTlkQzlEMzg0MjUzNEQ3QmY0NzYAAAAANQAAAEFTMTJUUm9TY01kd0xLOFlwdDZOQkFwcHl6Q0Z3N1FlRzVlM3hGdnhwQ0FuQW5ZTGZ1TVVUKgAAADB4NTM4NDRGOTU3N0MyMzM0ZTU0MUFlYzdEZjcxNzRFQ2U1ZEYxZkNmMKc2qgAAAAAA" - operation, msgToSign, err := prepareOperation(acc, fees, operationB64, 4, ChainIDUnitTests) + operation, msgToSign, err := prepareOperation(acc, fees, operationB64, ChainIDUnitTests) assert.NoError(t, err) expected := []byte{0xe8, 0x7, 0xa4, 0xf8, 0x8, 0x4, 0x80, 0xce, 0xe4, 0xcd, 0x2, 0xa0, 0x8d, 0x6, 0x1, 0x0, 0x5c, 0x1c, 0x14, 0xc3, 0x7f, 0x4d, 0x5, 0x6, 0x22, 0xc7, 0xc3, 0xaf, 0xa6, 0x1d, 0x13, 0x52, 0x22, 0x6e, 0xc, 0x31, 0x27, 0x94, 0x56, 0x14, 0x3e, 0xb, 0x1b, 0x78, 0xc6, 0xeb, 0x3, 0x87, 0xb, 0x66, 0x6f, 0x72, 0x77, 0x61, 0x72, 0x64, 0x42, 0x75, 0x72, 0x6e, 0xc5, 0x1, 0x0, 0xe0, 0x7d, 0x8e, 0xdf, 0x2d, 0x6e, 0xea, 0xa7, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2a, 0x0, 0x0, 0x0, 0x30, 0x78, 0x66, 0x43, 0x44, 0x44, 0x41, 0x45, 0x32, 0x35, 0x31, 0x30, 0x30, 0x36, 0x32, 0x31, 0x61, 0x35, 0x62, 0x43, 0x38, 0x38, 0x31, 0x39, 0x64, 0x43, 0x39, 0x44, 0x33, 0x38, 0x34, 0x32, 0x35, 0x33, 0x34, 0x44, 0x37, 0x42, 0x66, 0x34, 0x37, 0x36, 0x0, 0x0, 0x0, 0x0, 0x35, 0x0, 0x0, 0x0, 0x41, 0x53, 0x31, 0x32, 0x54, 0x52, 0x6f, 0x53, 0x63, 0x4d, 0x64, 0x77, 0x4c, 0x4b, 0x38, 0x59, 0x70, 0x74, 0x36, 0x4e, 0x42, 0x41, 0x70, 0x70, 0x79, 0x7a, 0x43, 0x46, 0x77, 0x37, 0x51, 0x65, 0x47, 0x35, 0x65, 0x33, 0x78, 0x46, 0x76, 0x78, 0x70, 0x43, 0x41, 0x6e, 0x41, 0x6e, 0x59, 0x4c, 0x66, 0x75, 0x4d, 0x55, 0x54, 0x2a, 0x0, 0x0, 0x0, 0x30, 0x78, 0x35, 0x33, 0x38, 0x34, 0x34, 0x46, 0x39, 0x35, 0x37, 0x37, 0x43, 0x32, 0x33, 0x33, 0x34, 0x65, 0x35, 0x34, 0x31, 0x41, 0x65, 0x63, 0x37, 0x44, 0x66, 0x37, 0x31, 0x37, 0x34, 0x45, 0x43, 0x65, 0x35, 0x64, 0x46, 0x31, 0x66, 0x43, 0x66, 0x30, 0xa7, 0x36, 0xaa, 0x0, 0x0, 0x0, 0x0, 0x0} assert.Equal(t, expected, operation) diff --git a/pkg/assets/asset.go b/pkg/assets/asset.go index 92904484..70a14002 100644 --- a/pkg/assets/asset.go +++ b/pkg/assets/asset.go @@ -7,6 +7,7 @@ import ( "path/filepath" "sync" + "github.com/go-openapi/swag" "github.com/massalabs/station-massa-wallet/api/server/models" "github.com/massalabs/station-massa-wallet/pkg/network" "github.com/massalabs/station-massa-wallet/pkg/wallet" @@ -51,6 +52,7 @@ type assetData struct { Name string `json:"name"` Symbol string `json:"symbol"` Decimals int64 `json:"decimals"` + ChainID int64 `json:"chainID"` } // NewAssetsStore creates and initializes a new instance of AssetsStore. @@ -127,6 +129,7 @@ func (s *AssetsStore) loadAccountsStore() error { Name: asset.Name, Symbol: asset.Symbol, Decimals: &decimals, + ChainID: swag.Int64(asset.ChainID), } accountAssets.ContractAssets[asset.ContractAddress] = assetInfo } @@ -176,6 +179,7 @@ func (s *AssetsStore) save() error { Name: assetInfo.Name, Symbol: assetInfo.Symbol, Decimals: *assetInfo.Decimals, + ChainID: *assetInfo.ChainID, } assetsData.Assets = append(assetsData.Assets, asset) } @@ -199,9 +203,9 @@ func (s *AssetsStore) save() error { } // AddAsset adds the asset information for a given account nickname in the JSON. -func (s *AssetsStore) AddAsset(nickname, assetAddress string, assetInfo models.AssetInfo) error { +func (s *AssetsStore) AddAsset(nickname string, assetInfo models.AssetInfo) error { // Update the ContractAssets map with the new asset information - s.AddAssetToMemory(nickname, assetAddress, assetInfo) + s.AddAssetToMemory(nickname, assetInfo) // Synchronize the AssetsStore map to JSON and write to the file if err := s.save(); err != nil { @@ -212,7 +216,7 @@ func (s *AssetsStore) AddAsset(nickname, assetAddress string, assetInfo models.A } // AddAssetToMemory adds the asset information for a given account nickname to the AssetsStore. -func (s *AssetsStore) AddAssetToMemory(nickname, assetAddress string, assetInfo models.AssetInfo) { +func (s *AssetsStore) AddAssetToMemory(nickname string, assetInfo models.AssetInfo) { s.StoreMutex.Lock() defer s.StoreMutex.Unlock() @@ -226,7 +230,7 @@ func (s *AssetsStore) AddAssetToMemory(nickname, assetAddress string, assetInfo } // Update the ContractAssets map of the specific *assets.AssetsStore with the new asset information - accountAssets.ContractAssets[assetAddress] = assetInfo + accountAssets.ContractAssets[assetInfo.Address] = assetInfo s.Assets[nickname] = accountAssets } @@ -264,7 +268,7 @@ func (s *AssetsStore) DeleteAsset(nickname, assetAddress string) error { // All returns all the assets associated with a specific account nickname. // It returns the default assets first, followed by the assets added by the user. // If user already added the default asset, it will not be duplicated. -func (s *AssetsStore) All(nickname string) []*AssetInfoWithBalances { +func (s *AssetsStore) All(nickname string, chainID int) []*AssetInfoWithBalances { defaultAssets, err := s.Default() if err != nil { logger.Errorf("Failed to get default assets: %s", err.Error()) @@ -276,6 +280,9 @@ func (s *AssetsStore) All(nickname string) []*AssetInfoWithBalances { includedAddresses := map[string]bool{} for _, asset := range defaultAssets { + if asset.ChainID != chainID { + continue + } decimals := asset.Decimals // Copy the decimals value to avoid a pointer to a local variable completeAsset := &AssetInfoWithBalances{ AssetInfo: &models.AssetInfo{ @@ -283,6 +290,7 @@ func (s *AssetsStore) All(nickname string) []*AssetInfoWithBalances { Decimals: &decimals, Name: asset.Name, Symbol: asset.Symbol, + ChainID: swag.Int64((int64(asset.ChainID))), }, Balance: "", MEXCSymbol: asset.MEXCSymbol, @@ -295,23 +303,26 @@ func (s *AssetsStore) All(nickname string) []*AssetInfoWithBalances { // Append default assets ensuring no duplication for _, asset := range s.Assets[nickname].ContractAssets { - // Append the asset info to the result slice if it is not already in the list - if _, exists := includedAddresses[asset.Address]; !exists { - completeAsset := &AssetInfoWithBalances{ - AssetInfo: &models.AssetInfo{ - Address: asset.Address, - Decimals: asset.Decimals, - Name: asset.Name, - Symbol: asset.Symbol, - }, - Balance: "", - MEXCSymbol: "", - DollarValue: nil, - IsDefault: false, - } - assetsInfo = append(assetsInfo, completeAsset) - includedAddresses[asset.Address] = true + // skip if it's already in the list or not in the same chain + _, exists := includedAddresses[asset.Address] + if *asset.ChainID != int64(chainID) || exists { + continue } + completeAsset := &AssetInfoWithBalances{ + AssetInfo: &models.AssetInfo{ + Address: asset.Address, + Decimals: asset.Decimals, + Name: asset.Name, + Symbol: asset.Symbol, + ChainID: asset.ChainID, + }, + Balance: "", + MEXCSymbol: "", + DollarValue: nil, + IsDefault: false, + } + assetsInfo = append(assetsInfo, completeAsset) + includedAddresses[asset.Address] = true } return assetsInfo diff --git a/pkg/assets/asset_test.go b/pkg/assets/asset_test.go index 5051a1d9..e0a05fe5 100644 --- a/pkg/assets/asset_test.go +++ b/pkg/assets/asset_test.go @@ -115,16 +115,18 @@ func TestAddAndDeleteAsset(t *testing.T) { // Test case 1: Add an asset and check if it's saved to JSON nickname := "dummyAccount" assetAddress := "0x1234567890abcdef" + chainID := int64(77658366) assetInfo := models.AssetInfo{ Address: assetAddress, Name: "TestToken", Symbol: "TT", Decimals: new(int64), + ChainID: &chainID, } *assetInfo.Decimals = 18 // Add the asset - err = store.AddAsset(nickname, assetAddress, assetInfo) + err = store.AddAsset(nickname, assetInfo) assert.NoError(t, err) // Check if the added asset exists diff --git a/pkg/assets/default_assets.go b/pkg/assets/default_assets.go index 46b47be7..1bf052c1 100644 --- a/pkg/assets/default_assets.go +++ b/pkg/assets/default_assets.go @@ -14,6 +14,7 @@ type DefaultAssetInfo struct { Symbol string `json:"symbol"` Decimals int64 `json:"decimals"` MEXCSymbol string `json:"MEXCSymbol"` + ChainID int `json:"chainID"` } func (s *AssetsStore) Default() ([]DefaultAssetInfo, error) { @@ -69,7 +70,7 @@ func (s *AssetsStore) InitDefault() error { } // if the content is different, overwrite the default assets JSON file - if string(content) != assetsJSON { + if string(content) != AssetsJSON { if err := s.createFileDefault(defaultAssetsJSONPath); err != nil { return err } @@ -86,68 +87,110 @@ func getDefaultJSONPath(assetsJSONDir string) (string, error) { // createFileDefault creates the default assets JSON file with the default assets. func (s *AssetsStore) createFileDefault(path string) error { - if err := os.WriteFile(path, []byte(assetsJSON), permissionUrwGrOr); err != nil { + if err := os.WriteFile(path, []byte(AssetsJSON), permissionUrwGrOr); err != nil { return err } return nil } -const assetsJSON = `[ +const AssetsJSON = `[ { "address": "AS12k8viVmqPtRuXzCm6rKXjLgpQWqbuMjc37YHhB452KSUUb9FgL", "name": "Sepolia USDC", "symbol": "USDC.s", "decimals": 6, - "MEXCSymbol": "USD" + "MEXCSymbol": "USD", + "ChainID": 77658366 }, { "address": "AS12LpYyAjYRJfYhyu7fkrS224gMdvFHVEeVWoeHZzMdhis7UZ3Eb", "name": "Sepolia tDAI", "symbol": "tDAI.s", "decimals": 18, - "MEXCSymbol": "USD" + "MEXCSymbol": "USD", + "ChainID": 77658366 }, { "address": "AS1gt69gqYD92dqPyE6DBRJ7KjpnQHqFzFs2YCkBcSnuxX5bGhBC", "name": "sepolia WETH", "symbol": "WETH.s", "decimals": 18, - "MEXCSymbol": "ETHUSDT" + "MEXCSymbol": "ETHUSDT", + "ChainID": 77658366 }, { "address": "AS12U4TZfNK7qoLyEERBBRDMu8nm5MKoRzPXDXans4v9wdATZedz9", "name": "Wrapped Massa", "symbol": "WMAS", "decimals": 9, - "MEXCSymbol": "MASUSDT" + "MEXCSymbol": "MASUSDT", + "ChainID": 77658377 }, { "address": "AS1hCJXjndR4c9vekLWsXGnrdigp4AaZ7uYG3UKFzzKnWVsrNLPJ", "name": "USD Coin", "symbol": "USDC.e", "decimals": 6, - "MEXCSymbol": "USD" + "MEXCSymbol": "USD", + "ChainID": 77658377 }, { "address": "AS1ZGF1upwp9kPRvDKLxFAKRebgg7b3RWDnhgV7VvdZkZsUL7Nuv", "name": "Dai Stablecoin", "symbol": "DAI.e", "decimals": 18, - "MEXCSymbol": "USD" + "MEXCSymbol": "USD", + "ChainID": 77658377 }, { "address": "AS124vf3YfAJCSCQVYKczzuWWpXrximFpbTmX4rheLs5uNSftiiRY", "name": "Wrapped Ether", "symbol": "WETH.e", "decimals": 18, - "MEXCSymbol": "ETHUSDT" + "MEXCSymbol": "ETHUSDT", + "ChainID": 77658377 }, { "address": "AS133eqPPaPttJ6hJnk3sfoG5cjFFqBDi1VGxdo2wzWkq8AfZnan", "name": "Purrfect Universe", "symbol": "PUR", "decimals": 18, - "MEXCSymbol": "" + "MEXCSymbol": "", + "ChainID": 77658377 + }, + { + "address": "AS12RmCXTA9NZaTBUBnRJuH66AGNmtEfEoqXKxLdmrTybS6GFJPFs", + "name": "Wrapped Ether", + "symbol": "WETH.bt", + "decimals": 18, + "MEXCSymbol": "ETHUSDT", + "ChainID": 77658366 + }, + { + "address": "AS12ix1Qfpue7BB8q6mWVtjNdNE9UV3x4MaUo7WhdUubov8sJ3CuP", + "name": "Wrapped Binance USD", + "symbol": "USDT.bt", + "decimals": 18, + "MEXCSymbol": "USD", + "ChainID": 77658366 } ]` + +// TODO: add the following assets with the addresses +// { +// "address": "", +// "name": "Wrapped Ether", +// "symbol": "WETH.b", +// "decimals": 18, +// "MEXCSymbol": "ETHUSDT", +// "ChainID": 77658377 +// }, +// { +// "address": "", +// "name": "Wrapped Binance USD", +// "symbol": "USDT.b", +// "decimals": 18, +// "MEXCSymbol": "USD", +// "ChainID": 77658377 +// }, diff --git a/pkg/assets/retrieve_sc.go b/pkg/assets/retrieve_sc.go index 4f738107..385b990c 100644 --- a/pkg/assets/retrieve_sc.go +++ b/pkg/assets/retrieve_sc.go @@ -74,12 +74,18 @@ func AssetInfo(contractAddress string, massaClient network.NodeFetcherInterface) symbol := <-symbolCh decimals := <-decimalsCh + nodeInfo, err := network.GetNetworkInfo() + if err != nil { + return nil, err + } + // Create the AssetInfo struct with the retrieved information assetInfoFromSC := &models.AssetInfo{ Address: contractAddress, Name: name, Symbol: symbol, Decimals: swag.Int64(int64(decimals)), + ChainID: swag.Int64((int64(nodeInfo.ChainID))), } return assetInfoFromSC, nil diff --git a/web-frontend/.prettierignore b/web-frontend/.prettierignore index d27026d7..1c0c6cc5 100644 --- a/web-frontend/.prettierignore +++ b/web-frontend/.prettierignore @@ -7,3 +7,4 @@ public *.md *.mdx package-lock.json +cypress-visual-report