Skip to content

Commit

Permalink
feat: P-584 added bitcoin holding amount vc using new dataprovider ht…
Browse files Browse the repository at this point in the history
  • Loading branch information
higherordertech authored and higherordertech committed Apr 26, 2024
1 parent 1c800ac commit d7a862d
Show file tree
Hide file tree
Showing 16 changed files with 378 additions and 4 deletions.
1 change: 1 addition & 0 deletions bitacross-worker/docker/docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,7 @@ services:
- CONTEST_LEGEND_DISCORD_ROLE_ID=CONTEST_LEGEND_DISCORD_ROLE_ID
- CONTEST_POPULARITY_DISCORD_ROLE_ID=CONTEST_POPULARITY_DISCORD_ROLE_ID
- CONTEST_PARTICIPANT_DISCORD_ROLE_ID=CONTEST_PARTICIPANT_DISCORD_ROLE_ID
- BLOCKCHAIN_INFO_API_URL=http://localhost:19527/blockchain_info/
networks:
- litentry-test-network
healthcheck:
Expand Down
3 changes: 3 additions & 0 deletions bitacross-worker/docker/multiworker-docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,7 @@ services:
- CONTEST_LEGEND_DISCORD_ROLE_ID=CONTEST_LEGEND_DISCORD_ROLE_ID
- CONTEST_POPULARITY_DISCORD_ROLE_ID=CONTEST_POPULARITY_DISCORD_ROLE_ID
- CONTEST_PARTICIPANT_DISCORD_ROLE_ID=CONTEST_PARTICIPANT_DISCORD_ROLE_ID
- BLOCKCHAIN_INFO_API_URL=http://localhost:19527/blockchain_info/
networks:
- litentry-test-network
healthcheck:
Expand Down Expand Up @@ -196,6 +197,7 @@ services:
- CONTEST_LEGEND_DISCORD_ROLE_ID=CONTEST_LEGEND_DISCORD_ROLE_ID
- CONTEST_POPULARITY_DISCORD_ROLE_ID=CONTEST_POPULARITY_DISCORD_ROLE_ID
- CONTEST_PARTICIPANT_DISCORD_ROLE_ID=CONTEST_PARTICIPANT_DISCORD_ROLE_ID
- BLOCKCHAIN_INFO_API_URL=http://localhost:19527/blockchain_info/
networks:
- litentry-test-network
healthcheck:
Expand Down Expand Up @@ -251,6 +253,7 @@ services:
- CONTEST_LEGEND_DISCORD_ROLE_ID=CONTEST_LEGEND_DISCORD_ROLE_ID
- CONTEST_POPULARITY_DISCORD_ROLE_ID=CONTEST_POPULARITY_DISCORD_ROLE_ID
- CONTEST_PARTICIPANT_DISCORD_ROLE_ID=CONTEST_PARTICIPANT_DISCORD_ROLE_ID
- BLOCKCHAIN_INFO_API_URL=http://localhost:19527/blockchain_info/
networks:
- litentry-test-network
healthcheck:
Expand Down
1 change: 1 addition & 0 deletions local-setup/.env.dev
Original file line number Diff line number Diff line change
Expand Up @@ -55,3 +55,4 @@ LITENTRY_ARCHIVE_URL=http://localhost:19527
MORALIS_API_URL=http://localhost:19527/moralis/
MORALIS_SOLANA_API_URL=http://localhost:19527/moralis_solana/
KARAT_DAO_API_URL=http://localhost:19527/karat_dao/
BLOCKCHAIN_INFO_API_URL=http://localhost:19527/blockchain_info/
9 changes: 9 additions & 0 deletions primitives/core/src/assertion/web3_token.rs
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,8 @@ pub enum Web3TokenType {
Sol,
#[codec(index = 24)]
Mcrt,
#[codec(index = 25)]
Btc,
}

impl Web3TokenType {
Expand All @@ -88,6 +90,13 @@ impl Web3TokenType {
Self::Nfp => vec![Web3Network::Bsc],
Self::Sol | Self::Mcrt =>
vec![Web3Network::Bsc, Web3Network::Ethereum, Web3Network::Solana],
Self::Btc => vec![
Web3Network::BitcoinP2tr,
Web3Network::BitcoinP2pkh,
Web3Network::BitcoinP2sh,
Web3Network::BitcoinP2wpkh,
Web3Network::BitcoinP2wsh,
],
_ => vec![Web3Network::Ethereum],
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -265,6 +265,7 @@ pub enum TokenHoldingAmountCommand {
Nfp,
Sol,
Mcrt,
Btc,
}

#[derive(Subcommand, Debug)]
Expand Down Expand Up @@ -606,6 +607,7 @@ impl Command {
TokenHoldingAmountCommand::Nfp => TokenHoldingAmount(Web3TokenType::Nfp),
TokenHoldingAmountCommand::Sol => TokenHoldingAmount(Web3TokenType::Sol),
TokenHoldingAmountCommand::Mcrt => TokenHoldingAmount(Web3TokenType::Mcrt),
TokenHoldingAmountCommand::Btc => TokenHoldingAmount(Web3TokenType::Btc),
},
Command::PlatformUser(arg) => match arg {
PlatformUserCommand::KaratDaoUser => PlatformUser(PlatformUserType::KaratDaoUser),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,7 @@ export default {
"Nfp",
"Sol",
"Mcrt",
"Btc",
],
},
// PlatformUserType
Expand Down
1 change: 1 addition & 0 deletions tee-worker/docker/docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,7 @@ services:
- CONTEST_PARTICIPANT_DISCORD_ROLE_ID=CONTEST_PARTICIPANT_DISCORD_ROLE_ID
- LITENTRY_ARCHIVE_URL=http://localhost:19527
- VIP3_URL=http://localhost:19527
- BLOCKCHAIN_INFO_API_URL=http://localhost:19527/blockchain_info/
networks:
- litentry-test-network
healthcheck:
Expand Down
3 changes: 3 additions & 0 deletions tee-worker/docker/multiworker-docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,7 @@ services:
- CONTEST_PARTICIPANT_DISCORD_ROLE_ID=CONTEST_PARTICIPANT_DISCORD_ROLE_ID
- LITENTRY_ARCHIVE_URL=http://localhost:19527
- VIP3_URL=http://localhost:19527
- BLOCKCHAIN_INFO_API_URL=http://localhost:19527/blockchain_info/
networks:
- litentry-test-network
healthcheck:
Expand Down Expand Up @@ -200,6 +201,7 @@ services:
- CONTEST_PARTICIPANT_DISCORD_ROLE_ID=CONTEST_PARTICIPANT_DISCORD_ROLE_ID
- LITENTRY_ARCHIVE_URL=http://localhost:19527
- VIP3_URL=http://localhost:19527
- BLOCKCHAIN_INFO_API_URL=http://localhost:19527/blockchain_info/
networks:
- litentry-test-network
healthcheck:
Expand Down Expand Up @@ -257,6 +259,7 @@ services:
- CONTEST_PARTICIPANT_DISCORD_ROLE_ID=CONTEST_PARTICIPANT_DISCORD_ROLE_ID
- LITENTRY_ARCHIVE_URL=http://localhost:19527
- VIP3_URL=http://localhost:19527
- BLOCKCHAIN_INFO_API_URL=http://localhost:19527/blockchain_info/
networks:
- litentry-test-network
healthcheck:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,9 @@ mod tests {
data_provider_config
.set_nodereal_api_chain_network_url(url.clone() + "/nodereal_jsonrpc/")
.unwrap();
data_provider_config
.set_blockchain_info_api_url(url.clone() + "/blockchain_info/")
.unwrap();
data_provider_config.set_achainable_url(url.clone()).unwrap();
data_provider_config.set_moralis_api_url(url.clone() + "/moralis/").unwrap();
data_provider_config
Expand Down Expand Up @@ -608,4 +611,52 @@ mod tests {
},
}
}

#[test]
fn build_btc_holding_amount_works() {
let data_provider_config: DataProviderConfig = init();
// bc1pgr5fw4p9gl9me0vzjklnlnap669caxc0gsk4j62gff2qktlw6naqm4m3d0
let address = decode_hex(
"0x02e8c39e82aaaa143c3def8d3c7084a539b227244ac9067c3f7fc86cb73a0b7aed"
.as_bytes()
.to_vec(),
)
.unwrap()
.as_slice()
.try_into()
.unwrap();
let identities: Vec<IdentityNetworkTuple> =
vec![(Identity::Bitcoin(address), vec![Web3Network::BitcoinP2tr])];

let req = crate_assertion_build_request(Web3TokenType::Btc, identities);

match build(&req, Web3TokenType::Btc, &data_provider_config) {
Ok(credential) => {
log::info!("build btc TokenHoldingAmount done");
assert_eq!(
*(credential.credential_subject.assertions.first().unwrap()),
AssertionLogic::And {
items: vec![
create_token_assertion_logic(Web3TokenType::Btc),
create_network_address_assertion_logics(Web3TokenType::Btc),
Box::new(AssertionLogic::Item {
src: "$holding_amount".into(),
op: Op::GreaterEq,
dst: "1600".into()
}),
Box::new(AssertionLogic::Item {
src: "$holding_amount".into(),
op: Op::LessThan,
dst: "3000".into()
})
]
}
);
assert_eq!(*(credential.credential_subject.values.first().unwrap()), true);
},
Err(e) => {
panic!("build btc TokenHoldingAmount failed with error {:?}", e);
},
}
}
}
7 changes: 6 additions & 1 deletion tee-worker/litentry/core/common/src/web3_token/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ impl TokenName for Web3TokenType {
Self::Nfp => "NFP",
Self::Sol => "SOL",
Self::Mcrt => "MCRT",
Self::Btc => "BTC",
}
}
}
Expand Down Expand Up @@ -214,7 +215,11 @@ impl TokenDecimals for Web3TokenType {
// Wbtc
(Self::Wbtc, Web3Network::Bsc) | (Self::Wbtc, Web3Network::Ethereum) |
// Mcrt
(Self::Mcrt, Web3Network::Solana) => 8,
(Self::Mcrt, Web3Network::Solana) |
// Btc
(Self::Btc, Web3Network::BitcoinP2tr) | (Self::Btc, Web3Network::BitcoinP2pkh) |
(Self::Btc, Web3Network::BitcoinP2sh) | (Self::Btc, Web3Network::BitcoinP2wpkh) |
(Self::Btc, Web3Network::BitcoinP2wsh) => 8,
// Usdc
(Self::Usdc, Web3Network::Ethereum) |
// Usdt
Expand Down
166 changes: 166 additions & 0 deletions tee-worker/litentry/core/data-providers/src/blockchain_info.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@
// Copyright 2020-2024 Trust Computing GmbH.
// This file is part of Litentry.
//
// Litentry is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Litentry is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Litentry. If not, see <https://www.gnu.org/licenses/>.

#[cfg(all(not(feature = "std"), feature = "sgx"))]
use crate::sgx_reexport_prelude::*;

#[cfg(all(not(feature = "std"), feature = "sgx"))]
extern crate sgx_tstd as std;

use crate::{
build_client_with_cert, DataProviderConfig, Error, HttpError, ReqPath, RetryOption,
RetryableRestGet,
};
use http::header::CONNECTION;
use http_req::response::Headers;
use itc_rest_client::{
http_client::{HttpClient, SendWithCertificateVerification},
rest_client::RestClient,
RestPath,
};
use log::debug;
use serde::{Deserialize, Serialize};
use std::{
format, str,
string::{String, ToString},
vec,
vec::Vec,
};

pub struct BlockChainInfoClient {
retry_option: RetryOption,
client: RestClient<HttpClient<SendWithCertificateVerification>>,
}

#[derive(Debug)]
pub struct BlockChainInfoRequest {
path: String,
query: Option<Vec<(String, String)>>,
}

impl BlockChainInfoClient {
pub fn new(data_provider_config: &DataProviderConfig) -> Self {
let api_retry_delay = data_provider_config.blockchain_info_api_retry_delay;
let api_retry_times = data_provider_config.blockchain_info_api_retry_times;
let api_url = data_provider_config.blockchain_info_api_url.clone();
let retry_option =
RetryOption { retry_delay: Some(api_retry_delay), retry_times: Some(api_retry_times) };

let mut headers = Headers::new();
headers.insert(CONNECTION.as_str(), "close");
let client = build_client_with_cert(api_url.as_str(), headers);

BlockChainInfoClient { retry_option, client }
}

fn get<T>(&mut self, params: BlockChainInfoRequest, fast_fail: bool) -> Result<T, Error>
where
T: serde::de::DeserializeOwned + for<'a> RestPath<ReqPath<'a>>,
{
let retry_option: Option<RetryOption> =
if fast_fail { None } else { Some(self.retry_option.clone()) };
if let Some(query) = params.query {
let transformed_query: Vec<(&str, &str)> =
query.iter().map(|(k, v)| (k.as_str(), v.as_str())).collect();
self.client.get_with_retry::<ReqPath, T>(
ReqPath::new(params.path.as_str()),
&transformed_query,
retry_option,
)
} else {
self.client
.get_retry::<ReqPath, T>(ReqPath::new(params.path.as_str()), retry_option)
}
}
}

#[derive(Serialize, Deserialize, Debug)]
pub struct GetSingleAddressResponse {
pub final_balance: u128,
}

impl<'a> RestPath<ReqPath<'a>> for GetSingleAddressResponse {
fn get_path(path: ReqPath) -> Result<String, HttpError> {
Ok(path.path.into())
}
}

pub trait BlockChainInfoDataApi {
fn get_single_address(
&mut self,
address: String,
fail_fast: bool,
) -> Result<GetSingleAddressResponse, Error>;
}

impl BlockChainInfoDataApi for BlockChainInfoClient {
fn get_single_address(
&mut self,
address: String,
fail_fast: bool,
) -> Result<GetSingleAddressResponse, Error> {
let query: Vec<(String, String)> = vec![("limit".to_string(), "0".into())];

let params =
BlockChainInfoRequest { path: format!("rawaddr/{}", address), query: Some(query) };

debug!("get_single_address, params: {:?}", params);

match self.get::<GetSingleAddressResponse>(params, fail_fast) {
Ok(resp) => {
debug!("get_single_address, response: {:?}", resp);
Ok(resp)
},
Err(e) => {
debug!("get_single_address, error: {:?}", e);
Err(e)
},
}
}
}

#[cfg(test)]
mod tests {
use super::*;
use lc_mock_server::run;

fn init() -> DataProviderConfig {
let _ = env_logger::builder().is_test(true).try_init();
let url = run(0).unwrap() + "/blockchain_info/";

let mut config = DataProviderConfig::new().unwrap();
config.set_blockchain_info_api_url(url).unwrap();
config
}

#[test]
fn does_get_single_address_works() {
let config = init();
let mut client = BlockChainInfoClient::new(&config);
let mut response = client
.get_single_address(
"bc1pgr5fw4p9gl9me0vzjklnlnap669caxc0gsk4j62gff2qktlw6naqm4m3d0".into(),
true,
)
.unwrap();
assert_eq!(response.final_balance, 185123167511);

response = client
.get_single_address("bc1qxhmdufsvnuaaaer4ynz88fspdsxq2h9e9cetdj".into(), false)
.unwrap();
assert_eq!(response.final_balance, 0);
}
}
Loading

0 comments on commit d7a862d

Please sign in to comment.