From dbbbeae44ead903bda6d62bcb79aede72cf2d851 Mon Sep 17 00:00:00 2001 From: Stefan Popov Date: Wed, 14 Aug 2024 12:38:04 +0200 Subject: [PATCH] Release 1.39 (#1495) (#1496) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Release 1.39 (#1495) * Update ValidatorsDialog.vue * Fix * Xor commission fix * Add vote on survey and new banner (#1251) * Add new banner * Add vote on survey & move SORA mobile link * Add survey image --------- Co-authored-by: Stefan Popov <17688105+stefashkaa@users.noreply.github.com> * Fixes * Fixes * Fixes * Translation fix * Editable fiat amount in input (#1250) * use token-input in bridge, remove outdates styles * add fiat input * improve fiat value calculations * fiat input fixes * Fix colors * Fix * Fixes * Fixes * Fix * Remove imports * fix chart current price (#1256) * refactoring * remove lib from resolutions * fix retry button visibility (#1254) * fix retry button visibility * Update package.json * return 1.27.0 version --------- Co-authored-by: Stefan Popov <17688105+stefashkaa@users.noreply.github.com> * Sidebar hide button (#1249) * add collapse button to sidebar * add tooltip to icon * sidebar hover effect * update translations * update menu css * update wallet * Improve Eth bridge fees calculation (#1257) * fix retry button visibility * refactoring sign methods * calc incoming fee * transfer method to eth bridge utils * update BridgeInitMixin * add fallback calculation * update amount to calculate fee * fix sonar issues * Fix rewards destination * Fixes * Fixes * Revert env.json * Fixes * Remove tooltip * Translation fix * Remove utils * Rename function * Fix translation file * Remove all rewards info * Fix styles * Staking badge click (#1258) * Validators search input fix (#1262) * Staking badge click * Validators search input fix * Fix release issues 1.27 (#1261) * Make mx button hidden when hide balances is enabled * Fix issues --------- Co-authored-by: Stefan Popov <17688105+stefashkaa@users.noreply.github.com> * Refactor staking (#1263) * Refactor * Fix validators list style * Fix commission format * Fix change validators disable * Fix styles * Fixes * Use stakingStakers * Fix staking lang keys * Update json files * Update messages.ts * Add comments * Update zh_CN.json * Update env.json --------- Co-authored-by: Stefan Popov <17688105+stefashkaa@users.noreply.github.com> Co-authored-by: RDMStreet * Add staking routing in menu (#1265) Co-authored-by: Stefan Popov <17688105+stefashkaa@users.noreply.github.com> * Correct staking balance formatting (#1267) * Correct staking balance formatting * Remove unused import * Add 6M filter for stats page (#1270) Co-authored-by: Stefan Popov <17688105+stefashkaa@users.noreply.github.com> * Add sora card maintenance page (#1269) (#1271) * Add maintenance page for SORA Card * Hide crowdloan ad --------- Co-authored-by: Stefan Popov <17688105+stefashkaa@users.noreply.github.com> * Improve zh_CN keys (#1272) * Fix zh_CN keys * Update package.json --------- Co-authored-by: Stefan Popov <17688105+stefashkaa@users.noreply.github.com> * Update dojoProductType * [Bridge] Add Polkadot bridge support (#1277) * add polkadot consts usage * update config & icon * set network fee 0.02 DOT * subquery endpoint as in master * fix ui issue with sora hash for incomng tx * add polkadot xcm fee * update polkadot network fee * soraCard:false * Subsquid prod endpoint * [BRIDGE] check for asset valid address on bridge contract (#1283) * check for asset valid address on bridge contract * remove console.log * Update wallet * Use 1000 page size for subsquid * Prepare prod config (#1285) Co-authored-by: Stefan Popov <17688105+stefashkaa@users.noreply.github.com> * Fix import * fix ss58 check (#1289) * set kusama incoming xcm fee 0.01KSM (#1290) * set kusama incoming xcm fee 0.01KSM * Update package.json --------- Co-authored-by: Stefan Popov <17688105+stefashkaa@users.noreply.github.com> * order book (#1089) * prework * prework * book list * prework for table popover * establish vuex store * write basic logic * create order history widget * add tables * start book widget * Update BookWidget.vue * make market widget * resolve conflicts * Update OrderBook.vue * embed charts * make api working * style table * filter books * make filters to amount and price * remove debug info * Update BuySell.vue * fix price constraints * Update Jenkinsfile * make aggregation * Update Jenkinsfile * add checks * make update * update * make sell market order * Update OpenOrders.vue * add change * fix * add market order, spread checks, confirm dialog * add confirm cancel dialog * fix dark mode * improve dark mode * hide native scrolls * add tooltips & improve UX * improve responsive * improve ux * fixes * improve mobile, tablet, desktop responsibility * fix market order * fix input/output * fix * fix errors * make huge screen usable * add missing data * Update OpenOrders.vue * add translations * upgrade lib & add translations * forbid cancelling when book is stopped * dynamic fee * enable market trades widget * hide market trades * fixes * allow whole row click * add pagination * Order book indexer requests (#1223) * wip queries * account orders request * add order book subscription * refactoring deals * update types & subscription * add orders table data & subscription to order book updates * fix order query * fix all orders table * add order books stats to popover * update stats on popover opening * add deals to market trades * fix deals * refactoring subscriptions & data architecture * add userLimitOrders type * update wallet * add last deal price * format buySell price * update table amount * order table component * fix filled * refactoring order table & mixins * add scaler * allow whitelist only * update orders request * fix cancel * fix ui issues * fix wallet version 1.26.2 * fix orders sort * fix column * improve adaptive ui * implement steps * Update OrderTable.vue * fix wiping out * fix * add checks * hide debug info * hide native scrollbar * improve adaptive design * up version * remove mixin * fix * Update index.ts * Update BookWidget.vue * fix not updating book issue * make small adjustments * align values * align book values * fixes * Update BookWidget.vue * fix input wiping out * round up styles * fixes * fixes * add margins * Update OrderBook.vue * Update package.json * fix assetsDataTable * fix scrollbar in orders table * Order book price chart (#1237) * transfer asset price query from wallet * add order book data to chart * prepare subscription * set chart subscription * fix sorting bug * fix max button fills wrong value * Update BuySell.vue * fix precision * Update BuySell.vue * warn user when error in input & aggregation logic * fill price when click on book * Update BuySell.vue * fixes * add feature flag & refactoring * hide expiry date for market * refactor * fix * [OrderBook] add volume chart (#1248) * add volume to dataset * add volume example * add color to bars * improve tooltip & labels localization * build spec depends on volume support * use filters from line chart * remove commented code * add typings * fix typings * Update orderBook.ts * add slider for amount * remove corridor checks * Update env.json * fix on slider * Update BuySell.vue * Update TokenInput.vue * resolve conflicts * Update _mixins.scss * inject slider * Update HistoryOrderWidget.vue * Revert "Merge branch 'develop' into feature/order-book" This reverts commit d02e1a65e7d2db20b07cd8055b2e171a61bee639, reversing changes made to 1f58ed6efe9c8d8d1cd54765382be1e5e26fc766. * fix chart * fix fee on place order * fix disappearance * Update BookWidget.vue * fix sonar issues * fix sonar * fix * fixes * fix issues * add slider focus * fix css values * move collapse logic to store * enable aggregation * trim when fiat is input * resolve conflicts * Spot limitations (#1255) * add consts * Update BuySell.vue * Update package.json * fix * add locked to transaction details * Update TransactionDetails.vue * customise prework * resolve typings * add limit for single price * Update package.json * bump --------- Co-authored-by: Vladimir Shelkovnikov <99356504+C4tWithShell@users.noreply.github.com> * Order book refactoring (#1281) * refactoring BookWidget * book widget methods refactoring * BuySell refactoring * HistoryOrderWidget refactoring --------- Co-authored-by: Rustem * fix * recalculate orders & remove possible overlap * Update BuySell.vue * Update BookWidget.vue * fix with precision * fix tab freeze when switching * fix * Update BookWidget.vue * fix langs switch * fix for input with different locales * turn card off * Update deps * Update yarn.lock * Bump version * Fix lint warnings * Blur fiat el during slider usage for TokenInput * Update AppMenu.vue * Fix icons * Update index.ts * Fix shadow * Remove unused styles * Fix lint issues * Update BookWidget.vue * Update BuySell.vue * Update CustomisePage.vue * Resolve linter issues * Add duration in days for ordertable * Improve tables * Fix styles * Remove empty DatePicker * Update HistoryOrderWidget.vue * Restrict autofill from orderbook for mkt * Update index.ts * Fix font * Remove duplicated methods from util --------- Co-authored-by: Nikita Polyakov <53777036+Nikita-Polyakov@users.noreply.github.com> Co-authored-by: Nikita-Polyakov Co-authored-by: Stefan Popov <17688105+stefashkaa@users.noreply.github.com> Co-authored-by: Vladimir Shelkovnikov <99356504+C4tWithShell@users.noreply.github.com> * Fix 1.29 release (#1292) * Update dot, ksm nodes * Improve SORA Card maintenance styles --------- Co-authored-by: Stefan Popov <17688105+stefashkaa@users.noreply.github.com> * Update BuySell.vue (#1295) * Single chart filter (#1293) * prework * prework * book list * prework for table popover * establish vuex store * write basic logic * create order history widget * add tables * start book widget * Update BookWidget.vue * make market widget * resolve conflicts * Update OrderBook.vue * embed charts * make api working * style table * filter books * make filters to amount and price * remove debug info * Update BuySell.vue * fix price constraints * Update Jenkinsfile * make aggregation * Update Jenkinsfile * add checks * make update * update * make sell market order * Update OpenOrders.vue * add change * fix * add market order, spread checks, confirm dialog * add confirm cancel dialog * fix dark mode * improve dark mode * hide native scrolls * add tooltips & improve UX * improve responsive * improve ux * fixes * improve mobile, tablet, desktop responsibility * fix market order * fix input/output * fix * fix errors * make huge screen usable * add missing data * Update OpenOrders.vue * add translations * upgrade lib & add translations * forbid cancelling when book is stopped * dynamic fee * enable market trades widget * hide market trades * fixes * allow whole row click * add pagination * Order book indexer requests (#1223) * wip queries * account orders request * add order book subscription * refactoring deals * update types & subscription * add orders table data & subscription to order book updates * fix order query * fix all orders table * add order books stats to popover * update stats on popover opening * add deals to market trades * fix deals * refactoring subscriptions & data architecture * add userLimitOrders type * update wallet * add last deal price * format buySell price * update table amount * order table component * fix filled * refactoring order table & mixins * add scaler * allow whitelist only * update orders request * fix cancel * fix ui issues * fix wallet version 1.26.2 * fix orders sort * fix column * improve adaptive ui * implement steps * Update OrderTable.vue * fix wiping out * fix * add checks * hide debug info * hide native scrollbar * improve adaptive design * up version * remove mixin * fix * Update index.ts * Update BookWidget.vue * fix not updating book issue * make small adjustments * align values * align book values * fixes * Update BookWidget.vue * fix input wiping out * round up styles * fixes * fixes * add margins * Update OrderBook.vue * Update package.json * fix assetsDataTable * fix scrollbar in orders table * Order book price chart (#1237) * transfer asset price query from wallet * add order book data to chart * prepare subscription * set chart subscription * fix sorting bug * fix max button fills wrong value * Update BuySell.vue * fix precision * Update BuySell.vue * warn user when error in input & aggregation logic * fill price when click on book * Update BuySell.vue * fixes * add feature flag & refactoring * hide expiry date for market * refactor * fix * [OrderBook] add volume chart (#1248) * add volume to dataset * add volume example * add color to bars * improve tooltip & labels localization * build spec depends on volume support * use filters from line chart * remove commented code * add typings * fix typings * Update orderBook.ts * add slider for amount * remove corridor checks * Update env.json * fix on slider * Update BuySell.vue * Update TokenInput.vue * resolve conflicts * Update _mixins.scss * inject slider * Update HistoryOrderWidget.vue * Revert "Merge branch 'develop' into feature/order-book" This reverts commit d02e1a65e7d2db20b07cd8055b2e171a61bee639, reversing changes made to 1f58ed6efe9c8d8d1cd54765382be1e5e26fc766. * fix chart * fix fee on place order * fix disappearance * Update BookWidget.vue * fix sonar issues * fix sonar * fix * fixes * fix issues * add slider focus * fix css values * move collapse logic to store * enable aggregation * trim when fiat is input * resolve conflicts * Spot limitations (#1255) * add consts * Update BuySell.vue * Update package.json * fix * add locked to transaction details * Update TransactionDetails.vue * customise prework * resolve typings * add limit for single price * Update package.json * bump --------- Co-authored-by: Vladimir Shelkovnikov <99356504+C4tWithShell@users.noreply.github.com> * Order book refactoring (#1281) * refactoring BookWidget * book widget methods refactoring * BuySell refactoring * HistoryOrderWidget refactoring --------- Co-authored-by: Rustem * fix * recalculate orders & remove possible overlap * Update BuySell.vue * Update BookWidget.vue * fix with precision * fix tab freeze when switching * fix * Update BookWidget.vue * fix langs switch * fix for input with different locales * turn card off * set filters like in candle * set chart animation to false * remove merge conflicts * return default chart type * add order book queries for subsquid * change zoom after filter siwtch * reset zoom on filter tab * refactoring * update types & subsquid requests * update wallet to 1.29.1 --------- Co-authored-by: RustemYuzlibaev Co-authored-by: Stefan Popov <17688105+stefashkaa@users.noreply.github.com> Co-authored-by: Vladimir Shelkovnikov <99356504+C4tWithShell@users.noreply.github.com> Co-authored-by: NaghmeMohammadifar <45916098+Naghme98@users.noreply.github.com> * fix (#1296) * Feature/order book translations (#1284) * prework * prework * book list * prework for table popover * establish vuex store * write basic logic * create order history widget * add tables * start book widget * Update BookWidget.vue * make market widget * resolve conflicts * Update OrderBook.vue * embed charts * make api working * style table * filter books * make filters to amount and price * remove debug info * Update BuySell.vue * fix price constraints * Update Jenkinsfile * make aggregation * Update Jenkinsfile * add checks * make update * update * make sell market order * Update OpenOrders.vue * add change * fix * add market order, spread checks, confirm dialog * add confirm cancel dialog * fix dark mode * improve dark mode * hide native scrolls * add tooltips & improve UX * improve responsive * improve ux * fixes * improve mobile, tablet, desktop responsibility * fix market order * fix input/output * fix * fix errors * make huge screen usable * add missing data * Update OpenOrders.vue * add translations * upgrade lib & add translations * forbid cancelling when book is stopped * dynamic fee * enable market trades widget * hide market trades * fixes * allow whole row click * add pagination * Order book indexer requests (#1223) * wip queries * account orders request * add order book subscription * refactoring deals * update types & subscription * add orders table data & subscription to order book updates * fix order query * fix all orders table * add order books stats to popover * update stats on popover opening * add deals to market trades * fix deals * refactoring subscriptions & data architecture * add userLimitOrders type * update wallet * add last deal price * format buySell price * update table amount * order table component * fix filled * refactoring order table & mixins * add scaler * allow whitelist only * update orders request * fix cancel * fix ui issues * fix wallet version 1.26.2 * fix orders sort * fix column * improve adaptive ui * implement steps * Update OrderTable.vue * fix wiping out * fix * add checks * hide debug info * hide native scrollbar * improve adaptive design * up version * remove mixin * fix * Update index.ts * Update BookWidget.vue * fix not updating book issue * make small adjustments * align values * align book values * fixes * Update BookWidget.vue * fix input wiping out * round up styles * fixes * fixes * add margins * Update OrderBook.vue * Update package.json * fix assetsDataTable * fix scrollbar in orders table * Order book price chart (#1237) * transfer asset price query from wallet * add order book data to chart * prepare subscription * set chart subscription * fix sorting bug * fix max button fills wrong value * Update BuySell.vue * fix precision * Update BuySell.vue * warn user when error in input & aggregation logic * fill price when click on book * Update BuySell.vue * fixes * add feature flag & refactoring * hide expiry date for market * refactor * fix * [OrderBook] add volume chart (#1248) * add volume to dataset * add volume example * add color to bars * improve tooltip & labels localization * build spec depends on volume support * use filters from line chart * remove commented code * add typings * fix typings * Update orderBook.ts * add slider for amount * remove corridor checks * Update env.json * fix on slider * Update BuySell.vue * Update TokenInput.vue * resolve conflicts * Update _mixins.scss * inject slider * Update HistoryOrderWidget.vue * Revert "Merge branch 'develop' into feature/order-book" This reverts commit d02e1a65e7d2db20b07cd8055b2e171a61bee639, reversing changes made to 1f58ed6efe9c8d8d1cd54765382be1e5e26fc766. * fix chart * fix fee on place order * fix disappearance * Update BookWidget.vue * fix sonar issues * fix sonar * fix * fixes * fix issues * add slider focus * fix css values * move collapse logic to store * enable aggregation * trim when fiat is input * make translation prework * resolve conflicts * create translations * translations * fix merge issues * embed missing translations * add missing translations * fix * fix ru lang * add order status translations * make room for additional space * Update BuySell.vue * add descriptive message * add descriptive message for all langs * reset * cancel reset when market order --------- Co-authored-by: Nikita Polyakov <53777036+Nikita-Polyakov@users.noreply.github.com> Co-authored-by: Nikita-Polyakov Co-authored-by: Stefan Popov <17688105+stefashkaa@users.noreply.github.com> * Explore order books (#1276) * prepare explore books data * fix issues * update price column * refactoring explore page mixin * add filter to order books query * update wallet 1.28.0 * fix price formatting * pools from indexer * remove unused method * add pool tokens column * rename quoteAsset to targetAsset for search * refactoring queries * refactoring * update translation key & fix tokens page search * Fix explore books sorting (#1299) * fix computed property for table * refactoring * fix changeSort type * Fix release 1.29 (#1294) * Remove unused import * Add notification and loading for stake dialog during TX sign * Fix staking extrinsics notifications and loading states * Fix redeemable VAL -> XOR * Update package.json * Make orderbook open orders reactive & fix cancel orders selection algo * Remove unused staking methods * Fix issue with horizontal & vertical scroll * Update StakingMixin.ts * Update actions.ts * Update OpenOrders.vue * Update OrderTable.vue * Improve styles * Fix sync issues * Fix empty page issues * Fix styles * Add Intl percent formatter * Improve global html styles * Fix scrollbar * Refactor source code for PlaceOrder component * Refactor place order logic * Fix cancel orders logic and styles * Update HistoryOrderWidget.vue * Fix translations for MarketTradesWidget * Fix connect account styles * Fix styles * Remove unused prop * Move user orders subscription to history widget * Update PlaceOrder.vue * Fix issues * Update SelectedTokensRouteMixin.ts * Add dynamic routing for orderbook * Refactor types * Update OrderBook.vue * Improve routes (common states for Swap and Orderbook) * fix translations * fix mismatch on cancel * Update deps --------- Co-authored-by: Stefan Popov <17688105+stefashkaa@users.noreply.github.com> Co-authored-by: RustemYuzlibaev * Fix orderbook notifications and orders history (#1300) Co-authored-by: Stefan Popov <17688105+stefashkaa@users.noreply.github.com> * Fix 1.29 issues (#1303) * Remove marketing research & add transition * Update wallet * Fix the flickering collapsed menu when hovering on expand button over the status bar --------- Co-authored-by: Stefan Popov <17688105+stefashkaa@users.noreply.github.com> Co-authored-by: shlavik * Update AppMenu.vue (#1304) Co-authored-by: Stefan Popov <17688105+stefashkaa@users.noreply.github.com> * Fix 1.29.0 issues (#1306) * Fix menu styles * Update AppMenu.vue * Fix click on tooltip for mobile devices * Update PairListPopover.vue * Revert "Update AppMenu.vue" This reverts commit 5147d349b2f15829cd54fd133ab6263d7aa011e3. * Update wallet * Fix styles --------- Co-authored-by: Stefan Popov <17688105+stefashkaa@users.noreply.github.com> * Update subquery endpoint (#1308) Co-authored-by: Stefan Popov <17688105+stefashkaa@users.noreply.github.com> * update wallet 1.29.8 (#1309) * Fix explore menu navigation (#1310) * Fix explore menu navigation * update wallet 1.29.9 --------- Co-authored-by: Stefan Popov <17688105+stefashkaa@users.noreply.github.com> Co-authored-by: Nikita-Polyakov * Fix cancel all orders (#1313) Co-authored-by: Stefan Popov <17688105+stefashkaa@users.noreply.github.com> * Replace explore tabs with dropdown * Update soramitsuUI.ts * Update Container.vue * Fix selected colors * Update BuySell.vue (#1301) * Update BuySell.vue * handle different side change * reduce watchers --------- Co-authored-by: Stefan Popov Co-authored-by: Nikita Polyakov <53777036+Nikita-Polyakov@users.noreply.github.com> * add missing balance to token (#1315) * Fix bridge tx sign with google & mint\burn translations (#1323) * add beforeSign call * update wallet & translations from localise * fix ts issues * add mint & burn translations * Add KEN distribution page (#1320) * validation refactoring (#1319) * validation refactoring * add generic component * log in * refactor * Update BookWidget.vue * hide scaler * fix zero appearance * remove commented code * improve validation * improve check for unique prices * add multiply translation * replace translation * aggregate conditions * Update en.json (#1327) * Fix ken title (#1330) * Fix KEN title * Enable orderbook on mainnet * Bump version --------- Co-authored-by: Stefan Popov <17688105+stefashkaa@users.noreply.github.com> * fix (#1331) * fix * add error handling for small balances * move to dev * Staking fixes (#1268) * Staking fixes * Fix * Fixes * Fix * Redeem dialogs * Fixes * Fix subscribeOnCurrentEraTotalStake * Withdraw * Fixes * Some fixes * Countdown * Fix countdown position * Fix countdown calc * Validators list * Sorting * Validator name * Revert env * Change default validators sort * Fixes * Max * focus * Countdown translation * unbondPeriodFormatted fix * Remove comments * Fix colors * Template fixes * Update translations * Fix blackout * Fix input styles * Update EraCountdown.vue * Fix Sonar issues * Fix notification for withdraw operation * Max validators * Validators list style fixes * Remove new stake network fee * Fix styles * Max fix * Update translations * Remove empty translations --------- Co-authored-by: Stefan Popov Co-authored-by: Vladimir Shelkovnikov <99356504+C4tWithShell@users.noreply.github.com> Co-authored-by: Stefan Popov <17688105+stefashkaa@users.noreply.github.com> * expand total text (#1333) * [Bridge] fix insufficient balance check (#1329) * fix insufficient balance check * remove kusama hardcoded xcm * update Kusama fee to 0.002 KSM * update polkadot treasury fee * Fix orderbook styles * Fix lang --------- Co-authored-by: Rustem Co-authored-by: Stefan Popov <17688105+stefashkaa@users.noreply.github.com> Co-authored-by: Stefan Popov * update order book quote subscription (#1335) * [Tech] queries from wallet (#1336) * transfer pools queries * update referrals * update wallet & refactoring * Сhart volume update (#1332) * refactoring fetchData * update chart subscription to fetch last snapshot * update chart tooltip * update chart styles * save zoom level after chart type switch * sonar fixes * Remove unnecessary imports * Fix type * [Tech] update packages (#1337) * update types * update charts libs * update jwt-decode * update sass & package.json node version * update typescript * Max count * Fix SubsquidOrderBooksQuery * Fix chart volume update for XOR (#1348) * fix xor volume update * set interval polling for chart assets updates * fixes after review * update wallet 1.32.3 * deduplicate yarn.lock * Fix Eth bridge tx replacement (#1350) * refactoring eth utils methods * fix replaceable tx tracking * refactoring * Update package.json (#1353) * Update package.json * Update yarn.lock --------- Co-authored-by: Stefan Popov <17688105+stefashkaa@users.noreply.github.com> * Demeter fixes (#1355) * fix selectedPool getter * translations from localise * add calculating text * Fix quote rpc (#1356) Co-authored-by: Stefan Popov <17688105+stefashkaa@users.noreply.github.com> * Remove new stake page (#1343) Co-authored-by: Stefan Popov <17688105+stefashkaa@users.noreply.github.com> * Add swap last transactions widget (#1342) * add BaseWidget component * replace StatsCard for BaseWidget * create SwapFormWidget * refactoring base widget * wip transactions table * table demo data * update transactions widget data * add links dropdown, improve paddings * update table styles * add fromTimestamp to limit query results * add withParentLoading to ScrollableTable * swap page custom layout * add distribution as widget, style fixes * swap layout fixes * change swap widgets folder structure * fix sonar issues * fix icon hover & dropdown focus * remove fixed table * set dropdown foruc rounded * update table head titles * mixin fix * fix transactions loading * update table column order --------- Co-authored-by: Stefan Popov <17688105+stefashkaa@users.noreply.github.com> * Fix issues after PRs merge (#1360) * Fix * Remove not used styles --------- Co-authored-by: Stefan Popov <17688105+stefashkaa@users.noreply.github.com> * [Sub Bridge] add ability to select substrate node (#1346) * transfer to liberland * transfer from liberland * fix history fetch * refactoring adapters * update history restoration * change autoselectSubAddress * add asset outgoing minimum amount * update visible min limit * update config to sub network endpoint * multiple endpoints in adapter * update sup network apps & incoming transfer tracking * add props to SelectNodeDialog * simplify NodeErrorMixin * create connection class file * simplify trusted node check * remove nodeConnectionAllowance * remove some nodes getters * move action to class * refactoring connectToNode * transfer wallet init to App.vue * use appConnection for sora nodes * fix node info loading state * use NodesConnection in SubAdapter * sub node dialog demo * update node dialog texts * update network name in select node dialog * refactoring NodesConnection reactivity * simplify adapter * add BridgeNodeIcon * ui node name fixes * ts fixes * remove todo comments * fix failed sub tx status in history * add externalNativeMinBalance * improve connection wait logic * refactoring min deposit usage, add translation keys * check min balance in transferable amount * update bridge apps after reconnect * fix select-network disabled css * update external min balance fetch * hardcode liberland network fee * set dns regexp with exact start * add reload button to node list * refactoring after review * update translations --------- Co-authored-by: Stefan Popov Co-authored-by: Stefan Popov <17688105+stefashkaa@users.noreply.github.com> * Add skeleton to swap distribution widget (#1361) * add distribution skeleton, set tx table columns width * fix distribution sources css * fix flex-cell * return sidebar collapsed css * Update substrate lib --------- Co-authored-by: Stefan Popov <17688105+stefashkaa@users.noreply.github.com> * Fix 1.32 issues (#1363) * Add links to bridge transfer modal (#1362) * add links to modal, update BridgeTransactionMixin * fix sub tx recipientAmount in reducer * account links in BridgeTransactionView * refactoring transaction view links * add node connection allowance timeout * return app align center * remove rococo block explorer url * fix ts issue * refactoring sonar issues * remove isOutgoingType from mixin * remove unused code * Improve bridge icons (#1364) * Add orderbook research link (#1366) Co-authored-by: Stefan Popov <17688105+stefashkaa@users.noreply.github.com> * improve external links (#1367) * Improve bridge sora links (#1370) * improve external links * add tokens.Deposited handler * fix sub blocks left & account formatting * improve sora links * improve sora links & refactoring (#1371) * update network & xcm fees (#1373) * Add ability to hide swap widgets (#1374) * add ability to hide swap widgets * add WidgetsVisibilityModel * Collapsed menu background overlaps neighbor fix * align chart header with swap widget * update customise widget * update translations * style fixes --------- Co-authored-by: shlavik * update wallet 1.32.7 (#1376) * Fix liberland adapter balance for custom tokens (#1378) * Fix liberland adapter balance for custom tokens * liberland fixes * update min balance amount & update config --------- Co-authored-by: Stefan Popov <17688105+stefashkaa@users.noreply.github.com> Co-authored-by: Nikita-Polyakov * Reduce network icons svg size (#1380) * Improve bridge locked amount check (#1381) * check bridge locked amount usinf asset kind * return bridge history search field * fix first connection logic * improve bridge history search * Set Tokens as default tab for Explore page (#1383) * Use PSWAP token instead of file-file-text-24 (#1384) * Use PSWAP token instead of file-file-text-24 * Update wallet lib --------- Co-authored-by: Stefan Popov <17688105+stefashkaa@users.noreply.github.com> * Fix default explore page (#1386) Co-authored-by: Stefan Popov <17688105+stefashkaa@users.noreply.github.com> * bump wallet (#1389) * Fix SubsquidPoolsQuery * Fix chart volume update for XOR (#1348) * fix xor volume update * set interval polling for chart assets updates * fixes after review * update wallet 1.32.3 * deduplicate yarn.lock * Fix Eth bridge tx replacement (#1350) * refactoring eth utils methods * fix replaceable tx tracking * refactoring * Update package.json (#1353) * Update package.json * Update yarn.lock --------- Co-authored-by: Stefan Popov <17688105+stefashkaa@users.noreply.github.com> * Demeter fixes (#1355) * fix selectedPool getter * translations from localise * add calculating text * Fix quote rpc (#1356) Co-authored-by: Stefan Popov <17688105+stefashkaa@users.noreply.github.com> * Remove new stake page (#1343) Co-authored-by: Stefan Popov <17688105+stefashkaa@users.noreply.github.com> * Add swap last transactions widget (#1342) * add BaseWidget component * replace StatsCard for BaseWidget * create SwapFormWidget * refactoring base widget * wip transactions table * table demo data * update transactions widget data * add links dropdown, improve paddings * update table styles * add fromTimestamp to limit query results * add withParentLoading to ScrollableTable * swap page custom layout * add distribution as widget, style fixes * swap layout fixes * change swap widgets folder structure * fix sonar issues * fix icon hover & dropdown focus * remove fixed table * set dropdown foruc rounded * update table head titles * mixin fix * fix transactions loading * update table column order --------- Co-authored-by: Stefan Popov <17688105+stefashkaa@users.noreply.github.com> * Fix issues after PRs merge (#1360) * Fix * Remove not used styles --------- Co-authored-by: Stefan Popov <17688105+stefashkaa@users.noreply.github.com> * [Sub Bridge] add ability to select substrate node (#1346) * transfer to liberland * transfer from liberland * fix history fetch * refactoring adapters * update history restoration * change autoselectSubAddress * add asset outgoing minimum amount * update visible min limit * update config to sub network endpoint * multiple endpoints in adapter * update sup network apps & incoming transfer tracking * add props to SelectNodeDialog * simplify NodeErrorMixin * create connection class file * simplify trusted node check * remove nodeConnectionAllowance * remove some nodes getters * move action to class * refactoring connectToNode * transfer wallet init to App.vue * use appConnection for sora nodes * fix node info loading state * use NodesConnection in SubAdapter * sub node dialog demo * update node dialog texts * update network name in select node dialog * refactoring NodesConnection reactivity * simplify adapter * add BridgeNodeIcon * ui node name fixes * ts fixes * remove todo comments * fix failed sub tx status in history * add externalNativeMinBalance * improve connection wait logic * refactoring min deposit usage, add translation keys * check min balance in transferable amount * update bridge apps after reconnect * fix select-network disabled css * update external min balance fetch * hardcode liberland network fee * set dns regexp with exact start * add reload button to node list * refactoring after review * update translations --------- Co-authored-by: Stefan Popov Co-authored-by: Stefan Popov <17688105+stefashkaa@users.noreply.github.com> * Add skeleton to swap distribution widget (#1361) * add distribution skeleton, set tx table columns width * fix distribution sources css * fix flex-cell * return sidebar collapsed css * Update substrate lib --------- Co-authored-by: Stefan Popov <17688105+stefashkaa@users.noreply.github.com> * Fix 1.32 issues (#1363) * Add links to bridge transfer modal (#1362) * add links to modal, update BridgeTransactionMixin * fix sub tx recipientAmount in reducer * account links in BridgeTransactionView * refactoring transaction view links * add node connection allowance timeout * return app align center * remove rococo block explorer url * fix ts issue * refactoring sonar issues * remove isOutgoingType from mixin * remove unused code * Improve bridge icons (#1364) * Add orderbook research link (#1366) Co-authored-by: Stefan Popov <17688105+stefashkaa@users.noreply.github.com> * improve external links (#1367) * Improve bridge sora links (#1370) * improve external links * add tokens.Deposited handler * fix sub blocks left & account formatting * improve sora links * improve sora links & refactoring (#1371) * update network & xcm fees (#1373) * Add ability to hide swap widgets (#1374) * add ability to hide swap widgets * add WidgetsVisibilityModel * Collapsed menu background overlaps neighbor fix * align chart header with swap widget * update customise widget * update translations * style fixes --------- Co-authored-by: shlavik * update wallet 1.32.7 (#1376) * Fix liberland adapter balance for custom tokens (#1378) * Fix liberland adapter balance for custom tokens * liberland fixes * update min balance amount & update config --------- Co-authored-by: Stefan Popov <17688105+stefashkaa@users.noreply.github.com> Co-authored-by: Nikita-Polyakov * Reduce network icons svg size (#1380) * Improve bridge locked amount check (#1381) * check bridge locked amount usinf asset kind * return bridge history search field * fix first connection logic * improve bridge history search * Set Tokens as default tab for Explore page (#1383) * Use PSWAP token instead of file-file-text-24 (#1384) * Use PSWAP token instead of file-file-text-24 * Update wallet lib --------- Co-authored-by: Stefan Popov <17688105+stefashkaa@users.noreply.github.com> * Fix default explore page (#1386) Co-authored-by: Stefan Popov <17688105+stefashkaa@users.noreply.github.com> * bump wallet (#1389) * Change SUBSQUID_ENDPOINT * Acala support (#1382) * add Alphanet to consts * save stage config * transfer subBridgeConnector to store * add moonbase alpha icon * address format research * refactoring * revert some changes * add Acala icon & sub config * fetch acala assets metadata * acala balance fetching * add acala min deposit for token * add acala extrinsic * incoming tx history restoration * refactoring outgoing process * refactoring outgoing * update reducer * refactoring * remove lib from resolutions * add moonbase xcm fee & util resolution * fixes & improvements for acala * update prod env.json to enable acala * update wallet 1.33.1 * update sub networks config in const * remove store dependency in reducer * only ACA as supported bridge token * history restoration updates * change liberland nodes order * fix adapter withConnection & selectNetwork action (#1391) * Fix bridge tx account address issues (#1393) * fix bridge tx account address issues * refactoring * update ethers & eth fee request (#1396) * improve eth fee calculation (#1397) * Account signature settings (#1394) * Burn page (#1401) * Add KARMA distribution page * Update translations * Remove subsquid * Update translations * Update package.json * Update zh_CN.json --------- Co-authored-by: Stefan Popov <17688105+stefashkaa@users.noreply.github.com> * Add changes from master (#1403) * Update Burn.vue * Remove Liberland Governance node --------- Co-authored-by: Stefan Popov <17688105+stefashkaa@users.noreply.github.com> * Fix min max block for Burn page (#1404) Co-authored-by: Stefan Popov <17688105+stefashkaa@users.noreply.github.com> * Remove orderbook research banner (#1405) * Add disabled state for Burn page items (#1406) * Hide SORA Card from menu (#1407) Co-authored-by: Stefan Popov <17688105+stefashkaa@users.noreply.github.com> * fix history restoration & balance deposit & transaction view account addresses (#1409) * Improve calc algo & loading state for Burn page (#1410) Co-authored-by: Stefan Popov <17688105+stefashkaa@users.noreply.github.com> * formatted amount & lp fixes (#1413) * kensetsu (#1352) * Draft * Update BasePageMixin.ts * Update BasePageMixin.ts * Update yarn.lock * Add asset owner page * Improve responsive class * Fix responsive issues related to charts * Add send token tx & fix styles * Add mint tx & fix styles during tx processing * Add burn tx & fix styles during tx processing * Fix disabled state for TokenInput with slider * Support new update-name event for AddressBookInput * Draft for token creation * Update vue.config.js * Improve asset owner page * Refactor Asset owner page * Add vault store * Update state.ts * Remove useless getter from vault * Update index.ts * Add bold prop for GenericPageHeader * Add filter fn prop to SelectToken * Add kensetsu draft * Update AppMenu.vue * Use multiple quote subscriptions * Update App.vue * Refactor CreateVaultDialog * Update Vaults page * Fix max button for borrow amount * Improve styles * Add getLiquidationPenalty * Improve UI * Fix * Update AssetOwnerDetails.vue * Update kusd * Fix LtvProgressBar styles * Fix negative value for XOR as collateral * Fix styles for Vaults page * Add draft for min deposit collateral * Fix formatted values on Vaults page * AddCollateralDialog draft * Update lib version * Add PrevNextInfoLine * Add minDeposit check to Vault creation dialog * Add slot to prev-next-info-line * Fix styles for CreateVaultDialog * Add logic for AddCollateralDialog * Update AddCollateralDialog.vue * Fix decimals issues * Add BorrowMoreDialog * Update CreateVaultDialog.vue * Add RepayDebtDialog * Improve dialogs error handling & reactivity * Add close vault dialog * Add missed non-centered classes * TokenInput: remove focus & add balanceText prop * Improve numbers format for CloseVault and AddCollateral * Fix error icon size * Improve LtvProgressBar * Add new icons * Update api * Add slippage tolerance component to Kensetsu * Add subscriptions * Fix data kensetsu subscriptions * Fix PW-1562 * Update CreateVaultDialog.vue * Fix PW-1564 * Add isAddCollateralUnavailable * Update deps * Remove ken distribution page * Update translation strings * Update en.json * Add translation keys * Fix ltv calc and add en strings * Add translation strings * Fix debt calc * Refactor templates * Update CloseVaultDialog.vue * Add history based translations * Update ru.json * Improve translation strings for Kensetsu * Fix header styles * Add stats draft * Update index.ts * Add stats * Adjust ltv with max ltv * Fix format percent functions * Add title divider for Vaults page * Add MAX LTV * Update ExploreCollaterals.vue * Add kensetsu overall stats * Fix percents * Handle price tools error * Fix styles * Make borrow required during the vault creation * Improve vault creation dialog behaviour * Check total available debt for collateral in Borrow More dialog * Fix * Improve hover icon * Add borrow tax to kusdAvailable for cdp creation * Update collaterals & reduce price subs updates * Improve styles of CreateVaultDialog * Add available check for explore collaterals * Prevent events if swap button is clicked * Exclude borrow tax from available to borrow * Update BorrowMoreDialog.vue * Add collaterals subscription per block * Add paddings for collateral stats * Add ResponsiveTabs component * Update ResponsiveTabs.vue * Update substrate-js * Update electron deps * Improve responsive layouts for Kensetsu * Add feature flags * Improve available debt checks for Explore collaterals * Fix borrow link in menu * Add --sidebar-width * Fix logout state for Explore collaterals * Improve responsive design for Explore components * Fix conflicts * Stability fee -> Interest * Update messages.ts * Improve CreateVault & CloseVault translations * Improve Vaults & VaultDetails translations * Update kensetsu translations (vault -> position)) * Download files from lokalise * Update ExploreCollaterals.vue * Add kensetsu subquery queries * Add Vault Details History * Update VaultDetailsHistory.vue * Add vaults history * Update package.json * Update package.json * Fix checks * Add missed translations * Update Vaults.vue --------- Co-authored-by: Stefan Popov <17688105+stefashkaa@users.noreply.github.com> Co-authored-by: NaghmeMohammadifar <45916098+Naghme98@users.noreply.github.com> Co-authored-by: Nikita-Polyakov * add missing translation (#1415) * Borrow -> Kensetsu (#1417) * Borrow -> Kensetsu * Update ru.json * Fix empty vaults state --------- Co-authored-by: Stefan Popov <17688105+stefashkaa@users.noreply.github.com> * cede payment integration (#1398) * Update FiatDepositOptions.vue * preload widget * add widget * remove legacy * change theme * Update CedeStoreWidget.vue * update widget * change wordings * provide colors * remove occurrences * add cede translations * debug * clear cached data * Update env.json * Add pagination to Vault history (#1416) * add pagination to Vault history * fix TransactionsWidget ts * update FetchVariables ts * fix accessor --------- Co-authored-by: Stefan Popov * fix bridge sora link (#1418) * Add KEN icon (#1420) Co-authored-by: Stefan Popov <17688105+stefashkaa@users.noreply.github.com> * Fix from master 1.35 (#1424) * Fix release issues (#1421) * Update env.json (#1423) Co-authored-by: Stefan Popov <17688105+stefashkaa@users.noreply.github.com> --------- Co-authored-by: Stefan Popov <17688105+stefashkaa@users.noreply.github.com> * update wallet to 1.35.0 (#1425) * check_refer_address_sora * changed_regex_to_api_format_address * update wallet to 1.35.2 (#1429) * transform dialog to page (#1427) * transform dialog to page * Update CedeStore.vue * fix namings * change name * save localStorage field * Update index.ts * bump wallet * make btn pressed * change url * use util method * multiple fiat dialog (#1388) * copy logic * create UI * make fiat on inputs & stats * improve search * Update SelectCurrencyDialog.vue * Update ChartSkeleton.vue * make proof of concept * Revert "make proof of concept" This reverts commit a4a18075081803b9408b6cff820fa4e5705b7c45. * bump wallet * bump wallet * add missing conversion * update wallet * bump wallet * Update AppHeaderMenu.vue * fix vice versa conversion * refactor icons * Delete polkaswap_icons copy.ttf * add translations * add missing types & fixes * Update PriceChart.vue --------- Co-authored-by: Stefan Popov * Added subsquid queries * Test * Remove all filter * [Bridge] Astar support (#1399) * add astar to consts & add logo * add astar adapter methods * update wallet * add shiden to consts * add astar transfer extrinsic * improve history restoration for astar * update reducer to support astar * add todo * fix shiden link --------- Co-authored-by: Stefan Popov * Kensetsu phase 2 (#1433) * Update package.json * Update ExploreOverallStats.vue * Update marketing banner * Update OrderBook.vue * Set predev temporarily * Update deps temporarily * Update deps * Update library * Update api * Set dev * Update vault store * Upgrade kensetsu * Update action button text for Burn page * Update env.json * Update VaultDetails.vue --------- Co-authored-by: Stefan Popov <17688105+stefashkaa@users.noreply.github.com> Co-authored-by: Nikita Polyakov <53777036+Nikita-Polyakov@users.noreply.github.com> * [Bridge] Support second account connect for substrate networks (#1435) * update adapters * update SelectProvider * add selectSubAccount action * use inheritance in SubAdapter * update account inject * incoming tx history update * update selectSubAccount * adding ConnectionView * connection integration * connect wallet on Bridge view * update wallet * fix change account butn * update wallet 1.38.0-beta.1 * wallet 1.38.0-beta.2 * update changeSubAccountName * add SelectSoraAccountDialog * fix sonar issues * open SORA account connect dialog on pages * fix referral route * fix build * update wallet 1.38.0 * Fix Kusama sign tx (#1437) * update adapters * update SelectProvider * add selectSubAccount action * use inheritance in SubAdapter * update account inject * incoming tx history update * update selectSubAccount * adding ConnectionView * connection integration * connect wallet on Bridge view * update wallet * fix change account butn * update wallet 1.38.0-beta.1 * wallet 1.38.0-beta.2 * update changeSubAccountName * add SelectSoraAccountDialog * fix sonar issues * open SORA account connect dialog on pages * fix referral route * fix build * create sub connection using latest polkadot api * update wallet 1.38.0 * update yarn.lock * dont call getNetworkFee on not supported networks (#1438) * Update dependencies & fix bridge account icon (#1439) * update dependencies & fix bridge account icon * deduplicate yarn.lock * app in window concept (#1422) * Update App.vue * Update App.vue * check * Update App.vue * check * Revert "check" This reverts commit 4d6bd61a960173d2ec2a6a01ac2b3b133a00f104. * Update index.html * Update App.vue * check * Update App.vue * Update App.vue * Update App.vue * Update App.vue * use npm module * include script * update wallet * Update App.vue * Update App.vue * add package * Update App.vue * Update App.vue * Update App.vue * Update App.vue * Update App.vue * Update App.vue * Update shims-tsx.d.ts * update * clean packages * Update App.vue * Update App.vue * Update App.vue * support wallet connect only * up wallet * Update NetworkStats.vue * Update Container.vue * Update Swap.vue * add missing translations * Update App.vue * Update App.vue * Update App.vue * Update App.vue * Update App.vue * remove unused keys * Fix issues * Update version * Update TokenInput.vue * Update Bridge.vue * Add new keys * Download from lokalise * Bigger Kensetsu icon --------- Co-authored-by: Stefan Popov Co-authored-by: Vladimir Shelkovnikov <99356504+C4tWithShell@users.noreply.github.com> Co-authored-by: Stefan Popov <17688105+stefashkaa@users.noreply.github.com> Co-authored-by: shlavik * Set configurable min limit for burn (#1432) (#1442) * convert on graphs (#1443) * convert on graphs * Update BarChart.vue * Update TvlChart.vue * Update PriceChart.vue * Update PriceChart.vue * Fix merge issue * Fix TvlChart issues related to currency selection * Fix BarChart issues related to currency selection * remove css fix * Update App.vue --------- Co-authored-by: Stefan Popov <17688105+stefashkaa@users.noreply.github.com> * deleted_shadow_on_the_left * Fix release 1.38 (#1444) * Fix ken distribution data * Update burnXor.ts * Fix shadows issue during Kensetsu loading * Add currency support for Kensetsu overall stats * Use usd values for isBorrowMoreUnavailable & isRepayDebtUnavailable * Add XOR as fiat currency --------- Co-authored-by: Stefan Popov <17688105+stefashkaa@users.noreply.github.com> * updated_with_variable_change * fixed_variables * Add bug fixes from master (#1449) * Release 0.1.2 (#80) * Add base project files * Add About page * Add unit tests * Remove unused files * Update library version * Moved images to img folder. * Refactored some styles, added normalize css. * Fixed article card header font weight. * Fix About snapshot * Fix styles and its imports * PSS-132: Token list store * Add env.json and readme * PSS-134 DevOps: Develop CI and CD processes for Polkaswap web project (#5) * add ci cd Signed-off-by: Bulat Saifullin * fix Dockerfile Signed-off-by: Bulat Saifullin * add pull_request_template.md Signed-off-by: Bulat Saifullin * fix template Signed-off-by: Bulat Saifullin * PSS-132: Select token screen * PSS-132: Refactoring * PSS-132: Change short name to symbol * PSS-132: Add i18n to select token * PSS-132: Add unit tests * PSS-132: Remove elements from tests * Added Swap Interface draft (#4) * Swap Interface: Added screen, Unit Tests, Updated UI Lib version. * PSS-132: Create pair * PSS-132: Fixes for select token * PSS-132: Fix title style * PSS-132: UPdate snaphots * PSS-132: Fix shadow * PSS-132: Fix variable style using * Swap Interface Confirmation Screens (#8) * Added Transaction Submit dialog. * Swap Interface: Moved some variables to store for better relations between different screens and dialogs. * Confirm Swap Dialog: Fixed dialog opening, added confirmation flag to the store. * Added token default logo image, refactored translation call for liquidity. * Added SelectToken dialog on click. * PSS-126: Confirm supply modal * Confirmation screens for create pair * Design fixes * Update ui lib * PSS-126: Logo component * Update tests * Wallet integration and styles issues (#10) * Wallet integration * Fix routing issues * Update UI library version * Refactor all styles * Fix wallet connected state * Update tests * Update test * Update Dockerfile (#12) * PSS-129: Add and remove liquidity page * Design fixes * Token logo check fixes * Refactoring and fixes * Add pair token logo for add liquidity * Settings implementation (#15) * Add settings dialog * Add tests * Update tests * Fix titles for info card * Pool Interface Start Screens (#11) * Pool Interface: Added Start Screen. * Refactored components due to UI Lib updates: set size and border-radius of elements. * Created Dialog wrapper component, refactored dialogs, added fixed top position, fixed close behaviour. * Refactored components imports. * Converted logo icon to link to the home page. * Fixed error in console for Create pair component. * Added Back link behaviour for several components. * Updated unit tests. * PSS-172: Dynamic Page Title (#14) * Added dynamic page title. * PSS-128: Add confirmation screens for pool (#16) * PSS-128: Add confirmation screens for pool Co-authored-by: alexnatalia * Mocks for pool screen * Refactoring * Update tests * Add liquidity button for pairs * Design Fixes and Refactoring (#17) * Refactored TokenLogo and PairTokenLogo components, fixed some bugs, updated unit tests. Refactored components headers. * Added Popper class for info tooltips. Fixed default prop value for Object types. Updated Unit tests. * Design Issues Fix (#19) * Updated configuration variables and Exchange tabs styles. * Updated About page images and styles, Header styles and Menu colors settings. Hid unused links and buttons in header. * Updeted typography variables and Font Styles: Updated Font Size, Line Height and Font Weight Configuration. * Updated Create Pair button styles. Updated Ui Lib version. * Fixed tokens icons for Pool screen. * Updated tooltips to one consistent style. Fixed Pool screen bug. * Refactored: Created special component for Generic Header. Fixed Back icon. * Updated some fonts and Pool screen styles. * Added Empty icon for Select token popup. * Added First Liquidity Provider message to Create a Pair screen. * Hid tooltip for Slider element on Settings screen, hid tooltips for Swap Confirmation. * Updated unit tests. * PSS-205: Remove liquidity: everything should be clickable and with recalculation * Update tests * Fix set remove part to 0 * Inpur for remove part * Fixes * Price container fixes * Update tests * PS-223: Fix remove liquidity in safari * PSS-205: Design Review Issues (#21) * Fixed titles case. Updated buttons with text and icons. Updated typography styles. * Update wallet version & add blockchain integration (#23) * Update wallet version & add blockchain integration * Commented out unit tests. Co-authored-by: alexnatalia * PSS-123: Select token integration * Fix async behavior for dexApi (#25) * Fix async behavior for dexApi * Update .eslintrc.js * PSS-247: Custom Slippage Tolerance Fix (#27) * Updated STab styles. * Updated UI Lib and Wallet versions and styles according to UI Lib fixes. * PSS-129: Add liquiditiy integration * PSS-74 Swap Interface Integration (#26) * Hid swap info for not connected wallet. * Updated SelectToken search by name, added check for translation existance. * Added Swap Integration. * Refactored formatNumber calls. * Hid swap info under buttons for zero amount. * Fixed Header Menu colors. * Fixed swap from Wallet assets. * Updated tooltips. * Updated About page text and Main menu links order. * Fixed Card title color for About page. * Updated Default token setting. * Updated Wallet version. * Hid Transaction Deadline area for Settings. * Removed unneeded tooltip from Settings dialog. * Added validation for Settings. * Added validation for Insufficient Amount error from server. * Added loading while not conencted, changed store to not strict mode, updated tokens setting in store. * Fixed focused behaviour for Swap input fields. * Fix wallet connection & select token behavior * Fixed Min Received format. Co-authored-by: Stefan Popov * Swap result calculation for non connected mode (#28) * Fixed Swap result calculation for non connected mode. * Fixed About page text and styles. * Fix i18n (#30) * Updated Swap input width and Max swap behaviour. Updated Swap Info styles. (#29) * PSS-271: Medium and GitHub links (#31) * Added Github and Medium links for About page. * Upated the Wallet version. * Fixed wallet button color on hover. * Calculate total suply * PSS-216: Design Issues Fixing (#32) * Updated content primary color. * Fixed Price and Token areas horizontal alignment. * Updated tooltips. * Updated Generic Header tooltip. * Updated Token item height for Select Token dialog. * Added Token icons. * Updated token icons names. * PSS-129: Create pair integration * Remove mocks * Refactoring * Add network fee calculation * Fixes * PSS-281: Recalculate Input Values On Select Token (#33) * Added util method to check isNumber value. Removed Max button from token To area. * Added Max sold for reversed swap. * Updated Swap Integration. * Updated UI Lib version. * Added recalc on Select Token. * Fixed Swap for Polkadot.js * Updated isExchangeB param in methods. * Hid Node Address area for Settings popup. * Added Network Fee field to Swap component. * Updated Custom slippage tolerance for Settings. * Fixed paste string value to Swap fields. * Updated Network Fee calls, updated Wallet version, fixed swap tokens balance. * Added isExchangeB parameter to swap call. * Refactoring * fix total supply * PSS-129: Share of pool * Remove share of pool mock * Fix get asset symbol * Hide add liquidity Fix slippage tolerance for add liquidity Fix share of pool Fix unsupprted assets error message * Disable max button for add liquidity Reset values after change tokens * Fixes * Updated Tokens Icons, added PAL icon. (#35) * Wallet connection issues (#38) * Fix wallet connection issues * Fix styles * Update wallet version * Update favicon.ico * PSS-297: check fee on max amount * PSS-295: Added Insufficient Balance Checking (#37) * Added Insufficient balance checking. * Updated FPNumber parameters. * Removed formatNumber usage from Swap screens. * Fixed focus and placeholders values for Swap. * Updated some styles for huge number values. * Refactored due to PR comments. * Result Dialog Styles Fix (#41) * Fixed Result Dialog button styles. * Renamed USD icon. * Update library * Fix swap, liquidity behavior * Update index.ts * TODO: Revert this commit after PSS-309 * Updated wallet version. Co-authored-by: Stefan Popov * PSS-273: WEB UI: Connect Wallet - Close button leads always on Exchange page, not to the previous page (#42) * Fix routing issue * Update wallet version * PSS-295: Confirm Swap Insufficient Balance Checking (#43) * Fixed console error on tokens switch. * Added Is Insufficient Balance checking for Confirm Swap dialog. * Updated Confirm Swap styles. * Updated Swap info after Swap, added max button to init screen. (#44) * Update ui library version (#46) * Update ui library version * Update wallet * BP-312: Fixes for pool * Fix icons position (#47) * Fix icons position * Fix logo * PSS-287: Swap Amount Fields Formatting (#45) * Added Swap fields formatter. * Fixed Slippage Tolerance editing and Swap fields formatting. * Updated wallet version. * Change toString to toFixed * Change formatNumber to toFixed * Fix remove liquidity price * Move back toFixed to toString * Fixed estimated label existence for zero values (#50) * Refactored, added some comments, fixed estimated label existence for zero values. * Modify env config file (#49) Co-authored-by: Bulat Saifullin * Add custom notifications & notification tracking service (#51) * Add custom notifications & notificatio… * Fix conflicts --------- Signed-off-by: Nikita Zaporozhets Signed-off-by: BAStos525 Co-authored-by: Nikita-Polyakov Co-authored-by: Stefan Popov <17688105+stefashkaa@users.noreply.github.com> Co-authored-by: RDMStreet Co-authored-by: NaghmeMohammadifar <45916098+Naghme98@users.noreply.github.com> Co-authored-by: Nikita Polyakov <53777036+Nikita-Polyakov@users.noreply.github.com> Co-authored-by: C4tWithShell Co-authored-by: marat-biriushev <49524488+marat-biriushev@users.noreply.github.com> Co-authored-by: Rustem Co-authored-by: Vladimir Shelkovnikov <99356504+C4tWithShell@users.noreply.github.com> Co-authored-by: shlavik Co-authored-by: f33r0 <95526886+f33r0@users.noreply.github.com> Co-authored-by: Kron1749 <70746258+Kron1749@users.noreply.github.com> Co-authored-by: alexnatalia Co-authored-by: Aleksandr Makhnev Co-authored-by: Bulat Saifullin Co-authored-by: Alex Natalia <38787212+alexnatalia@users.noreply.github.com> Co-authored-by: Dmitriy Creed Co-authored-by: alexnatalia Co-authored-by: Nikita Polyakov Co-authored-by: Alex Natalia Co-authored-by: Pavel Golovkin Co-authored-by: Pavel Co-authored-by: Pobepto Co-authored-by: Tarmo Vannas Co-authored-by: 武宮誠 Co-authored-by: Denis Nikiforov <45266099+DenisNikiforov@users.noreply.github.com> Co-authored-by: Ahmed Elkashef Co-authored-by: Nikita Zaporozhets Co-authored-by: sunlucky163 Co-authored-by: sunlucky163 <44086186+sunlucky163@users.noreply.github.com> Co-authored-by: Bao Tran Co-authored-by: Bao Nguyen Tran Co-authored-by: Pavel Varfolomeev Co-authored-by: wpi86 <86880521+wpi86@users.noreply.github.com> Co-authored-by: Pavel Varfolomeev Co-authored-by: German Vechtomov <89127595+ox7a59@users.noreply.github.com> Co-authored-by: frodan Co-authored-by: Daniil Fronts Co-authored-by: BAStos525 Co-authored-by: BAStos525 <66615487+BAStos525@users.noreply.github.com> Co-authored-by: Aleksey Kazakov Co-authored-by: William Richter <88400283+WRRicht3r@users.noreply.github.com> Co-authored-by: Timofey Trepalin Co-authored-by: Maksim Baranov <33489381+MaksimBaranov98@users.noreply.github.com> Co-authored-by: timofeytrepalin <97504184+timofeytrepalin@users.noreply.github.com> Co-authored-by: Aleksandr Iakimov Co-authored-by: safinsaf <45899673+safinsaf@users.noreply.github.com> --- src/abi/ethereum/internal/MASTER.json | 106 +++--- src/abi/ethereum/other/BRIDGE.json | 308 +++++++++--------- src/abi/ethereum/other/ERC20.json | 230 ++++++------- src/abi/ethereum/other/moonbeam/xTokens.json | 94 ------ src/assets/img/networks/alphanet.svg | 136 -------- src/assets/img/networks/moonbeam.svg | 48 --- src/components/mixins/InternalConnectMixin.ts | 8 +- .../mixins/NetworkFormatterMixin.ts | 6 - src/components/mixins/WalletConnectMixin.ts | 5 +- src/components/pages/Bridge/AccountPanel.vue | 78 +---- .../pages/Bridge/TransferNotification.vue | 52 +-- .../shared/Dialog/SelectSoraAccount.vue | 2 +- src/consts/sub.ts | 49 +-- src/store/assets/actions.ts | 67 ++-- src/store/bridge/actions.ts | 38 +-- src/store/bridge/getters.ts | 21 +- src/store/moonpay/actions.ts | 2 +- src/store/web3/actions.ts | 29 +- src/store/web3/getters.ts | 18 +- src/styles/common.scss | 22 +- src/types/bridge.ts | 2 - src/utils/bridge/common/classes.ts | 15 +- src/utils/bridge/common/utils.ts | 59 +--- src/utils/bridge/eth/classes/history.ts | 4 +- src/utils/bridge/eth/classes/reducers.ts | 43 ++- src/utils/bridge/eth/utils.ts | 30 +- src/utils/bridge/evm/utils.ts | 10 +- src/utils/bridge/sub/classes/adapter.ts | 61 ++-- .../sub/classes/adapters/parachain/acala.ts | 67 ++-- .../sub/classes/adapters/parachain/astar.ts | 75 +++-- .../classes/adapters/parachain/moonbase.ts | 158 +-------- .../classes/adapters/parachain/parachain.ts | 85 ----- .../adapters/{relaychain => }/relaychain.ts | 6 +- .../classes/adapters/relaychain/alphanet.ts | 24 -- .../classes/adapters/standalone/liberland.ts | 4 +- .../bridge/sub/classes/adapters/substrate.ts | 6 +- src/utils/bridge/sub/classes/history.ts | 86 ++--- src/utils/bridge/sub/classes/reducers.ts | 74 ++--- src/utils/bridge/sub/utils.ts | 99 ++---- src/utils/ethers-util.ts | 13 +- src/views/Bridge.vue | 123 ++++--- src/views/Rewards.vue | 3 +- 42 files changed, 823 insertions(+), 1543 deletions(-) delete mode 100644 src/abi/ethereum/other/moonbeam/xTokens.json delete mode 100644 src/assets/img/networks/alphanet.svg delete mode 100644 src/assets/img/networks/moonbeam.svg delete mode 100644 src/utils/bridge/sub/classes/adapters/parachain/parachain.ts rename src/utils/bridge/sub/classes/adapters/{relaychain => }/relaychain.ts (94%) delete mode 100644 src/utils/bridge/sub/classes/adapters/relaychain/alphanet.ts diff --git a/src/abi/ethereum/internal/MASTER.json b/src/abi/ethereum/internal/MASTER.json index 3a79fc419..ed2b5af6c 100644 --- a/src/abi/ethereum/internal/MASTER.json +++ b/src/abi/ethereum/internal/MASTER.json @@ -1,52 +1,54 @@ -[ - { - "constant": false, - "inputs": [ - { - "internalType": "address", - "name": "tokenAddress", - "type": "address" - }, - { - "internalType": "uint256", - "name": "amount", - "type": "uint256" - }, - { - "internalType": "address", - "name": "beneficiary", - "type": "address" - }, - { - "internalType": "bytes32", - "name": "txHash", - "type": "bytes32" - }, - { - "internalType": "uint8[]", - "name": "v", - "type": "uint8[]" - }, - { - "internalType": "bytes32[]", - "name": "r", - "type": "bytes32[]" - }, - { - "internalType": "bytes32[]", - "name": "s", - "type": "bytes32[]" - }, - { - "internalType": "address", - "name": "from", - "type": "address" - } - ], - "name": "mintTokensByPeers", - "outputs": [], - "payable": false, - "stateMutability": "nonpayable", - "type": "function" - } -] +{ + "abi": [ + { + "constant": false, + "inputs": [ + { + "internalType": "address", + "name": "tokenAddress", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "internalType": "address", + "name": "beneficiary", + "type": "address" + }, + { + "internalType": "bytes32", + "name": "txHash", + "type": "bytes32" + }, + { + "internalType": "uint8[]", + "name": "v", + "type": "uint8[]" + }, + { + "internalType": "bytes32[]", + "name": "r", + "type": "bytes32[]" + }, + { + "internalType": "bytes32[]", + "name": "s", + "type": "bytes32[]" + }, + { + "internalType": "address", + "name": "from", + "type": "address" + } + ], + "name": "mintTokensByPeers", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + } + ] +} diff --git a/src/abi/ethereum/other/BRIDGE.json b/src/abi/ethereum/other/BRIDGE.json index 94de998c5..9b7d6a609 100644 --- a/src/abi/ethereum/other/BRIDGE.json +++ b/src/abi/ethereum/other/BRIDGE.json @@ -1,153 +1,155 @@ -[ - { - "inputs": [ - { - "internalType": "bytes32", - "name": "", - "type": "bytes32" - } - ], - "name": "_sidechainTokens", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "tokenAddress", - "type": "address" - }, - { - "internalType": "uint256", - "name": "amount", - "type": "uint256" - }, - { - "internalType": "address payable", - "name": "to", - "type": "address" - }, - { - "internalType": "address", - "name": "from", - "type": "address" - }, - { - "internalType": "bytes32", - "name": "txHash", - "type": "bytes32" - }, - { - "internalType": "uint8[]", - "name": "v", - "type": "uint8[]" - }, - { - "internalType": "bytes32[]", - "name": "r", - "type": "bytes32[]" - }, - { - "internalType": "bytes32[]", - "name": "s", - "type": "bytes32[]" - } - ], - "name": "receiveByEthereumAssetAddress", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes32", - "name": "sidechainAssetId", - "type": "bytes32" - }, - { - "internalType": "uint256", - "name": "amount", - "type": "uint256" - }, - { - "internalType": "address", - "name": "to", - "type": "address" - }, - { - "internalType": "address", - "name": "from", - "type": "address" - }, - { - "internalType": "bytes32", - "name": "txHash", - "type": "bytes32" - }, - { - "internalType": "uint8[]", - "name": "v", - "type": "uint8[]" - }, - { - "internalType": "bytes32[]", - "name": "r", - "type": "bytes32[]" - }, - { - "internalType": "bytes32[]", - "name": "s", - "type": "bytes32[]" - } - ], - "name": "receiveBySidechainAssetId", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes32", - "name": "to", - "type": "bytes32" - }, - { - "internalType": "uint256", - "name": "amount", - "type": "uint256" - }, - { - "internalType": "address", - "name": "tokenAddress", - "type": "address" - } - ], - "name": "sendERC20ToSidechain", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes32", - "name": "to", - "type": "bytes32" - } - ], - "name": "sendEthToSidechain", - "outputs": [], - "stateMutability": "payable", - "type": "function" - } -] \ No newline at end of file +{ + "abi": [ + { + "inputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "name": "_sidechainTokens", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "tokenAddress", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "internalType": "address payable", + "name": "to", + "type": "address" + }, + { + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "internalType": "bytes32", + "name": "txHash", + "type": "bytes32" + }, + { + "internalType": "uint8[]", + "name": "v", + "type": "uint8[]" + }, + { + "internalType": "bytes32[]", + "name": "r", + "type": "bytes32[]" + }, + { + "internalType": "bytes32[]", + "name": "s", + "type": "bytes32[]" + } + ], + "name": "receiveByEthereumAssetAddress", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "sidechainAssetId", + "type": "bytes32" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "internalType": "bytes32", + "name": "txHash", + "type": "bytes32" + }, + { + "internalType": "uint8[]", + "name": "v", + "type": "uint8[]" + }, + { + "internalType": "bytes32[]", + "name": "r", + "type": "bytes32[]" + }, + { + "internalType": "bytes32[]", + "name": "s", + "type": "bytes32[]" + } + ], + "name": "receiveBySidechainAssetId", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "to", + "type": "bytes32" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "internalType": "address", + "name": "tokenAddress", + "type": "address" + } + ], + "name": "sendERC20ToSidechain", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "to", + "type": "bytes32" + } + ], + "name": "sendEthToSidechain", + "outputs": [], + "stateMutability": "payable", + "type": "function" + } + ] +} diff --git a/src/abi/ethereum/other/ERC20.json b/src/abi/ethereum/other/ERC20.json index 0623a6669..528b15672 100644 --- a/src/abi/ethereum/other/ERC20.json +++ b/src/abi/ethereum/other/ERC20.json @@ -1,128 +1,130 @@ -[ - { - "inputs": [ - { - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "internalType": "address", - "name": "spender", - "type": "address" - } - ], - "name": "allowance", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "spender", - "type": "address" - }, - { - "internalType": "uint256", - "name": "value", - "type": "uint256" - } - ], - "name": "approve", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "owner", - "type": "address" - } - ], - "name": "balanceOf", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "spender", - "type": "address" - }, - { - "internalType": "uint256", - "name": "addedValue", - "type": "uint256" - } - ], - "name": "increaseAllowance", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "decimals", - "outputs": [ +{ + "abi": [ + { + "inputs": [ { + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "internalType": "address", + "name": "spender", + "type": "address" + } + ], + "name": "allowance", + "outputs": [ + { + "internalType": "uint256", "name": "", - "type": "uint8" + "type": "uint256" } - ], - "payable": false, - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ { - "name": "to", + "internalType": "address", + "name": "spender", "type": "address" }, { + "internalType": "uint256", "name": "value", "type": "uint256" } - ], - "name": "transfer", - "outputs": [ + ], + "name": "approve", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "owner", + "type": "address" + } + ], + "name": "balanceOf", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "spender", + "type": "address" + }, + { + "internalType": "uint256", + "name": "addedValue", + "type": "uint256" + } + ], + "name": "increaseAllowance", + "outputs": [ { + "internalType": "bool", "name": "", "type": "bool" } - ], - "payable": false, - "stateMutability": "nonpayable", - "type": "function" - } -] + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "decimals", + "outputs": [ + { + "name": "", + "type": "uint8" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "name": "to", + "type": "address" + }, + { + "name": "value", + "type": "uint256" + } + ], + "name": "transfer", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + } + ] +} diff --git a/src/abi/ethereum/other/moonbeam/xTokens.json b/src/abi/ethereum/other/moonbeam/xTokens.json deleted file mode 100644 index 34ee16fa2..000000000 --- a/src/abi/ethereum/other/moonbeam/xTokens.json +++ /dev/null @@ -1,94 +0,0 @@ -[ - { - "inputs": [ - { - "internalType": "address", - "name": "currency_address", - "type": "address" - }, - { - "internalType": "uint256", - "name": "amount", - "type": "uint256" - }, - { - "components": [ - { - "internalType": "uint8", - "name": "parents", - "type": "uint8" - }, - { - "internalType": "bytes[]", - "name": "interior", - "type": "bytes[]" - } - ], - "internalType": "structXtokens.Multilocation", - "name": "destination", - "type": "tuple" - }, - { - "internalType": "uint64", - "name": "weight", - "type": "uint64" - } - ], - "name": "transfer", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "components": [ - { - "internalType": "uint8", - "name": "parents", - "type": "uint8" - }, - { - "internalType": "bytes[]", - "name": "interior", - "type": "bytes[]" - } - ], - "internalType": "structXtokens.Multilocation", - "name": "asset", - "type": "tuple" - }, - { - "internalType": "uint256", - "name": "amount", - "type": "uint256" - }, - { - "components": [ - { - "internalType": "uint8", - "name": "parents", - "type": "uint8" - }, - { - "internalType": "bytes[]", - "name": "interior", - "type": "bytes[]" - } - ], - "internalType": "structXtokens.Multilocation", - "name": "destination", - "type": "tuple" - }, - { - "internalType": "uint64", - "name": "weight", - "type": "uint64" - } - ], - "name": "transfer_multiasset", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - } -] \ No newline at end of file diff --git a/src/assets/img/networks/alphanet.svg b/src/assets/img/networks/alphanet.svg deleted file mode 100644 index 1714c1059..000000000 --- a/src/assets/img/networks/alphanet.svg +++ /dev/null @@ -1,136 +0,0 @@ - - diff --git a/src/assets/img/networks/moonbeam.svg b/src/assets/img/networks/moonbeam.svg deleted file mode 100644 index bfc782321..000000000 --- a/src/assets/img/networks/moonbeam.svg +++ /dev/null @@ -1,48 +0,0 @@ - - - - - - - diff --git a/src/components/mixins/InternalConnectMixin.ts b/src/components/mixins/InternalConnectMixin.ts index cb5356ca3..15b61d701 100644 --- a/src/components/mixins/InternalConnectMixin.ts +++ b/src/components/mixins/InternalConnectMixin.ts @@ -3,13 +3,11 @@ import { Component, Mixins } from 'vue-property-decorator'; import TranslationMixin from '@/components/mixins/TranslationMixin'; import { PageNames } from '@/consts'; import { goTo } from '@/router'; -import { action, getter, mutation, state } from '@/store/decorators'; +import { getter, mutation, state } from '@/store/decorators'; import { formatAddress } from '@/utils'; @Component export default class InternalConnectMixin extends Mixins(TranslationMixin) { - @action.wallet.account.logout public logout!: () => Promise; - @state.wallet.account.address public soraAddress!: string; @getter.wallet.account.isLoggedIn public isLoggedIn!: boolean; @@ -22,10 +20,6 @@ export default class InternalConnectMixin extends Mixins(TranslationMixin) { this.setSoraAccountDialogVisibility(true); } - public disconnectSoraWallet(): void { - this.logout(); - } - public navigateToWallet(): void { goTo(PageNames.Wallet); } diff --git a/src/components/mixins/NetworkFormatterMixin.ts b/src/components/mixins/NetworkFormatterMixin.ts index 60989601f..3d43475bd 100644 --- a/src/components/mixins/NetworkFormatterMixin.ts +++ b/src/components/mixins/NetworkFormatterMixin.ts @@ -145,8 +145,6 @@ export default class NetworkFormatterMixin extends Mixins(TranslationMixin) { return 'acala'; case SubNetworkId.PolkadotAstar: return 'astar'; - case SubNetworkId.PolkadotMoonbeam: - return 'moonbeam'; case SubNetworkId.Kusama: return 'kusama'; case SubNetworkId.KusamaShiden: @@ -159,10 +157,6 @@ export default class NetworkFormatterMixin extends Mixins(TranslationMixin) { return 'sora-kusama'; case SubNetworkId.Liberland: return 'liberland'; - case SubNetworkId.Alphanet: - return 'alphanet'; - case SubNetworkId.AlphanetSora: - return 'sora-alphanet'; case SubNetworkId.AlphanetMoonbase: return 'moonbase'; default: diff --git a/src/components/mixins/WalletConnectMixin.ts b/src/components/mixins/WalletConnectMixin.ts index 9d627a959..83e87a60a 100644 --- a/src/components/mixins/WalletConnectMixin.ts +++ b/src/components/mixins/WalletConnectMixin.ts @@ -17,18 +17,15 @@ export default class WalletConnectMixin extends Mixins(InternalConnectMixin) { @state.web3.networkType networkType!: BridgeNetworkType; @getter.bridge.isSubBridge isSubBridge!: boolean; - @getter.bridge.isSubAccountType isSubAccountType!: boolean; @mutation.web3.setSubAccountDialogVisibility setSubAccountDialogVisibility!: (flag: boolean) => void; @mutation.web3.setSelectProviderDialogVisibility setSelectProviderDialogVisibility!: (flag: boolean) => void; @action.web3.changeEvmNetworkProvided changeEvmNetworkProvided!: AsyncFnWithoutArgs; @action.web3.selectEvmProvider selectEvmProvider!: (provider: Provider) => Promise; + @action.web3.resetEvmProviderConnection resetEvmProviderConnection!: FnWithoutArgs; @action.web3.disconnectExternalNetwork disconnectExternalNetwork!: AsyncFnWithoutArgs; - @action.web3.resetEvmProviderConnection disconnectEvmWallet!: FnWithoutArgs; - @action.web3.resetSubAccount disconnectSubWallet!: FnWithoutArgs; - connectSubWallet(): void { this.setSubAccountDialogVisibility(true); } diff --git a/src/components/pages/Bridge/AccountPanel.vue b/src/components/pages/Bridge/AccountPanel.vue index 7b73b3f87..937b192d2 100644 --- a/src/components/pages/Bridge/AccountPanel.vue +++ b/src/components/pages/Bridge/AccountPanel.vue @@ -1,37 +1,13 @@ diff --git a/src/components/pages/Bridge/TransferNotification.vue b/src/components/pages/Bridge/TransferNotification.vue index eb9c16a24..8b93f1c66 100644 --- a/src/components/pages/Bridge/TransferNotification.vue +++ b/src/components/pages/Bridge/TransferNotification.vue @@ -26,13 +26,10 @@ import { Component, Mixins } from 'vue-property-decorator'; import BridgeTransactionMixin from '@/components/mixins/BridgeTransactionMixin'; import { getter, state, mutation } from '@/store/decorators'; import { isOutgoingTransaction } from '@/utils/bridge/common/utils'; -import { subBridgeApi } from '@/utils/bridge/sub/api'; -import type { SubNetworksConnector } from '@/utils/bridge/sub/classes/adapter'; import ethersUtil from '@/utils/ethers-util'; import type { IBridgeTransaction } from '@sora-substrate/util'; import type { Whitelist, RegisteredAccountAsset } from '@sora-substrate/util/build/assets/types'; -import type { SubNetwork } from '@sora-substrate/util/build/bridgeProxy/sub/types'; import type { BridgeNetworkId } from '@sora-substrate/util/build/bridgeProxy/types'; @Component({ @@ -45,7 +42,6 @@ import type { BridgeNetworkId } from '@sora-substrate/util/build/bridgeProxy/typ }) export default class BridgeTransferNotification extends Mixins(BridgeTransactionMixin) { @state.bridge.notificationData private notificationData!: Nullable; - @state.bridge.subBridgeConnector private subBridgeConnector!: SubNetworksConnector; @getter.wallet.account.whitelist private whitelist!: Whitelist; @getter.assets.assetDataByAddress private getAsset!: (addr?: string) => Nullable; @@ -77,22 +73,13 @@ export default class BridgeTransferNotification extends Mixins(BridgeTransaction return this.asset?.symbol ?? ''; } - get isSubEvm(): boolean { - return subBridgeApi.isEvmAccount(this.tx?.externalNetwork as SubNetwork); - } - - get isEvmNetwork(): boolean { - if (!this.tx?.externalNetworkType) return false; - if (this.tx.externalNetworkType === BridgeNetworkType.Sub && !this.isSubEvm) return false; - return true; - } - get addTokenBtnVisibility(): boolean { - if (!this.isEvmNetwork) return false; - - const address = this.asset?.externalAddress; + if (!this.tx?.externalNetworkType) return false; + if (this.tx.externalNetworkType === BridgeNetworkType.Sub) return false; - return !!address && !ethersUtil.isNativeEvmTokenAddress(address) && isOutgoingTransaction(this.tx); + return ( + !!this.asset && !ethersUtil.isNativeEvmTokenAddress(this.asset.externalAddress) && isOutgoingTransaction(this.tx) + ); } get txLink() { @@ -131,30 +118,11 @@ export default class BridgeTransferNotification extends Mixins(BridgeTransaction async addToken(): Promise { if (!this.asset) return; - try { - const { externalAddress, externalDecimals, symbol, address } = this.asset; - const image = this.whitelist[address]?.icon; - - let tokenAddress = externalAddress; - let tokenSymbol = symbol; - let tokenDecimals = +externalDecimals; - - if (this.isSubEvm) { - const adapter = this.subBridgeConnector.parachain; - if (!adapter) throw new Error('Adapter not found'); - const assetMeta = adapter.getAssetMeta(this.asset); - if (!assetMeta) throw new Error('Asset metadata not found'); - tokenAddress = adapter.assetIdToEvmContractAddress(externalAddress); - tokenSymbol = assetMeta.symbol; - tokenDecimals = assetMeta.decimals; - } - - await ethersUtil.addToken(tokenAddress, tokenSymbol, tokenDecimals, image); - } catch (error) { - console.error(error); - } finally { - this.visibility = false; - } + const { externalAddress, externalDecimals, symbol, address } = this.asset; + const image = this.whitelist[address]?.icon; + await ethersUtil.addToken(externalAddress, symbol, +externalDecimals, image); + + this.visibility = false; } } diff --git a/src/components/shared/Dialog/SelectSoraAccount.vue b/src/components/shared/Dialog/SelectSoraAccount.vue index bea8dffd7..095e52f18 100644 --- a/src/components/shared/Dialog/SelectSoraAccount.vue +++ b/src/components/shared/Dialog/SelectSoraAccount.vue @@ -33,7 +33,7 @@ export default class SelectSoraAccountDialog extends Mixins(TranslationMixin) { @getter.wallet.account.account public soraAccount!: Nullable; @action.wallet.account.loginAccount public loginAccount!: (account: WALLET_TYPES.PolkadotJsAccount) => Promise; - @action.wallet.account.logout public logout!: () => Promise; + @action.wallet.account.logout public logout!: (forgetAddress?: string) => Promise; @action.wallet.account.renameAccount public rename!: (data: { address: string; name: string }) => Promise; get chainApi() { diff --git a/src/consts/sub.ts b/src/consts/sub.ts index 8f7591fa3..d2d05bd7f 100644 --- a/src/consts/sub.ts +++ b/src/consts/sub.ts @@ -98,31 +98,6 @@ export const SUB_NETWORKS: Partial> = { }, ], }, - [SubNetworkId.PolkadotMoonbeam]: { - id: SubNetworkId.PolkadotMoonbeam, - name: 'Moonbeam', - nativeCurrency: { - name: 'GLMR', - symbol: 'GLMR', - decimals: 18, - }, - endpointUrls: ['https://rpc.api.moonbeam.network', 'https://moonbeam-rpc.dwellir.com'], - blockExplorerUrls: ['https://moonbeam.subscan.io'], - shortName: 'Moonbeam', - nodes: [ - { - chain: 'Moonbeam', - name: 'Moonbeam Foundation', - address: 'wss://wss.api.moonbeam.network', - }, - { - chain: 'Moonbeam', - name: 'Dwellir', - address: 'wss://moonbeam-rpc.dwellir.com', - }, - ], - evmId: 1284, - }, [SubNetworkId.Rococo]: { id: SubNetworkId.Rococo, name: 'Rococo', @@ -155,7 +130,7 @@ export const SUB_NETWORKS: Partial> = { { chain: 'Moonbase Relay Testnet', name: 'Parity', - address: 'wss://fro-moon-rpc-1-moonbase-relay-rpc-1.moonbase.ol-infra.network', + address: 'wss://frag-moonbase-relay-rpc-ws.g.moonbase.moonbeam.network', }, ], }, @@ -167,9 +142,8 @@ export const SUB_NETWORKS: Partial> = { symbol: 'GLMR', // "DEV" decimals: 18, }, - endpointUrls: ['https://rpc.api.moonbase.moonbeam.network', 'https://moonbase-rpc.dwellir.com'], - blockExplorerUrls: ['https://moonbase.subscan.io'], - shortName: 'Moonbase', + blockExplorerUrls: [], + shortName: 'Alpha', nodes: [ { chain: 'Moonbase Alpha', @@ -177,7 +151,6 @@ export const SUB_NETWORKS: Partial> = { address: 'wss://wss.api.moonbase.moonbeam.network', }, ], - evmId: 1287, }, // SORA Parachains [SubNetworkId.RococoSora]: { @@ -327,24 +300,10 @@ export const SUB_TRANSFER_FEES: SubNetworksFees = { [BridgeTxDirection.Incoming]: '0', }, }, - [SubNetworkId.Alphanet]: { - ALPHA: { - [BridgeTxDirection.Outgoing]: '2700000000', - [BridgeTxDirection.Incoming]: '0', - }, - }, [SubNetworkId.AlphanetMoonbase]: { - GLMR: { + ACA: { [BridgeTxDirection.Outgoing]: '34313700000000', [BridgeTxDirection.Incoming]: '0', }, - ALPHA: { - [BridgeTxDirection.Outgoing]: '44415350668', - [BridgeTxDirection.Incoming]: '46453162841', - }, - XOR: { - [BridgeTxDirection.Outgoing]: '8140448382622083802', - [BridgeTxDirection.Incoming]: '0', - }, }, }; diff --git a/src/store/assets/actions.ts b/src/store/assets/actions.ts index b0f6f2856..c0c378edd 100644 --- a/src/store/assets/actions.ts +++ b/src/store/assets/actions.ts @@ -91,6 +91,31 @@ async function getSubRegisteredAssets( if (!subNetwork) return []; const subNetworkId = subNetwork as SubNetwork; + + // [TODO] remove when non native parachain tokens are supported + if (subNetworkId === SubNetworkId.PolkadotAcala) { + return [ + { + '0x001ddbe1a880031da72f7ea421260bec635fa7d1aa72593d5412795408b6b2ba': { + address: '', + decimals: 12, + kind: 'Sidechain', + }, + }, + ]; + } + if (subNetworkId === SubNetworkId.PolkadotAstar) { + return [ + { + '0x009dd037fcb32f4fe17c513abd4641a2ece844d106e30788124f0c0acc6e748e': { + address: '', + decimals: 18, + kind: 'Sidechain', + }, + }, + ]; + } + const networkAssets = await subBridgeApi.getRegisteredAssets(subNetworkId); const registeredAssets = Object.entries(networkAssets).map(([soraAddress, assetData]) => { return { @@ -105,36 +130,6 @@ async function getSubRegisteredAssets( return registeredAssets; } -async function updateSubAssetsData(context: ActionContext): Promise { - const { state, commit, rootState, rootGetters } = assetsActionContext(context); - const { registeredAssets } = state; - - const { destinationNetwork, soraParachain, parachain } = rootState.bridge.subBridgeConnector; - - if (!subBridgeApi.isParachain(destinationNetwork)) return; - - if (!(soraParachain && parachain)) return; - - await Promise.all([soraParachain.connect(), parachain.connect()]); - - const updatedEntries = await Promise.all( - Object.entries(registeredAssets).map(async ([soraAddress, assetData]) => { - const asset = { ...assetData }; - const soraAsset = rootGetters.wallet.account.assetsDataTable[soraAddress]; - if (!asset.address && soraAsset) { - const multilocation = await subBridgeApi.soraParachainApi.getAssetMulilocation(soraAddress, soraParachain.api); - const id = await parachain.getAssetIdByMultilocation(soraAsset, multilocation); - asset.address = id; - } - return [soraAddress, asset]; - }) - ); - - const assets = Object.fromEntries(updatedEntries); - - commit.setRegisteredAssets(assets); -} - async function getRegisteredAssets(context: ActionContext): Promise[]> { const { rootState } = assetsActionContext(context); @@ -178,16 +173,14 @@ const actions = defineActions({ async updateRegisteredAssets(context): Promise { const { commit, rootState } = assetsActionContext(context); + // only for ETH bridge, because of sora assets broken registration + if (rootState.web3.networkType === BridgeNetworkType.Eth) { + commit.setRegisteredAssetsFetching(true); - commit.setRegisteredAssetsFetching(true); - - if (rootState.web3.networkType === BridgeNetworkType.Sub) { - await updateSubAssetsData(context); - } else { await updateEthAssetsData(context); - } - commit.setRegisteredAssetsFetching(false); + commit.setRegisteredAssetsFetching(false); + } }, }); diff --git a/src/store/bridge/actions.ts b/src/store/bridge/actions.ts index bec895a54..67d517d76 100644 --- a/src/store/bridge/actions.ts +++ b/src/store/bridge/actions.ts @@ -84,26 +84,6 @@ function getBridgeApi(context: ActionContext) { return ethBridgeApi; } -async function switchAmounts(context: ActionContext): Promise { - const { state, dispatch } = bridgeActionContext(context); - - if (state.focusedField === FocusedField.Received) { - await dispatch.setSendedAmount(state.amountReceived); - } else { - await dispatch.setReceivedAmount(state.amountSend); - } -} - -async function updateAmounts(context: ActionContext): Promise { - const { state, dispatch } = bridgeActionContext(context); - - if (state.focusedField === FocusedField.Received) { - await dispatch.setReceivedAmount(state.amountReceived); - } else { - await dispatch.setSendedAmount(state.amountSend); - } -} - function checkEvmNetwork(context: ActionContext): void { const { rootGetters } = bridgeActionContext(context); if (!rootGetters.web3.isValidNetwork) { @@ -414,7 +394,7 @@ async function updateSoraNetworkFee(context: ActionContext): Promise): Promise { +async function updateBalancesAndFees(context: ActionContext): Promise { const { dispatch } = bridgeActionContext(context); await Promise.allSettled([ @@ -468,14 +448,19 @@ const actions = defineActions({ }, async switchDirection(context): Promise { - const { commit, state } = bridgeActionContext(context); + const { commit, dispatch, state } = bridgeActionContext(context); commit.setSoraToEvm(!state.isSoraToEvm); commit.setAssetSenderBalance(); commit.setAssetRecipientBalance(); - await updateBalancesFeesAndAmounts(context); - await switchAmounts(context); + await updateBalancesAndFees(context); + + if (state.focusedField === FocusedField.Received) { + await dispatch.setSendedAmount(state.amountReceived); + } else { + await dispatch.setReceivedAmount(state.amountSend); + } }, async setAssetAddress(context, address?: string): Promise { @@ -489,9 +474,8 @@ const actions = defineActions({ dispatch.updateOutgoingMinLimit(), dispatch.updateOutgoingMaxLimit(), dispatch.updateIncomingMinLimit(), - updateBalancesFeesAndAmounts(context), + updateBalancesAndFees(context), ]); - await updateAmounts(context); }, async updateExternalBalance(context): Promise { @@ -583,7 +567,7 @@ const actions = defineActions({ const subscription = api.system.updated.subscribe(() => { updateExternalBlockNumber(context); - updateBalancesFeesAndAmounts(context); + updateBalancesAndFees(context); }); commit.setBlockUpdatesSubscription(subscription); diff --git a/src/store/bridge/getters.ts b/src/store/bridge/getters.ts index 2da5b4384..3d8a24dbd 100644 --- a/src/store/bridge/getters.ts +++ b/src/store/bridge/getters.ts @@ -110,22 +110,11 @@ const getters = defineGetters()({ return assetIds[0]; }, - isSubAccountType(...args): boolean { - const { rootState } = bridgeGetterContext(args); - const { networkSelected, networkType } = rootState.web3; - - if (networkType === BridgeNetworkType.Sub) { - return !subBridgeApi.isEvmAccount(networkSelected as SubNetwork); - } - - return false; - }, - externalAccount(...args): string { const { getters, rootState } = bridgeGetterContext(args); const { evmAddress, subAddress } = rootState.web3; - if (getters.isSubAccountType) { + if (getters.isSubBridge) { return subAddress; } else { return evmAddress; @@ -139,7 +128,7 @@ const getters = defineGetters()({ if (state.isSoraToEvm) return soraAddress; - return getters.isSubAccountType ? chainAddress(subAddress, state.subBridgeConnector) : evmAddress; + return getters.isSubBridge ? chainAddress(subAddress, state.subBridgeConnector) : evmAddress; }, senderName(...args): string { @@ -149,7 +138,7 @@ const getters = defineGetters()({ if (state.isSoraToEvm) return soraName; - return getters.isSubAccountType ? subAddressName : ''; + return getters.isSubBridge ? subAddressName : ''; }, recipient(...args): string { @@ -159,7 +148,7 @@ const getters = defineGetters()({ if (!state.isSoraToEvm) return soraAddress; - return getters.isSubAccountType ? chainAddress(subAddress, state.subBridgeConnector) : evmAddress; + return getters.isSubBridge ? chainAddress(subAddress, state.subBridgeConnector) : evmAddress; }, recipientName(...args): string { @@ -169,7 +158,7 @@ const getters = defineGetters()({ if (!state.isSoraToEvm) return soraName; - return getters.isSubAccountType ? subAddressName : ''; + return getters.isSubBridge ? subAddressName : ''; }, isEthBridge(...args): boolean { diff --git a/src/store/moonpay/actions.ts b/src/store/moonpay/actions.ts index eded9490d..b23cd4384 100644 --- a/src/store/moonpay/actions.ts +++ b/src/store/moonpay/actions.ts @@ -84,7 +84,7 @@ const actions = defineActions({ }; } else { // Parse ERC-20 transfer - const abi = SmartContracts[SmartContractType.ERC20]; + const abi = SmartContracts[SmartContractType.ERC20].abi; const inter = new ethers.Interface(abi); const decodedInput = inter.parseTransaction({ data: tx.data }); diff --git a/src/store/web3/actions.ts b/src/store/web3/actions.ts index 9fa2abe67..77ba5f684 100644 --- a/src/store/web3/actions.ts +++ b/src/store/web3/actions.ts @@ -1,8 +1,9 @@ import { BridgeNetworkType } from '@sora-substrate/util/build/bridgeProxy/consts'; import { SubNetworkId } from '@sora-substrate/util/build/bridgeProxy/sub/consts'; import { BridgeNetworkId } from '@sora-substrate/util/build/bridgeProxy/types'; -import { api as soraApi, accountUtils, WALLET_TYPES, WALLET_CONSTS } from '@soramitsu/soraneo-wallet-web'; +import { accountUtils, WALLET_TYPES, WALLET_CONSTS } from '@soramitsu/soraneo-wallet-web'; import { defineActions } from 'direct-vuex'; +import { ethers } from 'ethers'; import { KnownEthBridgeAsset, SmartContracts, SmartContractType } from '@/consts/evm'; import { web3ActionContext } from '@/store/web3'; @@ -172,18 +173,21 @@ const actions = defineActions({ }, async changeEvmNetworkProvided(context): Promise { - const { getters } = web3ActionContext(context); + const { getters, state } = web3ActionContext(context); const { selectedNetwork } = getters; + const { networkType } = state; - if (!selectedNetwork) return; - - await ethersUtil.switchOrAddChain(selectedNetwork); + if (selectedNetwork && networkType !== BridgeNetworkType.Sub) { + await ethersUtil.switchOrAddChain(selectedNetwork); + } }, async getSupportedApps(context): Promise { const { commit, getters } = web3ActionContext(context); - // production mock - let supportedApps = { + // [TODO] uncomment + // const supportedApps = await api.bridgeProxy.getListApps(); + // [TODO] remove this production mock after nodes update + const supportedApps = { [BridgeNetworkType.Eth]: {}, [BridgeNetworkType.Evm]: {}, [BridgeNetworkType.Sub]: [ @@ -197,12 +201,6 @@ const actions = defineActions({ ], }; - try { - supportedApps = await soraApi.bridgeProxy.getListApps(); - } catch (error) { - console.error(error); - } - commit.setSupportedApps(supportedApps as any); const networks = getters.availableNetworks[BridgeNetworkType.Sub]; @@ -249,12 +247,13 @@ const actions = defineActions({ if (!soraAssetId) { return ''; } - const contractAbi = SmartContracts[SmartContractType.EthBridge][KnownEthBridgeAsset.Other]; + const contractAbi = SmartContracts[SmartContractType.EthBridge][KnownEthBridgeAsset.Other].abi; const contractAddress = getters.contractAddress(KnownEthBridgeAsset.Other); if (!contractAddress || !contractAbi) { throw new Error('Contract address/abi is not found'); } - const contractInstance = await ethersUtil.getContract(contractAddress, contractAbi); + const signer = await ethersUtil.getSigner(); + const contractInstance = new ethers.Contract(contractAddress, contractAbi, signer); const methodArgs = [soraAssetId]; const externalAddress = await contractInstance._sidechainTokens(...methodArgs); // Not (wrong) registered Sora asset on bridge contract return '0' address (like native token) diff --git a/src/store/web3/getters.ts b/src/store/web3/getters.ts index 10533d3db..7e3c675c8 100644 --- a/src/store/web3/getters.ts +++ b/src/store/web3/getters.ts @@ -14,7 +14,7 @@ import type { BridgeNetworkId } from '@sora-substrate/util/build/bridgeProxy/typ const getters = defineGetters()({ availableNetworks(...args): Record>> { - const { state } = web3GetterContext(args); + const { state, rootState } = web3GetterContext(args); const hashi = [state.ethBridgeEvmNetwork].reduce((buffer, id) => { const data = EVM_NETWORKS[id]; @@ -79,21 +79,11 @@ const getters = defineGetters()({ }, isValidNetwork(...args): boolean { - const { state, getters } = web3GetterContext(args); - const { evmProviderNetwork } = state; - const { selectedNetwork } = getters; - - if (!selectedNetwork) return false; + const { state } = web3GetterContext(args); - if (state.networkType === BridgeNetworkType.Sub) { - if (selectedNetwork.evmId) { - return evmProviderNetwork === selectedNetwork.evmId; - } else { - return true; - } - } + if (state.networkType === BridgeNetworkType.Sub) return true; - return evmProviderNetwork === selectedNetwork.id; + return state.evmProviderNetwork === state.networkSelected; }, contractAddress(...args): (asset: KnownEthBridgeAsset) => Nullable { diff --git a/src/styles/common.scss b/src/styles/common.scss index 380a49e41..396a81201 100644 --- a/src/styles/common.scss +++ b/src/styles/common.scss @@ -22,7 +22,7 @@ $country-emoji-font: 'Twemoji Country Flags'; } } -$networks: 'sora', 'ethereum', 'ethereum-classic', 'avalanche', 'klaytn', 'polygon', 'binance-smart-chain', 'rococo', 'polkadot', 'kusama', 'acala', 'astar', 'shiden', 'liberland', 'alphanet', 'moonbase', 'moonbeam', 'sora-polkadot', 'sora-kusama'; +$networks: 'sora', 'ethereum', 'ethereum-classic', 'avalanche', 'klaytn', 'polygon', 'binance-smart-chain', 'rococo', 'polkadot', 'kusama', 'acala', 'astar', 'shiden', 'liberland', 'moonbase', 'sora-polkadot', 'sora-kusama'; /* Networks Icons */ .network-icon { display: inline-block; @@ -41,17 +41,15 @@ $networks: 'sora', 'ethereum', 'ethereum-classic', 'avalanche', 'klaytn', 'polyg } } - @each $network in 'rococo', 'alphanet' { - &--sora-#{$network} { - background-image: url('~@/assets/img/networks/#{$network}.svg'); - &::after { - content: ''; - display: block; - width: 50%; - height: 50%; - filter: drop-shadow(2px 4px 6px black); - background-image: url('~@/assets/img/networks/sora.svg'); - } + &--sora-rococo { + background-image: url('~@/assets/img/networks/rococo.svg'); + &::after { + content: ''; + display: block; + width: 50%; + height: 50%; + filter: drop-shadow(2px 4px 6px black); + background-image: url('~@/assets/img/networks/sora.svg'); } } } diff --git a/src/types/bridge.ts b/src/types/bridge.ts index f0e306b5d..1227f5467 100644 --- a/src/types/bridge.ts +++ b/src/types/bridge.ts @@ -19,8 +19,6 @@ export interface NetworkData { endpointUrls?: string[]; /** Nodes for Substrate network */ nodes?: Node[]; - /** Evm chain id for substrate network */ - evmId?: number; } export type SubNetworksFees = Partial>>>; diff --git a/src/utils/bridge/common/classes.ts b/src/utils/bridge/common/classes.ts index 9ebef9dd5..12d6a6f7f 100644 --- a/src/utils/bridge/common/classes.ts +++ b/src/utils/bridge/common/classes.ts @@ -18,7 +18,6 @@ import type { IBridgeConstructorOptions, TransactionHandlerPayload, } from '@/utils/bridge/common/types'; -import { isUnsignedTx } from '@/utils/bridge/common/utils'; import type { IBridgeTransaction } from '@sora-substrate/util'; @@ -181,27 +180,25 @@ export class BridgeReducer implements IB } private async checkTransactionBlockId(id: string): Promise { - const { blockId, externalBlockId } = this.getTransaction(id); + const { blockId } = this.getTransaction(id); - if (blockId || externalBlockId) return; + if (blockId) return; await delay(1_000); await this.checkTransactionBlockId(id); } async waitForTransactionBlockId(id: string): Promise { - const tx = this.getTransaction(id); + const { txId } = this.getTransaction(id); - if (isUnsignedTx(tx)) { - throw new Error( - `[${this.constructor.name}]: Transaction "id" or "externalHash" is empty, first sign the transaction` - ); + if (!txId) { + throw new Error(`[${this.constructor.name}]: Transaction "id" is empty, first sign the transaction`); } try { await Promise.race([ this.checkTransactionBlockId(id), - delay(BLOCK_PRODUCE_TIME * 10, false), // 60s + delay(BLOCK_PRODUCE_TIME * 6, false), // 36s ]); } catch (error) { console.info(`[${this.constructor.name}]: Implement "blockId" restoration by "txId"`); diff --git a/src/utils/bridge/common/utils.ts b/src/utils/bridge/common/utils.ts index 3cb8cd989..37c9737a9 100644 --- a/src/utils/bridge/common/utils.ts +++ b/src/utils/bridge/common/utils.ts @@ -1,11 +1,10 @@ -import { isEthOperation, isEvmOperation, isSubstrateOperation } from '@sora-substrate/util'; +import { Operation, isEthOperation, isEvmOperation, isSubstrateOperation } from '@sora-substrate/util'; import { api as soraApi } from '@soramitsu/soraneo-wallet-web'; import { ethers } from 'ethers'; -import type { GetTransaction, UpdateTransaction } from '@/utils/bridge/common/types'; -import { isUnsignedTx as isUnsignedEthTx, isOutgoingTx as isOutgoingEthTx } from '@/utils/bridge/eth/utils'; -import { isUnsignedTx as isUnsignedEvmTx, isOutgoingTx as isOutgoingEvmTx } from '@/utils/bridge/evm/utils'; -import { isUnsignedTx as isUnsignedSubTx, isOutgoingTx as isOutgoingSubTx } from '@/utils/bridge/sub/utils'; +import { isUnsignedTx as isUnsignedEthTx } from '@/utils/bridge/eth/utils'; +import { isUnsignedTx as isUnsignedEvmTx } from '@/utils/bridge/evm/utils'; +import { isUnsignedTx as isUnsignedSubTx } from '@/utils/bridge/sub/utils'; import ethersUtil from '@/utils/ethers-util'; import type { ApiPromise } from '@polkadot/api'; @@ -14,13 +13,6 @@ import type { EthHistory } from '@sora-substrate/util/build/bridgeProxy/eth/type import type { EvmHistory } from '@sora-substrate/util/build/bridgeProxy/evm/types'; import type { SubHistory } from '@sora-substrate/util/build/bridgeProxy/sub/types'; -export const getEvmTransactionFee = (tx: ethers.TransactionResponse | ethers.TransactionReceipt) => { - const gasPrice = tx.gasPrice; - const gasAmount = 'gasUsed' in tx ? tx.gasUsed : tx.gasLimit; - - return ethersUtil.calcEvmFee(gasPrice, gasAmount); -}; - export const waitForEvmTransactionMined = async ( tx: ethers.TransactionResponse | null, replaceCallback?: (tx: ethers.TransactionResponse | null) => void @@ -85,11 +77,7 @@ export const getTransactionEvents = async (blockHash: string, transactionHash: s export const isOutgoingTransaction = (transaction: Nullable): boolean => { if (!transaction?.type) return false; - if (isEthOperation(transaction.type)) return isOutgoingEthTx(transaction as EthHistory); - if (isEvmOperation(transaction.type)) return isOutgoingEvmTx(transaction as EvmHistory); - if (isSubstrateOperation(transaction.type)) return isOutgoingSubTx(transaction as SubHistory); - - return false; + return [Operation.EthBridgeOutgoing, Operation.EvmOutgoing, Operation.SubstrateOutgoing].includes(transaction.type); }; export const isUnsignedTx = (transaction: Nullable): boolean => { @@ -101,40 +89,3 @@ export const isUnsignedTx = (transaction: Nullable): boolean return true; }; - -export const onEvmTransactionPending = async ( - id: string, - getTransaction: GetTransaction, - updateTransaction: UpdateTransaction -) => { - const tx = getTransaction(id); - const hash = tx.externalHash; - - if (!hash) throw new Error(`[onEvmTransactionPending] Evm transaction hash is empty`); - - const txResponse = await ethersUtil.getEvmTransaction(hash); - const txReceipt = await waitForEvmTransactionMined(txResponse, (replacedTx) => { - if (replacedTx) { - updateTransaction(id, { - externalHash: replacedTx.hash, - externalNetworkFee: getEvmTransactionFee(replacedTx), - }); - } - }); - - const { fee, blockNumber, blockHash } = txReceipt || {}; - - if (!(fee && blockNumber && blockHash)) { - updateTransaction(id, { externalHash: undefined, externalNetworkFee: undefined }); - throw new Error( - `[onEvmTransactionPending]: Ethereum transaction not found, hash: ${tx.externalHash}. 'externalHash' is reset` - ); - } - - // In EthHistory 'blockHeight' will store evm block number - updateTransaction(id, { - externalNetworkFee: fee.toString(), - externalBlockHeight: blockNumber, - externalBlockId: blockHash, - }); -}; diff --git a/src/utils/bridge/eth/classes/history.ts b/src/utils/bridge/eth/classes/history.ts index 0d4f20e0c..c122fa706 100644 --- a/src/utils/bridge/eth/classes/history.ts +++ b/src/utils/bridge/eth/classes/history.ts @@ -33,8 +33,8 @@ export default class EtherscanHistoryProvider extends EtherscanProvider { } const BRIDGE_INTERFACE = new ethers.Interface([ - ...SmartContracts[SmartContractType.EthBridge][KnownEthBridgeAsset.XOR], // XOR or VAL - ...SmartContracts[SmartContractType.EthBridge][KnownEthBridgeAsset.Other], // Other + ...SmartContracts[SmartContractType.EthBridge][KnownEthBridgeAsset.XOR].abi, // XOR or VAL + ...SmartContracts[SmartContractType.EthBridge][KnownEthBridgeAsset.Other].abi, // Other ]); const { ETH_BRIDGE_STATES } = WALLET_CONSTS; diff --git a/src/utils/bridge/eth/classes/reducers.ts b/src/utils/bridge/eth/classes/reducers.ts index ee7a2f40f..09c6c1e0f 100644 --- a/src/utils/bridge/eth/classes/reducers.ts +++ b/src/utils/bridge/eth/classes/reducers.ts @@ -3,10 +3,16 @@ import first from 'lodash/fp/first'; import { BridgeReducer } from '@/utils/bridge/common/classes'; import type { IBridgeReducerOptions, GetBridgeHistoryInstance, SignExternal } from '@/utils/bridge/common/types'; -import { getTransactionEvents, getEvmTransactionFee, onEvmTransactionPending } from '@/utils/bridge/common/utils'; +import { getTransactionEvents, waitForEvmTransactionMined } from '@/utils/bridge/common/utils'; import { ethBridgeApi } from '@/utils/bridge/eth/api'; import type { EthBridgeHistory } from '@/utils/bridge/eth/classes/history'; -import { getTransaction, waitForApprovedRequest, waitForIncomingRequest } from '@/utils/bridge/eth/utils'; +import { + getTransaction, + getTransactionFee, + waitForApprovedRequest, + waitForIncomingRequest, +} from '@/utils/bridge/eth/utils'; +import ethersUtil from '@/utils/ethers-util'; import type { IBridgeTransaction } from '@sora-substrate/util'; import type { RegisteredAccountAsset } from '@sora-substrate/util/build/assets/types'; @@ -34,7 +40,36 @@ export class EthBridgeReducer extends BridgeReducer { } async onEvmPending(id: string): Promise { - await onEvmTransactionPending(id, this.getTransaction, this.updateTransactionParams); + const tx = this.getTransaction(id); + const hash = tx.externalHash; + + if (!hash) throw new Error(`[${this.constructor.name}]: Ethereum transaction hash is empty`); + + const txResponse = await ethersUtil.getEvmTransaction(hash); + const txReceipt = await waitForEvmTransactionMined(txResponse, (replacedTx) => { + if (replacedTx) { + this.updateTransactionParams(id, { + externalHash: replacedTx.hash, + externalNetworkFee: getTransactionFee(replacedTx), + }); + } + }); + + const { fee, blockNumber, blockHash } = txReceipt || {}; + + if (!(fee && blockNumber && blockHash)) { + this.updateTransactionParams(id, { externalHash: undefined, externalNetworkFee: undefined }); + throw new Error( + `[${this.constructor.name}]: Ethereum transaction not found, hash: ${tx.externalHash}. 'externalHash' is reset` + ); + } + + // In EthHistory 'blockHeight' will store evm block number + this.updateTransactionParams(id, { + externalNetworkFee: fee.toString(), + externalBlockHeight: blockNumber, + externalBlockId: blockHash, + }); } async onEvmSubmitted(id: string, signExternal: SignExternal): Promise { @@ -48,7 +83,7 @@ export class EthBridgeReducer extends BridgeReducer { // update after sign this.updateTransactionParams(id, { externalHash: signedTx.hash, - externalNetworkFee: getEvmTransactionFee(signedTx), + externalNetworkFee: getTransactionFee(signedTx), }); } catch (error: any) { // maybe transaction already completed, try to restore ethereum transaction hash diff --git a/src/utils/bridge/eth/utils.ts b/src/utils/bridge/eth/utils.ts index c6f4d3945..cde815bb4 100644 --- a/src/utils/bridge/eth/utils.ts +++ b/src/utils/bridge/eth/utils.ts @@ -1,6 +1,7 @@ import { Operation, FPNumber } from '@sora-substrate/util'; import { BridgeTxStatus } from '@sora-substrate/util/build/bridgeProxy/consts'; import { EthCurrencyType, EthAssetKind } from '@sora-substrate/util/build/bridgeProxy/eth/consts'; +import { ethers } from 'ethers'; import { SmartContractType, KnownEthBridgeAsset, SmartContracts } from '@/consts/evm'; import { asZeroValue } from '@/utils'; @@ -19,15 +20,13 @@ type EthTxParams = { request?: EthApprovedRequest; }; -export const isOutgoingTx = (tx: EthHistory): boolean => { - return tx.type === Operation.EthBridgeOutgoing; -}; - export const isUnsignedFromPart = (tx: EthHistory): boolean => { - if (isOutgoingTx(tx)) { + if (tx.type === Operation.EthBridgeOutgoing) { return !tx.blockId && !tx.txId; - } else { + } else if (tx.type === Operation.EthBridgeIncoming) { return !tx.externalHash; + } else { + return true; } }; @@ -125,12 +124,14 @@ export const waitForIncomingRequest = async (tx: EthHistory): Promise<{ hash: st export async function getIncomingEvmTransactionData({ asset, value, recipient, getContractAddress }: EthTxParams) { const isNativeEvmToken = ethersUtil.isNativeEvmTokenAddress(asset.externalAddress); + const signer = await ethersUtil.getSigner(); const accountId = ethersUtil.accountAddressToHex(recipient); + const amount = new FPNumber(value, asset.externalDecimals).toCodecString(); const contractAddress = getContractAddress(KnownEthBridgeAsset.Other) as string; - const contractAbi = SmartContracts[SmartContractType.EthBridge][KnownEthBridgeAsset.Other]; - const contract = await ethersUtil.getContract(contractAddress, contractAbi); + const contractAbi = SmartContracts[SmartContractType.EthBridge][KnownEthBridgeAsset.Other].abi; + const contract = new ethers.Contract(contractAddress, contractAbi, signer); const method = isNativeEvmToken ? 'sendEthToSidechain' : 'sendERC20ToSidechain'; const methodArgs = isNativeEvmToken @@ -161,14 +162,14 @@ export async function getOutgoingEvmTransactionData({ }: EthTxParams) { if (!request) throw new Error('request is required!'); + const signer = await ethersUtil.getSigner(); const symbol = asset.symbol as KnownEthBridgeAsset; const isValOrXor = [KnownEthBridgeAsset.XOR, KnownEthBridgeAsset.VAL].includes(symbol); const bridgeAsset: KnownEthBridgeAsset = isValOrXor ? symbol : KnownEthBridgeAsset.Other; - const contractAddress = getContractAddress(bridgeAsset) as string; - const contractAbi = SmartContracts[SmartContractType.EthBridge][bridgeAsset]; - const contract = await ethersUtil.getContract(contractAddress, contractAbi); + const contractAbi = SmartContracts[SmartContractType.EthBridge][bridgeAsset].abi; + const contract = new ethers.Contract(contractAddress, contractAbi, signer); const amount = new FPNumber(value, asset.externalDecimals).toCodecString(); const isEthereumCurrency = request.currencyType === EthCurrencyType.TokenAddress; @@ -291,3 +292,10 @@ export async function getEthNetworkFee( return ethersUtil.calcEvmFee(gasPrice, gasLimitTotal); } + +export const getTransactionFee = (tx: ethers.TransactionResponse | ethers.TransactionReceipt) => { + const gasPrice = tx.gasPrice; + const gasAmount = 'gasUsed' in tx ? tx.gasUsed : tx.gasLimit; + + return ethersUtil.calcEvmFee(gasPrice, gasAmount); +}; diff --git a/src/utils/bridge/evm/utils.ts b/src/utils/bridge/evm/utils.ts index 5dca0845c..8640cd6ee 100644 --- a/src/utils/bridge/evm/utils.ts +++ b/src/utils/bridge/evm/utils.ts @@ -4,15 +4,13 @@ import { evmBridgeApi } from '@/utils/bridge/evm/api'; import type { EvmHistory } from '@sora-substrate/util/build/bridgeProxy/evm/types'; -export const isOutgoingTx = (tx: EvmHistory): boolean => { - return tx.type === Operation.EvmOutgoing; -}; - export const isUnsignedTx = (tx: EvmHistory): boolean => { - if (isOutgoingTx(tx)) { + if (tx.type === Operation.EvmOutgoing) { return !tx.blockId && !tx.txId; + } else if (tx.type === Operation.EvmIncoming) { + return true; } else { - return !tx.externalHash; + return true; } }; diff --git a/src/utils/bridge/sub/classes/adapter.ts b/src/utils/bridge/sub/classes/adapter.ts index 4880e970a..ca668c2b0 100644 --- a/src/utils/bridge/sub/classes/adapter.ts +++ b/src/utils/bridge/sub/classes/adapter.ts @@ -10,10 +10,8 @@ import { determineTransferType } from '@/utils/bridge/sub/utils'; import { AcalaParachainAdapter } from './adapters/parachain/acala'; import { AstarParachainAdapter } from './adapters/parachain/astar'; import { MoonbaseParachainAdapter } from './adapters/parachain/moonbase'; -import { ParachainAdapter } from './adapters/parachain/parachain'; import { SoraParachainAdapter } from './adapters/parachain/sora'; -import { AlphanetRelaychainAdapter } from './adapters/relaychain/alphanet'; -import { RelaychainAdapter } from './adapters/relaychain/relaychain'; +import { RelaychainAdapter } from './adapters/relaychain'; import { LiberlandAdapter } from './adapters/standalone/liberland'; import { SubAdapter } from './adapters/substrate'; @@ -29,8 +27,8 @@ type PathNetworks = { export class SubNetworksConnector { public soraParachain?: SoraParachainAdapter; - public relaychain?: RelaychainAdapter; - public parachain?: ParachainAdapter; + public relaychain?: SubAdapter; + public parachain?: SubAdapter; public standalone?: SubAdapter; public destinationNetwork!: SubNetwork; @@ -97,9 +95,6 @@ export class SubNetworksConnector { protected getAdapter(network: SubNetwork) { if (subBridgeApi.isRelayChain(network)) { - if (network === SubNetworkId.Alphanet) { - return new AlphanetRelaychainAdapter(network); - } return new RelaychainAdapter(network); } if (subBridgeApi.isParachain(network)) { @@ -115,7 +110,6 @@ export class SubNetworksConnector { if (subBridgeApi.isSoraParachain(network)) { return new SoraParachainAdapter(network); } - return new ParachainAdapter(network); } if (subBridgeApi.isStandalone(network)) { if (network === SubNetworkId.Liberland) { @@ -198,38 +192,27 @@ export class SubNetworksConnector { await Promise.all(this.uniqueAdapters.map((c) => c.stop())); } - /** - * Transfer funds from SORA to destination network - */ - public async outgoingTransfer(asset: RegisteredAsset, recipient: string, amount: string | number, historyId: string) { - await subBridgeApi.transfer(asset, recipient, amount, this.destinationNetwork, historyId); - } - /** * Transfer funds from destination network to SORA */ - public async incomingTransfer(asset: RegisteredAsset, recipient: string, amount: string | number, historyId: string) { - if (subBridgeApi.isEvmAccount(this.destinationNetwork)) { - await this.network.transfer(asset, recipient, amount, historyId); - } else { - const { api, accountPair, signer } = this.accountApi; - - if (!accountPair) throw new Error(`[${this.constructor.name}] Account pair is not set.`); - - const historyItem = subBridgeApi.getHistory(historyId as string) ?? { - type: Operation.SubstrateIncoming, - symbol: asset.symbol, - assetAddress: asset.address, - amount: `${amount}`, - externalNetwork: this.destinationNetwork, - externalNetworkType: BridgeNetworkType.Sub, - from: subBridgeApi.address, // "from" is always SORA account address - to: this.accountApi.address, - }; - - const extrinsic = this.network.getTransferExtrinsic(asset, recipient, amount); - // submit extrinsic using SORA api, because current implementation using "subHistory" from SORA api scope - await subBridgeApi.submitApiExtrinsic(api, extrinsic as any, accountPair, signer, historyItem); - } + public async transfer(asset: RegisteredAsset, recipient: string, amount: string | number, historyId?: string) { + const { api, accountPair, signer } = this.accountApi; + + if (!accountPair) throw new Error(`[${this.constructor.name}] Account pair is not set.`); + + const historyItem = subBridgeApi.getHistory(historyId as string) ?? { + type: Operation.SubstrateIncoming, + symbol: asset.symbol, + assetAddress: asset.address, + amount: `${amount}`, + externalNetwork: this.destinationNetwork, + externalNetworkType: BridgeNetworkType.Sub, + from: subBridgeApi.address, // "from" is always SORA account address + to: this.accountApi.address, + }; + + const extrinsic = this.network.getTransferExtrinsic(asset, recipient, amount); + // submit extrinsic using SORA api, because current implementation using "subHistory" from SORA api scope + await subBridgeApi.submitApiExtrinsic(api, extrinsic as any, accountPair, signer, historyItem); } } diff --git a/src/utils/bridge/sub/classes/adapters/parachain/acala.ts b/src/utils/bridge/sub/classes/adapters/parachain/acala.ts index 5f8b7a97d..05ea461ea 100644 --- a/src/utils/bridge/sub/classes/adapters/parachain/acala.ts +++ b/src/utils/bridge/sub/classes/adapters/parachain/acala.ts @@ -3,10 +3,10 @@ import { formatBalance } from '@sora-substrate/util/build/assets'; import { ZeroStringValue } from '@/consts'; -import { ParachainAdapter, type IParachainAssetMetadata } from './parachain'; +import { SubAdapter } from '../substrate'; import type { CodecString } from '@sora-substrate/util'; -import type { Asset, RegisteredAsset } from '@sora-substrate/util/build/assets/types'; +import type { RegisteredAsset } from '@sora-substrate/util/build/assets/types'; enum AcalaPrimitivesCurrencyCurrencyId { Token = 'Token', @@ -29,6 +29,13 @@ type IAcalaCurrencyId = [AcalaPrimitivesCurrencyCurrencyId.Erc20]: string; }; +type IAcalaAssetMetadata = { + id: IAcalaCurrencyId; + symbol: string; + decimals: number; + minimalBalance: string; +}; + function getAcalaCurrencyId(nature: any): Nullable { if (nature.isNativeAssetId) { const value = nature.asNativeAssetId; @@ -43,18 +50,13 @@ function getAcalaCurrencyId(nature: any): Nullable { return null; } -export class AcalaParachainAdapter extends ParachainAdapter { - // overrides "SubAdapter" - public override async connect(): Promise { - await super.connect(); - await this.getAssetsMetadata(); - } +export class AcalaParachainAdapter extends SubAdapter { + protected assets: Record | null = null; - // overrides "ParachainAdapter" - protected override async getAssetsMetadata(): Promise { - if (Array.isArray(this.assets)) return; + protected async getAssetsMetadata(): Promise { + if (this.assets) return; - const assets: IParachainAssetMetadata[] = []; + const assets = {}; const entries = await (this.api.query.assetRegistry as any).assetMetadatas.entries(); for (const [key, option] of entries) { @@ -67,36 +69,32 @@ export class AcalaParachainAdapter extends ParachainAdapter { const decimals = option.value.decimals.toNumber(); const minimalBalance = option.value.minimalBalance.toString(); - assets.push({ id, symbol, decimals, minimalBalance }); + assets[symbol] = { id, symbol, decimals, minimalBalance }; } this.assets = Object.freeze(assets); } - // overrides "ParachainAdapter" - public override getAssetMeta(asset: RegisteredAsset): Nullable> { - if (!Array.isArray(this.assets)) return null; + private getAssetMeta(asset: RegisteredAsset): Nullable { + if (!(asset.symbol && this.assets)) return null; - return this.assets.find( - (item) => JSON.stringify(item.id) === asset.externalAddress || item.symbol === asset.symbol - ); + return this.assets[asset.symbol]; } - // overrides "ParachainAdapter" - public override async getAssetIdByMultilocation(asset: Asset, multilocation: any): Promise { - const v3Multilocation = multilocation; + // overrides SubAdapter + public override async connect(): Promise { + await super.connect(); + await this.getAssetsMetadata(); + } - const result = await (this.api.query.assetRegistry as any).locationToCurrencyIds(v3Multilocation); + protected override async getAssetDeposit(asset: RegisteredAsset): Promise { + const assetMeta = this.getAssetMeta(asset); - let id!: Nullable; + if (!assetMeta) return ZeroStringValue; - if (result.isEmpty) { - id = { [AcalaPrimitivesCurrencyCurrencyId.Token]: asset.symbol }; - } else { - id = getAcalaCurrencyId(result.unwrap()); - } + const minBalance = assetMeta.minimalBalance; - return id ? JSON.stringify(id) : ''; + return minBalance > '1' ? minBalance : ZeroStringValue; } protected override async getAccountAssetBalance( @@ -115,7 +113,7 @@ export class AcalaParachainAdapter extends ParachainAdapter { }, ZeroStringValue); } - // overrides "SubAdapter" + // overrides SubAdapter public override getTransferExtrinsic(asset: RegisteredAsset, recipient: string, amount: number | string) { const assetMeta = this.getAssetMeta(asset); @@ -150,4 +148,11 @@ export class AcalaParachainAdapter extends ParachainAdapter { 'Unlimited' ); } + + public override async getNetworkFee(asset: RegisteredAsset, sender: string, recipient: string): Promise { + /* Throws error until Substrate 5 migration */ + // return await super.getNetworkFee(asset, sender, recipient); + // Hardcoded value for Acala - 0.003 ACA + return '3000000000'; + } } diff --git a/src/utils/bridge/sub/classes/adapters/parachain/astar.ts b/src/utils/bridge/sub/classes/adapters/parachain/astar.ts index 3c4239e38..eab8b563f 100644 --- a/src/utils/bridge/sub/classes/adapters/parachain/astar.ts +++ b/src/utils/bridge/sub/classes/adapters/parachain/astar.ts @@ -1,32 +1,60 @@ import { FPNumber } from '@sora-substrate/util'; +import { formatBalance } from '@sora-substrate/util/build/assets'; import { ZeroStringValue } from '@/consts'; -import { ParachainAdapter } from './parachain'; +import { SubAdapter } from '../substrate'; import type { CodecString } from '@sora-substrate/util'; -import type { Asset, RegisteredAsset } from '@sora-substrate/util/build/assets/types'; +import type { RegisteredAsset } from '@sora-substrate/util/build/assets/types'; + +type IAstarAssetMetadata = { + id: string; + symbol: string; + decimals: number; + minimalBalance: string; +}; + +export class AstarParachainAdapter extends SubAdapter { + protected assets: Record | null = null; + + protected async getAssetsMetadata(): Promise { + if (this.assets) return; + + const assets = {}; + const entries = await (this.api.query.assets as any).metadata.entries(); + + for (const [key, value] of entries) { + const id = key.args[0].toString(); + const symbol = new TextDecoder().decode(value.symbol); // bytes to string + const decimals = value.decimals.toNumber(); + const minimalBalance = value.deposit.toString(); + + assets[symbol] = { id, symbol, decimals, minimalBalance }; + } + + this.assets = Object.freeze(assets); + } + + private getAssetMeta(asset: RegisteredAsset): Nullable { + if (!(asset.symbol && this.assets)) return null; + + return this.assets[asset.symbol]; + } -export class AstarParachainAdapter extends ParachainAdapter { - // overrides "SubAdapter" public override async connect(): Promise { await super.connect(); await this.getAssetsMetadata(); } - // overrides "ParachainAdapter" - public override async getAssetIdByMultilocation(asset: Asset, multilocation: any): Promise { - const versionedMultilocation = { - V3: multilocation, - }; - - const result = await (this.api.query.xcAssetConfig as any).assetLocationToId(versionedMultilocation); + protected override async getAssetDeposit(asset: RegisteredAsset): Promise { + const assetMeta = this.getAssetMeta(asset); - if (result.isEmpty) return ''; + if (!assetMeta) return ZeroStringValue; - const id = result.unwrap().toString(); + const minBalance = assetMeta.minimalBalance; - return id; + return minBalance > '1' ? minBalance : ZeroStringValue; } protected override async getAccountAssetBalance( @@ -40,12 +68,6 @@ export class AstarParachainAdapter extends ParachainAdapter { return await this.assetsAccountRequest(accountAddress, assetMeta.id); } - public override getTransferExtrinsic(asset: RegisteredAsset, recipient: string, amount: number | string) { - return asset.symbol === this.chainSymbol - ? this.getNativeTransferExtrinsic(asset, recipient, amount) - : this.getAssetTransferExtrinsic(asset, recipient, amount); - } - /** * Transfer native token (ASTR) */ @@ -135,4 +157,17 @@ export class AstarParachainAdapter extends ParachainAdapter { 'Unlimited' ); } + + public override getTransferExtrinsic(asset: RegisteredAsset, recipient: string, amount: number | string) { + return asset.symbol === this.chainSymbol + ? this.getNativeTransferExtrinsic(asset, recipient, amount) + : this.getAssetTransferExtrinsic(asset, recipient, amount); + } + + public async getNetworkFee(asset: RegisteredAsset, sender: string, recipient: string): Promise { + /* Throws error until Substrate 5 migration */ + // return await super.getNetworkFee(asset, sender, recipient); + // Hardcoded value for Astar - 0.057 ASTR + return '57000000000000000'; + } } diff --git a/src/utils/bridge/sub/classes/adapters/parachain/moonbase.ts b/src/utils/bridge/sub/classes/adapters/parachain/moonbase.ts index 76dfeebe6..3bc0669c7 100644 --- a/src/utils/bridge/sub/classes/adapters/parachain/moonbase.ts +++ b/src/utils/bridge/sub/classes/adapters/parachain/moonbase.ts @@ -1,147 +1,13 @@ -import { FPNumber, TransactionStatus } from '@sora-substrate/util'; -import { SubNetworkId } from '@sora-substrate/util/build/bridgeProxy/sub/consts'; -import BN from 'bignumber.js'; - -import xTokensAbi from '@/abi/ethereum/other/moonbeam/xTokens.json'; -import { ZeroStringValue } from '@/consts'; -import { SUB_NETWORKS } from '@/consts/sub'; -import { delay } from '@/utils'; -import { getEvmTransactionFee, onEvmTransactionPending } from '@/utils/bridge/common/utils'; -import { getTransaction, updateTransaction } from '@/utils/bridge/sub/utils'; -import ethersUtil from '@/utils/ethers-util'; - -import { ParachainAdapter } from './parachain'; - -import type { CodecString } from '@sora-substrate/util'; -import type { Asset, RegisteredAsset } from '@sora-substrate/util/build/assets/types'; -import type { ethers } from 'ethers'; - -const MOONBASE_DATA = SUB_NETWORKS[SubNetworkId.AlphanetMoonbase]; - -export class MoonbaseParachainAdapter extends ParachainAdapter { - protected nativeAssetContractAddress = '0x0000000000000000000000000000000000000802'; - protected xTokensContractAddress = '0x0000000000000000000000000000000000000804'; - - // overrides "WithConnectionApi" - override get chainSymbol(): string | undefined { - return MOONBASE_DATA?.nativeCurrency?.symbol; - } - - // overrides "WithConnectionApi" - public override formatAddress(address: string, _withPrefix = true): string { - // return evm address without changes - return address; - } - - // overrides "SubAdapter" - public override async connect(): Promise { - await super.connect(); - await this.getAssetsMetadata(); - } - - // overrides "SubAdapter" - protected override async getAccountAssetBalance( - accountAddress: string, - asset: RegisteredAsset - ): Promise { - return await this.assetsAccountRequest(accountAddress, asset.externalAddress); - } - - // Assets has not minimal deposit on Moonbase - // overrides "ParachainAdapter" - protected override async getAssetDeposit(asset: RegisteredAsset): Promise { - return ZeroStringValue; - } - - // overrides "ParachainAdapter" - public override async getAssetIdByMultilocation(asset: Asset, multilocation: any): Promise { - const assetType = { - XCM: multilocation, - }; - - const result = await (this.api.query.assetManager as any).assetTypeId(assetType); - - if (result.isEmpty) return ''; - - const id = result.unwrap().toString(); - - return id; - } - - // overrides "ParachainAdapter" - public override assetIdToEvmContractAddress(id: string): string { - const base = new BN(id).toString(16); - const padded = base.padStart(40, 'f'); - return `0x${padded}`; - } - - /** - * Convert parachain id to xcm junction - */ - protected toParachainAddress(id: number | undefined): string { - const selector = '0x00'; // Parachain selector - const address = Number(id ?? 0) - .toString(16) - .padStart(8, '0'); // bytes4 - - return selector + address; - } - - /** - * Convert substrate account address to xcm junction - */ - protected toAccountId32(address: string): string { - const selector = '0x01'; // AccountKey32 selector - const publicKey = this.getPublicKeyByAddress(address); // AccountId32 address in hex - const networkOption = '00'; // Network(Option) Null - - return selector + publicKey + networkOption; - } - - public override async transfer( - asset: RegisteredAsset, - recipient: string, - amount: string | number, - historyId: string - ) { - const currencyAddress = - asset.symbol === this.chainSymbol - ? this.nativeAssetContractAddress - : this.assetIdToEvmContractAddress(asset.externalAddress); - - const value = new FPNumber(amount, asset.externalDecimals).toCodecString(); - const weight = 5_000_000_000; // max weight, taken from successful xcm message on SORA parachain - - const parents = 1; - const parachainJunction = this.toParachainAddress(this.getSoraParachainId()); - const accountJunction = this.toAccountId32(recipient); - const interior = [parachainJunction, accountJunction]; // interior = X2 (the array has a length of 2) - const destination = [parents, interior]; - - const xTokens = await ethersUtil.getContract(this.xTokensContractAddress, xTokensAbi); - - const signedTx: ethers.TransactionResponse = await xTokens.transfer(currencyAddress, value, destination, weight); - - updateTransaction(historyId, { - externalHash: signedTx.hash, - externalNetworkFee: getEvmTransactionFee(signedTx), - status: TransactionStatus.InBlock, - }); - - // wait a little to update tx in storage - await delay(); - - // run non blocking promise to update tx data - onEvmTransactionPending(historyId, getTransaction, updateTransaction) - .then(() => { - updateTransaction(historyId, { - status: TransactionStatus.Finalized, - }); - }) - .catch(() => { - updateTransaction(historyId, { - status: TransactionStatus.Error, - }); - }); - } +import { u8aToHex } from '@polkadot/util'; +import { addressToEvm } from '@polkadot/util-crypto'; + +import { SubAdapter } from '../substrate'; + +export class MoonbaseParachainAdapter extends SubAdapter { + // overrides SubAdapter method + public formatAddress = (address?: string): string => { + if (!address) return ''; + // [TODO] research how to get evm address as on moonbase + return u8aToHex(addressToEvm(address)); + }; } diff --git a/src/utils/bridge/sub/classes/adapters/parachain/parachain.ts b/src/utils/bridge/sub/classes/adapters/parachain/parachain.ts deleted file mode 100644 index b6f7f7cfd..000000000 --- a/src/utils/bridge/sub/classes/adapters/parachain/parachain.ts +++ /dev/null @@ -1,85 +0,0 @@ -import { SubNetworkId } from '@sora-substrate/util/build/bridgeProxy/sub/consts'; - -import { ZeroStringValue } from '@/consts'; - -import { SubAdapter } from '../substrate'; - -import type { CodecString } from '@sora-substrate/util'; -import type { Asset, RegisteredAsset } from '@sora-substrate/util/build/assets/types'; - -export type IParachainAssetMetadata = { - id: AssetId; - symbol: string; - decimals: number; - minimalBalance?: string; -}; - -export class ParachainAdapter extends SubAdapter { - protected assets: readonly IParachainAssetMetadata[] | null = null; - - protected async getAssetsMetadata(): Promise { - if (Array.isArray(this.assets)) return; - - const assets: IParachainAssetMetadata[] = []; - const entries = await (this.api.query.assets as any).metadata.entries(); - - for (const [key, value] of entries) { - const id = key.args[0].toString(); - const symbol = new TextDecoder().decode(value.symbol); // bytes to string - const decimals = value.decimals.toNumber(); - - assets.push({ id, symbol, decimals }); - } - - this.assets = Object.freeze(assets); - } - - public getAssetMeta(asset: RegisteredAsset): Nullable> { - if (!Array.isArray(this.assets)) return null; - - return this.assets.find((item) => item.id === asset.externalAddress || item.symbol === asset.symbol); - } - - /** - * Get asset external address by multilocation (for "registeredAsset.externalAddress" struct)) - */ - public async getAssetIdByMultilocation(asset: Asset, multilocation: any): Promise { - throw new Error(`[${this.constructor.name}] "getAssetIdByMultilocation" method is not implemented`); - } - - /** - * Convert substrate asset id to evm token contract address - */ - public assetIdToEvmContractAddress(id: string): string { - throw new Error(`[${this.constructor.name}] "assetIdToEvmContractAddress" method is not implemented`); - } - - // overrides SubAdapter - protected override async getAssetDeposit(asset: RegisteredAsset): Promise { - const assetMeta = this.getAssetMeta(asset); - - if (!assetMeta) return ZeroStringValue; - - const { minimalBalance, id } = assetMeta; - - if (minimalBalance) return minimalBalance; - - return await this.assetMinBalanceRequest(id as string); - } - - public override async getNetworkFee(asset: RegisteredAsset, sender: string, recipient: string): Promise { - /* Throws error until Substrate 5 migration */ - // return await super.getNetworkFee(asset, sender, recipient); - // Hardcoded values - switch (this.subNetwork) { - case SubNetworkId.PolkadotAcala: - return '3000000000'; - case SubNetworkId.PolkadotAstar: - return '57000000000000000'; - case SubNetworkId.AlphanetMoonbase: - return '40000000000000'; - default: - return '0'; - } - } -} diff --git a/src/utils/bridge/sub/classes/adapters/relaychain/relaychain.ts b/src/utils/bridge/sub/classes/adapters/relaychain.ts similarity index 94% rename from src/utils/bridge/sub/classes/adapters/relaychain/relaychain.ts rename to src/utils/bridge/sub/classes/adapters/relaychain.ts index dc226789e..5adc2fcca 100644 --- a/src/utils/bridge/sub/classes/adapters/relaychain/relaychain.ts +++ b/src/utils/bridge/sub/classes/adapters/relaychain.ts @@ -1,7 +1,7 @@ import { FPNumber } from '@sora-substrate/util'; import { SubNetworkId } from '@sora-substrate/util/build/bridgeProxy/sub/consts'; -import { SubAdapter } from '../substrate'; +import { SubAdapter } from './substrate'; import type { CodecString } from '@sora-substrate/util'; import type { RegisteredAsset } from '@sora-substrate/util/build/assets/types'; @@ -71,11 +71,11 @@ export class RelaychainAdapter extends SubAdapter { case SubNetworkId.Rococo: return toCodec(0.000125); case SubNetworkId.Alphanet: - return toCodec(0.019 + 0.037); + return toCodec(0.019); case SubNetworkId.Kusama: return toCodec(0.002); case SubNetworkId.Polkadot: - return toCodec(0.019 + 0.037); + return toCodec(0.059); default: return '0'; } diff --git a/src/utils/bridge/sub/classes/adapters/relaychain/alphanet.ts b/src/utils/bridge/sub/classes/adapters/relaychain/alphanet.ts deleted file mode 100644 index 0c16e220c..000000000 --- a/src/utils/bridge/sub/classes/adapters/relaychain/alphanet.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { SubNetworkId } from '@sora-substrate/util/build/bridgeProxy/sub/consts'; - -import { SUB_NETWORKS } from '@/consts/sub'; - -import { RelaychainAdapter } from './relaychain'; - -const ALPHANET_DATA = SUB_NETWORKS[SubNetworkId.Alphanet]; - -export class AlphanetRelaychainAdapter extends RelaychainAdapter { - // overrides "WithConnectionApi" - override get chainSymbol(): string | undefined { - return ALPHANET_DATA?.nativeCurrency?.symbol; - } - - // overrides "WithConnectionApi" - override get chainDecimals(): number | undefined { - return ALPHANET_DATA?.nativeCurrency?.decimals; - } - - // overrides "WithConnectionApi" - override get chainSS58(): number | undefined { - return 42; // (Substrate, 42) - } -} diff --git a/src/utils/bridge/sub/classes/adapters/standalone/liberland.ts b/src/utils/bridge/sub/classes/adapters/standalone/liberland.ts index db4bbdea7..dae7d0931 100644 --- a/src/utils/bridge/sub/classes/adapters/standalone/liberland.ts +++ b/src/utils/bridge/sub/classes/adapters/standalone/liberland.ts @@ -9,9 +9,7 @@ import type { RegisteredAsset } from '@sora-substrate/util/build/assets/types'; export class LiberlandAdapter extends SubAdapter { protected override async getAssetDeposit(asset: RegisteredAsset): Promise { - const assetId = Number(asset.externalAddress); - - return await this.assetMinBalanceRequest(assetId); + return await this.assetsAssetMinBalanceRequest(Number(asset.externalAddress)); } protected override async getAccountAssetBalance( diff --git a/src/utils/bridge/sub/classes/adapters/substrate.ts b/src/utils/bridge/sub/classes/adapters/substrate.ts index 4b7ddf6e9..68856c606 100644 --- a/src/utils/bridge/sub/classes/adapters/substrate.ts +++ b/src/utils/bridge/sub/classes/adapters/substrate.ts @@ -135,10 +135,6 @@ class BaseSubAdapter extends WithConnectionApi { public getTransferExtrinsic(asset: RegisteredAsset, recipient: string, amount: string | number) { throw new Error(`[${this.constructor.name}] "getTransferExtrinsic" method is not implemented`); } - - public async transfer(asset: RegisteredAsset, recipient: string, amount: string | number, historyId: string) { - throw new Error(`[${this.constructor.name}] "transfer" method is not implemented`); - } } export class SubAdapter extends BaseSubAdapter { @@ -158,7 +154,7 @@ export class SubAdapter extends BaseSubAdapter { }, ZeroStringValue); } - protected async assetMinBalanceRequest(assetId: number | string): Promise { + protected async assetsAssetMinBalanceRequest(assetId: number | string): Promise { return await this.withConnection(async () => { const result = await (this.api.query.assets as any).asset(assetId); diff --git a/src/utils/bridge/sub/classes/history.ts b/src/utils/bridge/sub/classes/history.ts index 20da783af..36a498a0a 100644 --- a/src/utils/bridge/sub/classes/history.ts +++ b/src/utils/bridge/sub/classes/history.ts @@ -12,14 +12,10 @@ import { getDepositedBalance, getMessageAcceptedNonces, getMessageDispatchedNonces, - getParachainSystemMessageHash, isMessageDispatchedNonces, getReceivedAmount, - isParaInclusion, + isEvent, isTransactionFeePaid, - isBridgeProxyHash, - isMessageAccepted, - isQueueMessage, } from '@/utils/bridge/sub/utils'; import type { ApiPromise } from '@polkadot/api'; @@ -49,7 +45,9 @@ const getTxEvents = (blockEvents: any[], txIndex: number) => { const findTxInBlock = async (blockHash: string, soraHash: string) => { const blockEvents = await api.system.getBlockEvents(blockHash); - const event = blockEvents.find((e) => isBridgeProxyHash(e, soraHash)); + const event = blockEvents.find( + (e) => isEvent(e, 'bridgeProxy', 'RequestStatusUpdate') && e.event.data?.[0]?.toString() === soraHash + ); if (!event) throw new Error('Unable to find "bridgeProxy.RequestStatusUpdate" event'); @@ -243,7 +241,7 @@ class SubBridgeHistory extends SubNetworksConnector { const soraFeeEvent = events.find((e) => isTransactionFeePaid(e)); history.soraNetworkFee = soraFeeEvent.event.data[1].toString(); // sended from SORA nonces - const [soraBatchNonce, soraMessageNonce] = getMessageAcceptedNonces(events); + const [soraBatchNonce, soraMessageNonce] = getMessageAcceptedNonces(events, this.soraApi); // api for Standalone network or SORA parachain const networkApi = this.getIntermediateApi(history); const networkBlockId = history.externalBlockId as string; @@ -252,7 +250,7 @@ class SubBridgeHistory extends SubNetworksConnector { const networkEventsReversed = [...networkEvents].reverse(); // Network received nonces const messageDispatchedIndex = networkEventsReversed.findIndex((e) => - isMessageDispatchedNonces(soraBatchNonce, soraMessageNonce, e) + isMessageDispatchedNonces(soraBatchNonce, soraMessageNonce, e, networkApi) ); if (messageDispatchedIndex === -1) { @@ -271,15 +269,19 @@ class SubBridgeHistory extends SubNetworksConnector { // SORA Parachain extrinsic events for next search const parachainExtrinsicEvents = networkEventsReversed.slice(messageDispatchedIndex); - // sended from SORA Parachain message hash (1) - const messageHash = getParachainSystemMessageHash(parachainExtrinsicEvents); + // sended from SORA Parachain to Relaychain message hash (1) + const messageToRelaychain = parachainExtrinsicEvents.find((e) => + isEvent(e, 'parachainSystem', 'UpwardMessageSent') + ); + // sended from SORA Parachain to Parachain message hash (2) + const messageToParachain = parachainExtrinsicEvents.find((e) => isEvent(e, 'xcmpQueue', 'XcmpMessageSent')); - if (!messageHash) { + if (!messageToRelaychain && !messageToParachain) { return await this.processOutgoingToSoraParachain(history, asset, parachainExtrinsicEvents); } - const isRelaychain = subBridgeApi.isRelayChain(externalNetwork); - const isParachain = subBridgeApi.isParachain(externalNetwork); + const isRelaychain = subBridgeApi.isRelayChain(externalNetwork) && messageToRelaychain; + const isParachain = subBridgeApi.isParachain(externalNetwork) && messageToParachain; if (!isRelaychain && !isParachain) { console.info(`[${history.id}] not "${externalNetwork}" transaction, skip;`); @@ -288,6 +290,7 @@ class SubBridgeHistory extends SubNetworksConnector { this.updateSoraParachainBlockData(history); + const messageHash = (messageToRelaychain ?? messageToParachain).event.data.messageHash.toString(); const relayChainBlockNumber = await subBridgeApi.soraParachainApi.getRelayChainBlockNumber( history.parachainBlockId as string, soraParachainApi @@ -331,7 +334,7 @@ class SubBridgeHistory extends SubNetworksConnector { const [receivedAmount, externalEventIndex] = getDepositedBalance( extrinsicEvents, history.to as string, - soraParachain + soraParachainApi ); // balances.Deposit event index history.externalEventIndex = externalEventIndex; @@ -364,15 +367,23 @@ class SubBridgeHistory extends SubNetworksConnector { txEvents: any[]; blockEvents: any[]; }): Promise> { + const { soraApi } = this; // Token is minted to account event - const [_, eventIndex] = getDepositedBalance(blockEvents, history.from as string, subBridgeApi); + const [_, eventIndex] = getDepositedBalance(blockEvents, history.from as string, this.soraApi); history.payload.eventIndex = eventIndex; // find SORA hash event index - const requestStatusUpdateEventIndex = txEvents.findIndex((e) => isBridgeProxyHash(e, history.id as string)); + const requestStatusUpdateEventIndex = txEvents.findIndex((e) => { + if (!isEvent(e, 'bridgeProxy', 'RequestStatusUpdate')) return false; + + const hash = e.event.data[0].toString(); + + return hash === history.id; + }); // Received on SORA nonces const [soraBatchNonce, soraMessageNonce] = getMessageDispatchedNonces( - txEvents.slice(requestStatusUpdateEventIndex) + txEvents.slice(requestStatusUpdateEventIndex), + soraApi ); // api for Standalone network or SORA parachain const networkApi = this.getIntermediateApi(history); @@ -381,9 +392,9 @@ class SubBridgeHistory extends SubNetworksConnector { const networkEvents = await api.system.getBlockEvents(networkBlockId, networkApi); // Network message sended to SORA const messageToSoraEvent = networkEvents.find((e) => { - if (!isMessageAccepted(e)) return false; + if (!isEvent(e, 'substrateBridgeOutboundChannel', 'MessageAccepted')) return false; - const [networkBatchNonce, networkMessageNonce] = getMessageAcceptedNonces([e]); + const [networkBatchNonce, networkMessageNonce] = getMessageAcceptedNonces([e], networkApi); return networkBatchNonce === soraBatchNonce && networkMessageNonce === soraMessageNonce; }); @@ -417,7 +428,7 @@ class SubBridgeHistory extends SubNetworksConnector { if (!soraParachainApi) throw new Error('SORA Parachain Api is not exists'); // If transfer received from Parachain, extrinsic events should have xcmpQueue.Success event - const messageEvent = networkExtrinsicEvents.find((e) => isQueueMessage(e)); + const messageEvent = networkExtrinsicEvents.find((e) => isEvent(e, 'xcmpQueue', 'Success')); const externalNetwork = history.externalNetwork as SubNetwork; const isRelayChain = subBridgeApi.isRelayChain(externalNetwork) && !messageEvent; const isParachain = @@ -436,7 +447,7 @@ class SubBridgeHistory extends SubNetworksConnector { ); if (isParachain) { - const messageHash = messageEvent.event.data[0].toString(); + const messageHash = messageEvent.event.data.messageHash.toString(); // Parachain block, found through relaychain validation data const parachainBlockId = await this.findParachainBlockIdOnRelaychain(history, relayChainBlockNumber, false); @@ -455,7 +466,7 @@ class SubBridgeHistory extends SubNetworksConnector { // relay chain should have send message in this blocks range const startSearch = relayChainBlockNumber; - const endSearch = startSearch - 10; + const endSearch = startSearch - 6; for (let relaychainBlockHeight = startSearch; relaychainBlockHeight >= endSearch; relaychainBlockHeight--) { const blockId = await api.system.getBlockHash(relaychainBlockHeight, this.externalApi); @@ -517,7 +528,7 @@ class SubBridgeHistory extends SubNetworksConnector { // relay chain should have send validation data in this blocks range const startSearch = relayChainBlockNumber; - const blocksRange = 10; + const blocksRange = 3; const endSearch = isOutgoing ? startSearch + blocksRange : startSearch - blocksRange; for (let relaychainBlockHeight = startSearch; relaychainBlockHeight !== endSearch; ) { @@ -525,14 +536,11 @@ class SubBridgeHistory extends SubNetworksConnector { const events = await api.system.getBlockEvents(blockId, relaychainApi); for (const e of events) { - if (!isParaInclusion(e)) continue; + if (!isEvent(e, 'paraInclusion', 'CandidateIncluded')) continue; const { descriptor } = e.event.data[0]; - const descriptorParaId = descriptor.paraId.toNumber(); - const paraId = network.getParachainId(); - - if (descriptorParaId !== paraId) continue; + if (descriptor.paraId.toNumber() !== network.getParachainId()) continue; history.relaychainBlockHeight = relaychainBlockHeight; history.relaychainBlockId = blockId; @@ -564,10 +572,10 @@ class SubBridgeHistory extends SubNetworksConnector { const extrinsicEvents = parachainBlockEvents.filter( ({ phase }) => phase.isApplyExtrinsic && phase.asApplyExtrinsic.toNumber() === extrinsicIndex ); + const messageSentEvent = extrinsicEvents.find((e) => isEvent(e, 'xcmpQueue', 'XcmpMessageSent')); - const messageSentHash = getParachainSystemMessageHash(extrinsicEvents); - - if (messageSentHash !== messageHash) continue; + if (!messageSentEvent) continue; + if (messageSentEvent.event.data[0].toString() !== messageHash) continue; const parachainBlockHeight = await api.system.getBlockNumber(parachainBlockId, externalApi); const signer = extrinsic.signer.toString(); @@ -596,17 +604,15 @@ class SubBridgeHistory extends SubNetworksConnector { endSearch: number ) { for (let blockHeight = startSearch; blockHeight <= endSearch; blockHeight++) { - let isReliableMessage = false; - try { const blockId = await api.system.getBlockHash(blockHeight, this.externalApi); const blockEvents = await api.system.getBlockEvents(blockId, this.externalApi); const messageEventIndex = blockEvents.findIndex((e) => { - if (isQueueMessage(e)) { - isReliableMessage = e.event.data[0].toString() === messageHash; + if (isEvent(e, 'messageQueue', 'Processed') || isEvent(e, 'xcmpQueue', 'Success')) { + const messageHashMatches = e.event.data[0].toString() === messageHash; - return true; + return messageHashMatches; } return false; }); @@ -620,7 +626,7 @@ class SubBridgeHistory extends SubNetworksConnector { const [receivedAmount, externalEventIndex] = getDepositedBalance( blockEvents.slice(0, messageEventIndex), history.to, - this.network + this.externalApi ); // Deposit event index @@ -637,11 +643,7 @@ class SubBridgeHistory extends SubNetworksConnector { return history; } catch { - if (isReliableMessage) { - break; - } else { - continue; - } + continue; } } diff --git a/src/utils/bridge/sub/classes/reducers.ts b/src/utils/bridge/sub/classes/reducers.ts index 031d09024..5aa0958bd 100644 --- a/src/utils/bridge/sub/classes/reducers.ts +++ b/src/utils/bridge/sub/classes/reducers.ts @@ -21,9 +21,8 @@ import { determineTransferType, getReceivedAmount, getParachainSystemMessageHash, - isXcmPalletAttempted, + isEvent, isTransactionFeePaid, - isQueueMessage, } from '@/utils/bridge/sub/utils'; import type { ApiRx } from '@polkadot/api'; @@ -106,11 +105,6 @@ export class SubBridgeReducer extends BridgeReducer { // update history data this.updateTransactionPayload(id, { startBlock }); } - - async waitForTxBlockAndStatus(id: string): Promise { - await this.waitForTransactionStatus(id); - await this.waitForTransactionBlockId(id); - } } export class SubBridgeIncomingReducer extends SubBridgeReducer { @@ -162,7 +156,7 @@ export class SubBridgeIncomingReducer extends SubBridgeReducer { // open connections await this.connector.start(); // sign transaction (from is sora account) - await this.connector.incomingTransfer(asset, tx.from as string, tx.amount as string, id); + await this.connector.transfer(asset, tx.from as string, tx.amount as string, id); // save start block when tx was signed await this.saveStartBlock(id); } @@ -189,7 +183,6 @@ export class SubBridgeIncomingReducer extends SubBridgeReducer { private async updateTxExternalData(id: string): Promise { const tx = this.getTransaction(id); - const adapter = this.connector.network; await adapter.connect(); @@ -207,7 +200,7 @@ export class SubBridgeIncomingReducer extends SubBridgeReducer { } if (this.transferType === SubTransferType.Relaychain) { - const xcmEvent = transactionEvents.find((e) => isXcmPalletAttempted(e)); + const xcmEvent = transactionEvents.find((e) => isEvent(e, 'xcmPallet', 'Attempted')); if (!xcmEvent?.event?.data?.[0]?.isComplete) { throw new Error(`[${this.constructor.name}]: Transaction is not completed`); @@ -216,10 +209,8 @@ export class SubBridgeIncomingReducer extends SubBridgeReducer { } private async updateTxIncomingData(id: string): Promise { - await this.waitForTxBlockAndStatus(id); - - if (subBridgeApi.isEvmAccount(this.getTransaction(id).externalNetwork as SubNetwork)) return; - + await this.waitForTransactionStatus(id); + await this.waitForTransactionBlockId(id); await this.updateTxSigningData(id); await this.updateTxExternalData(id); } @@ -240,8 +231,8 @@ export class SubBridgeIncomingReducer extends SubBridgeReducer { const isFirstStep = [SubTransferType.SoraParachain, SubTransferType.Standalone].includes(this.transferType); const sended = new FPNumber(tx.amount as string, this.asset.externalDecimals).toCodecString(); - const sender = tx.to as string; - const recipient = tx.from as string; + const from = tx.from as string; + const to = tx.to as string; let subscription!: Subscription; let messageNonce!: number; @@ -271,7 +262,7 @@ export class SubBridgeIncomingReducer extends SubBridgeReducer { if (!isStandalone) { assetSendEventIndex = events.findIndex((e) => - isAssetAddedToChannel(e, this.asset, recipient, sended, adapter) + isAssetAddedToChannel(e, this.asset, to, sended, adapter.api) ); if (assetSendEventIndex !== -1) { @@ -282,7 +273,7 @@ export class SubBridgeIncomingReducer extends SubBridgeReducer { } } else { assetSendEventIndex = events.findIndex((e) => - isSoraBridgeAppBurned(e, this.asset, sender, recipient, sended, adapter) + isSoraBridgeAppBurned(e, this.asset, from, to, sended, adapter.api) ); if (assetSendEventIndex !== -1) { @@ -293,7 +284,7 @@ export class SubBridgeIncomingReducer extends SubBridgeReducer { if (assetSendEventIndex === -1) return; blockNumber = blockHeight; - [batchNonce, messageNonce] = getMessageAcceptedNonces(events.slice(assetSendEventIndex)); + [batchNonce, messageNonce] = getMessageAcceptedNonces(events.slice(assetSendEventIndex), adapter.api); resolve(); } catch (error) { @@ -350,16 +341,16 @@ export class SubBridgeIncomingReducer extends SubBridgeReducer { try { const events = [...eventsVec.toArray()].reverse(); const substrateDispatchEventIndex = events.findIndex((e) => - isMessageDispatchedNonces(tx.payload.batchNonce, tx.payload.messageNonce, e) + isMessageDispatchedNonces(tx.payload.batchNonce, tx.payload.messageNonce, e, subBridgeApi.api) ); if (substrateDispatchEventIndex === -1) return; const foundedEvents = events.slice(substrateDispatchEventIndex); - soraHash = getBridgeProxyHash(foundedEvents); + soraHash = getBridgeProxyHash(foundedEvents, subBridgeApi.api); - [amount, eventIndex] = getDepositedBalance(foundedEvents, tx.from as string, subBridgeApi); + [amount, eventIndex] = getDepositedBalance(foundedEvents, tx.to as string, subBridgeApi.api); resolve(); } catch (error) { @@ -378,9 +369,9 @@ export class SubBridgeIncomingReducer extends SubBridgeReducer { } private async waitSoraBlockByHash(id: string): Promise { - const { hash, from, externalNetwork } = this.getTransaction(id); + const { hash, to, externalNetwork } = this.getTransaction(id); - if (!(hash && from && externalNetwork)) { + if (!(hash && to && externalNetwork)) { throw new Error(`[${this.constructor.name}] Lost transaction params`); } @@ -389,7 +380,7 @@ export class SubBridgeIncomingReducer extends SubBridgeReducer { try { await new Promise((resolve) => { - subscription = subBridgeApi.subscribeOnTransactionDetails(from, externalNetwork, hash).subscribe((data) => { + subscription = subBridgeApi.subscribeOnTransactionDetails(to, externalNetwork, hash).subscribe((data) => { if (data?.endBlock) { soraBlockNumber = data.endBlock; resolve(); @@ -426,7 +417,8 @@ export class SubBridgeOutgoingReducer extends SubBridgeReducer { this.updateTransactionParams(id, { transactionState: BridgeTxStatus.Pending }); await this.checkTxId(id); - await this.waitForTxBlockAndStatus(id); + await this.waitForTransactionStatus(id); + await this.waitForTransactionBlockId(id); await this.waitForSendingExecution(id); await this.waitForIntermediateExecution(id); @@ -474,7 +466,7 @@ export class SubBridgeOutgoingReducer extends SubBridgeReducer { // open connections await this.connector.start(); // sign transaction - await this.connector.outgoingTransfer(asset, tx.to as string, tx.amount as string, id); + await subBridgeApi.transfer(asset, tx.to as string, tx.amount as string, tx.externalNetwork as SubNetwork, id); // save start block when tx was signed await this.saveStartBlock(id); } @@ -488,10 +480,10 @@ export class SubBridgeOutgoingReducer extends SubBridgeReducer { const transactionHash = tx.txId as string; const transactionEvents = await getTransactionEvents(blockHash, transactionHash, subBridgeApi.api); - const hash = getBridgeProxyHash(transactionEvents); + const hash = getBridgeProxyHash(transactionEvents, subBridgeApi.api); this.updateTransactionParams(id, { hash }); - const [batchNonce, messageNonce] = getMessageAcceptedNonces(transactionEvents); + const [batchNonce, messageNonce] = getMessageAcceptedNonces(transactionEvents, subBridgeApi.api); this.updateTransactionPayload(id, { batchNonce, messageNonce }); } @@ -529,7 +521,7 @@ export class SubBridgeOutgoingReducer extends SubBridgeReducer { try { const events = [...eventsVec.toArray()].reverse(); const substrateDispatchEventIndex = events.findIndex((e) => - isMessageDispatchedNonces(tx.payload.batchNonce, tx.payload.messageNonce, e) + isMessageDispatchedNonces(tx.payload.batchNonce, tx.payload.messageNonce, e, adapter.api) ); if (substrateDispatchEventIndex === -1) return; @@ -542,11 +534,11 @@ export class SubBridgeOutgoingReducer extends SubBridgeReducer { [amountReceived] = getDepositedBalance( events.slice(substrateDispatchEventIndex), tx.to as string, - adapter + adapter.api ); } } else { - messageHash = getParachainSystemMessageHash(events.slice(substrateDispatchEventIndex)); + messageHash = getParachainSystemMessageHash(events.slice(substrateDispatchEventIndex), adapter.api); } resolve(); @@ -609,16 +601,11 @@ export class SubBridgeOutgoingReducer extends SubBridgeReducer { subscription = combineLatest([eventsObservable, blockNumberObservable]).subscribe( ([eventsVec, blockHeight]) => { - // when received message is equal to sended - let isReliableMessage = false; - try { const events = eventsVec.toArray(); const messageQueueProcessedEventIndex = events.findIndex((e) => { - if (isQueueMessage(e)) { - isReliableMessage = e.event.data[0].toString() === messageHash; - - return true; + if (isEvent(e, 'messageQueue', 'Processed') || isEvent(e, 'xcmpQueue', 'Success')) { + return e.event.data[0].toString() === messageHash; } return false; }); @@ -626,19 +613,16 @@ export class SubBridgeOutgoingReducer extends SubBridgeReducer { if (messageQueueProcessedEventIndex === -1) return; blockNumber = blockHeight; - // throws error, is deposit not found + [amount, externalEventIndex] = getDepositedBalance( events.slice(0, messageQueueProcessedEventIndex), tx.to as string, - adapter + adapter.api ); resolve(); } catch (error) { - // The message is reliable, but the deposit was not found - if (isReliableMessage) { - reject(error); - } + reject(error); } } ); diff --git a/src/utils/bridge/sub/utils.ts b/src/utils/bridge/sub/utils.ts index a328fd3fe..401bd4a99 100644 --- a/src/utils/bridge/sub/utils.ts +++ b/src/utils/bridge/sub/utils.ts @@ -1,21 +1,15 @@ -import { FPNumber, Operation } from '@sora-substrate/util'; +import { FPNumber } from '@sora-substrate/util'; import { subBridgeApi } from '@/utils/bridge/sub/api'; import { SubTransferType } from '@/utils/bridge/sub/types'; -import type { CodecString, WithConnectionApi } from '@sora-substrate/util'; +import type { ApiPromise } from '@polkadot/api'; +import type { CodecString } from '@sora-substrate/util'; import type { RegisteredAccountAsset } from '@sora-substrate/util/build/assets/types'; import type { SubNetwork, SubHistory } from '@sora-substrate/util/build/bridgeProxy/sub/types'; -export const isOutgoingTx = (tx: SubHistory): boolean => { - return tx.type === Operation.SubstrateOutgoing; -}; - export const isUnsignedTx = (tx: SubHistory): boolean => { - const signId = - subBridgeApi.isEvmAccount(tx.externalNetwork as SubNetwork) && !isOutgoingTx(tx) ? tx.externalHash : tx.txId; - - return !tx.blockId && !signId; + return !tx.blockId && !tx.txId; }; export const getTransaction = (id: string): SubHistory => { @@ -44,26 +38,8 @@ export const determineTransferType = (network: SubNetwork) => { } }; -export const isEvent = (e, section: string, method: string) => { - return e.event.section === section && e.event.method === method; -}; - -export const isQueueMessage = (e) => - isEvent(e, 'messageQueue', 'Processed') || - isEvent(e, 'xcmpQueue', 'Success') || - isEvent(e, 'xcmpQueue', 'Fail') || - isEvent(e, 'dmpQueue', 'ExecutedDownward'); - -export const isParaInclusion = (e) => isEvent(e, 'paraInclusion', 'CandidateIncluded'); - -export const isXcmPalletAttempted = (e) => isEvent(e, 'xcmPallet', 'Attempted'); - -export const isTransactionFeePaid = (e) => isEvent(e, 'transactionPayment', 'TransactionFeePaid'); - -export const isBridgeProxyUpdate = (e) => isEvent(e, 'bridgeProxy', 'RequestStatusUpdate'); - -export const getBridgeProxyHash = (events: Array): string => { - const bridgeProxyEvent = events.find((e) => isBridgeProxyUpdate(e)); +export const getBridgeProxyHash = (events: Array, api: ApiPromise): string => { + const bridgeProxyEvent = events.find((e) => api.events.bridgeProxy.RequestStatusUpdate.is(e.event)); if (!bridgeProxyEvent) { throw new Error(`Unable to find "bridgeProxy.RequestStatusUpdate" event`); @@ -72,16 +48,14 @@ export const getBridgeProxyHash = (events: Array): string => { return bridgeProxyEvent.event.data[0].toString(); }; -export const isBridgeProxyHash = (e: any, hash: string): boolean => { - if (!isBridgeProxyUpdate(e)) return false; - - const proxyHash = e.event.data[0].toString(); - - return hash === proxyHash; +export const isEvent = (e, section: string, method: string) => { + return e.event.section === section && e.event.method === method; }; -export const getDepositedBalance = (events: Array, to: string, chainApi: WithConnectionApi): [string, number] => { - const recipient = chainApi.formatAddress(to).toLowerCase(); +export const isTransactionFeePaid = (e) => isEvent(e, 'transactionPayment', 'TransactionFeePaid'); + +export const getDepositedBalance = (events: Array, to: string, api: ApiPromise): [string, number] => { + const recipient = subBridgeApi.formatAddress(to); const index = events.findIndex((e) => { let eventRecipient = ''; @@ -90,15 +64,11 @@ export const getDepositedBalance = (events: Array, to: string, chainApi: Wi eventRecipient = e.event.data.who.toString(); } else if (isEvent(e, 'assets', 'Transfer')) { eventRecipient = e.event.data[1].toString(); - } else if (isEvent(e, 'assets', 'Issued')) { - eventRecipient = e.event.data.owner.toString(); } if (!eventRecipient) return false; - const formatted = chainApi.formatAddress(eventRecipient).toLowerCase(); - - return formatted === recipient; + return subBridgeApi.formatAddress(eventRecipient) === recipient; }); if (index === -1) throw new Error(`Unable to find balance deposit like event`); @@ -118,22 +88,22 @@ export const getReceivedAmount = (sendedAmount: string, receivedAmount: CodecStr return { amount: amount2, transferFee }; }; -export const getParachainSystemMessageHash = (events: Array) => { +export const getParachainSystemMessageHash = (events: Array, api: ApiPromise) => { const parachainSystemEvent = events.find( - (e) => isEvent(e, 'parachainSystem', 'UpwardMessageSent') || isEvent(e, 'xcmpQueue', 'XcmpMessageSent') + (e) => api.events.parachainSystem.UpwardMessageSent.is(e.event) || api.events.xcmpQueue.XcmpMessageSent.is(e.event) ); if (!parachainSystemEvent) { throw new Error(`Unable to find "parachainSystem.UpwardMessageSent" event`); } - return parachainSystemEvent.event.data[0].toString(); + return parachainSystemEvent.event.data.messageHash.toString(); }; -export const isMessageAccepted = (e) => isEvent(e, 'substrateBridgeOutboundChannel', 'MessageAccepted'); - -export const getMessageAcceptedNonces = (events: Array): [number, number] => { - const messageAcceptedEvent = events.find((e) => isMessageAccepted(e)); +export const getMessageAcceptedNonces = (events: Array, api: ApiPromise): [number, number] => { + const messageAcceptedEvent = events.find((e) => + api.events.substrateBridgeOutboundChannel.MessageAccepted.is(e.event) + ); if (!messageAcceptedEvent) { throw new Error('Unable to find "substrateBridgeOutboundChannel.MessageAccepted" event'); @@ -145,10 +115,8 @@ export const getMessageAcceptedNonces = (events: Array): [number, number] = return [batchNonce, messageNonce]; }; -export const isMessageDispatched = (e) => isEvent(e, 'substrateDispatch', 'MessageDispatched'); - -export const getMessageDispatchedNonces = (events: Array): [number, number] => { - const messageDispatchedEvent = events.find((e) => isMessageDispatched(e)); +export const getMessageDispatchedNonces = (events: Array, api: ApiPromise): [number, number] => { + const messageDispatchedEvent = events.find((e) => api.events.substrateDispatch.MessageDispatched.is(e.event)); if (!messageDispatchedEvent) { throw new Error('Unable to find "substrateDispatch.MessageDispatched" event'); @@ -161,8 +129,13 @@ export const getMessageDispatchedNonces = (events: Array): [number, number] return [eventBatchNonce, eventMessageNonce]; }; -export const isMessageDispatchedNonces = (sendedBatchNonce: number, sendedMessageNonce: number, e: any): boolean => { - if (!isMessageDispatched(e)) return false; +export const isMessageDispatchedNonces = ( + sendedBatchNonce: number, + sendedMessageNonce: number, + e: any, + api: ApiPromise +): boolean => { + if (!api.events.substrateDispatch.MessageDispatched.is(e.event)) return false; const { batchNonce, messageNonce } = e.event.data[0]; @@ -183,13 +156,13 @@ export const isAssetAddedToChannel = ( asset: RegisteredAccountAsset, to: string, sended: CodecString, - chainApi: WithConnectionApi + api: ApiPromise ): boolean => { - if (!isEvent(e, 'xcmApp', 'AssetAddedToChannel')) return false; + if (!api.events.xcmApp.AssetAddedToChannel.is(e.event)) return false; const { amount, assetId, recipient } = e.event.data[0].asTransfer; // address check - if (chainApi.formatAddress(recipient.toString()) !== chainApi.formatAddress(to)) return false; + if (subBridgeApi.formatAddress(recipient.toString()) !== subBridgeApi.formatAddress(to)) return false; // asset check if (assetId.toString() !== asset.address) return false; // amount check @@ -206,9 +179,9 @@ export const isSoraBridgeAppBurned = ( from: string, to: string, sended: CodecString, - chainApi: WithConnectionApi + api: ApiPromise ) => { - if (!isEvent(e, 'soraBridgeApp', 'Burned')) return false; + if (!api.events.soraBridgeApp.Burned.is(e.event)) return false; const [networkIdCodec, assetIdCodec, senderCodec, recipientCodec, amountCodec] = e.event.data; @@ -220,8 +193,8 @@ export const isSoraBridgeAppBurned = ( const amount = amountCodec.toString(); // address check - if (chainApi.formatAddress(sender) !== chainApi.formatAddress(from)) return false; - if (chainApi.formatAddress(recipient) !== chainApi.formatAddress(to)) return false; + if (subBridgeApi.formatAddress(sender) !== subBridgeApi.formatAddress(from)) return false; + if (subBridgeApi.formatAddress(recipient) !== subBridgeApi.formatAddress(to)) return false; // asset check if (assetId !== asset.externalAddress) return false; // amount check diff --git a/src/utils/ethers-util.ts b/src/utils/ethers-util.ts index 3a11feb11..b64ccebe5 100644 --- a/src/utils/ethers-util.ts +++ b/src/utils/ethers-util.ts @@ -160,15 +160,9 @@ async function getAccount(): Promise { return signer.getAddress(); } -async function getContract(contractAddress: string, contractAbi: ethers.InterfaceAbi): Promise { - const signer = await getSigner(); - const contract = new ethers.Contract(contractAddress, contractAbi, signer); - - return contract; -} - async function getTokenContract(tokenAddress: string): Promise { - const contract = await getContract(tokenAddress, SmartContracts[SmartContractType.ERC20]); + const signer = await getSigner(); + const contract = new ethers.Contract(tokenAddress, SmartContracts[SmartContractType.ERC20].abi, signer); return contract; } @@ -302,7 +296,7 @@ async function addToken(address: string, symbol: string, decimals: number, image * @param chainName translated chain name */ async function switchOrAddChain(network: NetworkData, chainName?: string): Promise { - const chainId = ethers.toQuantity(network.evmId ?? network.id); + const chainId = ethers.toQuantity(network.id); try { await ethereumProvider.request({ @@ -454,7 +448,6 @@ export default { getAccount, getAccountBalance, getAccountAssetBalance, - getContract, getTokenContract, getTokenDecimals, getAllowance, diff --git a/src/views/Bridge.vue b/src/views/Bridge.vue index ffba73f6d..2ed68c431 100644 --- a/src/views/Bridge.vue +++ b/src/views/Bridge.vue @@ -68,15 +68,31 @@ /> - + + + + +
+ + {{ t('changeAccountText') }} + + + {{ t('disconnectWalletText') }} + +
+ + + type="primary" + @click="connectWallet(isSoraToEvm)" + > + {{ t('connectWalletText') }} + - + + + + +
+ + {{ t('changeAccountText') }} + + + {{ t('disconnectWalletText') }} + +
+ + + type="primary" + @click="connectWallet(!isSoraToEvm)" + > + {{ t('connectWalletText') }} + @@ -687,9 +696,34 @@ export default class Bridge extends Mixins(