Giter Club home page Giter Club logo

safe-client-gateway's Introduction

Safe Client Gateway

Actions Status Coverage Status

⚠️ This project is no longer being maintained. A new version which supports the same API can be found on https://github.com/safe-global/safe-client-gateway-nest. For the teams running an instance of this service, we strongly advise using the new version as it will include new features and any security related updates.

Motivation

This project is a gateway between the Safe clients (Android/ iOS/ web) and the Safe backend services (transaction service and Ethereum nodes). It is providing a more UI-oriented mapping and multi-sourced data structures for ease of integration and rendering.

Documentation

Quickstart

This project requires rustup and redis

git clone https://github.com/safe-global/safe-client-gateway.git
cd safe-client-gateway
cp .env.sample .env
redis-server
cargo run
./add_rustfmt_git_hook.sh  # It installs a git precommit hook that will autoformat the code on every commit

After doing any change code must be formatted using Rustfmt

Configuration

Rocket specific configurations (including databases) can be configured via the Rocket.toml for local development (see https://rocket.rs/v0.4/guide/configuration/#rockettoml).

For configurations specific to this service the .env file can be used. See next section.

Environment

Place a .env file in the root of the project containing URL pointing to the environment in which you want the gateway to run.

The contents of the file should be the following (see .env.sample for an example)

Tests

In order to run the test suite of the project:

  1. Have an instance of Redis running (as some of them test the integration with Redis).
redis-server
  1. Make sure that the required environment variables are set (the following example assumes that Redis is runnning on the default port 6379):
export REDIS_URI=redis://localhost:6379
export REDIS_URI_MAINNET=redis://localhost:6379
  1. Run the tests
cargo test -- --test-threads 1

By default, cargo test will execute the tests in the test suite in parallel. Because some of the tests update some shared local state (eg.: environment variables) the tests should be executed on a single thread – thus --test-threads 1.

safe-client-gateway's People

Contributors

0xjuancito avatar antomor avatar biafra23 avatar dependabot[bot] avatar fmrsabino avatar gmonty030 avatar hectorgomezv avatar inomurko avatar jpalvarezl avatar masayil avatar mmv08 avatar moisses89 avatar rmeissner avatar uxio0 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

safe-client-gateway's Issues

Map MultisigTransaction into transaction domain types

Preconditions

  • The SafeInfo is fetched and cached (needed for status calculation) #28
  • The Tokens endpoint is fetched and cached (to serve the correct info for both historic and pending transactions) #29

Is your feature request related to a problem? Please describe.
Multisig transactions should be mapped into all domain types as defined in #24. Additionally, the status of the transaction should be calculated as in the TransactionRepository in Android for now.

Describe the solution you'd like
The detection of transaction type is already done (like in Android) by observing the dataDecoded field. However, in certain cases we have erroneous classifications, as certain ERC721 tokens call methods with the same signature as ERC20 for transfers. Therefore the heuristic should be implemented to match that of iOS.
The safe and tokenInfo should be fetched and cached for each transaction (beyond the scope of this issue, see preconditions ☝️ )

Additional context
For reference, the classes described in #24 will be used. For mapping logic the TransactionRepository implementation will be used and filling out of data will be done as needed.

Android Multisig-app consuming API demo

Describe the solution you'd like
Write a version of the multisig android app that consumes the API for rendering the transactions list. The result should be presented as a link to a branch in the gnosis/safe-android repo .

Additional context
The android app, just like the iOS app, extensively maps the backend types into the domain types. This duplication is error prone. This will be a first PoC to establish the usefulness of the client gateway.

Clean up service

  • Check endpoint naming #47
  • Check project structure (e.g. modules)
  • Check warnings
  • Convert prints to logs #50

Nullable TokenInfo for Transfers

Describe the bug
We get a 500 when the TokenInfo struct is null in a Transfer struct from the backend.

To Reproduce
Steps to reproduce the behavior:

  • Load a 2nd page of data for the safe in the path displayed here: transactions/0x1230B3d59858296A31053C1b8562Ecf89A2f888b?next=limit%3D20%26offset%3D20

Expected behavior
We should return make TokenInfo nullable for Transfers as the /tokens/{address} endpoint probably won't contain these tokens anyhow.

Transactions list: The transaction status is changed with a big delay

Describe the bug
Status of the transaction is changed with the delay of more than 10 min from awaiting execution to execute.
The same was with changing statuses from awaiting confirmation to awaiting execution - the status was updated when the new transaction was created

To Reproduce
Steps to reproduce the behavior:

  1. Create a transaction in the safe with a few confirmation

  2. Open mobile app

  3. Check transactions list
    Current result: The transaction in the Queue appears

  4. Confirm transaction without executing

  5. Wait til the status is updated in the web app

  6. Refresh the page ( pull to refresh, switch safes, go to another page and come back, restart the app)
    Current result: The transaction status is not changed for a long time.

Expected behavior
The status on the client should be changed as soon as it's changed on the back-end

Desktop (please complete the following information):

  • OS: android
  • Version 0.2.0

Additional context
Add any other context about the problem here.

Add caching via redis

Tasks

  • Add redis to service
  • Add possibility to enable simple caching (set/ get cache by key with timeout)
  • Add possibility to invalidate cache (by key)

Successfully executed transaction has status Cancelled

Bug description
The successfully executed transaction ( it has status success in webapp and the receiver got the tokens) is marked as cancelled in the mobile app
"isExecuted": true,
"isSuccessful": true,
Steps To Reproduce

  1. Load safe with a few owners ( all owners or at least 2 of them should confirm transaction)
  2. Send funds in the web app in the same safe
  3. Confirm and execute the transaction

Current result:
The cancelled transaction appears in history. After page reloading, the cancelled transaction is replaced with successful with new execution time

Expected Result
It's confusing to see the same transaction with two different states.
Why cancelled transaction appears?

Screenshots
Look at a transaction with nonce 53 ( pay attantion to the date and time )
image.png
The same transaction in a few sec after page updating:
image.png

Device & App version

  • Device/OS: iPhone X/13.15.1
  • App version: 0.5.0 (61)

Additional info
(Optional)

Refactor extraction of params from DataDecoded

Currently it is quite tedious to extract params from DataDecode with fallbacks (e.g. to and _to). It would be nice to have a easy way to handle this.

Note

It should be safer to use the position of the argument rather than the name of the argument.

[Android] Some of the outgoing tx for ERC20, ERC721, ETH are displayed as custom tx

@liliya-soroka commented on Thu Aug 06 2020

Describe the bug
Custom transactions are displayed for some of the ERC20, ERC721, ETH outgoing tx
Actual for the transactions in waiting for confirmation and executed statuses

To Reproduce
Steps to reproduce the behavior:

ERC20 and ERC721:

  1. Go to the safe 0x1230B3d59858296A31053C1b8562Ecf89A2f888b
  2. Open transactions details
  3. Check txs with nonce 176,175,174

ETH:

  1. Go to the safe 0x938bae50a210b80EA233112800Cd5Bc2e7644300
  2. Open transactions details
  3. Check txs with 46

Expected behavior
If it's outgoing ERC20 or ERC721 tx it should be displayed as outgoing tx ( not custom)

Screenshots
in android app image.png

on web image.png

Smartphone (please complete the following information):

  • Device: Huawei P30
  • Android Version: 10
  • App Version 1.12.1-79

Additional context
Add any other context about the problem here.

Dockerize project

Tasks

  • Add docker support
  • Check requirements by devops for deployment

Notes

  • Configure redis (see #17)

Polymorphic DataDecoded -> Parameter crash

Describe the bug
Sometimes Parameters.value can be either a string or an array. The field is named the same, just the type changes.

"parameters": [
            {
                "name": "_owners",
                "type": "address[]",
                "value": [
                    "0x65F8236309e5A99Ff0d129d04E486EBCE20DC7B0",
                    "0xF2CeA96575d6b10f51d9aF3b10e3e4E5738aa6bd"
                ]
            },
            {
                "name": "_threshold",
                "type": "uint256",
                "value": "2"
            },
//...

To Reproduce

  • Add the data_decoded field to the CreationTransaction struct for the backend
  • Make a request to /safe/0x1230B3d59858296A31053C1b8562Ecf89A2f888b/creation to the transaction service, try deserialisation 🔥

Expected behaviour
The service should not crash and handle the case when Parameters have a flat value or a vector seamlessly.

Transaction domain types

Is your feature request related to a problem? Please describe.
The clients currently deserialise the polymorphic response from the /safe/{address}/all-transactions into Multisig, Module and Ethereum transactions. Then map each of those types into Transfer, Settings or Custom transaction types.

Describe the solution you'd like
Deserialization is already largely implemented. The domain types (Transfer, Settings and Custom) should be defined according to the needs of the apps.

Additional context
For reference, the domain transaction data layouts expected by Android are as follow:

sealed class Transaction {
    abstract val status: TransactionStatus

    // If status is Successful, Failed or Canceled, the confirmations can be null
    abstract val confirmations: Int?

    data class Custom(
        override val status: TransactionStatus,
        override val confirmations: Int?,
        val nonce: BigInteger?,
        val address: Solidity.Address,
        val dataSize: Long,
        val date: String?,
        val value: BigInteger
    ) : Transaction()

    data class SettingsChange(
        override val status: TransactionStatus,
        override val confirmations: Int?,
        val dataDecoded: DataDecodedDto,
        val date: String?,
        val nonce: BigInteger
    ) : Transaction()

    data class Transfer(
        override val status: TransactionStatus,
        override val confirmations: Int?,
        val recipient: Solidity.Address,
        val sender: Solidity.Address,
        val value: BigInteger,
        val date: String?,
        val tokenInfo: ServiceTokenInfo?,
        val nonce: BigInteger?
    ) : Transaction()
}

enum class TransactionStatus() {
    AwaitingConfirmations,
    AwaitingExecution,
    Cancelled,
    Failed,
    Success,
    Pending // Not supported yet as these correspond to the ones issued from the device
}

Refactor Multisig Transaction classification logic

Is your feature request related to a problem? Please describe.
Multisig Transaction classification is a bit confusing and could be refactored. Specifically, there is a token_info request on every classification, which doesn't make sense in 60% of the cases (in the unit tests we just mock it as an error reponse). These cases are Transfer::Ether, SettingsChange and Custom transaction.

Describe the solution you'd like
The solution should prevent unnecessary requests to the InfoProvider even though we have a cache, we are not able to distinguish an error that matters from an error that happens when the request doesn't make sense given the context.

Describe alternatives you've considered
Switching the order of checks so that we only request token information when we strictly need it. However, the order in which we check could matter. First, we should cover with unit tests before commencing this refactor.

Add `dataDecoded` to parameters in DataDecoded

Currently we only display name, type and value, but the transaction service also returns dataDecoded if it possible. This should be forwarded to the clients, so that they can display it.

TokenInfo fetching and caching for Multisig Transactions

Describe the solution you'd like
We need to fetch and cache the full list of tokens so that we can appropriately classify Transfer transactions and attach the required data to the response for correct rendering in the UI.

The token info can be found in the /tokens/ endpoint of the Safe Transaction service. Be mindful that the result is paginated (maybe we should set a large limit?)

This endpoint returns ERC20 and ERC721, we should later on serialise the data polymorphically to prevent excessive optionals in the apps. (ERC20, ERC721 and Ether would be the cases thus far).

Additional context
This is required, as currently the iOS app pre-fetches and caches the full list of tokens whereas the Android app simply looks at the dataDecoded field of the transaction and sometimes misinterprets the data. This information should be included in the Transfer object for Multisig transaction mapping #27

Update about endpoint

  • transaction service endpoint
  • name
  • version
  • (Optional) service version
  • (Optional) buildnumber or commit

Map ModuleTransaction into transaction domain types

Is your feature request related to a problem? Please describe.
Module transactions should be mapped (at least so far) only into Custom as defined in #24

Describe the solution you'd like
There should be a mechanism to detect and map any ModuleTransaction into a CustomTransaction

Additional context
For reference, the classes described in #24 will be used. For mapping logic the TransactionRepository implementation will be used and filling out of data will be done as needed.

Safe creation transaction

Is your feature request related to a problem? Please describe.
Currently, the safe creation transaction is available as a separate endpoint in the transaction service.
For example: https://safe-transaction.gnosis.io/api/v1/safes/0xA063Cb7CFd8E57c30c788A0572CBbf2129ae56B6/creation/

In order to integrate it into the transaction list on the client, the client app needs then to make additional request when the last page of the all-transactions is reached, and then augment the response with the response from the endpoint above.

Describe the solution you'd like
The solution would be to receive the safe creation transaction from the transactions response. If the creation endpoint response structure is preserved, then we need to augment it at least with a new "txType" for the creation transaction. Alternatively, if there's a way to format the response as another 'settings' transaction, that could also work.

Describe alternatives you've considered
Alternative: to request the creation transaction data from the client

Additional context
This appeared as part of working on requirements for the issue 5afe/safe#315

Handle pure safeTxHash in details endpoint

Currently the clients get push notifications that only contain the safeTxHash not the id generated by the client gateway. Therefore this should be possible to be used.

Casing mismatch of fields names for Erc20 and Erc721 TransferInfo structs

Describe the bug
TransferInfo structs serialise field names with lower case snake casing and the apps usually expect camel casing.

To Reproduce
call the transactions/{safe_address} endpoint and find an ERC20 transfer

Expected behavior
All field names should be camel cased and enums SCREAMING_SNAKE_CASED

Additional tests for "converters" module

Describe the solution you'd like
converters modules contain the core logic of the gateway and as such should be rigorously tested
This issue can be close when these issues are completed:

Describe alternatives you've considered
Test should be done against json taken from transaction service API

Additional context
There are tests also missing for the multisig case that should be addressed see #69

Map EthereumTransaction into transaction domain types

Is your feature request related to a problem? Please describe.
Ethereum transactions should be mapped (at least so far) only into Custom and Transfer transactions as defined in #24

Describe the solution you'd like
There should be a mechanism to detect and map any EthereumTransaction into a CustomTransaction and TransferTransaction.

The decision for each mapping is:

  • Is the EthereumTransaction list of transfers not empty? If so expand the list to contain one domain Transfer from #24 for each TransferDto coming from the backend
  • Is the EthereumTransaction list of transfers empty and data is not null or empty? then map into a CustomTransaction from #24
  • else -> Map into a domainTransferTransaction using the parent EthereumTransaction struct as the base for mapping.

Additional context
For reference, the classes described in #24 will be used. For mapping logic the TransactionRepository implementation will be used and filling out of data will be done as needed.

Renaming endpoints

Is your feature request related to a problem? Please describe.
The endpoints naming are not compliant with the standard.

Describe the solution you'd like
Endpoints should be renamed. Proposal:
/transactions/<safe_address>?<next> -> /v1/safes/<safe_address>/transactions?<next>
/transactions/<tx_hash> -> /v1/transactions/<tx_hash>
/transactions/about -> /about

Additional context
https://restfulapi.net/resource-naming/

Map "next" and "previous" URLs coming from the backend

Is your feature request related to a problem? Please describe.
Currently paged data returns the links provided by the backend as the next and previous links for pagination. This will direct the clients to the service we are trying to map from.

Describe the solution you'd like
We want to map these URLs so that we can process them in this service.

Additional context
https://github.com/rmeissner/safe-merc-service/blob/master/src/renderer/overview.rs#L44

Custom transaction is displayed instead of Change Mastercopy

Describe the bug
Custom transaction is displayed instead of Change Mastercopy when the contract version is updated in gnosis safe web app through settings
The same for ios

To Reproduce
Steps to reproduce the behavior:

  1. Load safe with old contact version ( change contract version from 1.1.1 to 1.0.0 - short instruction https://docs.google.com/spreadsheets/d/1J4bTGU3tute-DurP-v-YpV-3H59ptuIG0xSCC3Kl_1s/edit?usp=sharing )
  2. Go to the settings in the gnosis safe and press Update
  3. Go to the transactions in web app
  4. Contract upgrade tx is created on UI
  5. Check the same tx in the mobile app

Safe with wrong tx
0x1230B3d59858296A31053C1b8562Ecf89A2f888b
tx nonce 56

Expected behavior
Change Mastercopy transaction should be created if the mastercopy is upgraded to the new or downgraded

Smartphone (please complete the following information):

  • Device: Pixel 4
  • Android Version: 10
  • App Version 0.4.2- alpha-debug

Additional context
Add any other context about the problem here.

SafeInfo fetching and caching

Is your feature request related to a problem? Please describe.
The SafeInfo is required for calculating the status (according to #24 ). Particularly, the threshold and nonce are necessary to determine certain statuses.

Describe the solution you'd like
SafeInfo should be fetch from the /safe/{address} endpoint and cached.

Additional context
The class layout should look like in the swagger. Here is the Kotlin equivalent:

data class SafeInfo(
    val address: Solidity.Address,
    val nonce: BigInteger,
    val threshold: Int,
    val owners: List<Solidity.Address>,
    val masterCopy: Solidity.Address,
    val modules: List<Solidity.Address>,
    val fallbackHandler: Solidity.Address?
)

Emit certain Transfers as Custom TX

According to https://docs.google.com/document/d/1vhTu5NbB-6m8nE3cqTS3bRONigPO3NA5YkJqNTA6AOk/edit?skip_itp2_check=true a transfer that has the current safe as the tx initiator but neither to or from (row 10 in the table) , should be regarded as a custom transaction.

Here is an example:

{
      "safe": "0x938bae50a210b80EA233112800Cd5Bc2e7644300",
      "to": "0xc778417E063141139Fce010982780140Aa0cD5Ab",
      "value": "0",
      "data": "0x23b872dd0000000000000000000000001230b3d59858296a31053c1b8562ecf89a2f888b000000000000000000000000f2565317f3ae8ae9ea98e9fe1e7fadc77f823cbd00000000000000000000000000000000000000000000000000038d7ea4c68000",
      "operation": 0,
      "gasToken": "0x0000000000000000000000000000000000000000",
      "safeTxGas": 59217,
      "baseGas": 0,
      "gasPrice": "0",
      "refundReceiver": "0x0000000000000000000000000000000000000000",
      "nonce": 34,
      "executionDate": "2020-07-24T15:23:11Z",
      "submissionDate": "2020-07-24T15:23:11Z",
      "modified": "2020-07-24T15:23:11Z",
      "blockNumber": 6896576,
      "transactionHash": "0xc2ef20669265c7d448beb9f51d81c245dda735ae716888ab03e46b2eda16167f",
      "safeTxHash": "0x45228f489cdcf8b8fbf790ba959044ad69ab044d329b1dce0c0830329c7cfffb",
      "executor": "0xF2CeA96575d6b10f51d9aF3b10e3e4E5738aa6bd",
      "isExecuted": true,
      "isSuccessful": true,
      "ethGasPrice": "1000000000",
      "gasUsed": 79626,
      "fee": "79626000000000",
      "origin": null,
      "dataDecoded": {
        "method": "transferFrom",
        "parameters": [
          {
            "name": "from",
            "type": "address",
            "value": "0x1230B3d59858296A31053C1b8562Ecf89A2f888b"
          },
          {
            "name": "to",
            "type": "address",
            "value": "0xf2565317F3Ae8Ae9EA98E9Fe1e7FADC77F823cbD"
          },
          {
            "name": "value",
            "type": "uint256",
            "value": "1000000000000000"
          }
        ]
      },
      "confirmationsRequired": 1,
      "confirmations": [
        {
          "owner": "0xF2CeA96575d6b10f51d9aF3b10e3e4E5738aa6bd",
          "submissionDate": "2020-07-24T15:23:38.979651Z",
          "transactionHash": null,
          "confirmationType": "CONFIRMATION",
          "signature": "0x000000000000000000000000f2cea96575d6b10f51d9af3b10e3e4e5738aa6bd000000000000000000000000000000000000000000000000000000000000000001",
          "signatureType": "APPROVED_HASH"
        }
      ],
      "signatures": "0x000000000000000000000000f2cea96575d6b10f51d9af3b10e3e4e5738aa6bd000000000000000000000000000000000000000000000000000000000000000001",
      "transfers": [
        
      ],
      "txType": "MULTISIG_TRANSACTION"
    }

This can be found in a response to: https://safe-transaction.staging.gnosisdev.com/api/v1/safes/0x938bae50a210b80EA233112800Cd5Bc2e7644300/all-transactions/?limit=100

Look for "nonce":34

The mobile apps are supposed to treat this not as a transfer but as a Custom tx.
The gateway could emit this as a custom transfer.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.