Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

multi: show more bond info on dexsettings page #2485

Merged
merged 10 commits into from
Oct 13, 2023
29 changes: 14 additions & 15 deletions client/webserver/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -425,24 +425,23 @@ func (s *WebServer) apiPostBond(w http.ResponseWriter, r *http.Request) {
}
defer zero(pass)

feeBuffer, err := s.bondsFeeBuffer(assetID) // could also put it in postBondForm, with some work on the frontend
if err != nil {
s.writeAPIError(w, err)
return
}

_, err = s.core.PostBond(&core.PostBondForm{
Addr: post.Addr,
Cert: []byte(post.Cert),
AppPass: pass,
Bond: post.Bond,
Asset: &assetID,
LockTime: post.LockTime,
FeeBuffer: feeBuffer,
bondForm := &core.PostBondForm{
Addr: post.Addr,
Cert: []byte(post.Cert),
AppPass: pass,
Bond: post.Bond,
Asset: &assetID,
LockTime: post.LockTime,
// Options valid only when creating an account with bond:
MaintainTier: post.Maintain,
MaxBondedAmt: post.MaxBondedAmt,
})
}

if post.FeeBuffer != nil {
bondForm.FeeBuffer = *post.FeeBuffer
}

_, err = s.core.PostBond(bondForm)
if err != nil {
s.writeAPIError(w, fmt.Errorf("add bond error: %w", err))
return
Expand Down
10 changes: 10 additions & 0 deletions client/webserver/locales/en-us.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ var EnUS = map[string]string{
"reg_confirm_submit": `When you submit this form, funds will be spent from your wallet to post a fidelity bond, which is redeemable by you in the future.`,
"bond_strength": "Bond Strength",
"update_bond_options": "Update Bond Options",
"bond_options": "Bond Options",
"bond_options_update_success": "Bond Options have been updated successfully",
"target_tier": "Target Tier",
"target_tier_tooltip": "This is the target account tier you wish to maintain. Set to zero if you wish to disable tier maintenance (do not post new bonds).",
Expand Down Expand Up @@ -419,4 +420,13 @@ var EnUS = map[string]string{
"market_making_running": "Market making is running",
"cannot_manually_trade": "You cannot manually place orders while market making is running",
"back": "Back",
"bond_details": "Bond Details",
"current_tier": "Current Tier",
"current_tier_tooltip": "Number of active bonds that have not yet reached the expiry threshold as reported by the DEX server. Increase your target tier to raise your account tier, boost your trading limits, and offset penalties, if any.",
"current_target_tier_tooltip": "This is the target account tier you wish to maintain. If zero, bond maintenance will be disabled and new bonds will not be posted.",
"current_target_tier": "Current Target Tier",
"bond_cost": "Bond Cost",
"bond_cost_tooltip": "Cost of a single bond without fees and bond maintenance fund reservation.",
"bond_reservations": "Bond Reservation",
"bond_reservations_tooltip": "Total funds that will be locked when you post a bond to cover fees and bond maintenance costs.",
}
6 changes: 3 additions & 3 deletions client/webserver/site/src/css/forms.scss
Original file line number Diff line number Diff line change
Expand Up @@ -323,16 +323,16 @@ button.form-button {
#dexAddrForm,
#verifyForm,
#appPWForm,
#deleteArchivedRecordsForm,
#updateBondOptionsForm {
#deleteArchivedRecordsForm {
width: 325px;
}

#sendForm,
#vSendForm,
#exportSeedAuth,
#cancelForm,
#quickConfigForm {
#quickConfigForm,
#bondDetailsForm {
width: 375px;
}

Expand Down
4 changes: 2 additions & 2 deletions client/webserver/site/src/html/bodybuilder.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
<link rel="icon" href="/img/favicon.png?v=AK4XS4">
<meta name="description" content="Decred DEX Client Web Portal">
<title>{{.Title}}</title>
<link href="/css/style.css?v=f1e5270a|fd2cb731" rel="stylesheet">
<link href="/css/style.css?v=b23a3c7d|6ef4531c" rel="stylesheet">
</head>
<body {{if .UserInfo.DarkMode}} class="dark"{{end}}>
<div class="popup-notes" id="popupNotes">
Expand Down Expand Up @@ -103,7 +103,7 @@
{{end}}

{{define "bottom"}}
<script src="/js/entry.js?v=d42b3e73|6583bddc"></script>
<script src="/js/entry.js?v=565ace87|afe996f3"></script>
</body>
</html>
{{end}}
54 changes: 45 additions & 9 deletions client/webserver/site/src/html/dexsettings.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@
<div>
<button id="disableAcctBtn" class="bg2 selected">[[[Disable Account]]]</button>
</div>
<div{{if .Exchange.ViewOnly}} class="d-hide"{{end}}>
<button id="updateBondOptionsBtn" class="bg2 selected">[[[update_bond_options]]]</button>
<div {{if .Exchange.ViewOnly}} class="d-hide"{{end}}>
<button id="bondDetailsBtn" class="bg2 selected">[[[bond_details]]]</button>
</div>
<div>
<input type="file" class="form-control select d-none" id="certFileInput">
Expand Down Expand Up @@ -46,25 +46,61 @@
{{template "dexAddrForm" .}}
</form>

{{- /* UPDATE BOND OPTIONS */ -}}
<form class="d-hide" id="updateBondOptionsForm" autocomplete="off">
{{- /* BOND DETAILS */ -}}
<form class="d-hide" id="bondDetailsForm" autocomplete="off">
<div class="form-closer hoverbg"><span class="ico-cross"></span></div>
<div class="py-1 text-center fs28 sans-light">[[[update_bond_options]]]</div>
<div class="selectBondAsset mt-3">
<div class="py-1 fs28 text-center sans-light">[[[bond_details]]]</div>
<div class="d-flex justify-content-around my-3">
<span class="text-center">
[[[current_tier]]]
<span class="ico-info" data-tooltip="[[[current_tier_tooltip]]]"></span>
<br>
<span id="currentTier"></span>
</span>
<span class="text-center">
[[[current_target_tier]]]
<span class="ico-info" data-tooltip="[[[current_target_tier_tooltip]]]"></span>
<br>
<span id="currentTargetTier"></span>
</span>
</div>
<div class="d-flex justify-content-around my-3">
<span class="text-center">
[[[bond_cost]]]
<span class="ico-info" data-tooltip="[[[bond_cost_tooltip]]]"></span>
<br>
<span id="bondCost"></span>
<span class="bondAssetSym mx-2"></span>
<br>
<span class="d-flex d-hide justify-content-center grey fs14">
~<span id="bondCostFiat" class="mx-1"></span>USD
</span>
</span>
<span class="text-center justify-content-center">
[[[bond_reservations]]]
<span class="ico-info" data-tooltip="[[[bond_reservations_tooltip]]]"></span>
<br>
<span id="bondReservationAmt"></span>
<span class="bondAssetSym mx-2"></span>
<br>
<span class="d-flex d-hide justify-content-center grey fs14">
~<span id="bondReservationAmtFiat" class="mx-1"></span>USD
</span>
</div>
<div class="fs18 mt-2">[[[bond_options]]]:</div>
<div class="selectBondAsset py-1">
<label for="bondAssetSelect" class="form-label">[[[Asset]]]</label>
<select id="bondAssetSelect" class="w-100"></select>
</div>

<div class="mt-3">
<label for="bondTargetTier" class="form-label">
[[[target_tier]]]
<span class="ico-info fs12" data-tooltip="[[[target_tier_tooltip]]]"></span>
</label>
<input type="number" min="0" class="form-control select bg1" id="bondTargetTier" autocomplete="off">
</div>

<div class="d-flex justify-content-end mt-3">
<button id="updateBondOptionsConfirm" class="submit bg2 fs18 selected">[[[Submit]]]</button>
<button id="updateBondOptionsConfirm" class="submit bg2 fs18 selected">[[[update_bond_options]]]</button>
</div>
<div id="bondOptionsErr" class="fs15 pt-3 text-center d-hide errcolor text-break"></div>
<div id="bondOptionsMsg" class="fs15 pt-3 text-center d-hide text-break">[[[bond_options_update_success]]]</div>
Expand Down
77 changes: 69 additions & 8 deletions client/webserver/site/src/js/dexsettings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import {
} from './registry'

const animationLength = 300
const bondOverlap = 2 // See client/core/bond.go#L28

export default class DexSettingsPage extends BasePage {
body: HTMLElement
Expand All @@ -22,6 +23,7 @@ export default class DexSettingsPage extends BasePage {
host: string
keyup: (e: KeyboardEvent) => void
dexAddrForm: forms.DEXAddressForm
bondFeeBufferCache: Record<string, number>

constructor (body: HTMLElement) {
super()
Expand All @@ -32,16 +34,18 @@ export default class DexSettingsPage extends BasePage {

Doc.bind(page.exportDexBtn, 'click', () => this.prepareAccountExport(page.authorizeAccountExportForm))
Doc.bind(page.disableAcctBtn, 'click', () => this.prepareAccountDisable(page.disableAccountForm))
Doc.bind(page.updateBondOptionsBtn, 'click', () => this.prepareUpdateBondOptions())
Doc.bind(page.bondDetailsBtn, 'click', () => this.prepareBondDetailsForm())
Doc.bind(page.updateCertBtn, 'click', () => page.certFileInput.click())
Doc.bind(page.updateHostBtn, 'click', () => this.prepareUpdateHost())
Doc.bind(page.certFileInput, 'change', () => this.onCertFileChange())
Doc.bind(page.bondAssetSelect, 'change', () => this.updateBondAssetCosts())
Doc.bind(page.bondTargetTier, 'input', () => this.updateBondAssetCosts())

this.dexAddrForm = new forms.DEXAddressForm(page.dexAddrForm, async (xc: Exchange) => {
window.location.assign(`/dexsettings/${xc.host}`)
}, undefined, this.host)

forms.bind(page.updateBondOptionsForm, page.updateBondOptionsConfirm, () => this.updateBondOptions())
forms.bind(page.bondDetailsForm, page.updateBondOptionsConfirm, () => this.updateBondOptions())
forms.bind(page.authorizeAccountExportForm, page.authorizeExportAccountConfirm, () => this.exportAccount())
forms.bind(page.disableAccountForm, page.disableAccountConfirm, () => this.disableAccount())

Expand Down Expand Up @@ -156,11 +160,17 @@ export default class DexSettingsPage extends BasePage {
this.showForm(disableAccountForm)
}

// prepareUpdateBondOptions resets and prepares the Update Bond Options form.
async prepareUpdateBondOptions () {
// prepareBondDetailsForm resets and prepares the Bond Details form.
async prepareBondDetailsForm () {
const page = this.page
const xc = app().user.exchanges[this.host]
page.bondTargetTier.setAttribute('placeholder', xc.auth.targetTier.toString())
// Update bond details on this form
const targetTier = xc.auth.targetTier.toString()
page.currentTargetTier.textContent = `${targetTier}`
page.currentTier.textContent = `${xc.auth.effectiveTier}`
page.bondTargetTier.setAttribute('placeholder', targetTier)
page.bondTargetTier.value = ''
this.bondFeeBufferCache = {}
Doc.empty(page.bondAssetSelect)
for (const [assetSymbol, bondAsset] of Object.entries(xc.bondAssets)) {
const option = document.createElement('option') as HTMLOptionElement
Expand All @@ -171,7 +181,52 @@ export default class DexSettingsPage extends BasePage {
}
page.bondOptionsErr.textContent = ''
Doc.hide(page.bondOptionsErr)
this.showForm(page.updateBondOptionsForm)
await this.updateBondAssetCosts()
this.showForm(page.bondDetailsForm)
}

async updateBondAssetCosts () {
const xc = app().user.exchanges[this.host]
const page = this.page
const bondAssetID = parseInt(page.bondAssetSelect.value ?? '')
Doc.hide(page.bondCostFiat.parentElement as Element)
Doc.hide(page.bondReservationAmtFiat.parentElement as Element)
const assetInfo = xc.assets[bondAssetID]
const bondAsset = xc.bondAssets[assetInfo.symbol]

const bondCost = bondAsset.amount
const ui = assetInfo.unitInfo
const assetID = bondAsset.id
Doc.applySelector(page.bondDetailsForm, '.bondAssetSym').forEach((el) => { el.textContent = assetInfo.symbol.toLocaleUpperCase() })
page.bondCost.textContent = Doc.formatFullPrecision(bondCost, ui)
const xcRate = app().fiatRatesMap[assetID]
Doc.showFiatValue(page.bondCostFiat, bondCost, xcRate, ui)

let feeBuffer = this.bondFeeBufferCache[assetInfo.symbol]
if (!feeBuffer) {
feeBuffer = await this.getBondsFeeBuffer(assetID, page.bondDetailsForm)
if (feeBuffer > 0) this.bondFeeBufferCache[assetInfo.symbol] = feeBuffer
}
if (feeBuffer === 0) {
page.bondReservationAmt.textContent = intl.prep(intl.ID_UNAVAILABLE)
return
}
const targetTier = parseInt(page.bondTargetTier.value ?? '')
let reservation = 0
if (targetTier > 0) reservation = bondCost * targetTier * bondOverlap + feeBuffer
page.bondReservationAmt.textContent = Doc.formatFullPrecision(reservation, ui)
Doc.showFiatValue(page.bondReservationAmtFiat, reservation, xcRate, ui)
}

// Retrieve an estimate for the tx fee needed to create new bond reserves.
async getBondsFeeBuffer (assetID: number, form: HTMLElement) {
const loaded = app().loading(form)
const res = await postJSON('/api/bondsfeebuffer', { assetID })
loaded()
if (!app().checkResponse(res)) {
return 0
}
return res.feeBuffer
}

async prepareUpdateHost () {
Expand Down Expand Up @@ -238,12 +293,18 @@ export default class DexSettingsPage extends BasePage {
const targetTier = parseInt(page.bondTargetTier.value ?? '')
const bondAssetID = parseInt(page.bondAssetSelect.value ?? '')

const bondOptions = {
const bondOptions: Record<any, any> = {
host: this.host,
targetTier: targetTier,
bondAssetID: bondAssetID
}

const assetInfo = app().assets[bondAssetID]
if (assetInfo) {
const feeBuffer = this.bondFeeBufferCache[assetInfo.symbol]
if (feeBuffer > 0) bondOptions.feeBuffer = feeBuffer
}

const loaded = app().loading(this.body)
const res = await postJSON('/api/updatebondoptions', bondOptions)
loaded()
Expand All @@ -255,12 +316,12 @@ export default class DexSettingsPage extends BasePage {
Doc.show(page.bondOptionsMsg)
setTimeout(() => {
Doc.hide(page.bondOptionsMsg)
Doc.hide(page.forms)
}, 5000)
// update the in-memory values.
const xc = app().user.exchanges[this.host]
xc.auth.bondAssetID = bondAssetID
xc.auth.targetTier = targetTier
page.currentTargetTier.textContent = `${targetTier}`
}
}
}
8 changes: 8 additions & 0 deletions client/webserver/site/src/js/doc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -466,6 +466,14 @@ export default class Doc {
el.textContent = msg
Doc.show(el)
}

// showFiatValue displays the fiat equivalent for the provided amount.
static showFiatValue (display: PageElement, amount: number, rate: number, ui: UnitInfo): void {
if (rate) {
display.textContent = Doc.formatFiatConversion(amount, rate, ui)
Doc.show(display.parentElement as Element)
} else Doc.hide(display.parentElement as Element)
}
}

/*
Expand Down
Loading