Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

get rid of Coins, use FT instead #52

Merged
merged 2 commits into from
Dec 15, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 0 additions & 2 deletions DB_DESIGN.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,6 @@ Major thing: it fits into `i128` (10^38).

## New requirements for assets__fungible_token_events table:
1. Change old/new account_id to affected/involved account_id.
2. Add absolute value column. Required for balance request.
3. Rename it to something_with_coins, add coin_id column (later we will also store MT there).

## New requirements for account_changes and balances table:
1. Change the table so that we have the same enumeration column. Required for native_history (pagination)
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ Still under heavy development.

### Phase 1 goals: [development goes here now]
- Provide NEAR balances information, recent history
- Provide FT balances information, recent FT coin history for the contracts implementing Events NEP
- Provide FT balances information, recent FT history for the contracts implementing Events NEP
- Provide NFT information and recent history for the contracts implementing Events NEP
- Provide corresponding Metadata for FT, NFT contracts, NFT items
- [aspirational] Collect usage statistics which could help us to prioritize next steps
Expand All @@ -22,7 +22,7 @@ See also our thoughts about the proposed [DB design](DB_DESIGN.md) which will he
- Add reconciliation logic
- [aspirational] Show data from failed receipts in the history
- [aspirational] Support MT contracts
- [aspirational] Support of querying the balance/history info by symbol (e.g. `GET "/accounts/{account_id}/coins/USN"`)
- [aspirational] Support of querying the balance/history info by symbol (e.g. `GET "/accounts/{account_id}/FT/USN"`)

### Future plans. Phase 3+ goals:
- Make wrappers around existing RPC endpoints for the general blockchain info (blocks, chunks, transactions, etc.)
Expand Down
3 changes: 2 additions & 1 deletion src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,8 @@ We would love to hear from you on the data APIs you need, please leave feedback
.route("/", actix_web::web::get().to(playground_ui))
.wrap_api_with_spec(spec);

app = app.configure(modules::coin::register_services);
app = app.configure(modules::native::register_services);
app = app.configure(modules::ft::register_services);
app = app.configure(modules::nft::register_services);

app.with_json_spec_at(format!("{base_path}/spec/v2.json").as_str())
Expand Down
8 changes: 0 additions & 8 deletions src/modules/coin/data_provider/mod.rs

This file was deleted.

32 changes: 0 additions & 32 deletions src/modules/coin/mod.rs

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,50 +1,15 @@
use crate::modules::coin;
use crate::{db_helpers, errors, rpc_helpers, types};
use crate::modules::ft;
use crate::{db_helpers, rpc_helpers, types};
use std::str::FromStr;

pub(crate) async fn get_near_balance(
pool: &sqlx::Pool<sqlx::Postgres>,
block: &db_helpers::Block,
account_id: &near_primitives::types::AccountId,
) -> crate::Result<coin::schemas::NearBalanceResponse> {
let balances =
db_helpers::select_retry_or_panic::<super::models::AccountChangesBalance>(
pool,
r"
WITH t AS (
SELECT affected_account_nonstaked_balance + affected_account_staked_balance balance
FROM account_changes
WHERE affected_account_id = $1 AND changed_in_block_timestamp <= $2::numeric(20, 0)
ORDER BY changed_in_block_timestamp DESC
)
SELECT * FROM t LIMIT 1
",
&[account_id.to_string(), block.timestamp.to_string()],
).await?;

match balances.first() {
Some(balance) => Ok(coin::schemas::NearBalanceResponse {
balance: types::numeric::to_u128(&balance.balance)?.into(),
metadata: super::metadata::get_near_metadata(),
block_timestamp_nanos: block.timestamp.into(),
block_height: block.height.into(),
}),
None => Err(errors::ErrorKind::DBError(format!(
"Could not find the data in account_changes table for account_id {}",
account_id
))
.into()),
}
}

// TODO PHASE 2 pagination (recently updated go first), by artificial index added to assets__fungible_token_events
pub(crate) async fn get_coin_balances(
pub(crate) async fn get_ft_balances(
pool: &sqlx::Pool<sqlx::Postgres>,
rpc_client: &near_jsonrpc_client::JsonRpcClient,
block: &db_helpers::Block,
account_id: &near_primitives::types::AccountId,
pagination: &types::query_params::Pagination,
) -> crate::Result<Vec<coin::schemas::Coin>> {
) -> crate::Result<Vec<ft::schemas::FtBalance>> {
let query = r"
SELECT DISTINCT emitted_by_contract_account_id account_id
FROM assets__fungible_token_events
Expand All @@ -64,12 +29,11 @@ pub(crate) async fn get_coin_balances(
)
.await?;

let mut balances: Vec<coin::schemas::Coin> = vec![];
let mut balances: Vec<ft::schemas::FtBalance> = vec![];
for contract in contracts {
if let Ok(contract_id) = near_primitives::types::AccountId::from_str(&contract.account_id) {
balances.append(
&mut get_coin_balances_by_contract(rpc_client, block, &contract_id, account_id)
.await?,
balances.push(
get_ft_balance_by_contract(rpc_client, block, &contract_id, account_id).await?,
);
}
}
Expand All @@ -78,38 +42,36 @@ pub(crate) async fn get_coin_balances(

// TODO PHASE 2 change RPC call to DB call by adding absolute amount values to assets__fungible_token_events
// TODO PHASE 2 add metadata tables to the DB, with periodic autoupdate
pub(crate) async fn get_coin_balances_by_contract(
pub(crate) async fn get_ft_balance_by_contract(
rpc_client: &near_jsonrpc_client::JsonRpcClient,
block: &db_helpers::Block,
contract_id: &near_primitives::types::AccountId,
account_id: &near_primitives::types::AccountId,
) -> crate::Result<Vec<coin::schemas::Coin>> {
let (balance, metadata) = (
get_ft_balance_by_contract(
) -> crate::Result<ft::schemas::FtBalance> {
let (amount, metadata) = (
get_ft_amount(
rpc_client,
contract_id.clone(),
account_id.clone(),
block.height,
)
.await?,
super::metadata::get_ft_contract_metadata(rpc_client, contract_id.clone(), block.height)
.await?,
super::metadata::get_ft_metadata(rpc_client, contract_id.clone(), block.height).await?,
);

Ok(vec![coin::schemas::Coin {
standard: "nep141".to_string(),
contract_account_id: Some(contract_id.clone().into()),
balance: balance.into(),
metadata: coin::schemas::CoinMetadata {
Ok(ft::schemas::FtBalance {
amount: amount.into(),
contract_account_id: contract_id.clone().into(),
metadata: ft::schemas::Metadata {
name: metadata.name,
symbol: metadata.symbol,
icon: metadata.icon,
decimals: metadata.decimals,
},
}])
})
}

pub(crate) async fn get_ft_balance_by_contract(
pub(crate) async fn get_ft_amount(
rpc_client: &near_jsonrpc_client::JsonRpcClient,
contract_id: near_primitives::types::AccountId,
account_id: near_primitives::types::AccountId,
Expand All @@ -126,40 +88,20 @@ pub(crate) async fn get_ft_balance_by_contract(
Ok(serde_json::from_slice::<types::U128>(&response.result)?.0)
}

impl From<coin::schemas::NearBalanceResponse> for coin::schemas::Coin {
fn from(near_coin: coin::schemas::NearBalanceResponse) -> Self {
coin::schemas::Coin {
standard: "nearprotocol".to_string(),
balance: near_coin.balance,
contract_account_id: None,
metadata: near_coin.metadata,
}
}
}

#[cfg(test)]
mod tests {
use super::*;
use crate::modules::tests::*;
use std::str::FromStr;

#[tokio::test]
async fn test_near_balance() {
let pool = init_db().await;
let block = get_block();
let account = near_primitives::types::AccountId::from_str("tomato.near").unwrap();
let balance = get_near_balance(&pool, &block, &account).await;
insta::assert_debug_snapshot!(balance);
}

#[tokio::test]
async fn test_coin_balances() {
let pool = init_db().await;
let rpc_client = init_rpc();
let block = get_block();
let account = near_primitives::types::AccountId::from_str("patagonita.near").unwrap();
let pagination = types::query_params::Pagination { limit: 10 };
let balance = get_coin_balances(&pool, &rpc_client, &block, &account, &pagination).await;
let balance = get_ft_balances(&pool, &rpc_client, &block, &account, &pagination).await;
insta::assert_debug_snapshot!(balance);
}

Expand All @@ -170,7 +112,7 @@ mod tests {
let block = get_block();
let account = near_primitives::types::AccountId::from_str("olga.near").unwrap();
let pagination = types::query_params::Pagination { limit: 10 };
let balance = get_coin_balances(&pool, &rpc_client, &block, &account, &pagination)
let balance = get_ft_balances(&pool, &rpc_client, &block, &account, &pagination)
.await
.unwrap();
assert!(balance.is_empty());
Expand All @@ -183,7 +125,7 @@ mod tests {
let contract = near_primitives::types::AccountId::from_str("nexp.near").unwrap();
let account = near_primitives::types::AccountId::from_str("patagonita.near").unwrap();

let balance = get_coin_balances_by_contract(&rpc_client, &block, &contract, &account).await;
let balance = get_ft_balance_by_contract(&rpc_client, &block, &contract, &account).await;
insta::assert_debug_snapshot!(balance);
}

Expand All @@ -194,7 +136,7 @@ mod tests {
let contract = near_primitives::types::AccountId::from_str("olga.near").unwrap();
let account = near_primitives::types::AccountId::from_str("patagonita.near").unwrap();

let balance = get_coin_balances_by_contract(&rpc_client, &block, &contract, &account).await;
let balance = get_ft_balance_by_contract(&rpc_client, &block, &contract, &account).await;
insta::assert_debug_snapshot!(balance);
}

Expand All @@ -205,7 +147,7 @@ mod tests {
let contract = near_primitives::types::AccountId::from_str("comic.paras.near").unwrap();
let account = near_primitives::types::AccountId::from_str("patagonita.near").unwrap();

let balance = get_coin_balances_by_contract(&rpc_client, &block, &contract, &account).await;
let balance = get_ft_balance_by_contract(&rpc_client, &block, &contract, &account).await;
insta::assert_debug_snapshot!(balance);
}
}
Loading