From b85af97c73de29fc5852729df43476808d6aa7fc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=89=9B=E5=95=A4?= Date: Tue, 2 Apr 2024 15:40:45 +0800 Subject: [PATCH] Feat: v2 native to evm txs. (#242) --- docs/api_v2.md | 209 ++++++++++++++++++++++- explorer/src/main.rs | 5 +- explorer/src/service/api.rs | 183 ++++++++++---------- explorer/src/service/v1/validator.rs | 6 + explorer/src/service/v2/native_to_evm.rs | 76 +++++++++ 5 files changed, 382 insertions(+), 97 deletions(-) diff --git a/docs/api_v2.md b/docs/api_v2.md index dac1dec..7211012 100644 --- a/docs/api_v2.md +++ b/docs/api_v2.md @@ -1,4 +1,4 @@ -# Findora V2 API Spec +# Findora Explorer V2 API Spec * [1.1 根据地址获取Asset](#1.1) * [1.2 获取asset集合](#1.2) @@ -7,6 +7,9 @@ * [1.5 根据交易hash获取delegate记录](#1.5) * [1.6 获取delegate记录](#1.6) * [1.7 获取undelegate记录](#1.7) +* [1.8 根据交易hash获取undelegate记录](#1.8) +* [1.9 获取交易](#1.9) +* [1.10 获取用户发出的prism交易记录](#1.10)

1.1 根据地址查询Asset

@@ -332,7 +335,7 @@

1.5 根据交易hash获取delegate记录

-* `GET /v2/staking/delegation/:tx_hash` +* `GET /api/v2/staking/delegation/:tx_hash` * 参数 | 参数 | 类型 | 必传 | 说明 | @@ -375,7 +378,7 @@

1.6 获取delegate记录

-* `GET /v2/staking/delegations` +* `GET /api/v2/staking/delegations` * 参数 | 参数 | 类型 | 必传 | 说明 | @@ -450,7 +453,7 @@ ```

1.7 获取undelegate记录

-* `GET /v2/staking/undelegations` +* `GET /api/v2/staking/undelegations` * 参数 | 参数 | 类型 | 必传 | 说明 | @@ -463,6 +466,7 @@ * 获取undelegate记录: `/api/v2/staking/undelegations?page=1&page_size=2` * 获取用户的undelegate记录:`/api/v2/staking/undelegations?address=fra1vrvnc9kfnnl02rhafvdn4yssll4rz0flfc73xkj3w9tlsggy38rskgv35t&page=1&page_size=2` * Response: + * 按区块高度降序排列 ```json { "code": 200, @@ -526,20 +530,207 @@ } ``` +

1.8 根据交易hash获取undelegate记录

+* `GET /api/v2/staking/undelegation/:tx_hash` +* 参数 +| 参数 | 类型 | 必传 | 说明 | +|---------|--------|----|------| +| tx_hash | string | Y | 交易哈希 | +* Request: `/api/v2/staking/undelegation/583d9071df8299978e227d4b62d122225e4d2bc7fce0f581b4396b5c35f63dbd` +* Response: +```json +{ + "code": 200, + "data": { + "amount": 96442598104, + "block_hash": "53E86050C1B6519B8A6B6A09086810A92B97DC2905F6C14BF319B5D694CF74EF", + "from": "fra1vrvnc9kfnnl02rhafvdn4yssll4rz0flfc73xkj3w9tlsggy38rskgv35t", + "height": 5162087, + "new_delegator": "5ax5Bb8xQ4Ag7eV_cA8PGAAJ2_M-BPZhrF3R5uzd17o=", + "target_validator": "E012AA66C83999E3862C8AA534B9CE66FC14A37A", + "timestamp": 1705780393, + "tx_hash": "583d9071df8299978e227d4b62d122225e4d2bc7fce0f581b4396b5c35f63dbd", + "value": { + "UnDelegation": { + "body": { + "nonce": [ + [90, 0, 11, 166, 133, 201, 223, 219], 129078 + ], + "pu": { + "am": 96442598104, + "new_delegator_id": "5ax5Bb8xQ4Ag7eV_cA8PGAAJ2_M-BPZhrF3R5uzd17o=", + "target_validator": [224, 18, 170, 102, 200, 57, 153, 227, 134, 44, 138, 165, 52, 185, 206, 102, 252, 20, 163, 122] + } + }, + "pubkey": "YNk8Fsmc_vUO_UsbOpIQ_-oxPT9OPRNaUXFX-CEEicc=", + "signature": "0bwIKjNsCqfDMPp6iAtOM81nMHw4voGwyl_YjNazfx2A6Wt-BWWR0B-bruWANPMNncGRbBuYs2Brjigd566LAw==" + } + } + }, + "message": "" +} +``` +

1.9 获取交易

+* `GET /api/v2/txs` +* 参数 +| 参数 | 类型 | 必传 | 说明 | +|--------------|--------|----|-------| +| block_hash | string | N | 区块哈希 | +| block_height | number | N | 区块高度 | +| from | string | N | 发送者地址 | +| to | string | N | 接收者地址 | +| ty | number | N | 交易类型 | +| start_time | number | N | 开始时间戳 | +| end_time | number | N | 截止时间戳 | +| page | number | N | 页码 | +| page_size | number | N | 页大小 | + +* Request: `/api/v2/txs?page=1&page_size=2` +* Response: + * 按timestamp降序排列 +```json +{ + "code": 200, + "data": { + "page": 1, + "page_size": 2, + "total": 2460630, + "txs": [{ + "block_hash": "B92B8B1AB4BB145AA66E4EA245706A8F833AD7FBED02D2603CA9003CD0324E9D", + "code": 0, + "evm_tx_hash": "", + "height": 5478292, + "log": "", + "origin": "ZXZtOnsic2lnbmF0dXJlIjpudWxsLCJmdW5jdGlvbiI6eyJFdGhlcmV1bSI6eyJUcmFuc2FjdCI6eyJub25jZSI6IjB4OTBiOTAiLCJnYXNfcHJpY2UiOiIweDI1NDBiZTQwMCIsImdhc19saW1pdCI6IjB4MjQ5ZjAiLCJhY3Rpb24iOnsiQ2FsbCI6IjB4YjUyZWYyOTI2NTFmODY5MjA1M2FjM2QzOTkyMWE0M2ZlMTM1MzNjOCJ9LCJ2YWx1ZSI6IjB4MCIsImlucHV0IjpbMTk4LDY0LDExNyw0NSwwLDAsMCwwLDAsMCwwLDAsMCwwLDAsMCwxNzUsMjUsMTA4LDQ1LDEyMCwxMTIsMTgxLDIwLDExMSwyLDIxMiwxNTUsMSwyOSwyNDksMjUsMTI0LDksNjMsMjU0LDAsMCwwLDAsMCwwLDAsMCwwLDAsMCwwLDAsMCwwLDAsMCwwLDAsMCwwLDAsMCwwLDAsMCwwLDAsMCwwLDE2LDBdLCJzaWduYXR1cmUiOnsidiI6NDM0MCwiciI6IjB4OWUwNmExYjhjYzBmMjFiYzBmMTZiZTk1YzAzNjY5ZDQxMzE1NWE1M2E0ODc4MTJkNTUzNGFlY2JmNDViMjJjYiIsInMiOiIweDJiYmZkNDZjYzQwZDc5OWI2MjhlMjVmMzE4NmNjODZmNmU2YWRiZDE2NTU2ZWFmNDIwMzNmNjA4NTBiOWU4ODgifX19fX0=", + "result": { + "code": 0, + "codespace": "", + "data": "eyJDYWxsIjp7ImV4aXRfcmVhc29uIjp7IlN1Y2NlZWQiOiJTdG9wcGVkIn0sInZhbHVlIjpbXSwidXNlZF9nYXMiOiIweDlkNmIiLCJsb2dzIjpbXX19", + "events": [{ + "attributes": [{ + "key": "c2VuZGVy", + "value": "MHhkM2UwNzViZDAzMTQ5MDk3ZmExMzViMThhODc1NmI1MDI0YTQ1ZTVl" + }, { + "key": "dG8=", + "value": "MHhiNTJlZjI5MjY1MWY4NjkyMDUzYWMzZDM5OTIxYTQzZmUxMzUzM2M4" + }, { + "key": "Y29udHJhY3RfYWRkcmVzcw==", + "value": "MHgwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAw" + }, { + "key": "dHJhbnNhY3Rpb25faGFzaA==", + "value": "MHg3MzgxYWEyMTBiMWJjMmU4NmYxMTExN2Q5ZTFlODZjYmYyYmU2ZWE2YjdhZWQwODhiZjk2N2MzNmJjZjA5MGIw" + }, { + "key": "cmVhc29u", + "value": "U3VjY2VlZChTdG9wcGVkKQ==" + }], + "type": "ethereum_TransactionExecuted" + }], + "gasUsed": "40299", + "gasWanted": "150000", + "info": "", + "log": "" + }, + "timestamp": 1712037200, + "tx_hash": "11969300f45e0db1b5a74a1c102a252a2b443cb5cb1346e41d30bed234b4efe3", + "ty": 1, + "value": { + "function": { + "Ethereum": { + "Transact": { + "action": { + "Call": "0xb52ef292651f8692053ac3d39921a43fe13533c8" + }, + "from": "0xd3e075bd03149097fa135b18a8756b5024a45e5e", + "gas_limit": "0x249f0", + "gas_price": "0x2540be400", + "input": [198, 64, 117, 45, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 175, 25, 108, 45, 120, 112, 181, 20, 111, 2, 212, 155, 1, 29, 249, 25, 124, 9, 63, 254, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0], + "nonce": "0x90b90", + "signature": { + "r": "0x9e06a1b8cc0f21bc0f16be95c03669d413155a53a487812d5534aecbf45b22cb", + "s": "0x2bbfd46cc40d799b628e25f3186cc86f6e6adbd16556eaf42033f60850b9e888", + "v": 4340 + }, + "value": "0x0" + } + } + } + } + }, { + "block_hash": "8C4C163BCC93062974D2D5E6165DD0C399EAA1BAF615901610197C9F37509E2E", + "code": 0, + "evm_tx_hash": "", + "height": 5478291, + "log": "", + "origin": "ZXZtOnsic2lnbmF0dXJlIjpudWxsLCJmdW5jdGlvbiI6eyJFdGhlcmV1bSI6eyJUcmFuc2FjdCI6eyJub25jZSI6IjB4OTBiOGYiLCJnYXNfcHJpY2UiOiIweDI1NDBiZTQwMCIsImdhc19saW1pdCI6IjB4MjQ5ZjAiLCJhY3Rpb24iOnsiQ2FsbCI6IjB4YjUyZWYyOTI2NTFmODY5MjA1M2FjM2QzOTkyMWE0M2ZlMTM1MzNjOCJ9LCJ2YWx1ZSI6IjB4MCIsImlucHV0IjpbMTk4LDY0LDExNyw0NSwwLDAsMCwwLDAsMCwwLDAsMCwwLDAsMCwwLDAsMCwwLDAsMCwwLDAsMCwwLDAsMCwwLDAsMCwwLDAsMCwxNiwwLDAsMCwwLDAsMCwwLDAsMCwwLDAsMCwwLDYsNTAsMTg2LDE2Miw5OCwxNTMsMjAxLDE1MSw0NiwyMTIsMjE3LDE3NSwyNTAsNjMsMjA4LDg3LDE2NywzNCw4MiwyNTVdLCJzaWduYXR1cmUiOnsidiI6NDM0MCwiciI6IjB4OTc0ZDBkYjQ1ZTQxMDM2ZmI3YjFmM2Q3ODNkZGE1ZTVlYjM4NTM4YzlmMzNhYzdmNjkxODk2YmY3OGU0MjhlNCIsInMiOiIweDFlOWYxMWVhYjRmMDU2MGFhNDU3ZTQ5OGI0ODg5ZmI0N2JhODRiNjY3MjhkODJkNjMwNjNhMWZjZjM0NzI3MjYifX19fX0=", + "result": { + "code": 0, + "codespace": "", + "data": "eyJDYWxsIjp7ImV4aXRfcmVhc29uIjp7IlN1Y2NlZWQiOiJTdG9wcGVkIn0sInZhbHVlIjpbXSwidXNlZF9nYXMiOiIweDlkNmIiLCJsb2dzIjpbXX19", + "events": [{ + "attributes": [{ + "key": "c2VuZGVy", + "value": "MHhkM2UwNzViZDAzMTQ5MDk3ZmExMzViMThhODc1NmI1MDI0YTQ1ZTVl" + }, { + "key": "dG8=", + "value": "MHhiNTJlZjI5MjY1MWY4NjkyMDUzYWMzZDM5OTIxYTQzZmUxMzUzM2M4" + }, { + "key": "Y29udHJhY3RfYWRkcmVzcw==", + "value": "MHgwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAw" + }, { + "key": "dHJhbnNhY3Rpb25faGFzaA==", + "value": "MHgzNGU4NzRjNzAxNDdlZmIxOGE5ODM0ZDkxMTg1YTI3ZTI1YjFjZWY1YTAwOTBjYTBmNzVjMjMyYTAxM2QyMWFi" + }, { + "key": "cmVhc29u", + "value": "U3VjY2VlZChTdG9wcGVkKQ==" + }], + "type": "ethereum_TransactionExecuted" + }], + "gasUsed": "40299", + "gasWanted": "150000", + "info": "", + "log": "" + }, + "timestamp": 1712037185, + "tx_hash": "039a2481e3b7b81dfb344e0627fca9bccb8e249f18b5892fd234833e128995a5", + "ty": 1, + "value": { + "function": { + "Ethereum": { + "Transact": { + "action": { + "Call": "0xb52ef292651f8692053ac3d39921a43fe13533c8" + }, + "from": "0xd3e075bd03149097fa135b18a8756b5024a45e5e", + "gas_limit": "0x249f0", + "gas_price": "0x2540be400", + "input": [198, 64, 117, 45, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 50, 186, 162, 98, 153, 201, 151, 46, 212, 217, 175, 250, 63, 208, 87, 167, 34, 82, 255], + "nonce": "0x90b8f", + "signature": { + "r": "0x974d0db45e41036fb7b1f3d783dda5e5eb38538c9f33ac7f691896bf78e428e4", + "s": "0x1e9f11eab4f0560aa457e498b4889fb47ba84b66728d82d63063a1fcf3472726", + "v": 4340 + }, + "value": "0x0" + } + } + } + } + }] + }, + "message": "" +} +``` +

1.10 获取用户发出的prism交易记录

- - - - - +* `GET /v2/tx/prism/send` diff --git a/explorer/src/main.rs b/explorer/src/main.rs index b2f1fa2..f9c4af6 100644 --- a/explorer/src/main.rs +++ b/explorer/src/main.rs @@ -1,6 +1,7 @@ mod service; use crate::service::api::Api; use anyhow::Result; +use log::info; use poem::middleware::Cors; use poem::{listener::TcpListener, EndpointExt, Route, Server}; use poem_openapi::OpenApiService; @@ -28,7 +29,7 @@ async fn main() -> Result<()> { .connect(&postgres_config) .await .unwrap(); - + info!("Connecting DB...ok"); // tendermint rpc let tendermint_rpc_client = TendermintRPC::new( Duration::from_secs(60), @@ -57,7 +58,7 @@ async fn main() -> Result<()> { let server_addr = format!("{}:{}", config.server.addr, config.server.port); let cors = Cors::new(); - + info!("Starting server...ok"); Server::new(TcpListener::bind(server_addr)) .run( Route::new() diff --git a/explorer/src/service/api.rs b/explorer/src/service/api.rs index 5dd27fd..b15179a 100644 --- a/explorer/src/service/api.rs +++ b/explorer/src/service/api.rs @@ -16,16 +16,13 @@ use crate::service::v1::staking::{ use crate::service::v1::transaction::{ PmtxsResponse, TxResponse, TxsResponse, V2PrismRecordResponse, }; -use crate::service::v1::validator::{ - CirculatingSupplyResponse, DelegatorListResponse, ValidatorDelegationResponse, - ValidatorDetailResponse, ValidatorHistoryResponse, ValidatorListResponse, - ValidatorSignedCountResponse, -}; +use crate::service::v1::validator::CirculatingSupplyResponse; use crate::service::v2::asset::{v2_get_asset, v2_get_asset_list, V2AssetTxResponse}; use crate::service::v2::claim::{v2_get_claim, v2_get_claims, V2ClaimResponse, V2ClaimsResponse}; use crate::service::v2::delegation::{ v2_get_delegation, v2_get_delegations, V2DelegationResponse, V2DelegationsResponse, }; +use crate::service::v2::native_to_evm::V2NativeToEvmTxsResponse; use crate::service::v2::native_to_evm::{ v2_get_n2e_tx, v2_get_prism_records_send, V2NativeToEvmTxResponse, }; @@ -409,31 +406,31 @@ impl Api { .map_err(handle_fetch_one_err) } - #[oai( - path = "/chain/validator_list", - method = "get", - tag = "ApiTags::BlockChain" - )] - async fn validator_list(&self) -> poem::Result { - service::v1::validator::validator_list(self) - .await - .map_err(handle_fetch_one_err) - } + // #[oai( + // path = "/chain/validator_list", + // method = "get", + // tag = "ApiTags::BlockChain" + // )] + // async fn validator_list(&self) -> poem::Result { + // service::v1::validator::validator_list(self) + // .await + // .map_err(handle_fetch_one_err) + // } - #[oai( - path = "/chain/validator_detail/:address", - method = "get", - tag = "ApiTags::BlockChain" - )] - async fn validator_detail( - &self, - /// validator address, e.g. 917454FB61CFBDB1995BC57C7A821E41FFB1AF43 - address: Path, - ) -> poem::Result { - service::v1::validator::validator_detail(self, address) - .await - .map_err(handle_fetch_one_err) - } + // #[oai( + // path = "/chain/validator_detail/:address", + // method = "get", + // tag = "ApiTags::BlockChain" + // )] + // async fn validator_detail( + // &self, + // /// validator address, e.g. 917454FB61CFBDB1995BC57C7A821E41FFB1AF43 + // address: Path, + // ) -> poem::Result { + // service::v1::validator::validator_detail(self, address) + // .await + // .map_err(handle_fetch_one_err) + // } #[oai( path = "/chain/circulating_supply", @@ -446,39 +443,39 @@ impl Api { .map_err(handle_fetch_one_err) } - #[oai( - path = "/chain/validator/signed_count", - method = "get", - tag = "ApiTags::BlockChain" - )] - async fn validator_signed_count( - &self, - /// validator address, e.g. 917454FB61CFBDB1995BC57C7A821E41FFB1AF43 - address: Query, - /// page index, the default is 1. - page: Query>, - /// page size, the default is 10. - page_size: Query>, - ) -> poem::Result { - service::v1::validator::validator_signed_count(self, address, page, page_size) - .await - .map_err(handle_fetch_one_err) - } + // #[oai( + // path = "/chain/validator/signed_count", + // method = "get", + // tag = "ApiTags::BlockChain" + // )] + // async fn validator_signed_count( + // &self, + // /// validator address, e.g. 917454FB61CFBDB1995BC57C7A821E41FFB1AF43 + // address: Query, + // /// page index, the default is 1. + // page: Query>, + // /// page size, the default is 10. + // page_size: Query>, + // ) -> poem::Result { + // service::v1::validator::validator_signed_count(self, address, page, page_size) + // .await + // .map_err(handle_fetch_one_err) + // } - #[oai( - path = "/chain/delegator_list/:address", - method = "get", - tag = "ApiTags::BlockChain" - )] - async fn delegator_list( - &self, - /// delegator address, e.g. 000E33AB7471186F3B1DE9FC08BB9C480F453590 - address: Path, - ) -> poem::Result { - service::v1::validator::delegator_list(self, address) - .await - .map_err(handle_fetch_one_err) - } + // #[oai( + // path = "/chain/delegator_list/:address", + // method = "get", + // tag = "ApiTags::BlockChain" + // )] + // async fn delegator_list( + // &self, + // /// delegator address, e.g. 000E33AB7471186F3B1DE9FC08BB9C480F453590 + // address: Path, + // ) -> poem::Result { + // service::v1::validator::delegator_list(self, address) + // .await + // .map_err(handle_fetch_one_err) + // } #[oai(path = "/simple/price", method = "get", tag = "ApiTags::Price")] async fn simple_price( @@ -528,17 +525,31 @@ impl Api { .map_err(handle_fetch_one_err) } + // #[oai( + // path = "/chain/validator_delegation", + // method = "get", + // tag = "ApiTags::BlockChain" + // )] + // async fn validator_delegation( + // &self, + // /// validator address, e.g. 000E33AB7471186F3B1DE9FC08BB9C480F453590 + // address: Query, + // ) -> poem::Result { + // service::v1::validator::validator_delegation(self, address) + // .await + // .map_err(handle_fetch_one_err) + // } #[oai( - path = "/chain/validator_delegation", + path = "/v2/txs/prism/n2e", method = "get", - tag = "ApiTags::BlockChain" + tag = "ApiTags::Transaction" )] - async fn validator_delegation( + async fn get_prism_n2e_txs( &self, - /// validator address, e.g. 000E33AB7471186F3B1DE9FC08BB9C480F453590 - address: Query, - ) -> poem::Result { - service::v1::validator::validator_delegation(self, address) + page: Query>, + page_size: Query>, + ) -> poem::Result { + service::v2::native_to_evm::v2_get_n2e_txs(self, page, page_size) .await .map_err(handle_fetch_one_err) } @@ -630,24 +641,24 @@ impl Api { .map_err(handle_fetch_one_err) } - #[oai( - path = "/chain/validator/history", - method = "get", - tag = "ApiTags::BlockChain" - )] - async fn get_validator_history( - &self, - /// validator address, e.g. 9E6717392EFDCFA101E33449A7C2A238251315B1 - address: Query, - /// page index, the default is 1. - page: Query>, - /// page size, the default is 10. - page_size: Query>, - ) -> poem::Result { - service::v1::validator::validator_history(self, address, page, page_size) - .await - .map_err(handle_fetch_one_err) - } + // #[oai( + // path = "/chain/validator/history", + // method = "get", + // tag = "ApiTags::BlockChain" + // )] + // async fn get_validator_history( + // &self, + // /// validator address, e.g. 9E6717392EFDCFA101E33449A7C2A238251315B1 + // address: Query, + // /// page index, the default is 1. + // page: Query>, + // /// page size, the default is 10. + // page_size: Query>, + // ) -> poem::Result { + // service::v1::validator::validator_history(self, address, page, page_size) + // .await + // .map_err(handle_fetch_one_err) + // } // #[oai( // path = "/chain/claim/:address", diff --git a/explorer/src/service/v1/validator.rs b/explorer/src/service/v1/validator.rs index 7d2002a..1b3208d 100644 --- a/explorer/src/service/v1/validator.rs +++ b/explorer/src/service/v1/validator.rs @@ -148,6 +148,7 @@ impl Validator { } } +#[allow(dead_code)] pub async fn validator_delegation( api: &Api, address: Query, @@ -175,6 +176,7 @@ pub async fn validator_delegation( ))) } +#[allow(dead_code)] pub async fn validator_list(api: &Api) -> Result { let mut conn = api.storage.lock().await.acquire().await?; @@ -220,6 +222,7 @@ pub async fn validator_list(api: &Api) -> Result { }))) } +#[allow(dead_code)] pub async fn validator_detail(api: &Api, address: Path) -> Result { let validator_detail_url = api .platform @@ -245,6 +248,7 @@ pub async fn validator_detail(api: &Api, address: Path) -> Result) -> Result { let delegator_list_url = api .platform @@ -328,6 +332,7 @@ pub struct ValidatorHistoryItem { pub timestamp: i64, } +#[allow(dead_code)] pub async fn validator_history( api: &Api, address: Query, @@ -450,6 +455,7 @@ pub struct ValidatorDetail { pub cur_height: i64, } +#[allow(dead_code)] pub async fn validator_signed_count( api: &Api, address: Query, diff --git a/explorer/src/service/v2/native_to_evm.rs b/explorer/src/service/v2/native_to_evm.rs index 88f337a..fe5dd8b 100644 --- a/explorer/src/service/v2/native_to_evm.rs +++ b/explorer/src/service/v2/native_to_evm.rs @@ -10,6 +10,82 @@ use serde::{Deserialize, Serialize}; use serde_json::Value; use sqlx::Row; +#[derive(ApiResponse)] +pub enum V2NativeToEvmTxsResponse { + #[oai(status = 200)] + Ok(Json), + #[oai(status = 404)] + NotFound, + #[oai(status = 500)] + InternalError, +} + +#[derive(Serialize, Deserialize, Debug, Object)] +pub struct V2NativeToEvmTxsResult { + pub code: u16, + pub message: String, + pub data: V2NativeToEvmTxsData, +} + +#[derive(Serialize, Deserialize, Debug, Object)] +pub struct V2NativeToEvmTxsData { + pub total: i64, + pub page: i32, + pub page_size: i32, + pub txs: Vec, +} + +pub async fn v2_get_n2e_txs( + api: &Api, + page: Query>, + page_size: Query>, +) -> Result { + let mut conn = api.storage.lock().await.acquire().await?; + let page = page.0.unwrap_or(1); + let page_size = page_size.0.unwrap_or(10); + + let sql_total = "SELECT count(*) FROM n2e"; + let row = sqlx::query(sql_total).fetch_one(&mut conn).await?; + let total: i64 = row.try_get("count")?; + + let sql_query = format!("SELECT tx,block,sender,receiver,asset,amount,height,timestamp,content FROM n2e ORDER BY timestamp DESC LIMIT {} OFFSET {}", page_size, (page-1)*page_size); + let mut res: Vec = vec![]; + let rows = sqlx::query(sql_query.as_str()).fetch_all(&mut conn).await?; + for row in rows { + let tx: String = row.try_get("tx")?; + let block: String = row.try_get("block")?; + let sender: String = row.try_get("sender")?; + let receiver: String = row.try_get("receiver")?; + let asset: String = row.try_get("asset")?; + let amount: String = row.try_get("amount")?; + let height: i64 = row.try_get("height")?; + let timestamp: i64 = row.try_get("timestamp")?; + let value: Value = row.try_get("content")?; + res.push(V2NativeToEvmTx { + tx_hash: tx, + block_hash: block, + from: sender, + to: receiver, + asset, + amount, + height, + timestamp, + value, + }) + } + + Ok(V2NativeToEvmTxsResponse::Ok(Json(V2NativeToEvmTxsResult { + code: 200, + message: "".to_string(), + data: V2NativeToEvmTxsData { + total, + page, + page_size, + txs: res, + }, + }))) +} + #[derive(ApiResponse)] pub enum V2NativeToEvmTxResponse { #[oai(status = 200)]