diff --git a/package-lock.json b/package-lock.json index f6da2b7..20fdd62 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,6 +10,7 @@ "license": "ISC", "dependencies": { "alchemy-sdk": "^2.2.3", + "d3-scale": "^4.0.2", "lightweight-charts": "^3.8.0", "sirv-cli": "^2.0.2" }, @@ -1250,6 +1251,81 @@ "type": "^1.0.1" } }, + "node_modules/d3-array": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-3.2.1.tgz", + "integrity": "sha512-gUY/qeHq/yNqqoCKNq4vtpFLdoCdvyNpWoC/KNjhGbhDuQpAM9sIQQKkXSNpXa9h5KySs/gzm7R88WkUutgwWQ==", + "dependencies": { + "internmap": "1 - 2" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-color": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-color/-/d3-color-3.1.0.tgz", + "integrity": "sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-format": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-format/-/d3-format-3.1.0.tgz", + "integrity": "sha512-YyUI6AEuY/Wpt8KWLgZHsIU86atmikuoOmCfommt0LYHiQSPjvX2AcFc38PX0CBpr2RCyZhjex+NS/LPOv6YqA==", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-interpolate": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-3.0.1.tgz", + "integrity": "sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==", + "dependencies": { + "d3-color": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-scale": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/d3-scale/-/d3-scale-4.0.2.tgz", + "integrity": "sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ==", + "dependencies": { + "d3-array": "2.10.0 - 3", + "d3-format": "1 - 3", + "d3-interpolate": "1.2.0 - 3", + "d3-time": "2.1.1 - 3", + "d3-time-format": "2 - 4" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-time": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-time/-/d3-time-3.1.0.tgz", + "integrity": "sha512-VqKjzBLejbSMT4IgbmVgDjpkYrNWUYJnbCGo874u7MMKIWsILRX+OpX/gTk8MqjpT1A/c6HY2dCA77ZN0lkQ2Q==", + "dependencies": { + "d3-array": "2 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-time-format": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/d3-time-format/-/d3-time-format-4.1.0.tgz", + "integrity": "sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg==", + "dependencies": { + "d3-time": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, "node_modules/debug": { "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", @@ -1637,6 +1713,14 @@ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" }, + "node_modules/internmap": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/internmap/-/internmap-2.0.3.tgz", + "integrity": "sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==", + "engines": { + "node": ">=12" + } + }, "node_modules/is-binary-path": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", @@ -3343,6 +3427,60 @@ "type": "^1.0.1" } }, + "d3-array": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-3.2.1.tgz", + "integrity": "sha512-gUY/qeHq/yNqqoCKNq4vtpFLdoCdvyNpWoC/KNjhGbhDuQpAM9sIQQKkXSNpXa9h5KySs/gzm7R88WkUutgwWQ==", + "requires": { + "internmap": "1 - 2" + } + }, + "d3-color": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-color/-/d3-color-3.1.0.tgz", + "integrity": "sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==" + }, + "d3-format": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-format/-/d3-format-3.1.0.tgz", + "integrity": "sha512-YyUI6AEuY/Wpt8KWLgZHsIU86atmikuoOmCfommt0LYHiQSPjvX2AcFc38PX0CBpr2RCyZhjex+NS/LPOv6YqA==" + }, + "d3-interpolate": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-3.0.1.tgz", + "integrity": "sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==", + "requires": { + "d3-color": "1 - 3" + } + }, + "d3-scale": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/d3-scale/-/d3-scale-4.0.2.tgz", + "integrity": "sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ==", + "requires": { + "d3-array": "2.10.0 - 3", + "d3-format": "1 - 3", + "d3-interpolate": "1.2.0 - 3", + "d3-time": "2.1.1 - 3", + "d3-time-format": "2 - 4" + } + }, + "d3-time": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-time/-/d3-time-3.1.0.tgz", + "integrity": "sha512-VqKjzBLejbSMT4IgbmVgDjpkYrNWUYJnbCGo874u7MMKIWsILRX+OpX/gTk8MqjpT1A/c6HY2dCA77ZN0lkQ2Q==", + "requires": { + "d3-array": "2 - 3" + } + }, + "d3-time-format": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/d3-time-format/-/d3-time-format-4.1.0.tgz", + "integrity": "sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg==", + "requires": { + "d3-time": "1 - 3" + } + }, "debug": { "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", @@ -3657,6 +3795,11 @@ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" }, + "internmap": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/internmap/-/internmap-2.0.3.tgz", + "integrity": "sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==" + }, "is-binary-path": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", diff --git a/package.json b/package.json index 095d0c0..4c39b5e 100644 --- a/package.json +++ b/package.json @@ -4,43 +4,42 @@ "description": "CAP UI Client", "main": "index.js", "scripts": { - "build": "rollup -c", - "dev": "rollup -c -w", - "start": "sirv build --single", - "deploy-ipfs": "npm run build && npx ipfs-deploy build" + "build": "rollup -c", + "dev": "rollup -c -w", + "start": "sirv build --single", + "deploy-ipfs": "npm run build && npx ipfs-deploy build" }, "repository": { - "type": "git", - "url": "git+https://github.com/capofficial/ui.git" + "type": "git", + "url": "git+https://github.com/capofficial/ui.git" }, "author": "", "license": "ISC", "bugs": { - "url": "https://github.com/capofficial/ui/issues" + "url": "https://github.com/capofficial/ui/issues" }, "homepage": "https://github.com/capofficial/ui#readme", "devDependencies": { - "@rollup/plugin-alias": "^3.1.9", - "@rollup/plugin-commonjs": "^22.0.2", - "@rollup/plugin-node-resolve": "^14.1.0", - "@rollup/plugin-replace": "^4.0.0", - "chart.js": "^3.9.1", - "ethers": "^5.7.1", - "rollup": "^2.79.0", - "rollup-plugin-copy": "^3.4.0", - "rollup-plugin-css-only": "^3.1.0", - "rollup-plugin-gzip": "^3.0.1", - "rollup-plugin-livereload": "^2.0.5", - "rollup-plugin-svelte": "^7.1.0", - "rollup-plugin-terser": "^7.0.2", - "svelte": "^3.50.1", - "svelte-drag": "^3.1.0", - "tippy.js": "^6.3.7" + "@rollup/plugin-alias": "^3.1.9", + "@rollup/plugin-commonjs": "^22.0.2", + "@rollup/plugin-node-resolve": "^14.1.0", + "@rollup/plugin-replace": "^4.0.0", + "chart.js": "^3.9.1", + "ethers": "^5.7.1", + "rollup": "^2.79.0", + "rollup-plugin-copy": "^3.4.0", + "rollup-plugin-css-only": "^3.1.0", + "rollup-plugin-gzip": "^3.0.1", + "rollup-plugin-livereload": "^2.0.5", + "rollup-plugin-svelte": "^7.1.0", + "rollup-plugin-terser": "^7.0.2", + "svelte": "^3.50.1", + "svelte-drag": "^3.1.0", + "tippy.js": "^6.3.7" }, "dependencies": { - "alchemy-sdk": "^2.2.3", - "lightweight-charts": "^3.8.0", - "sirv-cli": "^2.0.2" + "alchemy-sdk": "^2.2.3", + "d3-scale": "^4.0.2", + "sirv-cli": "^2.0.2" } - } - \ No newline at end of file +} diff --git a/src/App.svelte b/src/App.svelte index ce4108b..d476eaf 100644 --- a/src/App.svelte +++ b/src/App.svelte @@ -189,6 +189,24 @@ padding: 4px 10px; width: 120px; } + :global(button.primary, button.secondary) { + padding: 0 var(--base-padding); + height: 42px; + border-radius: var(--base-radius); + font-weight: 600; + color: var(--primary-darkest); + background-color: var(--primary); + white-space: nowrap; + font-size: 95%; + } + :global(button.secondary) { + background-color: var(--secondary); + color: var(--secondary-darkest); + } + :global(.buttons) { + display: flex; + justify-content: space-around; + } diff --git a/src/api/markets.js b/src/api/markets.js index 115a9df..3a80413 100644 --- a/src/api/markets.js +++ b/src/api/markets.js @@ -1,7 +1,9 @@ +import {get} from 'svelte/store' import { BPS_DIVIDER } from '@lib/config' import { getContract } from '@lib/contracts' -import { markets, fundingRate, OILong, OIShort } from '@lib/stores' +import { markets, fundingRate, OILong, OIShort, chainId } from '@lib/stores' import { formatUnits } from '@lib/formatters' +import { CHAINLINK_URL, CHAINDATA } from '../lib/config'; export async function getMarketsWithPrices() { const contract = getContract({name: 'Trade'}); @@ -26,4 +28,38 @@ export async function getOI(market) { const contract = getContract({name: 'Store'}); OILong.set(formatUnits(await contract.getOILong(market))); OIShort.set(formatUnits(await contract.getOIShort(market))); +} + +export async function getChainlinkPriceHistory(contractAddress) { + try { + const _chainId = get(chainId); + const response = await fetch(CHAINLINK_URL, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ + query: ` + query PriceHistoryQuery($schemaName: String!, $contractAddress: String!) { + priceHistory(schemaName: $schemaName, contractAddress: $contractAddress) { + nodes { + id + latestAnswer + blockNumber + } + } + } + `, + variables: { + schemaName: CHAINDATA[_chainId].chainlinkSchema, + contractAddress: contractAddress + } + }) + }); + const json = await response.json(); + const price = json?.data + return price; + } catch (e) { + console.error('/getChainlinkPriceHistory', e); + } } \ No newline at end of file diff --git a/src/components/layout/Input.svelte b/src/components/layout/Input.svelte index 1f02ff7..69ebad9 100644 --- a/src/components/layout/Input.svelte +++ b/src/components/layout/Input.svelte @@ -1,112 +1,167 @@ - + - - -
- - -
\ No newline at end of file diff --git a/src/components/layout/table/Cell.svelte b/src/components/layout/table/Cell.svelte new file mode 100644 index 0000000..b9038d2 --- /dev/null +++ b/src/components/layout/table/Cell.svelte @@ -0,0 +1,41 @@ + + +
+ +
+ + diff --git a/src/components/layout/table/Row.svelte b/src/components/layout/table/Row.svelte new file mode 100644 index 0000000..76defcc --- /dev/null +++ b/src/components/layout/table/Row.svelte @@ -0,0 +1,15 @@ + + +
+ + diff --git a/src/components/layout/table/Table.svelte b/src/components/layout/table/Table.svelte new file mode 100644 index 0000000..151f356 --- /dev/null +++ b/src/components/layout/table/Table.svelte @@ -0,0 +1,102 @@ + + +
+
+ {#each columns as column} + {#if column.key == "tools"} +
+ {:else} +
+ {getLabelForKey(column.key)} +
+ {/if} + {/each} +
+ +
+ {#if isLoading} +
{@html LOADING_ICON}
+ {:else if isEmpty} +
Nothing to show.
+ {:else} + + {/if} +
+
+ + diff --git a/src/components/modals/Deposit.svelte b/src/components/modals/Deposit.svelte index e817302..654a089 100644 --- a/src/components/modals/Deposit.svelte +++ b/src/components/modals/Deposit.svelte @@ -44,7 +44,7 @@ {#if $allowance * 1 <= amount * 1}
diff --git a/src/components/modals/MarketInfo.svelte b/src/components/modals/MarketInfo.svelte index fef4524..3842466 100644 --- a/src/components/modals/MarketInfo.svelte +++ b/src/components/modals/MarketInfo.svelte @@ -1,30 +1,19 @@ - - - - + + diff --git a/src/components/trade/Chart/Chart.svelte b/src/components/trade/Chart/Chart.svelte new file mode 100644 index 0000000..ded0cc0 --- /dev/null +++ b/src/components/trade/Chart/Chart.svelte @@ -0,0 +1,122 @@ + + + activeIndex = null}> + + + + + {#if activeIndex > 0} + + + ${(pointsY[activeIndex] || 0).toFixed(2)} + {/if} + + + + + + \ No newline at end of file diff --git a/src/components/trade/Trade.svelte b/src/components/trade/Trade.svelte index bbb8e55..29cce5d 100644 --- a/src/components/trade/Trade.svelte +++ b/src/components/trade/Trade.svelte @@ -19,7 +19,6 @@ background-color: var(--layerDark); max-width: 1280px; margin: 0 auto; - margin-top: 25px; border: 1px solid var(--layerDark); } diff --git a/src/components/trade/account/Account.svelte b/src/components/trade/account/Account.svelte index eaea45f..608dd9c 100644 --- a/src/components/trade/account/Account.svelte +++ b/src/components/trade/account/Account.svelte @@ -34,9 +34,6 @@ font-weight: 600; text-transform: uppercase; font-size: 85%; - } - .account { - } .data { display: flex; @@ -49,6 +46,33 @@ align-items: center; justify-content: space-between; } + .label, .value { + font-size: 14px; + } + button { + flex: 50%; + margin: 5px; + padding: 10px 5px; + width: 75%; + } + .buttons { + display: flex; + justify-content: space-around; + align-items: center; + margin: 0 10px; + } + @media screen and (max-width: 900px) { + .buttons { + flex-direction: column; + margin: 0; + } + button { + flex: 50%; + margin: 5px 10px; + padding: 10px 5px; + width: 90%; + } + } -
- - +
+ +
\ No newline at end of file diff --git a/src/components/trade/markets/Markets.svelte b/src/components/trade/markets/Markets.svelte index b055406..f51c342 100644 --- a/src/components/trade/markets/Markets.svelte +++ b/src/components/trade/markets/Markets.svelte @@ -1,10 +1,102 @@ -markets \ No newline at end of file +
Markets
+ + + diff --git a/src/components/trade/new-order/CreateNewOrder.svelte b/src/components/trade/new-order/CreateNewOrder.svelte new file mode 100644 index 0000000..af510ac --- /dev/null +++ b/src/components/trade/new-order/CreateNewOrder.svelte @@ -0,0 +1,146 @@ + + + +
+
+
+
setOrderType("market")} + > + Market +
+
setOrderType("limit")} + > + Limit +
+
setOrderType("stop")} + > + Stop +
+
+
+ + +
+
+
+ (size.set($balance))}/> +
+
+ + +
+ {#if orderType !== 'market'} +
+ +
+ {/if} +
+ + +
+
+
+
Margin
+
{formatForDisplay($size)} {$currencyName}
+
+
+
Fee (0.1%)
+
{formatForDisplay($size * 0.001)} {$currencyName}
+
+
+
+ + diff --git a/src/components/trade/new-order/NewOrder.svelte b/src/components/trade/new-order/NewOrder.svelte index 4813d61..d57e81d 100644 --- a/src/components/trade/new-order/NewOrder.svelte +++ b/src/components/trade/new-order/NewOrder.svelte @@ -1,5 +1,10 @@ -new order \ No newline at end of file +
+
+
+ {$selectedMarketInfo.symbol} + +
+ showModal("MarketInfo", $selectedMarketInfo)} + > + {@html INFO_ICON_CIRCLE} +
+
+
{$selectedMarketInfo.price}
+
+
+
+ +
+
+
+ +
+
+ + diff --git a/src/lib/config.js b/src/lib/config.js index 07f86b6..62261e3 100644 --- a/src/lib/config.js +++ b/src/lib/config.js @@ -26,7 +26,8 @@ export const CHAINDATA = { key: 'gDY8gANK8VJAg508BzJbdCpmZ4N43IZP', network: 'arbitrum', wsNetwork: 'arb-mainnet' - } + }, + chainlinkSchema: "ethereum-mainnet-arbitrum-1" }, 42161: { label: 'arbitrum', @@ -44,6 +45,12 @@ export const CHAINDATA = { key: 'gDY8gANK8VJAg508BzJbdCpmZ4N43IZP', network: 'arbitrum', wsNetwork: 'arb-mainnet' - } + }, + chainlinkSchema: "ethereum-mainnet-arbitrum-1" } +} +export const CHAINLINK_URL = "https://atlas-postgraphile.public.main.prod.cldev.sh/graphql" +export const CHAINLINK_CONTRACT_ADDRESSES = { + BTC_USD: "0x942d00008d658dbb40745bbec89a93c253f9b882", + ETH_USD: "0x3607e46698d218b3a5cae44bf381475c0a5e2ca7" } \ No newline at end of file diff --git a/src/lib/formatters.js b/src/lib/formatters.js index 9ce30c4..dc67c4f 100644 --- a/src/lib/formatters.js +++ b/src/lib/formatters.js @@ -152,15 +152,15 @@ export function formatMarket(market) { if (!market) return; return { - 'Name': market.name, - 'Category': market.category, + 'Name': market.symbol, + 'Category': 'Crypto', 'Chainlink Execution Allowed': market.allowChainlinkExecution ? 'Yes' : 'No', 'Fee': `${formatForDisplay(100 * market.fee / BPS_DIVIDER)}%`, - 'Is Closed': market.isClosed ? 'Yes' : 'No', - 'Liquidation Threshold': `${formatForDisplay(100 * market.liqThreshold / BPS_DIVIDER)}%`, - 'Max Deviation vs Chainlink': `${formatForDisplay(100 * market.maxDeviation / BPS_DIVIDER)}%`, + // 'Is Closed': market.isClosed ? 'Yes' : 'No', + // 'Liquidation Threshold': `${formatForDisplay(100 * market.liqThreshold / BPS_DIVIDER)}%`, + // 'Max Deviation vs Chainlink': `${formatForDisplay(100 * market.maxDeviation / BPS_DIVIDER)}%`, 'Max Leverage': market.maxLeverage, - 'Only Reduce-Only Allowed': market.isReduceOnly ? 'Yes' : 'No' + // 'Only Reduce-Only Allowed': market.isReduceOnly ? 'Yes' : 'No' } }