diff --git a/src/libs/data/data.js b/src/libs/data/data.js index ba948bd7..9cf69c0e 100644 --- a/src/libs/data/data.js +++ b/src/libs/data/data.js @@ -192,6 +192,10 @@ export function abbrMessage(msg) { return msg.typeUrl.substring(msg.typeUrl.lastIndexOf('.') + 1).replace('Msg', '') } +export function abbrAddress(address, length = 10) { + return address.substring(0, length).concat('...', address.substring(address.length - length)) +} + export function isStringArray(value) { let is = false if (Array.isArray(value)) { @@ -235,9 +239,9 @@ export function formatTokenAmount(tokenAmount, fraction = 2, denom = 'uatom') { return parseFloat(amount) } -export function formatToken(token) { +export function formatToken(token, IBCDenom = {}) { if (token) { - return `${formatTokenAmount(token.amount, 2, token.denom)} ${formatTokenDenom(token.denom)}` + return `${formatTokenAmount(token.amount, 2, token.denom)} ${formatTokenDenom(IBCDenom[token.denom] || token.denom)}` } return token } diff --git a/src/libs/fetch.js b/src/libs/fetch.js index 7db5292f..58f36536 100644 --- a/src/libs/fetch.js +++ b/src/libs/fetch.js @@ -236,6 +236,15 @@ const chainAPI = class ChainFetch { async getStakingUnbonding(address) { return this.get(`/cosmos/staking/v1beta1/delegators/${address}/unbonding_delegations`).then(data => commonProcess(data)) } + + async getBankBalances(address, config = null) { + return this.get('/bank/balances/'.concat(address), config).then(data => commonProcess(data)) + } + + async getIBCDenomTrace(hash, config = null) { + const h = hash.substring(hash.indexOf('/')) + return this.get('/ibc/applications/transfer/v1beta1/denom_traces/'.concat(h), config).then(data => commonProcess(data)) + } // /cosmos/staking/v1beta1/delegations/{delegator_addr} static async getBankBalance(baseurl, address) { diff --git a/src/views/OperationDelegateComponent.vue b/src/views/OperationDelegateComponent.vue index 2567a473..a2aae832 100644 --- a/src/views/OperationDelegateComponent.vue +++ b/src/views/OperationDelegateComponent.vue @@ -5,6 +5,7 @@ centered size="md" title="Delegate Token" + ok-title="Send" hide-header-close scrollable :ok-disabled="!selectedAddress" @@ -13,7 +14,30 @@ @show="loadBalance" > - + + + + + + + + {{ errors[0] }} + + + - {{ errors[0] }} - - - - - - - - + text-field="label" + > + + {{ format(x) }} + + {{ errors[0] }} @@ -84,13 +98,18 @@ rules="required|regex:^([0-9\.]+)$" name="amount" > - + + + + {{ printDenom() }} + + {{ errors[0] }} @@ -201,6 +220,13 @@ + + Connect Wallet + {{ error }} @@ -211,15 +237,14 @@ import { ValidationProvider, ValidationObserver } from 'vee-validate' import { BModal, BRow, BCol, BInputGroup, BFormInput, BFormGroup, BFormSelect, BFormSelectOption, - BForm, BFormRadioGroup, BFormRadio, + BForm, BFormRadioGroup, BFormRadio, BButton, BInputGroupAppend, } from 'bootstrap-vue' import { required, email, url, between, alpha, integer, password, min, digits, alphaDash, length, } from '@validations' import { - formatToken, getCachedValidators, getLocalAccounts, getLocalChains, setLocalTxHistory, sign, timeIn, + abbrAddress, formatToken, formatTokenDenom, getLocalAccounts, setLocalTxHistory, sign, timeIn, } from '@/libs/data' -import chainAPI from '@/libs/fetch' import vSelect from 'vue-select' import ToastificationContent from '@core/components/toastification/ToastificationContent.vue' @@ -238,6 +263,8 @@ export default { BFormRadioGroup, BFormRadio, vSelect, + BButton, + BInputGroupAppend, ValidationProvider, ValidationObserver, @@ -266,6 +293,7 @@ export default { selectedChain: '', balance: [], delegations: [], + IBCDenom: {}, memo: '', fee: '800', feeDenom: '', @@ -289,11 +317,7 @@ export default { }, computed: { valOptions() { - return this.validators.map(x => ({ value: x.operator_address, label: x.description.moniker })) - }, - tokenOptions() { - if (!this.balance) return [] - return this.balance.map(x => ({ value: x.denom, label: formatToken(x) })) + return this.validators.map(x => ({ value: x.operator_address, label: `${x.description.moniker} (${Number(x.commission.rate) * 100}%)` })) }, feeDenoms() { if (!this.balance) return [] @@ -304,56 +328,27 @@ export default { // console.log('address: ', this.address) }, methods: { - computeAccount() { - const accounts = getLocalAccounts() - const chains = getLocalChains() - const values = Object.values(accounts) - let array = [] - for (let i = 0; i < values.length; i += 1) { - const addrs = values[i].address.filter(x => x.chain === this.$route.params.chain) - if (addrs && addrs.length > 0) { - array = array.concat(addrs) - if (!this.selectedAddress) { - this.selectedAddress = addrs[0].addr - } - } - const addr = values[i].address.find(x => x.addr === this.selectedAddress) - if (addr) { - this.selectedChain = chains[addr.chain] - } - } - if (!this.selectedChain) { - this.selectedChain = chains[this.$route.params.chain] - } - this.selectedValidator = this.validatorAddress - const reducer = (t, c) => { - if (!(t.find(x => x.addr === c.addr))) t.push(c) - return t - } - return array.reduce(reducer, []) + printDenom() { + return formatTokenDenom(this.IBCDenom[this.token] || this.token) }, - loadBalance() { - this.account = this.computeAccount() - if (this.account && this.account.length > 0) this.selectedAddress = this.account[0].addr + onChange() { if (this.selectedAddress) { - if (!getCachedValidators(this.selectedChain.chain)) { - this.$http.getValidatorList().then(v => { - this.validators = v - }) - } else { - this.validators = JSON.parse(getCachedValidators(this.selectedChain.chain)) - } - if (this.selectedChain && this.selectedAddress) { - chainAPI.getBankBalance(this.selectedChain.api, this.selectedAddress).then(res => { - if (res && res.length > 0) { - this.balance = res - const token = this.balance.find(i => !i.denom.startsWith('ibc')) - this.token = token.denom - if (token) this.feeDenom = token.denom - } - }) - } - this.$http.getLatestBlock(this.selectedChain).then(ret => { + this.$http.getBankBalances(this.selectedAddress).then(res => { + if (res && res.length > 0) { + this.balance = res + const token = this.balance.find(i => !i.denom.startsWith('ibc')) + this.token = token.denom + if (token) this.feeDenom = token.denom + this.balance.filter(i => i.denom.startsWith('ibc')).forEach(x => { + if (!this.IBCDenom[x.denom]) { + this.$http.getIBCDenomTrace(x.denom).then(denom => { + this.IBCDenom[x.denom] = denom.denom_trace.base_denom + }) + } + }) + } + }) + this.$http.getLatestBlock().then(ret => { this.chainId = ret.block.header.chain_id const notSynced = timeIn(ret.block.header.time, 10, 'm') if (notSynced) { @@ -362,7 +357,7 @@ export default { this.error = null } }) - this.$http.getAuthAccount(this.selectedAddress, this.selectedChain).then(ret => { + this.$http.getAuthAccount(this.selectedAddress).then(ret => { if (ret.value.base_vesting_account) { this.accountNumber = ret.value.base_vesting_account.base_account.account_number this.sequence = ret.value.base_vesting_account.base_account.sequence @@ -372,10 +367,34 @@ export default { this.sequence = ret.value.sequence ? ret.value.sequence : 0 } }) - this.$http.getStakingDelegations(this.selectedAddress).then(res => { - this.delegations = res.delegation_responses - }) } + // this.$http.getStakingDelegations(this.selectedAddress).then(res => { + // this.delegations = res.delegation_responses + // }) + }, + computeAccount() { + const accounts = getLocalAccounts() + const values = Object.values(accounts) + let array = [] + for (let i = 0; i < values.length; i += 1) { + const addrs = values[i].address.filter(x => x.chain === this.$route.params.chain) + if (addrs && addrs.length > 0) { + array = array.concat(addrs.map(x => ({ value: x.addr, label: values[i].name.concat(' - ', abbrAddress(x.addr)) }))) + if (!this.selectedAddress) { + this.selectedAddress = addrs[0].addr + } + } + } + this.selectedValidator = this.validatorAddress + return array + }, + loadBalance() { + this.account = this.computeAccount() + // if (this.account && this.account.length > 0) this.selectedAddress + this.$http.getValidatorList().then(v => { + this.validators = v + }) + this.onChange() }, handleOk(bvModalEvt) { // console.log('send') @@ -397,7 +416,7 @@ export default { this.error = null }, format(v) { - return formatToken(v) + return formatToken(v, this.IBCDenom) }, async sendTx() { const txMsgs = [{ diff --git a/src/views/OperationTransferComponent.vue b/src/views/OperationTransferComponent.vue index 6c35fc5f..34694e4a 100644 --- a/src/views/OperationTransferComponent.vue +++ b/src/views/OperationTransferComponent.vue @@ -5,6 +5,7 @@ centered size="md" title="Transfer Tokens" + ok-title="Send" hide-header-close scrollable :ok-disabled="!address" @@ -54,14 +55,6 @@ v-model="recipient" :state="errors.length > 0 ? false:null" /> - {{ errors[0] }} @@ -115,7 +108,7 @@ type="number" /> - MAX + {{ printDenom() }} {{ errors[0] }} @@ -244,9 +237,8 @@ import { required, email, url, between, alpha, integer, password, min, digits, alphaDash, length, } from '@validations' import { - formatToken, getLocalAccounts, getLocalChains, setLocalTxHistory, sign, timeIn, + formatToken, formatTokenDenom, getLocalAccounts, getLocalChains, setLocalTxHistory, sign, timeIn, } from '@/libs/data' -import chainAPI from '@/libs/fetch' import { Cosmos } from '@cosmostation/cosmosjs' import ToastificationContent from '@core/components/toastification/ToastificationContent.vue' @@ -295,6 +287,7 @@ export default { sequence: 1, accountNumber: 0, account: [], + IBCDenom: {}, required, password, @@ -318,6 +311,9 @@ export default { // console.log('address: ', this.address) }, methods: { + printDenom() { + return formatTokenDenom(this.IBCDenom[this.token] || this.token) + }, computeAccount() { const accounts = getLocalAccounts() const chains = getLocalChains() @@ -335,11 +331,18 @@ export default { this.account = this.computeAccount() if (this.account && this.account.length > 0) this.address = this.account[0].addr if (this.address) { - chainAPI.getBankBalance(this.selectedChain.api, this.address).then(res => { + this.$http.getBankBalances(this.address, this.selectedChain).then(res => { if (res && res.length > 0) { this.balance = res this.token = this.balance[0].denom this.feeDenom = this.balance.find(x => !x.denom.startsWith('ibc')).denom + this.balance.filter(i => i.denom.startsWith('ibc')).forEach(x => { + if (!this.IBCDenom[x.denom]) { + this.$http.getIBCDenomTrace(x.denom).then(denom => { + this.IBCDenom[x.denom] = denom.denom_trace.base_denom + }) + } + }) } }) this.$http.getLatestBlock(this.selectedChain).then(ret => { @@ -379,7 +382,7 @@ export default { this.error = null }, format(v) { - return formatToken(v) + return formatToken(v, this.IBCDenom) }, async sendCosmos() { const cosmos = new Cosmos(this.selectedChain.api, this.chainId) diff --git a/src/views/OperationVoteComponent.vue b/src/views/OperationVoteComponent.vue index a8617081..17952edf 100644 --- a/src/views/OperationVoteComponent.vue +++ b/src/views/OperationVoteComponent.vue @@ -5,6 +5,7 @@ centered size="md" title="Vote" + ok-title="Send" hide-header-close scrollable :ok-disabled="!voter" @@ -30,12 +31,12 @@ rules="required" name="Voter" > - {{ errors[0] }} Please import an account first! @@ -207,11 +208,10 @@ import { required, email, url, between, alpha, integer, password, min, digits, alphaDash, length, } from '@validations' import { - formatToken, getLocalAccounts, getLocalChains, setLocalTxHistory, sign, timeIn, + abbrAddress, + formatToken, getLocalAccounts, setLocalTxHistory, sign, timeIn, } from '@/libs/data' -import chainAPI from '@/libs/fetch' import ToastificationContent from '@core/components/toastification/ToastificationContent.vue' -import vSelect from 'vue-select' export default { name: 'VoteDialogue', @@ -227,7 +227,6 @@ export default { BFormSelectOption, BFormRadioGroup, BFormRadio, - vSelect, ValidationProvider, ValidationObserver, @@ -281,44 +280,26 @@ export default { methods: { computeAccount() { const accounts = getLocalAccounts() - const chains = getLocalChains() const values = Object.values(accounts) let array = [] for (let i = 0; i < values.length; i += 1) { const addrs = values[i].address.filter(x => x.chain === this.$route.params.chain) if (addrs && addrs.length > 0) { - array = array.concat(addrs) - if (!this.voter) { - this.voter = addrs[0].addr - } - } - const addr = values[i].address.find(x => x.addr === this.selectedAddress) - if (addr) { - this.selectedChain = chains[addr.chain] + array = array.concat(addrs.map(x => ({ value: x.addr, label: values[i].name.concat(' - ', abbrAddress(x.addr)) }))) } } - if (!this.selectedChain) { - this.selectedChain = chains[this.$route.params.chain] - } - const reducer = (t, c) => { - if (!(t.find(x => x.addr === c.addr))) t.push(c) - return t - } - return array.reduce(reducer, []) + return array }, - loadBalance() { - this.accounts = this.computeAccount() - // eslint-disable-next-line prefer-destructuring - if (this.accounts && this.accounts.length > 0) this.voter = this.accounts[0].addr + onChange() { if (this.voter) { - chainAPI.getBankBalance(this.selectedChain.api, this.voter).then(res => { + this.$http.getBankBalances(this.voter).then(res => { if (res && res.length > 0) { this.balance = res const token = this.balance.find(i => !i.denom.startsWith('ibc')) if (token) this.feeDenom = token.denom } }) - this.$http.getLatestBlock(this.selectedChain).then(ret => { + this.$http.getLatestBlock().then(ret => { this.chainId = ret.block.header.chain_id const notSynced = timeIn(ret.block.header.time, 10, 'm') if (notSynced) { @@ -327,7 +308,7 @@ export default { this.error = null } }) - this.$http.getAuthAccount(this.voter, this.selectedChain).then(ret => { + this.$http.getAuthAccount(this.voter).then(ret => { if (ret.value.base_vesting_account) { this.accountNumber = ret.value.base_vesting_account.base_account.account_number this.sequence = ret.value.base_vesting_account.base_account.sequence @@ -339,6 +320,12 @@ export default { }) } }, + loadBalance() { + this.accounts = this.computeAccount() + // eslint-disable-next-line prefer-destructuring + if (this.accounts && this.accounts.length > 0) this.voter = this.accounts[0].value + this.onChange() + }, handleOk(bvModalEvt) { // console.log('send') // Prevent modal from closing