diff --git a/.env b/.env index e787d58..a965ca7 100644 --- a/.env +++ b/.env @@ -4,6 +4,7 @@ MAILTRAP_ADDRESS=smtp.mailtrap.io MAILTRAP_DOMAIN=smtp.mailtrap.io MAILTRAP_PORT=2525 MAILER_DEFAULT_URL_HOST=localhost:5000 +TATUM_API_KEY=d8f66b09-d3ff-43ca-9b59-31b1b78d2660 # SLACK_WEBHOOK_URL=https://hooks.slack.com/services/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 # production diff --git a/Gemfile b/Gemfile index 898a5f4..8329884 100644 --- a/Gemfile +++ b/Gemfile @@ -29,6 +29,7 @@ gem "enumerize" gem "graphql" gem "pundit" gem "ransack", "~> 2.4" +gem "httparty", "~> 0.19.0" group :development, :test do gem "dotenv-rails" diff --git a/Gemfile.lock b/Gemfile.lock index 1684e67..da0bb91 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -124,6 +124,9 @@ GEM graphql (1.12.14) graphql_playground-rails (2.1.0) rails (>= 5.1.0) + httparty (0.19.0) + mime-types (~> 3.0) + multi_xml (>= 0.5.2) i18n (1.8.10) concurrent-ruby (~> 1.0) image_processing (1.12.1) @@ -155,6 +158,9 @@ GEM mini_mime (>= 0.1.1) marcel (1.0.1) method_source (1.0.0) + mime-types (3.3.1) + mime-types-data (~> 3.2015) + mime-types-data (3.2021.0901) mini_magick (4.11.0) mini_mime (1.1.0) mini_portile2 (2.6.1) @@ -171,6 +177,7 @@ GEM money (~> 6.13.2) railties (>= 3.0) msgpack (1.4.2) + multi_xml (0.6.0) nio4r (2.5.8) nokogiri (1.12.1) mini_portile2 (~> 2.6.1) @@ -366,6 +373,7 @@ DEPENDENCIES foreman graphql graphql_playground-rails + httparty (~> 0.19.0) image_processing (~> 1.12) listen (~> 3.3) money-rails diff --git a/app/dashboards/fiat_balance_dashboard.rb b/app/dashboards/fiat_balance_dashboard.rb index bf4e29b..dc4e534 100644 --- a/app/dashboards/fiat_balance_dashboard.rb +++ b/app/dashboards/fiat_balance_dashboard.rb @@ -31,7 +31,7 @@ class FiatBalanceDashboard < Administrate::BaseDashboard # FORM_ATTRIBUTES # an array of attributes that will be displayed # on the model's form (`new` and `edit`) pages. - FORM_ATTRIBUTES = [:user, :amount_cents].freeze + FORM_ATTRIBUTES = [:amount_cents].freeze # COLLECTION_FILTERS # a hash that defines filters that can be used while searching via the search diff --git a/app/graphql/types/user_type.rb b/app/graphql/types/user_type.rb index 8221624..32f994c 100644 --- a/app/graphql/types/user_type.rb +++ b/app/graphql/types/user_type.rb @@ -10,7 +10,10 @@ module Types field :email, String, null: false field :first_name, String, null: false field :last_name, String, null: false - field :wallet_address, String, null: true field :fiat_balance, FiatBalanceType, null: false + field :wallet, WalletType, null: false + def wallet + Wallet.new(object) + end end end diff --git a/app/graphql/types/wallet_type.rb b/app/graphql/types/wallet_type.rb new file mode 100644 index 0000000..1757741 --- /dev/null +++ b/app/graphql/types/wallet_type.rb @@ -0,0 +1,9 @@ +# frozen_string_literal: true +module Types + class WalletType < Types::BaseObject + graphql_name "Wallet" + + field :address, String, null: true + field :cake_balance, String, null: false + end +end diff --git a/app/javascript/__generated__/schema.graphql b/app/javascript/__generated__/schema.graphql index 6091e7f..0a0c693 100644 --- a/app/javascript/__generated__/schema.graphql +++ b/app/javascript/__generated__/schema.graphql @@ -553,5 +553,10 @@ type User { firstName: String! id: ID! lastName: String! - walletAddress: String + wallet: Wallet! +} + +type Wallet { + address: String + cakeBalance: String! } diff --git a/app/javascript/src/__generated__/AppQuery.graphql.ts b/app/javascript/src/__generated__/AppQuery.graphql.ts index 71f5f3f..282b69c 100644 --- a/app/javascript/src/__generated__/AppQuery.graphql.ts +++ b/app/javascript/src/__generated__/AppQuery.graphql.ts @@ -27,7 +27,9 @@ query AppQuery { fragment UserProvider_user on User { firstName - walletAddress + wallet { + address + } } */ @@ -82,8 +84,19 @@ const node: ConcreteRequest = { { "alias": null, "args": null, - "kind": "ScalarField", - "name": "walletAddress", + "concreteType": "Wallet", + "kind": "LinkedField", + "name": "wallet", + "plural": false, + "selections": [ + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "address", + "storageKey": null + } + ], "storageKey": null }, { @@ -99,12 +112,12 @@ const node: ConcreteRequest = { ] }, "params": { - "cacheID": "56b4be302cf9b9ec226ad8145170961b", + "cacheID": "ae618245e5a3baf946034e1efe3682de", "id": null, "metadata": {}, "name": "AppQuery", "operationKind": "query", - "text": "query AppQuery {\n currentUser {\n ...UserProvider_user\n id\n }\n}\n\nfragment UserProvider_user on User {\n firstName\n walletAddress\n}\n" + "text": "query AppQuery {\n currentUser {\n ...UserProvider_user\n id\n }\n}\n\nfragment UserProvider_user on User {\n firstName\n wallet {\n address\n }\n}\n" } }; (node as any).hash = 'aac57a65620cf50754d54f3c8d6495cf'; diff --git a/app/javascript/src/contexts/UserProvider.tsx b/app/javascript/src/contexts/UserProvider.tsx index 6d295e8..8700339 100644 --- a/app/javascript/src/contexts/UserProvider.tsx +++ b/app/javascript/src/contexts/UserProvider.tsx @@ -33,7 +33,9 @@ export const UserProvider: FC = ({ userRef, children }) => { graphql` fragment UserProvider_user on User { firstName - walletAddress + wallet { + address + } } `, userRef @@ -42,7 +44,7 @@ export const UserProvider: FC = ({ userRef, children }) => { const user = userData ? { firstName: userData.firstName, - walletAddress: userData.walletAddress, + walletAddress: userData.wallet.address, } : null; diff --git a/app/javascript/src/contexts/__generated__/UserProvider_user.graphql.ts b/app/javascript/src/contexts/__generated__/UserProvider_user.graphql.ts index 46f7aa4..90b2356 100644 --- a/app/javascript/src/contexts/__generated__/UserProvider_user.graphql.ts +++ b/app/javascript/src/contexts/__generated__/UserProvider_user.graphql.ts @@ -6,7 +6,9 @@ import { ReaderFragment } from "relay-runtime"; import { FragmentRefs } from "relay-runtime"; export type UserProvider_user = { readonly firstName: string; - readonly walletAddress: string | null; + readonly wallet: { + readonly address: string | null; + }; readonly " $refType": "UserProvider_user"; }; export type UserProvider_user$data = UserProvider_user; @@ -33,13 +35,24 @@ const node: ReaderFragment = { { "alias": null, "args": null, - "kind": "ScalarField", - "name": "walletAddress", + "concreteType": "Wallet", + "kind": "LinkedField", + "name": "wallet", + "plural": false, + "selections": [ + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "address", + "storageKey": null + } + ], "storageKey": null } ], "type": "User", "abstractKey": null }; -(node as any).hash = 'ef997d2646b4d39178c6f3318509a7cb'; +(node as any).hash = '4f6b86f489ce0df288106cd92060b889'; export default node; diff --git a/app/javascript/src/pages/Home/PoolListing.tsx b/app/javascript/src/pages/Home/PoolListing.tsx index 07392f4..cbf7c1b 100644 --- a/app/javascript/src/pages/Home/PoolListing.tsx +++ b/app/javascript/src/pages/Home/PoolListing.tsx @@ -1,14 +1,30 @@ import React from "react"; +import { useLazyLoadQuery } from "react-relay"; +import { graphql } from "babel-plugin-relay/macro"; import { Pool } from "./Pool"; import { Spinner } from "../../components"; import { usePoolListing } from "./hooks"; +import type { PoolListingQuery } from "./__generated__/PoolListingQuery.graphql"; +import { formatCake } from "../../utils/cake"; export const PoolListing = () => { const { isLoading, validPools } = usePoolListing(); - // TODO: puxar valor da wallet - const balance = "0"; + const { currentUser } = useLazyLoadQuery( + graphql` + query PoolListingQuery { + currentUser { + wallet { + cakeBalance + } + } + } + `, + {} + ); + + const balance = formatCake(currentUser?.wallet.cakeBalance); if (isLoading && !validPools.length) { return ( diff --git a/app/javascript/src/pages/Home/__generated__/PoolListingQuery.graphql.ts b/app/javascript/src/pages/Home/__generated__/PoolListingQuery.graphql.ts new file mode 100644 index 0000000..3e10ed0 --- /dev/null +++ b/app/javascript/src/pages/Home/__generated__/PoolListingQuery.graphql.ts @@ -0,0 +1,112 @@ +/* tslint:disable */ +/* eslint-disable */ +// @ts-nocheck + +import { ConcreteRequest } from "relay-runtime"; +export type PoolListingQueryVariables = {}; +export type PoolListingQueryResponse = { + readonly currentUser: { + readonly wallet: { + readonly cakeBalance: string; + }; + } | null; +}; +export type PoolListingQuery = { + readonly response: PoolListingQueryResponse; + readonly variables: PoolListingQueryVariables; +}; + + + +/* +query PoolListingQuery { + currentUser { + wallet { + cakeBalance + } + id + } +} +*/ + +const node: ConcreteRequest = (function(){ +var v0 = { + "alias": null, + "args": null, + "concreteType": "Wallet", + "kind": "LinkedField", + "name": "wallet", + "plural": false, + "selections": [ + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "cakeBalance", + "storageKey": null + } + ], + "storageKey": null +}; +return { + "fragment": { + "argumentDefinitions": [], + "kind": "Fragment", + "metadata": null, + "name": "PoolListingQuery", + "selections": [ + { + "alias": null, + "args": null, + "concreteType": "User", + "kind": "LinkedField", + "name": "currentUser", + "plural": false, + "selections": [ + (v0/*: any*/) + ], + "storageKey": null + } + ], + "type": "Query", + "abstractKey": null + }, + "kind": "Request", + "operation": { + "argumentDefinitions": [], + "kind": "Operation", + "name": "PoolListingQuery", + "selections": [ + { + "alias": null, + "args": null, + "concreteType": "User", + "kind": "LinkedField", + "name": "currentUser", + "plural": false, + "selections": [ + (v0/*: any*/), + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "id", + "storageKey": null + } + ], + "storageKey": null + } + ] + }, + "params": { + "cacheID": "555226365d27590d8236ea1effdf9ddc", + "id": null, + "metadata": {}, + "name": "PoolListingQuery", + "operationKind": "query", + "text": "query PoolListingQuery {\n currentUser {\n wallet {\n cakeBalance\n }\n id\n }\n}\n" + } +}; +})(); +(node as any).hash = 'afdc45802c0d92b114c2ebb5c3530ec2'; +export default node; diff --git a/app/javascript/src/pages/Orders/Exchange/ExchangePanel/ExchangePanel.tsx b/app/javascript/src/pages/Orders/Exchange/ExchangePanel/ExchangePanel.tsx index fbf044f..1e46b24 100644 --- a/app/javascript/src/pages/Orders/Exchange/ExchangePanel/ExchangePanel.tsx +++ b/app/javascript/src/pages/Orders/Exchange/ExchangePanel/ExchangePanel.tsx @@ -9,6 +9,7 @@ import { commitCreateSellCryptoOrderMutation } from "./createSellCryptoOrder"; import { commitCreateBuyCryptoOrderMutation } from "./createBuyCryptoOrder"; import { Input, Button } from "../../../../components"; import type { ExchangePanel_user$key } from "./__generated__/ExchangePanel_user.graphql"; +import { formatCake } from "../../../../utils/cake"; const tabBaseStyles = "w-full text-base font-bold text-black px-4 py-2 focus:ring-blue-500"; @@ -32,14 +33,15 @@ export const ExchangePanel: FC = ({ userRef }) => { fiatBalance { amountCents } + wallet { + cakeBalance + } } `, userRef ); - // TODO: puxar valor da wallet - const balanceAmount = 0; - + const balanceAmount = formatCake(user?.wallet.cakeBalance); const fiatBalanceAmount = user?.fiatBalance.amountCents ?? 0; const avaliableCrypto = new BigNumber(balanceAmount); diff --git a/app/javascript/src/pages/Orders/Exchange/ExchangePanel/__generated__/ExchangePanel_user.graphql.ts b/app/javascript/src/pages/Orders/Exchange/ExchangePanel/__generated__/ExchangePanel_user.graphql.ts index 93e06ba..02930ed 100644 --- a/app/javascript/src/pages/Orders/Exchange/ExchangePanel/__generated__/ExchangePanel_user.graphql.ts +++ b/app/javascript/src/pages/Orders/Exchange/ExchangePanel/__generated__/ExchangePanel_user.graphql.ts @@ -8,6 +8,9 @@ export type ExchangePanel_user = { readonly fiatBalance: { readonly amountCents: number; }; + readonly wallet: { + readonly cakeBalance: string; + }; readonly " $refType": "ExchangePanel_user"; }; export type ExchangePanel_user$data = ExchangePanel_user; @@ -41,10 +44,28 @@ const node: ReaderFragment = { } ], "storageKey": null + }, + { + "alias": null, + "args": null, + "concreteType": "Wallet", + "kind": "LinkedField", + "name": "wallet", + "plural": false, + "selections": [ + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "cakeBalance", + "storageKey": null + } + ], + "storageKey": null } ], "type": "User", "abstractKey": null }; -(node as any).hash = '2058ddb20a60f148a524083fa0a680ea'; +(node as any).hash = '88cc0dedfa3a3b9bb73d6b4745e0cf5a'; export default node; diff --git a/app/javascript/src/pages/Orders/Exchange/__generated__/ExchangeQuery.graphql.ts b/app/javascript/src/pages/Orders/Exchange/__generated__/ExchangeQuery.graphql.ts index 5adf7a5..f834d84 100644 --- a/app/javascript/src/pages/Orders/Exchange/__generated__/ExchangeQuery.graphql.ts +++ b/app/javascript/src/pages/Orders/Exchange/__generated__/ExchangeQuery.graphql.ts @@ -68,6 +68,9 @@ fragment ExchangePanel_user on User { amountCents id } + wallet { + cakeBalance + } } */ @@ -192,6 +195,24 @@ return { ], "storageKey": null }, + { + "alias": null, + "args": null, + "concreteType": "Wallet", + "kind": "LinkedField", + "name": "wallet", + "plural": false, + "selections": [ + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "cakeBalance", + "storageKey": null + } + ], + "storageKey": null + }, (v0/*: any*/) ], "storageKey": null @@ -301,12 +322,12 @@ return { ] }, "params": { - "cacheID": "30aa6f9d81cfe033aee64b8577d15936", + "cacheID": "2168c066ea4bb43d5ab066a00a35a33b", "id": null, "metadata": {}, "name": "ExchangeQuery", "operationKind": "query", - "text": "query ExchangeQuery {\n currentUser {\n ...ExchangePanel_user\n id\n }\n buyCryptoOrders {\n ...ExchangeHistory_buyCryptoOrders\n }\n sellCryptoOrders {\n ...ExchangeHistory_sellCryptoOrders\n }\n}\n\nfragment ExchangeHistory_buyCryptoOrders on BuyCryptoOrderConnection {\n edges {\n node {\n id\n status\n createdAt\n paidAmountCents\n receivedAmount\n __typename\n }\n }\n}\n\nfragment ExchangeHistory_sellCryptoOrders on SellCryptoOrderConnection {\n edges {\n node {\n id\n status\n paidAmount\n receivedAmountCents\n createdAt\n __typename\n }\n }\n}\n\nfragment ExchangePanel_user on User {\n fiatBalance {\n amountCents\n id\n }\n}\n" + "text": "query ExchangeQuery {\n currentUser {\n ...ExchangePanel_user\n id\n }\n buyCryptoOrders {\n ...ExchangeHistory_buyCryptoOrders\n }\n sellCryptoOrders {\n ...ExchangeHistory_sellCryptoOrders\n }\n}\n\nfragment ExchangeHistory_buyCryptoOrders on BuyCryptoOrderConnection {\n edges {\n node {\n id\n status\n createdAt\n paidAmountCents\n receivedAmount\n __typename\n }\n }\n}\n\nfragment ExchangeHistory_sellCryptoOrders on SellCryptoOrderConnection {\n edges {\n node {\n id\n status\n paidAmount\n receivedAmountCents\n createdAt\n __typename\n }\n }\n}\n\nfragment ExchangePanel_user on User {\n fiatBalance {\n amountCents\n id\n }\n wallet {\n cakeBalance\n }\n}\n" } }; })(); diff --git a/app/javascript/src/pages/Wallet/Balance.tsx b/app/javascript/src/pages/Wallet/Balance.tsx index 191b46f..4dd01b5 100644 --- a/app/javascript/src/pages/Wallet/Balance.tsx +++ b/app/javascript/src/pages/Wallet/Balance.tsx @@ -1,13 +1,30 @@ +import { graphql } from "babel-plugin-relay/macro"; import type { FC } from "react"; import React from "react"; +import { useFragment } from "react-relay"; import { Table, TableRow } from "../../components"; +import { formatCake } from "../../utils/cake"; import { getCurrencyLogo } from "../../utils/getCurrencyLogo"; +import type { Balance_wallet$key } from "./__generated__/Balance_wallet.graphql"; -export const Balance: FC = () => { - const node = { - amount: "PUXAR VALOR DA CARTEIRA", - }; +type Props = { + userRef: Balance_wallet$key; +}; + +export const Balance: FC = ({ userRef }) => { + const { wallet } = useFragment( + graphql` + fragment Balance_wallet on User { + wallet { + cakeBalance + } + } + `, + userRef + ); + + const cakeBalance = formatCake(wallet.cakeBalance); return (
@@ -27,7 +44,7 @@ export const Balance: FC = () => {

CAKE

, - node.amount, + cakeBalance, ]} /> diff --git a/app/javascript/src/pages/Wallet/FiatBalance.tsx b/app/javascript/src/pages/Wallet/FiatBalance.tsx index 162a162..c1c8355 100644 --- a/app/javascript/src/pages/Wallet/FiatBalance.tsx +++ b/app/javascript/src/pages/Wallet/FiatBalance.tsx @@ -6,22 +6,24 @@ import { useFragment } from "react-relay"; import type { FiatBalance_fiatBalance$key } from "./__generated__/FiatBalance_fiatBalance.graphql"; type Props = { - fiatBalancesRef: FiatBalance_fiatBalance$key; + userRef: FiatBalance_fiatBalance$key; }; -export const FiatBalance: FC = ({ fiatBalancesRef }) => { - const userFiatBalance = useFragment( +export const FiatBalance: FC = ({ userRef }) => { + const { fiatBalance } = useFragment( graphql` - fragment FiatBalance_fiatBalance on FiatBalance { - amountCents - amountCurrency + fragment FiatBalance_fiatBalance on User { + fiatBalance { + amountCents + amountCurrency + } } `, - fiatBalancesRef + userRef ); - if (!userFiatBalance) return null; + if (!fiatBalance) return null; - const { amountCents, amountCurrency } = userFiatBalance; + const { amountCents, amountCurrency } = fiatBalance; const amount = (amountCents ? amountCents / 100 : 0).toFixed(2); diff --git a/app/javascript/src/pages/Wallet/Wallet.tsx b/app/javascript/src/pages/Wallet/Wallet.tsx index 6222eeb..ed6ae48 100644 --- a/app/javascript/src/pages/Wallet/Wallet.tsx +++ b/app/javascript/src/pages/Wallet/Wallet.tsx @@ -15,9 +15,8 @@ export const Wallet: FC = () => { graphql` query WalletQuery { currentUser { - fiatBalance { - ...FiatBalance_fiatBalance - } + ...FiatBalance_fiatBalance + ...Balance_wallet } } `, @@ -30,8 +29,8 @@ export const Wallet: FC = () => {
- - + +
diff --git a/app/javascript/src/pages/Wallet/__generated__/Balance_wallet.graphql.ts b/app/javascript/src/pages/Wallet/__generated__/Balance_wallet.graphql.ts new file mode 100644 index 0000000..94c3850 --- /dev/null +++ b/app/javascript/src/pages/Wallet/__generated__/Balance_wallet.graphql.ts @@ -0,0 +1,50 @@ +/* tslint:disable */ +/* eslint-disable */ +// @ts-nocheck + +import { ReaderFragment } from "relay-runtime"; +import { FragmentRefs } from "relay-runtime"; +export type Balance_wallet = { + readonly wallet: { + readonly cakeBalance: string; + }; + readonly " $refType": "Balance_wallet"; +}; +export type Balance_wallet$data = Balance_wallet; +export type Balance_wallet$key = { + readonly " $data"?: Balance_wallet$data; + readonly " $fragmentRefs": FragmentRefs<"Balance_wallet">; +}; + + + +const node: ReaderFragment = { + "argumentDefinitions": [], + "kind": "Fragment", + "metadata": null, + "name": "Balance_wallet", + "selections": [ + { + "alias": null, + "args": null, + "concreteType": "Wallet", + "kind": "LinkedField", + "name": "wallet", + "plural": false, + "selections": [ + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "cakeBalance", + "storageKey": null + } + ], + "storageKey": null + } + ], + "type": "User", + "abstractKey": null +}; +(node as any).hash = '27ddb42954aa66b033735eeea5746516'; +export default node; diff --git a/app/javascript/src/pages/Wallet/__generated__/FiatBalance_fiatBalance.graphql.ts b/app/javascript/src/pages/Wallet/__generated__/FiatBalance_fiatBalance.graphql.ts index 7b34332..b10924c 100644 --- a/app/javascript/src/pages/Wallet/__generated__/FiatBalance_fiatBalance.graphql.ts +++ b/app/javascript/src/pages/Wallet/__generated__/FiatBalance_fiatBalance.graphql.ts @@ -5,8 +5,10 @@ import { ReaderFragment } from "relay-runtime"; import { FragmentRefs } from "relay-runtime"; export type FiatBalance_fiatBalance = { - readonly amountCents: number; - readonly amountCurrency: string; + readonly fiatBalance: { + readonly amountCents: number; + readonly amountCurrency: string; + }; readonly " $refType": "FiatBalance_fiatBalance"; }; export type FiatBalance_fiatBalance$data = FiatBalance_fiatBalance; @@ -26,20 +28,31 @@ const node: ReaderFragment = { { "alias": null, "args": null, - "kind": "ScalarField", - "name": "amountCents", - "storageKey": null - }, - { - "alias": null, - "args": null, - "kind": "ScalarField", - "name": "amountCurrency", + "concreteType": "FiatBalance", + "kind": "LinkedField", + "name": "fiatBalance", + "plural": false, + "selections": [ + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "amountCents", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "amountCurrency", + "storageKey": null + } + ], "storageKey": null } ], - "type": "FiatBalance", + "type": "User", "abstractKey": null }; -(node as any).hash = 'dc28e4dca104c7d25465a30412661af2'; +(node as any).hash = '4371bbd59e9a50e7f32aa65bf982c19e'; export default node; diff --git a/app/javascript/src/pages/Wallet/__generated__/WalletQuery.graphql.ts b/app/javascript/src/pages/Wallet/__generated__/WalletQuery.graphql.ts index 224fb8a..13ad26e 100644 --- a/app/javascript/src/pages/Wallet/__generated__/WalletQuery.graphql.ts +++ b/app/javascript/src/pages/Wallet/__generated__/WalletQuery.graphql.ts @@ -7,9 +7,7 @@ import { FragmentRefs } from "relay-runtime"; export type WalletQueryVariables = {}; export type WalletQueryResponse = { readonly currentUser: { - readonly fiatBalance: { - readonly " $fragmentRefs": FragmentRefs<"FiatBalance_fiatBalance">; - }; + readonly " $fragmentRefs": FragmentRefs<"FiatBalance_fiatBalance" | "Balance_wallet">; } | null; }; export type WalletQuery = { @@ -22,17 +20,24 @@ export type WalletQuery = { /* query WalletQuery { currentUser { - fiatBalance { - ...FiatBalance_fiatBalance - id - } + ...FiatBalance_fiatBalance + ...Balance_wallet id } } -fragment FiatBalance_fiatBalance on FiatBalance { - amountCents - amountCurrency +fragment Balance_wallet on User { + wallet { + cakeBalance + } +} + +fragment FiatBalance_fiatBalance on User { + fiatBalance { + amountCents + amountCurrency + id + } } */ @@ -60,20 +65,14 @@ return { "plural": false, "selections": [ { - "alias": null, "args": null, - "concreteType": "FiatBalance", - "kind": "LinkedField", - "name": "fiatBalance", - "plural": false, - "selections": [ - { - "args": null, - "kind": "FragmentSpread", - "name": "FiatBalance_fiatBalance" - } - ], - "storageKey": null + "kind": "FragmentSpread", + "name": "FiatBalance_fiatBalance" + }, + { + "args": null, + "kind": "FragmentSpread", + "name": "Balance_wallet" } ], "storageKey": null @@ -122,6 +121,24 @@ return { ], "storageKey": null }, + { + "alias": null, + "args": null, + "concreteType": "Wallet", + "kind": "LinkedField", + "name": "wallet", + "plural": false, + "selections": [ + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "cakeBalance", + "storageKey": null + } + ], + "storageKey": null + }, (v0/*: any*/) ], "storageKey": null @@ -129,14 +146,14 @@ return { ] }, "params": { - "cacheID": "4397ad78f82d23c0a186b71bea7c3898", + "cacheID": "4631f43e84d22d8fdfa82706d907f478", "id": null, "metadata": {}, "name": "WalletQuery", "operationKind": "query", - "text": "query WalletQuery {\n currentUser {\n fiatBalance {\n ...FiatBalance_fiatBalance\n id\n }\n id\n }\n}\n\nfragment FiatBalance_fiatBalance on FiatBalance {\n amountCents\n amountCurrency\n}\n" + "text": "query WalletQuery {\n currentUser {\n ...FiatBalance_fiatBalance\n ...Balance_wallet\n id\n }\n}\n\nfragment Balance_wallet on User {\n wallet {\n cakeBalance\n }\n}\n\nfragment FiatBalance_fiatBalance on User {\n fiatBalance {\n amountCents\n amountCurrency\n id\n }\n}\n" } }; })(); -(node as any).hash = '83fd609428103b13e79c14d20fefaabe'; +(node as any).hash = 'a91fc17a25b5a68672b3016813de17bc'; export default node; diff --git a/app/javascript/src/utils/cake.ts b/app/javascript/src/utils/cake.ts new file mode 100644 index 0000000..d9e4fb7 --- /dev/null +++ b/app/javascript/src/utils/cake.ts @@ -0,0 +1,2 @@ +export const formatCake = (value?: string) => + parseFloat(value ?? "0").toFixed(5); diff --git a/app/models/application_record.rb b/app/models/application_record.rb index 767a072..06ba156 100644 --- a/app/models/application_record.rb +++ b/app/models/application_record.rb @@ -1,4 +1,6 @@ # frozen_string_literal: true class ApplicationRecord < ActiveRecord::Base self.abstract_class = true + + default_scope { order(created_at: :desc) } end diff --git a/app/models/concerns/processable.rb b/app/models/concerns/processable.rb index 56bde7c..a9d7f3c 100644 --- a/app/models/concerns/processable.rb +++ b/app/models/concerns/processable.rb @@ -5,6 +5,10 @@ module Processable included do enumerize :status, in: [:processing, :completed, :canceled], default: :processing + + status.values.each do |value| + scope value, -> { where(status: value) } + end end def processing? diff --git a/app/models/stake_order.rb b/app/models/stake_order.rb index b5f9561..bbc39fb 100644 --- a/app/models/stake_order.rb +++ b/app/models/stake_order.rb @@ -33,6 +33,9 @@ class StakeOrder < ApplicationRecord super & ["pool_name", "amount"] end + scope :add, -> { where("amount > 0") } + scope :remove, -> { where("amount < 0") } + private def notification_message diff --git a/app/models/user.rb b/app/models/user.rb index 3023f3c..fbbe797 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -29,6 +29,7 @@ class User < ApplicationRecord has_many :documents, class_name: "UserDocument", dependent: :destroy has_many :stake_orders, dependent: :restrict_with_error + has_many :sell_crypto_orders, dependent: :restrict_with_error has_one :fiat_balance, dependent: :restrict_with_error validates :first_name, :last_name, :email, presence: true diff --git a/app/services/bsc_client.rb b/app/services/bsc_client.rb new file mode 100644 index 0000000..ec3c061 --- /dev/null +++ b/app/services/bsc_client.rb @@ -0,0 +1,21 @@ +# frozen_string_literal: true +class BscClient + include HTTParty + + base_uri "api-eu1.tatum.io/v3" + + def initialize + @headers = { + "x-api-key": ENV["TATUM_API_KEY"], + } + end + + def token_balance(contract:, digits:, wallet_address:) + result = self.class.get( + "https://api-eu1.tatum.io/v3/blockchain/token/balance/BSC/#{contract}/#{wallet_address}", + headers: @headers + ).parsed_response["balance"] + + (result.to_f / (10**digits)).round(5) + end +end diff --git a/app/value_objects/wallet.rb b/app/value_objects/wallet.rb new file mode 100644 index 0000000..ab1819c --- /dev/null +++ b/app/value_objects/wallet.rb @@ -0,0 +1,34 @@ +# frozen_string_literal: true +class Wallet + attr_reader :user, :address, :cake_balance + + def initialize(user) + @user = user + @address = user.wallet_address + @cake_balance = total_cake + end + + private + + def total_cake + return 0 if address.blank? + + BscClient.new.token_balance( + contract: "0x0e09fabb73bd3ade0a17ecc321fd13a19e81ce82", + digits: 18, + wallet_address: address, + ) - total_cake_debit + end + + def total_cake_debit + total_cake_stake_debit + total_cake_sell_debit + end + + def total_cake_stake_debit + user.stake_orders.processing.add.sum(&:amount).to_f + end + + def total_cake_sell_debit + user.sell_crypto_orders.processing.sum(&:paid_amount).to_f + end +end