Skip to content

Commit

Permalink
Merge updates from Development to Main (#238)
Browse files Browse the repository at this point in the history
* Add new chains to available services

* Add transaction service documentation
- add transaction service overview
- add documentation about off-chain signatures

* Add offchain messages section

* Add transactions decode section

* Apply suggestions from code review

Co-authored-by: Tanay Pant <[email protected]>

* Fix offchain typo

* Add blockchain indexing section

* Apply suggestions from code review

Co-authored-by: Uxío <[email protected]>

* Apply suggestions from code review

Co-authored-by: Tanay Pant <[email protected]>

* Add Vale for linting (#239)

* Add Vale for linting

* Add Vale for linting - remove alex

---------

Co-authored-by: Tanay Pant <tanaypantprotonmail.com>

* Update relay-kit to latest implementation (#229)

* Update relay-kit to latest version interface

* Update safe-core-sdk/relay-kit/gelato.md

Co-authored-by: Tanay Pant <[email protected]>

* Update safe-core-sdk/relay-kit/gelato.md

Co-authored-by: Tanay Pant <[email protected]>

* Update protocol-kit link

---------

Co-authored-by: Germán Martínez <[email protected]>
Co-authored-by: Tanay Pant <[email protected]>

* chore: Update protocol-kit/README content (#232)

* [Chore](protocol-kit/README) Update content

Update "Initialize Signers, Providers, and EthAdapter" section's code snippet to import dotenv/config.

* Update safe-core-sdk/protocol-kit/README.md

---------

Co-authored-by: Germán Martínez <[email protected]>

* Style updates and minor fixes (#240)

* Update README.md

* Update README.md

* Update README.md

* Update README.md

* Update modules.md

* Update guards.md

* Update bug-bounty-program.md

* Create past-paid-bounties.md

* Add custom vocabulary for Vale

* Update bug-bounty-program.md

---------

Co-authored-by: Tanay Pant <tanaypantprotonmail.com>

* Protocol style updates (#243)

* Update README.md

* Update accept.txt

* Update README.md

---------

Co-authored-by: moisses89 <[email protected]>
Co-authored-by: Uxío <[email protected]>
Co-authored-by: Daniel <[email protected]>
Co-authored-by: Germán Martínez <[email protected]>
Co-authored-by: Amos Wu <[email protected]>
  • Loading branch information
6 people authored Oct 11, 2023
1 parent 942e06f commit 8bff332
Show file tree
Hide file tree
Showing 69 changed files with 3,167 additions and 168 deletions.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
8 changes: 8 additions & 0 deletions .vale.ini
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
StylesPath = styles
MinAlertLevel = suggestion
Vocab = default
Packages = Microsoft, write-good

[*]
BasedOnStyles = Vale, Microsoft, write-good

15 changes: 15 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# Contributing

Thank you for contributing to the Safe docs. Before starting, please review the existing documentation to understand the structure and writing conventions.

We use the [Microsoft Style Guide](https://learn.microsoft.com/en-us/style-guide/welcome/) for the styles and [Vale](https://vale.sh/docs/) for linting. This combination helps us use the style guide effectively.

## Using Vale

Install the [Vale CLI](https://vale.sh/docs/vale-cli/installation/) and run the following command:

```
vale --glob='*.md' .
```

You can also use Vale as a plugin for your IDE.
36 changes: 8 additions & 28 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,54 +2,34 @@
description: Everything you need to know to start building on Safe.
---

# What is Safe?
# Safe

[Safe](https://safe.global) brings digital ownership of accounts to everyone by building universal and open contract standards for the custody of digital assets, data, and identity.

Safe is at the forefront of modular Smart Account infrastructure, paving the way for developers to create a diverse range of applications and wallets.
Safe is at the forefront of modular smart account infrastructure, paving the way for developers to create various applications and wallets.

Our brand is separated into three categories and it is important to differentiate each of them:
Safe{Core} consists of three components:

<figure><img src=".gitbook/assets/core-brands.png" width="100%" alt="" /></figure></figure>

## Safe{Core} Protocol

The [Safe{Core} Protocol](safe-core-protocol/README.md) is an open, modular framework to make smart accounts secure, portable, and composable.

This section in the documentation contains information and relevant links about the Safe{Core} Protocol, what it is and what are the different elements involved.
This section in the documentation has information and relevant links about the Safe{Core} Protocol and the different elements involved.

## Safe{Core} AA SDK

The [Safe{Core} AA SDK](safe-core-sdk/README.md) is a set of developer kits that allow integrating Safe with different external service providers to provide developers and users the ability to abstract the complexity that comes with operating a smart contract account.
The [Safe{Core} Account Abstraction SDK](safe-core-sdk/README.md) is a set of developer kits that help integrate Safe with different external service providers. The SDK offers developers the ability to abstract the complexity that comes with operating a smart contract account.

This section in the documentation contains relevant information and tutorials on what SDK Kits there are and how to integrate them.
This section in the documentation has relevant information and tutorials on the SDK kits and how to integrate them.

## Safe{Core} API

The [Safe{Core} API](safe-core-api/available-services.md) makes reference to all the Safe infrastructure needed to power interfaces with all Safe account related information. This includes the Safe Transaction Service, Safe Events Service, etc.

This section in the documentation contains information related with the services architecture.
This section in the documentation has information related to the services architecture.

## Reference

The [Reference](reference/safe-core-sdk/auth-kit/README.md) section in this documentation contains technical details describing the different tools available at Safe in detail.

<!---
## Getting started
Safe has a lot of features which means a lot of information. To make it easier to navigate, here is a step-by-step guide you can follow:
1. [Learn about Smart Accounts](learn/what-is-a-smart-contract-account.md)
- Make a Safe
- Learn about Account Abstraction
2. [Learn about the different Safe{Core} tools](learn/safe-core/)
3. [Discover](discover/) interesting projects that others have built using Smart Accounts
- [Safe Hackathon Guide and List of Hackathon Winners](https://safe-global.notion.site/Safe-Hackathon-Success-Guide-53d2fb3c29424b58b1c4407519a54930)
4. [Build](build/) your own apps using smart accounts
There is also available the [Safe Ecosystem Diagram](https://viewer.diagrams.net/index.html?tags=%7B%7D&target=blank&highlight=0000ff&edit=_blank&layers=1&nav=1&page-id=atRejJyS5DeNAtDboIeV&title=Safe%20Diagrams.drawio#Uhttps%3A%2F%2Fdrive.google.com%2Fuc%3Fid%3D1WcTgdHoQttJ0K_fV8mDg-RmDZRYGe3D-%26export%3Ddownload):
<figure><img src=".gitbook/assets/diagram-safe-ecosystem.png" width="100%" alt="" /></figure>
--->
The [Reference](reference/safe-core-sdk/auth-kit/README.md) section in this documentation has technical details describing the different tools available at Safe in detail.
2 changes: 2 additions & 0 deletions safe-core-api/available-services.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,5 @@ description: This pages provides an overview of the available services
| Goerli | [https://safe-transaction-goerli.safe.global](https://safe-transaction-goerli.safe.global/) |
| Optimism | [https://safe-transaction-optimism.safe.global](https://safe-transaction-optimism.safe.global/) |
| Polygon | [https://safe-transaction-polygon.safe.global](https://safe-transaction-polygon.safe.global/) |
| Polygon zkEVM | [https://safe-transaction-zkevm.safe.global](https://safe-transaction-zkevm.safe.global/) |
| zkSync Era Mainnet | [https://safe-transaction-zksync.safe.global](https://safe-transaction-zksync.safe.global/) |
219 changes: 219 additions & 0 deletions safe-core-api/safe-transaction-service.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,219 @@
# Safe Transaction Service
## Overview

Safe transaction service keeps track of transactions sent via Safe contracts. It indexes these transactions by using events (L2 chains) and tracing (L1 chains) mechanisms.

**Key Features:**

- [**Blockchain Indexing**](#blockchain-indexing): Executed transactions, configuration changes, ERC-20/721 transfers, and onchain confirmations are automatically indexed from the blockchain.
- [**Offchain transaction signatures**](#offchain-transaction-signatures): Transactions can be sent to the service, enabling offchain signature collection. This feature helps inform owners about pending transactions that are awaiting confirmation to be executed.
- [**Offchain messages**](#offchain-messages): The service can collect offchain signatures to confirm messages following [EIP-1271](https://eips.ethereum.org/EIPS/eip-1271).
- [**Transactions decode**](#transactions-decode): The service keeps getting source and ABIs from contracts that interact with Safe to decode these interactions.

**Technology Stack Overview**

Safe transaction service is a [Django](https://www.djangoproject.com/) app written in Python that follows a very common architecture:

- [Gunicorn](https://gunicorn.org/): A Python WSGI HTTP Server.
- [Celery](https://docs.celeryq.dev/en/stable/): A task queue with focus on real-time processing, while also supporting task scheduling. Safe transaction service currently has a scheduler (for periodic tasks), a worker indexer to consume and execute indexing tasks, and a contracts worker mainly to get metadata from contracts.
- [RabbitMQ](https://www.rabbitmq.com/): A distributed message broker system Celery uses to share messages between the scheduler, workers, and the Django application.
- [PostgreSQL](https://www.postgresql.org/): An open source object-relational database system.
- [Redis](https://redis.com/): An open source, in-memory data structure store that can be used as a database, cache, message broker, and streaming engine. It is used for caching by the Safe transaction service.
- [safe-eth-py](https://github.com/safe-global/safe-eth-py): A library to interact with Safe and blockchains.

<figure><img src="../.gitbook/assets/transaction_service_architecture.png" width="100%" alt="" /></figure>

## Blockchain Indexing
Safe transaction service can index automatically executed transactions, configuration changes, ERC-20/721 transfers, and onchain confirmations.
The indexer is running on `worker-indexer` by different periodic [tasks](https://github.com/safe-global/safe-transaction-service/blob/master/safe_transaction_service/history/tasks.py).

ERC-20 and ERC-721 are indexed using [eth_getLogs](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_getlogs) filtered by the Transfer topic `keccak('Transfer(address,address,uint256)')`.

Safe creation, executed transactions, configuration changes, and onchain confirmations are indexed differently depending on whether the chain is L1 or L2.

For L1 chains, the indexer calls tracing methods. For the oldest blocks, [trace_filter](https://openethereum.github.io/JSONRPC-trace-module#trace_filter) is used filtering by singleton address of Safe contracts, and for the latest blocks [trace_block](https://openethereum.github.io/JSONRPC-trace-module#trace_block) is used, as `trace_filter` takes longer to return updated information. `trace_block` will be used if the block depth is lower than `ETH_INTERNAL_TXS_NUMBER_TRACE_BLOCKS`. The environment variables indexing uses are defined [here](https://github.com/safe-global/safe-transaction-service/blob/master/config/settings/base.py#L433).

For L2 chains, the indexing is by events with the [eth_getLogs](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_getlogs) method with the corresponding topics.

From Safe creation, the transaction service stores each contract change on the `SafeStatus` model as `nonce`, `owners`, etc. The latest and current status of a Safe is stored as `SafeLastStatus` for easy database access and optimization.

The following endpoints let us know the current indexing status of the Safe transaction service:
- `/v1/about/indexing/`

Response example:
```json
{
"currentBlockNumber": 9773327, // Last block on blockchain
"erc20BlockNumber": 9773326, // Last block indexed for erc20/721 events
"erc20Synced": true,
"masterCopiesBlockNumber": 9773327, // Last block indexed for executed transactions, ether transfers, configuration changes, etc.
"masterCopiesSynced": true,
"synced": true
}
```

### Reorgs handling
Every block is marked as `not confirmed` during indexing unless it has some depth (configured via the `ETH_REORG_BLOCKS` environment variable). Unconfirmed blocks are checked periodically to see if the blockchain `blockHash` for that number changed before it reaches the desired number of confirmations. If that's the case, all blocks from that block and related transactions are deleted, and indexing is restarted to the last confirmed block.

**Note:** No offchain signatures, transactions, or messages are lost in this process. Only onchain data is removed.

## Offchain Transaction Signatures
Safe Transaction Service can collect offchain transaction signatures, allowing the owners to share their signatures to reach the required threshold before executing a transaction and spending less gas than onchain approvals.

The following endpoints let us propose a transaction and collect every confirmation (offchain signatures):

- `POST /v1/safes/{address}/multisig-transactions/`: Create a new transaction. At least one signature is required.
- `POST /v1/multisig-transactions/{safe_tx_hash}/confirmations/`: Add a new confirmation. The `safe_tx_hash` is needed.
- `GET /v1/multisig-transactions/{safe_tx_hash}/`: Return all the multisig transaction information.
- `GET /v1/multisig-transactions/{safe_tx_hash}/confirmations/`: Return the list of all confirmations to a multisig transaction.

The following sequence diagram shows a use case for a Safe shared by Alice and Bob where at least one confirmation for each one is required:
``` mermaid
sequenceDiagram
participant A as Alice
participant B as Bob
A->>+SafeTransactionService: proposeTransaction POST /v1/safes/0x5Afe/multisig-transactions/
SafeTransactionService-->>-A: Http(201) {Created}
B->>+SafeTransactionService: GET /v1/safes/0x5Afe/multisig-transactions/?executed=false
SafeTransactionService-->>-B: Http(200) {..."safeTxHash":"0x5afe0001"}
B->>+SafeTransactionService: confirmTransaction POST /v1/multisig-transactions/0x5afe0001/confirmations/
SafeTransactionService->>-B: Http(201) {Created}
```
**What is the safe_tx_hash?**

`safe_tx_hash` is the unique identifier for a Safe transaction and is calculated using the [EIP-712](https://eips.ethereum.org/EIPS/eip-712) standard:
`keccak256(0x19 || 0x1 || domainSeparator || safeTxHashStruct)`
where `safeTxHashStruct` is the hashStruct of a Safe transaction.

The following example shows how to get a `safe_tx_hash` with [safe-eth-py](https://pypi.org/project/safe-eth-py/) with the parameter of the next transaction [0x34ae46cf7d884309a438a7e9a3161fa05dfc5068681ac3877a947971af845a18](https://safe-transaction-goerli.safe.global/api/v1/multisig-transactions/0x34ae46cf7d884309a438a7e9a3161fa05dfc5068681ac3877a947971af845a18/)
```python
from gnosis.safe.safe_tx import SafeTx
from gnosis.eth.ethereum_client import EthereumClient
eth_client = EthereumClient("https://rpc.goerli.eth.gateway.fm")
safe_tx = SafeTx(eth_client, "0x4127839cdf4F73d9fC9a2C2861d8d1799e9DF40C", "0xc6b82bA149CFA113f8f48d5E3b1F78e933e16DfD",10000000000000000,"",0,0,0,0,"0x0000000000000000000000000000000000000000","0x0000000000000000000000000000000000000000", safe_nonce=206)
print(safe_tx.safe_tx_hash.hex())
```
**Output**
```
0x34ae46cf7d884309a438a7e9a3161fa05dfc5068681ac3877a947971af845a18
```

## Offchain Messages
Safe transaction service can collect the necessary offchain signatures to confirm a message using [EIP-1271](https://ethereum.org/pt/developers/tutorials/eip-1271-smart-contract-signatures/#example-eip-1271-implementation-safe).
The message can be a string (EIP-191 is used to get the hash) or an object EIP-712.

**Messages endpoints**
- `GET /v1/safes/{address}/messages/`: Return the messages created for the given Safe address.
- `POST /v1/safes/{address}/messages/`: Create a message with at least one signature.
- `GET /v1/messages/{message_hash}/`: Return a message for a given message hash.
- `POST /v1/messages/{message_hash}/signatures/`: Add another signature to the message with the given message hash.

The following sequence diagram shows a use case for a Safe shared by Alice and Bob where at least one signature for each one is required to confirm a message fully:
``` mermaid
sequenceDiagram
participant A as Alice
participant B as Bob
A-->A: Prepare message and sign message_hash
A->>+SafeTransactionService: createMessage POST /v1/safes/0x5Afe/messages/
SafeTransactionService-->>-A: Http(201) {Created}
B-->B: Sign message_hash
B->>+SafeTransactionService: addConfirmation POST /v1/messages/{message_hash}/signatures/
SafeTransactionService-->>-B: Http(200)
```
**Message string example**
**Python**
safe-eth-py is required for this example.
```python
from gnosis.eth.ethereum_client import EthereumClient
from gnosis.safe.safe import Safe
from eth_account.messages import defunct_hash_message
from eth_account import Account
import requests

alice = Account.from_key("Alice_key")

# Message that we want to confirm
message = "Hello SafeMessages"
# Hash EIP-191
message_hash = defunct_hash_message(text=message)
# get message hash from safe
eth_client = EthereumClient("https://rpc.goerli.eth.gateway.fm")
safe_address = "TheAliceAndBobSafeAddress"
safe = Safe(safe_address, eth_client)
safe_message_hash = safe.get_message_hash(message_hash)

# Alice is going to create the message on safe transaction service
# First sign the safe_message_hash
signature_alice = alice.signHash(safe_message_hash)

# Create the request
body = {
"message": message,
"safeAppId": 0,
"signature": signature_alice.signature.hex()
}
requests.post(f'https://safe-transaction-goerli.safe.global/api/v1/safes/{safe_address}/messages/',json=body)

# Message was created, let's request by message hash
response = requests.get(f'https://safe-transaction-goerli.safe.global/api/v1/messages/{safe_message_hash.hex()}/')
print(response.json())

# Adding Bob confirmation
bob = Account.from_key("Bob_key")
signature_bob = bob.signHash(safe_message_hash)

# Create the request
body = {
"signature": signature_bob.signature.hex()
}
requests.post(f'https://safe-transaction-goerli.safe.global/api/v1/messages/{safe_message_hash.hex()}/signatures/',json=body)

```

## Transaction Decoder
The Safe transaction service can decode contract interactions. To achieve it, the service periodically gets source and ABIs from different sources like Sourcify, etherscan, and blockscout using the `safe-eth-py` library.
The detection of contract interactions is done in a periodic task executed every hour for `multisig-transaction` and `module-transactions` or every six hours for `multisend-transactions` on `worker-contracts-tokens`.
For every new contract, the service tries to download the source, and the ABI requests it first to Sourcify, then Etherscan, and as a last chance, Blockscout. It's important to know that not all these data sources are supported or configured for every network on `safe-eth-py`.
Supported and configured networks on `safe-eth-py`:
- [**Sourcify** supported networks](https://docs.sourcify.dev/docs/chains/)
- [**Etherscan** configured networks](https://github.com/safe-global/safe-eth-py/blob/master/gnosis/eth/clients/etherscan_client.py#L24)
- [**Blockscout** configured networks](https://github.com/safe-global/safe-eth-py/blob/master/gnosis/eth/clients/blockscout_client.py#L21)


**Transaction decoder endpoint**
- `POST /v1/data-decoder/` decode a transaction `data` passed on body for a `to` contract address.



**Example transaction decoder**
```bash
curl -X 'POST' \
'https://safe-transaction-goerli.safe.global/api/v1/data-decoder/' \
-H 'accept: application/json' \
-H 'Content-Type: application/json' \
-H 'X-CSRFToken: Gx1aRa8kIJGIAfReLAWwr9Q6dHv22dFt7VprdipLryHcxpfhk9aV0UDAhNz8gGYz' \
-d '{
"data": "0x095ea7b3000000000000000000000000e6fc577e87f7c977c4393300417dcc592d90acf8ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
"to": "0x4127839cdf4F73d9fC9a2C2861d8d1799e9DF40C"
}'
```
Output:
```
{
"method": "approve",
"parameters": [
{
"name": "spender",
"type": "address",
"value": "0xe6fC577E87F7c977c4393300417dCC592D90acF8"
},
{
"name": "value",
"type": "uint256",
"value": "115792089237316195423570985008687907853269984665640564039457584007913129639935"
}
]
}
```

This decoded data is also included as `dataDecoded` in `GET` of `multisig-transactions`, `module-transactions` and `all-transactions` endpoints.
Loading

0 comments on commit 8bff332

Please sign in to comment.