diff --git a/.gitignore b/.gitignore index 01827d765..eba7e40ee 100644 --- a/.gitignore +++ b/.gitignore @@ -16,3 +16,5 @@ dump.rdb **/venv + +*.DS_Store* diff --git a/scripts/generate_docs.sh b/scripts/generate_docs.sh new file mode 100755 index 000000000..5f76ba80e --- /dev/null +++ b/scripts/generate_docs.sh @@ -0,0 +1,7 @@ +#!/bin/bash + +rm -rf ./target/doc + +cargo doc --no-deps \ + --workspace \ + --open # TODO: remove diff --git a/src/macros.rs b/src/macros.rs index 7a35082a6..f48ae6a7c 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -34,6 +34,7 @@ macro_rules! bail { }; } +#[doc(hidden)] #[macro_export] macro_rules! api_error { ($msg:literal $(,)?) => { @@ -47,6 +48,7 @@ macro_rules! api_error { }; } +#[doc(hidden)] #[macro_export] macro_rules! client_error { ($status_code:expr, $message:expr) => { diff --git a/src/main.rs b/src/main.rs index 597cba962..b5b0813aa 100644 --- a/src/main.rs +++ b/src/main.rs @@ -12,16 +12,33 @@ extern crate rocket_contrib; extern crate dotenv; +#[doc(hidden)] #[macro_use] pub mod macros; +#[doc(hidden)] mod cache; +#[doc(hidden)] mod config; + +/// Models exposed by this service +/// +/// *Important:* Names, Enums and Polymorphism +/// +/// Every field in the structs that you will see in this documentation is **camelCased** on serialisation. +/// +/// Enums are **SCREAMING_SNAKE_CASED** on serialization and the variant is always put into a `type` json field for polymorphic cases. mod models; +#[doc(hidden)] mod monitoring; +#[doc(hidden)] mod providers; + +/// Collection of all endpoints all endpoints mod routes; +#[doc(hidden)] mod services; +#[doc(hidden)] mod utils; #[cfg(test)] @@ -34,6 +51,7 @@ use routes::active_routes; use std::time::Duration; use utils::cors::CORS; +#[doc(hidden)] #[launch] fn rocket() -> _ { dotenv().ok(); diff --git a/src/models/mod.rs b/src/models/mod.rs index e7a3d2c7f..c6b81dd2a 100644 --- a/src/models/mod.rs +++ b/src/models/mod.rs @@ -1,5 +1,7 @@ +#[doc(hidden)] pub mod backend; pub mod commons; +#[doc(hidden)] pub mod converters; pub mod service; diff --git a/src/models/service/about.rs b/src/models/service/about.rs index 087b07dbe..d905e7742 100644 --- a/src/models/service/about.rs +++ b/src/models/service/about.rs @@ -1,10 +1,28 @@ use serde::Serialize; +/// About +/// +///
+/// Sample +/// +/// ```json +/// { +/// "transactionServiceBaseUrl": "https://safe-transaction.staging.gnosisdev.com/api/v1", +/// "name": "safe-client-gateway", +/// "version": "0.2.0-9-g17dcd40", +/// "buildNumber": "48" +/// } +/// ``` +///
#[derive(Serialize, Debug)] #[serde(rename_all = "camelCase")] pub struct About { + /// base URL string used for backend requests pub transaction_service_base_url: String, + /// crate name pub name: String, + /// env variable `VERSION`, defaults to crate version pub version: String, + /// Build number from github action pub build_number: Option, } diff --git a/src/models/service/balances.rs b/src/models/service/balances.rs index 6fe01ed88..4207be3b7 100644 --- a/src/models/service/balances.rs +++ b/src/models/service/balances.rs @@ -13,6 +13,8 @@ pub struct Balance { #[derive(Serialize, Debug, PartialEq)] #[serde(rename_all = "camelCase")] pub struct Balances { + /// Aggregated fiat balance pub fiat_total: String, + /// Individual [Balance] entries for each ERC20 in the Safe pub items: Vec, } diff --git a/src/models/service/transactions/details.rs b/src/models/service/transactions/details.rs index 4598f0901..cc852084d 100644 --- a/src/models/service/transactions/details.rs +++ b/src/models/service/transactions/details.rs @@ -4,6 +4,129 @@ use crate::providers::info::{SafeAppInfo, TokenInfo}; use serde::Serialize; use std::collections::HashMap; +/// Top level object returned by the `/v1/transactions/` endpoint +/// +///
+/// Sample 1: Multisig Transaction awaiting confirmation +/// +/// ```json +/// { +/// "executedAt": null, +/// "txStatus": "AWAITING_CONFIRMATIONS", +/// "txInfo": { +/// "type": "SettingsChange", +/// "dataDecoded": { +/// "method": "changeThreshold", +/// "parameters": [ +/// { +/// "name": "_threshold", +/// "type": "uint256", +/// "value": "2" +/// } +/// ] +/// } +/// }, +/// "txData": { +/// "hexData": "0x694e80c30000000000000000000000000000000000000000000000000000000000000002", +/// "dataDecoded": { +/// "method": "changeThreshold", +/// "parameters": [ +/// { +/// "name": "_threshold", +/// "type": "uint256", +/// "value": "2" +/// } +/// ] +/// }, +/// "to": "0x1230B3d59858296A31053C1b8562Ecf89A2f888b", +/// "value": "0", +/// "operation": 0 +/// }, +/// "detailedExecutionInfo": { +/// "type": "MULTISIG", +/// "submittedAt": 1596792600322, +/// "nonce": 180, +/// "safeTxHash": "0x0ef685fb7984d7314c1368497e1b0c73016066bec41f966d32f18354b88fbd46", +/// "signers": [ +/// "0xBEA2F9227230976d2813a2f8b922c22bE1DE1B23", +/// "0x37e9F140A9Df5DCBc783C6c220660a4E15CBFe72", +/// "0xA3DAa0d9Ae02dAA17a664c232aDa1B739eF5ae8D", +/// "0xF2CeA96575d6b10f51d9aF3b10e3e4E5738aa6bd", +/// "0x65F8236309e5A99Ff0d129d04E486EBCE20DC7B0" +/// ], +/// "confirmationsRequired": 3, +/// "confirmations": [ +/// { +/// "signer": "0xBEA2F9227230976d2813a2f8b922c22bE1DE1B23", +/// "signature": "0x1b01f3d79a50576e82d1da31810c0313bed9b76b016e1d9c6216512b2c7e53bb70df8163e568ca8ec1b8c7e7ef0a8db52d6ab2b7f47dc51c31729dd064ce375b1c" +/// } +/// ] +/// }, +/// "txHash": null +/// } +/// ``` +///
+/// +/// +///
+/// Sample 2: Ethereum transaction +/// +/// ```json +/// { +/// "executedAt": 1596719563000, +/// "txStatus": "SUCCESS", +/// "txInfo": { +/// "type": "Transfer", +/// "sender": "0x938bae50a210b80EA233112800Cd5Bc2e7644300", +/// "recipient": "0x1230B3d59858296A31053C1b8562Ecf89A2f888b", +/// "direction": "INCOMING", +/// "transferInfo": { +/// "type": "ETHER", +/// "value": "50000000000000" +/// } +/// }, +/// "txData": null, +/// "detailedExecutionInfo": null, +/// "txHash": "0x70b3c7f81a49f270fe86673f6c08beecfee384a89ef8b0869e46584905d4ecc2" +/// } +/// ``` +///
+/// +/// +///
+/// Sample 3: Settings change +/// +/// ```json +/// { +/// "id": "multisig_0x57d94fe21bbee8f6646c420ee23126cd1ba1b9a53a6c9b10099a043da8f32eea", +/// "timestamp": 1595429831000, +/// "txStatus": "SUCCESS", +/// "txInfo": { +/// "type": "SettingsChange", +/// "dataDecoded": { +/// "method": "addOwnerWithThreshold", +/// "parameters": [ +/// { +/// "name": "owner", +/// "type": "address", +/// "value": "0xA3DAa0d9Ae02dAA17a664c232aDa1B739eF5ae8D" +/// }, +/// { +/// "name": "_threshold", +/// "type": "uint256", +/// "value": "2" +/// } +/// ] +/// } +/// }, +/// "executionInfo": { +/// "nonce": 135, +/// "confirmationsRequired": 2, +/// "confirmationsSubmitted": 2 +/// } +/// } +/// ``` +///
#[derive(Serialize, Debug, PartialEq)] #[serde(rename_all = "camelCase")] pub struct TransactionDetails { diff --git a/src/models/service/transactions/requests.rs b/src/models/service/transactions/requests.rs index 842f8a875..623bc35be 100644 --- a/src/models/service/transactions/requests.rs +++ b/src/models/service/transactions/requests.rs @@ -7,6 +7,29 @@ pub struct ConfirmationRequest { pub signed_safe_tx_hash: String, } +/// MultisigTransactionRequest +/// +///
+/// Example body of MultisigTransactionRequest for submitting a Cancellation Transaction +/// +/// ```json +/// { +/// "to": "0xBe8C10Dbf4c6148f9834C56C3331f8191f355552", +/// "value": "0", +/// "data": "0x", +/// "nonce": "39", +/// "operation": 0, +/// "safeTxGas": "0", +/// "baseGas": "0", +/// "gasPrice": "0", +/// "gasToken": "0x0000000000000000000000000000000000000000", +/// "refundReceiver": "0x0000000000000000000000000000000000000000", +/// "safeTxHash": "61b0acaeae49e74306536c3371cd80bb46aeb5732859b6ffd776ad24e2d57f8e", +/// "sender": "0xBe8C10Dbf4c6148f9834C56C3331f8191f355552", +/// "signature": "a519dd9aa226a5f6f1816035af85d43d834c3284912574bef0c04aaff1f21004602a5339da424cf53de9aac068f67a3417f3cba40e3049637ae901b6f345b4ac1b" +/// } +/// ``` +///
#[derive(Serialize, Deserialize, Debug, PartialEq)] #[serde(rename_all = "camelCase")] pub struct MultisigTransactionRequest { diff --git a/src/models/service/transactions/summary.rs b/src/models/service/transactions/summary.rs index 8c4d72307..8771d932b 100644 --- a/src/models/service/transactions/summary.rs +++ b/src/models/service/transactions/summary.rs @@ -2,6 +2,129 @@ use super::*; use crate::providers::info::SafeAppInfo; use serde::Serialize; +///TransactionSummary - object returned for [TransactionListItem::Transaction] +/// +///
+/// Sample 1: History of executed transactions with date labels per day +/// +/// ```json +/// { +/// "next": null, +/// "previous": null, +/// "results": [ +/// { +/// "type": "DATE_LABEL", +/// "timestamp": 1604620800000 +/// }, +/// { +/// "type": "TRANSACTION", +/// "transaction": { +/// "id": "multisig_0x126ab4d9e87b5cba98Ddeb75Df703E83500b6B7f_0x28b4cc29c036c2df40a1ba8d684cdab736abaf7d5cb84b217428462a2b4e3318", +/// "timestamp": 1604700419000, +/// "txStatus": "SUCCESS", +/// "txInfo": { +/// "type": "Custom", +/// "to": "0x8D29bE29923b68abfDD21e541b9374737B49cdAD", +/// "dataSize": "580", +/// "value": "0", +/// "methodName": "multiSend" +/// }, +/// "executionInfo": { +/// "nonce": 2, +/// "confirmationsRequired": 1, +/// "confirmationsSubmitted": 1 +/// } +/// }, +/// "conflictType": "None" +/// }, +/// { +/// "type": "TRANSACTION", +/// "transaction": { +/// "id": "multisig_0x126ab4d9e87b5cba98Ddeb75Df703E83500b6B7f_0x2729fd437ad8f523ea0b8ca7f46401de38fc96cd62f6a0b07ac5637c4c195f3b", +/// "timestamp": 1604684216000, +/// "txStatus": "SUCCESS", +/// "txInfo": { +/// "type": "Custom", +/// "to": "0x8D29bE29923b68abfDD21e541b9374737B49cdAD", +/// "dataSize": "580", +/// "value": "0", +/// "methodName": "multiSend" +/// }, +/// "executionInfo": { +/// "nonce": 1, +/// "confirmationsRequired": 1, +/// "confirmationsSubmitted": 1 +/// } +/// }, +/// "conflictType": "None" +/// }, +/// { +/// "type": "DATE_LABEL", +/// "timestamp": 1604448000000 +/// }, +/// { +/// "type": "TRANSACTION", +/// "transaction": { +/// "id": "multisig_0x126ab4d9e87b5cba98Ddeb75Df703E83500b6B7f_0xb487741c687a81496034b08d7e6d94986cbae38dc6ebd2aa8e547cb8f8542cc0", +/// "timestamp": 1604533603000, +/// "txStatus": "SUCCESS", +/// "txInfo": { +/// "type": "Custom", +/// "to": "0x8D29bE29923b68abfDD21e541b9374737B49cdAD", +/// "dataSize": "260", +/// "value": "0", +/// "methodName": "multiSend" +/// }, +/// "executionInfo": { +/// "nonce": 0, +/// "confirmationsRequired": 1, +/// "confirmationsSubmitted": 1 +/// } +/// }, +/// "conflictType": "None" +/// }, +/// { +/// "type": "TRANSACTION", +/// "transaction": { +/// "id": "ethereum_0x126ab4d9e87b5cba98Ddeb75Df703E83500b6B7f_0x7e95b9df8b1c1385665d0bccfbd5d6f913e18915750395d84dd490c7d9be9940_0xbf9e8a462afc9675", +/// "timestamp": 1604531696000, +/// "txStatus": "SUCCESS", +/// "txInfo": { +/// "type": "Transfer", +/// "sender": "0x05c85Ab5B09Eb8A55020d72daf6091E04e264af9", +/// "recipient": "0x126ab4d9e87b5cba98Ddeb75Df703E83500b6B7f", +/// "direction": "INCOMING", +/// "transferInfo": { +/// "type": "ETHER", +/// "value": "100000000000000000" +/// } +/// }, +/// "executionInfo": null +/// }, +/// "conflictType": "None" +/// }, +/// { +/// "type": "TRANSACTION", +/// "transaction": { +/// "id": "creation_0x126ab4d9e87b5cba98Ddeb75Df703E83500b6B7f", +/// "timestamp": 1604531396000, +/// "txStatus": "SUCCESS", +/// "txInfo": { +/// "type": "Creation", +/// "creator": "0x05c85Ab5B09Eb8A55020d72daf6091E04e264af9", +/// "transactionHash": "0xbfe5f021d0cfaf98ec445f757802be9e86b818301e2d892bcf3a9ee5e688d37f", +/// "implementation": "0x34CfAC646f301356fAa8B21e94227e3583Fe3F5F", +/// "factory": "0x76E2cFc1F5Fa8F6a5b3fC4c8F4788F0116861F9B" +/// }, +/// "executionInfo": null +/// }, +/// "conflictType": "None" +/// } +/// ] +/// } +/// ``` +/// +///
#[derive(Serialize, Debug, PartialEq)] #[serde(rename_all = "camelCase")] pub struct TransactionSummary { diff --git a/src/routes/about.rs b/src/routes/about.rs index cea97e9ca..605fe6adf 100644 --- a/src/routes/about.rs +++ b/src/routes/about.rs @@ -7,6 +7,22 @@ use crate::utils::context::Context; use crate::utils::errors::ApiResult; use rocket::response::content; +/** + * `/about`
+ * Returns [About](crate::models::service::about::About) + * + * # About + * + * The about endpoint provides information of the environmental variables set for the instance of `safe-client-gateway`. This would allow to identify on which commit and version the last deployment happened and to which safe transaction service backend environment the current instance of the gateway is pointing to. + * + * ## Path + * + * `/about` + * + * ## Query parameters + * + * There are no query parameters for this endpoint + */ #[get("/about")] pub async fn info(context: Context<'_>) -> ApiResult> { CacheResponse::new(context.uri()) @@ -16,6 +32,7 @@ pub async fn info(context: Context<'_>) -> ApiResult> { .await } +#[doc(hidden)] #[get("/about/backbone")] pub async fn backbone(context: Context<'_>) -> ApiResult> { let url = format!("{}/v1/about/", base_transaction_service_url()); @@ -24,6 +41,7 @@ pub async fn backbone(context: Context<'_>) -> ApiResult> )) } +#[doc(hidden)] #[get("/about/redis/")] pub fn redis(context: Context<'_>, token: String) -> ApiResult { if token != webhook_token() { diff --git a/src/routes/balances.rs b/src/routes/balances.rs index 5e4444ffc..482c22160 100644 --- a/src/routes/balances.rs +++ b/src/routes/balances.rs @@ -5,6 +5,27 @@ use crate::utils::context::Context; use crate::utils::errors::ApiResult; use rocket::response::content; +/** + * `/v1/safes//balances/?&`
+ * Returns [Balances](crate::models::service::balances::Balances) + * + * # Balances + * + * This endpoint returns the [crate::models::service::balances::Balances] with information (when available) of their converted balance into a designated fiat. The entries are sorted by their fiat balance value. + * + * The `fiat_code` can be selected from any of the values returned by the supported fiat endpoint. + * + * The total balance in the designated fiat is also part of the response. + * + * ## Path + * + * - `/v1/safes//balances/?&` returns the balance for every supported ERC20 token for a ``, as well as the aggregated fiat total in the fiat currency requested with `` . Sorted by fiat balance. + * + * ## Query parameters + * + * - `` : A token is defined as trusted by our core service process when adding them. Default value is `false` + * - ``: A token is defined as spam by our core service process when adding them. Default value is `true` + */ #[get("/v1/safes//balances/?&")] pub async fn get_balances( context: Context<'_>, @@ -28,6 +49,14 @@ pub async fn get_balances( .await } +/** + * `/v1/balances/supported-fiat-codes`
+ * Returns [Vec] of [String] + * + * Supported fiat codes for balances + * `/v1/balances/supported-fiat-codes` : returns the supported fiat codes to be included int the `` segment of the balance endpoint. + * The entries are sorted alphabetically, with the exception of `USD` and `EUR` being placed in the top of the list in that order. +*/ #[get("/v1/balances/supported-fiat-codes")] pub async fn get_supported_fiat(context: Context<'_>) -> ApiResult> { CacheResponse::new(context.uri()) diff --git a/src/routes/collectibles.rs b/src/routes/collectibles.rs index 252dbe320..9e3b437cb 100644 --- a/src/routes/collectibles.rs +++ b/src/routes/collectibles.rs @@ -4,6 +4,152 @@ use crate::utils::context::Context; use crate::utils::errors::ApiResult; use rocket::response::content; +/** + * `/v1/safes//collectibles?&`
+ * Returns collectibles from the transaction service + * + * # Collectibles + * + * The collectibles endpoint does not implement any logic in the client-gateway. The response from the core services is cached and then forwarded to the clients. + * + * ## Path + * + * - `/v1/safes//collectibles?&` : Returns a list of the ERC721 tokens stored in a safe + * + * ## Query parameters + * + * `` : A token is defined as trusted by our core service process when adding them. Default value is `false` + * ``: A token is defined as spam by our core service process when adding them. Default value is `true` + * + * ## Models + * + * For the most up-to-date version of the endpoint please check: + * + * ```json + * [ + * { + * "address": "string", + * "tokenName": "string", + * "tokenSymbol": "string", + * "logoUri": "string", + * "id": "string", + * "uri": "string", + * "name": "string", + * "description": "string", + * "imageUri": "string", + * "metadata": { + * "additionalProp1": "string", + * "additionalProp2": "string", + * "additionalProp3": "string" + * } + * } + * ] + * ``` + * + * ## JSON + * + *
+ * Full response + * + * ```json + * [ + * { + * "address": "0xD753e03c05533F85bA9695C139771b1E9698a53C", + * "tokenName": "Main", + * "tokenSymbol": "JOSE", + * "logoUri": "https://gnosis-safe-token-logos.s3.amazonaws.com/0xD753e03c05533F85bA9695C139771b1E9698a53C.png", + * "id": "2", + * "uri": "https://arweave.net/8Vje5kmuRKaJwYht19rl-tEte9J8WifCrXoCwAB2IK8", + * "name": "Chiken dinner", + * "description": "This token is meant for testing. ", + * "imageUri": "https://arweave.net/a_poR6wHyGUortY2G3ITFmpQJOsRGJUXngpUAharq8I", + * "metadata": { + * "minter": "0x4d3101d77aac1b90ae42efa38d235a81af270d40", + * "mintedOn": "2020-12-29T13:49:02.654Z", + * "contractAddress": "0xd753e03c05533f85ba9695c139771b1e9698a53c", + * "minted": "Minted on Mintbase.io", + * "fiatPrice": "$0.00", + * "name": "Chiken dinner", + * "description": "This token is meant for testing. ", + * "youtubeUrl": "", + * "price": 0, + * "ethPrice": "0", + * "amountToMint": "5", + * "visibility": "safe", + * "forSale": false, + * "image": "https://arweave.net/a_poR6wHyGUortY2G3ITFmpQJOsRGJUXngpUAharq8I", + * "attributes": [], + * "category": "DQFi8lDeEyqqoAOPesJb", + * "externalUrl": "https://mintbase.io/my-market/0xd753e03c05533f85ba9695c139771b1e9698a53c", + * "type": "ERC721" + * } + * }, + * { + * "address": "0xD753e03c05533F85bA9695C139771b1E9698a53C", + * "tokenName": "Main", + * "tokenSymbol": "JOSE", + * "logoUri": "https://gnosis-safe-token-logos.s3.amazonaws.com/0xD753e03c05533F85bA9695C139771b1E9698a53C.png", + * "id": "4", + * "uri": "https://arweave.net/8Vje5kmuRKaJwYht19rl-tEte9J8WifCrXoCwAB2IK8", + * "name": "Chiken dinner", + * "description": "This token is meant for testing. ", + * "imageUri": "https://arweave.net/a_poR6wHyGUortY2G3ITFmpQJOsRGJUXngpUAharq8I", + * "metadata": { + * "minter": "0x4d3101d77aac1b90ae42efa38d235a81af270d40", + * "mintedOn": "2020-12-29T13:49:02.654Z", + * "contractAddress": "0xd753e03c05533f85ba9695c139771b1e9698a53c", + * "minted": "Minted on Mintbase.io", + * "fiatPrice": "$0.00", + * "name": "Chiken dinner", + * "description": "This token is meant for testing. ", + * "youtubeUrl": "", + * "price": 0, + * "ethPrice": "0", + * "amountToMint": "5", + * "visibility": "safe", + * "forSale": false, + * "image": "https://arweave.net/a_poR6wHyGUortY2G3ITFmpQJOsRGJUXngpUAharq8I", + * "attributes": [], + * "category": "DQFi8lDeEyqqoAOPesJb", + * "externalUrl": "https://mintbase.io/my-market/0xd753e03c05533f85ba9695c139771b1e9698a53c", + * "type": "ERC721" + * } + * }, + * { + * "address": "0xD753e03c05533F85bA9695C139771b1E9698a53C", + * "tokenName": "Main", + * "tokenSymbol": "JOSE", + * "logoUri": "https://gnosis-safe-token-logos.s3.amazonaws.com/0xD753e03c05533F85bA9695C139771b1E9698a53C.png", + * "id": "5", + * "uri": "https://arweave.net/8Vje5kmuRKaJwYht19rl-tEte9J8WifCrXoCwAB2IK8", + * "name": "Chiken dinner", + * "description": "This token is meant for testing. ", + * "imageUri": "https://arweave.net/a_poR6wHyGUortY2G3ITFmpQJOsRGJUXngpUAharq8I", + * "metadata": { + * "minter": "0x4d3101d77aac1b90ae42efa38d235a81af270d40", + * "mintedOn": "2020-12-29T13:49:02.654Z", + * "contractAddress": "0xd753e03c05533f85ba9695c139771b1e9698a53c", + * "minted": "Minted on Mintbase.io", + * "fiatPrice": "$0.00", + * "name": "Chiken dinner", + * "description": "This token is meant for testing. ", + * "youtubeUrl": "", + * "price": 0, + * "ethPrice": "0", + * "amountToMint": "5", + * "visibility": "safe", + * "forSale": false, + * "image": "https://arweave.net/a_poR6wHyGUortY2G3ITFmpQJOsRGJUXngpUAharq8I", + * "attributes": [], + * "category": "DQFi8lDeEyqqoAOPesJb", + * "externalUrl": "https://mintbase.io/my-market/0xd753e03c05533f85ba9695c139771b1e9698a53c", + * "type": "ERC721" + * } + * } + * ] + * ``` + *
+ */ #[get("/v1/safes//collectibles?&")] pub async fn list( context: Context<'_>, diff --git a/src/routes/hooks.rs b/src/routes/hooks.rs index fa175bf97..fb5cfdcec 100644 --- a/src/routes/hooks.rs +++ b/src/routes/hooks.rs @@ -6,6 +6,7 @@ use crate::utils::context::Context; use crate::utils::errors::ApiResult; use rocket_contrib::json::Json; +#[doc(hidden)] #[post("/v1/hook/update/", format = "json", data = "")] pub fn update(context: Context<'_>, token: String, update: Json) -> ApiResult<()> { if token != webhook_token() { diff --git a/src/routes/mod.rs b/src/routes/mod.rs index 809defe66..eb7298bb7 100644 --- a/src/routes/mod.rs +++ b/src/routes/mod.rs @@ -5,12 +5,24 @@ use rocket::Catcher; use rocket::Route; use rocket_contrib::json::JsonValue; +/// # About endpoint pub mod about; +/// # Balance endpoints pub mod balances; +/// # Collectibles endpoint pub mod collectibles; +#[doc(hidden)] pub mod health; +#[doc(hidden)] pub mod hooks; +/// # Safe endpoints pub mod safes; + +/// # Transactions endpoints +/// +/// As presented by the endpoints in this service, we are taking in the types returned by the [transaction service](https://github.com/gnosis/safe-transaction-service-example), which to this data are `Multisig`, `Module` and `Ethereum` transaction types. +/// +/// The types served by the gate way are `Transfer`, `SettingsChange` and `Custom`. Additionally, we treat the `Creation` transaction as one additional type, as it is meant to be group with the rest of the items in the same UI component in the apps. pub mod transactions; pub fn active_routes() -> Vec { diff --git a/src/routes/safes.rs b/src/routes/safes.rs index 61cbe6d9f..df1b71c48 100644 --- a/src/routes/safes.rs +++ b/src/routes/safes.rs @@ -4,6 +4,10 @@ use crate::utils::context::Context; use crate::utils::errors::ApiResult; use rocket::response::content; +/** + * `/v1/safes/`
+ * Returns [SafeState](crate::models::service::safes::SafeState) + */ #[get("/v1/safes/")] pub async fn safe_info( context: Context<'_>, diff --git a/src/routes/transactions.rs b/src/routes/transactions.rs index c14e732f8..683860f2a 100644 --- a/src/routes/transactions.rs +++ b/src/routes/transactions.rs @@ -11,6 +11,24 @@ use rocket::response::content; use rocket_contrib::json::Json; use rocket_contrib::json::JsonError; +/** + * `/v1/transactions/`
+ * Returns [TransactionDetails](crate::models::service::transactions::details::TransactionDetails) + * + * # Transaction Details + * + * The transaction details endpoint provides additional information for a transaction, in much more detail than what the transaction summary endpoint does. It returns a single object [crate::models::service::transactions::details::TransactionDetails] + * + * ## Path + * + * `/v1/transactions/` + * + * `` can be either an `id` returned by the transaction summary list endpoint or a `safe_tx_hash` from the Safe Transaction API. + * + * ## Query paramets + * + * There aren't any query parameters that can be passed to this endpoint. + */ #[get("/v1/transactions/")] pub async fn details(context: Context<'_>, details_id: String) -> ApiResult> { CacheResponse::new(context.uri()) @@ -19,6 +37,26 @@ pub async fn details(context: Context<'_>, details_id: String) -> ApiResult/confirmations`
+ * Returns [TransactionDetails](crate::models::service::transactions::details::TransactionDetails) + * + * # Transaction Confirmation + * + * This endpoint provides a way for submitting confirmations for clients making use of the `safe_tx_hash` as part of the path, and the very same `safe_tx_hash` signed by an owner corresponding to the safe from which the transaction is being sent. + * + * If the confirmation is submitted successfully to the core services, then the local cache for that specific transaction is invalidated and the updated transaction details with the confirmation are returned in the request. + * + * ## Path + * + * `POST /v1/transactions//confirmations` + * + * The expected [crate::models::service::transactions::requests::ConfirmationRequest] body for this request, as well as the returned [crate::models::service::transactions::details::TransactionDetails] + * + * ## Query parameters + * + * No query parameters available for this endpoint. + */ #[post( "/v1/transactions//confirmations", format = "application/json", @@ -42,6 +80,39 @@ pub async fn submit_confirmation<'e>( .await } +/** + * `/v1/safes//transactions/history?&&`
+ * Returns a [Page](crate::models::commons::Page) of [TransactionListItem](crate::models::service::transactions::summary::TransactionListItem) + * + * # Transactions History + * + * This endpoint returns all the transactions that have been executed for a given safe. Cancelled + * transactions will not be shown in this endpoint. Therefore, there is no concept of conflicting `nonces` + * for this endpoint, as there could potentially be for queued transactions. + * + * This endpoint does not return any `TransactionListItem::Label` nor `TransactionListItem::ConflictHeader` + * as of the writing of this iteration of this document. + * + * Transaction are aggregated by day and for each day there is a `TransactionListItem::DateLabel` added. + * The timestamp returned corresponds to the **date** only, **time** fields should be therefore ignored. + * The dates are returned in UTC, in a later iteration this will be offset by the `timezone_offset` + * sent by the clients in the query parameter. + * + * `TransactionListItem::Transaction` is returned with the same data layout as in the `/transactions/queued` endpoint. + * + * The structure of the `transaction` object corresponds to that of a [crate::models::service::transactions::summary::TransactionSummary] + * + * ## Path + * + * `GET /v1/safes//transactions/history?&&` + * + * ## Query parameters + * + * - `` should be the checksummed address of the safe to be observed. + * - `` is the desired page of data to be loaded. Values for this parameter can be either `Page.next` or `Page.previous`. **WARNING:** Don't fiddle with the values of these 2 fields. + * - ``: Currently ignored by the gateway. + * - ``: forwarded directly to the core services. Only for debugging purposes clients **should not** send it (unless they know what they are doing). + */ #[get("/v1/safes//transactions/history?&")] pub async fn history_transactions( context: Context<'_>, @@ -62,6 +133,33 @@ pub async fn history_transactions( .await } +/** + * `/v1/safes//transactions/queued?&&`
+ * Returns a [Page](crate::models::commons::Page) of [TransactionListItem](crate::models::service::transactions::summary::TransactionListItem) + * + * # Transactions Queued + * + * This endpoint returns all the transactions that are still awaiting execution for a given safe. The list will contain a `Next` marker if there is a transaction matching the nonce of the safe, which means, that it will be the next transaction to be executed, provided there aren't any other transactions proposed utilizing the same nonce. If that were, the case a `ConflictHeader` will be introduced for which the `nonce` field will hold the conflicting value. + * + * Additionally to the `Next` marker, there is also `Queued`. Under this marker, transactions that have a nonce greater than that of the safe are listed. Analogously to the `Next` section of the list, a `ConflictHeader` will be introduced for any group of transactions sharing the same `nonce`. + * + * The structure of the transaction object corresponds to that of a [crate::models::service::transactions::summary::TransactionSummary] + * + * A `TransactionListItem` can be either a `Label` (containing either `Next` or `Queued`), `ConflictHeader` (with the conflicting `nonce`) and a `Transaction`, for which there is a `TransactionSummary` and a `ConflictType` associated. The conflict type can have `HasNext` or `End` value. These values signal to which extent a group of conflicting transactions spans, ending as soon as a `Transaction` type item contains a `ConflictType::End`. + * + * ## Path + * + * `GET /v1/safes//transactions/queued?&&` + * + * The response is a list of [crate::models::service::transactions::summary::TransactionListItem], which is a polymorphic struct. Details follow in the models sections. + * + * ## Query parameters + * + * - `` should be the checksummed address of the safe to be observed. + * - `` is the desired page of data to be loaded. Values for this parameter can be either `Page.next` or `Page.previous`. **WARNING:** Don't fiddle with the values of these 2 fields. + * - ``: Currently ignored by the gateway. + * - ``: forwarded directly to the core services. Only for debugging purposes clients **should not** send it (unless they know what they are doing). + */ #[get("/v1/safes//transactions/queued?&&")] pub async fn queued_transactions( context: Context<'_>, @@ -84,6 +182,25 @@ pub async fn queued_transactions( .await } +/** + * `/v1/transactions//propose`
+ * No return value + * + * # Transaction Proposal + * + * This endpoint provides a way for submitting transactions of any kind in the format expected by the core services. + * See the example `json` to see how to submit a cancellation transaction (you would need to supply a `nonce`, `signature` and `contractTransactionHash` appropriate to the transaction you are submitting) + * + * ## Path + * + * `POST /v1/transactions//propose` + * + * The expected [crate::models::service::transactions::requests::MultisigTransactionRequest] body for this request, can be found in the sections [models](https://github.com/gnosis/safe-client-gateway/wiki/transactions_confirmation#models) + * + * ## Query parameters + * + * No query parameters available for this endpoint. + */ #[post( "/v1/transactions//propose", format = "application/json",