-
Notifications
You must be signed in to change notification settings - Fork 4
Transaction app types and mapping from json to UI layer
-
Transaction DTO (backend)
-
Data layer mapping: (https://github.com/gnosis/safe/issues/324)
The following was taken directly from the issue #324. As mentioned in the feedback, the clients should not implement as of this writing, the "Backup Plan".
For now, we ignore this type of transaction and not show it in the user interface.
These are external transactions and they are already executed.
For each such transaction, we look into a tx.transfers
array.
if transfers is not empty
each transfer is a new UI cell
if transfers is empty or null
if data is not nulll
then it is custom transaction
else data is null,
so it is ETH transfer.
"tx.value" can be null or absent - then treat it as 0.
Each transfer represents a separate user interface row in the transaction list. A transfer may be incoming, or outgoing - you need to see at the transfer.to
and transfer.from
addresses and see if one of them is a tx.safe
address.
transfer.to
is a recipient address, and transfer.from
is a sender address of that transfer.
These are transactions originating from the user's safe. Each such transaction is represented by a single row in a transactions list user interface.
They include transactions that are already executed (tx.isExecuted
is true
), transactions that were not executed (isExecuted
is false) but superseeded by other executed transactions (we call them cancelled transactions), and transactions that are not yet executed.
Due to the technical details of the working with the blockchain data structures, for now, we must not rely on the transfers
array that we get in the transaction object, but rather classify the transaction to one of the user interface types based on the transaction's properties.
That is, we ignore the tx.transfers
for the transactions with tx.type MULTISIG_TRANSACTION
All conditions must be met:
tx.data == null
tx.operation == 0
tx.value == any
These will be ether transfers. The tx.to
is recipient, the tx.safe
is sender.
In all other cases the tx.data
is not null
, it is present.
The data is a hex-string serialized binary data. If the data is present, we expect backend to also provide the tx.dataDecoded
object with the details of the method call that this transaction is invoking.
if tx.dataDecoded == null
or empty, then the transaction is Custom transaction
All conditions must be met:
tx.to == safe address
tx.operation == 0
tx.dataDecoded.method is one of:
changeMasterCopy
setFallbackHandler
addOwnerWithThreshold
removeOwner
swapOwner
changeThreshold
enableModule
disableModule
Every interaction with the aforementioned methods of the Safe smart contract requires the smart contract itself to execute it, that is why we check that the tx.to
is the tx.safe
itself.
All conditions must be met:
tx.operation == 0
tx.contractInfo.type == "ERC20"
tx.dataDecoded.method is one of:
transfer
transferFrom
If the tx.contractInfo
is not present, treat the transaction as Custom transaction
Because this is an etherum transaction directed at the token smart contract, the tx.to
will be the token contract's address, and not the recipient of tokens.
To get the recipient of tokens, as well as amount transferred, you need to look at the parameters of the methods.
function transfer(address _to, uint256 _value) public returns (bool success)
For this method, the tx.safe
is the sender, the _to
parameter address is the recipient, and the _value
is the amount of tokens.
To get the information about the token's symbol
, decimals
, name
, etc. we look at the tx.contractInfo
object.
function transferFrom(address _from, address _to, uint256 _value) public returns (bool success)
For this method, the _from
parameter address is the sender, the _to
parameter address is the recipient, and the value
is the amount in the token's basic units.
To get the information about the token's symbol
, decimals
, name
, etc. we look at the tx.contractInfo
object.
All conditions must be met:
tx.operation == 0
tx.contractInfo.type == "ERC721"
tx.dataDecoded.method is one of:
safeTransferFrom
transferFrom
If the tx.contractInfo
is not present, treat the transaction as Custom transaction
function safeTransferFrom(address _from, address _to, uint256 _tokenId, bytes data) external payable;
function safeTransferFrom(address _from, address _to, uint256 _tokenId) external payable;
function transferFrom(address _from, address _to, uint256 _tokenId) external payable;
There are 3 possible methods. For each of them, the _from
parameter is sender, the _to
is recipient, the amount is 1, since this transfers only 1 token with specific _tokenId
.
Everything else is treated as a Custom transaction.
The tx.to
is recipient, the tx.data
is the data sent along with the transaction, the tx.value
is ETH value transferred with the transaction (can be positive number).
-
UI layer mapping: (each type is grouped by queued/history)
-
Transfer
- transfer direction:
if(Transfer.recipient == currentSafe) Incoming else Outgoing
- transfer direction:
-
SettingsChange
-
methodName = SettingsChange.dataDecoded.method
, define human readable assets for each method insettingMethodNames = ["setFallbackHandler", "addOwnerWithThreshold", "removeOwner", "swapOwner", "changeThreshold", "changeMasterCopy", "enableModule", "disableModule"]
-
-
ChangeMasterCopy (specification of SettingsChange)
-
SettingsChange.dataDecoded.method == "changeMasterCopy"
, get version name string from hardcoded asset (SettingsChange.dataDecoded.params[0].value)
-
-
Custom
- n/a
-
precondition: Safe info needs to be available. Should be fetched on the first page of transaction data and re-triggered on user refresh:
- queued = status is one of {pending, waitingForConfirmation, waitingFroExecution} sorted by nonce ascending, creation date descending. NOTE: since these are outgoing transactions, they must have nonce.
- Pending: Submitted from device, therefore not supported yet
- WaitingForConfirmation
- condition:
transactionDto.isExecuted != true && transactionDto.nonce >= safe.nonce && transactionDto.confirmations.size < safe.threshold
- WaitingForExecution
- condition:
transactionDto.isExecuted != true && transactionDto.nonce >= safe.nonce && transactionDto.confirmations.size >= safe.threshold
- history = status is one of {success, failed, cancelled} sorted by execution date (if null, then created date), descending
- Success
- condition:
transactionDto.isExecuted == true && transactionDto.isSuccessful == true
- Failed
- condition:
transactionDto.isExecuted == true && transactionDto.isSuccessful != true
- Cancelled
- condition:
transactionDto.isExecuted != true && transactionDto.nonce < safe.nonce
-
Pagination No dodgy business
-
Backend Assumptions: transfers - logical transfers inferred from the transaction
-
ETHER_TRANSFER
: ETH is transferred (data = null) -
ERC20_TRANSFER
: some token -
ERC721_TRANSFER
: some other token -
UNKNOWN
: might be a sh*t token