Skip to content

Commit

Permalink
Add table showing available markets when registering for dex.
Browse files Browse the repository at this point in the history
  • Loading branch information
martonp committed Aug 22, 2021
1 parent 75c9b7a commit 96d12e4
Show file tree
Hide file tree
Showing 9 changed files with 234 additions and 130 deletions.
2 changes: 2 additions & 0 deletions client/webserver/site/src/css/application.scss
Original file line number Diff line number Diff line change
Expand Up @@ -72,3 +72,5 @@ $grid-breakpoints: (
@import "./orders.scss";
@import "./order.scss";
@import "./settings.scss";
@import "./forms.scss";
@import "./forms_dark.scss";
22 changes: 22 additions & 0 deletions client/webserver/site/src/css/forms.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
table.marketstable {
border-collapse: collapse;
width: 100%;
margin-top: 10px;
margin-bottom: 10px;

th {
font-size: 15px;
font-family: sans-serif;
}

td {
font-size: 15px;
}

td,
th {
font-size: 15px;
width: 33.3%;
padding: 3px 0;
}
}
5 changes: 5 additions & 0 deletions client/webserver/site/src/css/forms_dark.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
body.dark {
table.marketstable {
color: #a1a1a1;
}
}
43 changes: 33 additions & 10 deletions client/webserver/site/src/html/forms.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -140,25 +140,48 @@
{{end}}

{{define "confirmRegistrationForm"}}
{{$passwordIsCached := .UserInfo.PasswordIsCached}}
<div class="bg2 px-2 py-1 text-center position-relative fs18">
<div class="bg2 px-2 py-1 text-center fs18">
Confirm Registration
<div class="form-closer hoverbg"><span class="ico-cross"></span></div>
</div>
<div class="p-4">
<div class="fs16">
<span {{if $passwordIsCached}}class="d-hide"{{end}}>Enter your app password to confirm DEX registration.</span>
When you submit this form, <span id="feeDisplay"></span> DCR will be spent from your Decred wallet to pay
registration fees.
Enter your app password to confirm DEX registration.
When you submit this form, <span id="feeDisplay"></span> DCR will be spent from your Decred wallet to pay registration fees.
</div>
<div class="fs16 mt-4">
The DCR lot size for the <span id="dcrBaseMarketName" class="mono"></span> market is <span id="dexDCRLotSize"></span> DCR.
All trades on this market are in multiples of this lot size.
This is the minimum possible trade amount in DCR.
This DEX provides the following markets:
<table class="marketstable">
<thead>
<tr>
<th class="text-center">Base</th>
<th class="text-center">Quote</th>
<th class="text-center">Lot Size</th>
</tr>
</thead>
<tbody id="marketsTableRows">
<tr id="marketRowTemplate">
<td>
<div class="d-flex justify-content-center align-items-center">
<img class="micro-icon mr-1" data-tmpl="baseicon">
<div data-tmpl="base"></div>
</div>
</td>
<td class="text-center">
<div class="d-flex justify-content-center align-items-center">
<img class="micro-icon mr-1" data-tmpl="quoteicon">
<div data-tmpl="quote"></div>
</div>
</td>
<td class="text-center" data-tmpl="lotsize"></td>
</tr>
</tbody>
</table>
All trades are in multiples of the lot size.
{{- /* this will change when lot size is a market setting, not an asset setting */ -}}
</div>
<hr class="dashed my-4">
<div {{if $passwordIsCached}}class="d-hide"{{end}}>
<hr class="dashed mt-4">
<div id="appPassBox">
<label for="appPass" class="pl-1 mb-1">Password</label>
<input type="password" class="form-control select" id="appPass" autocomplete="current-password">
</div>
Expand Down
23 changes: 1 addition & 22 deletions client/webserver/site/src/html/register.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -51,28 +51,7 @@

{{- /* Confirm registration with app password. */ -}}
<form class="card mx-auto my-5 bg1 d-hide" id="confirmRegForm">
<div class="bg2 px-2 py-1 text-center fs18">Confirm Registration</div>
<div class="p-4">
<div class="fs16">
When you submit this form, <span id="feeDisplay"></span> DCR will be spent from your Decred wallet to pay registration fees.
</div>
<div class="fs16 mt-4">
The lot size for the <span id="dcrBaseMarketName" class="mono"></span> market is <span id="dexDCRLotSize"></span> DCR.
All trades on this market are in multiples of this lot size.
This is the minimum possible trade amount in DCR.
{{- /* this will change when lot size is a market setting, not an asset setting */ -}}
</div>
<hr class="dashed mt-4">
<div id="appPassBox">
Enter your app password to confirm DEX registration.<br>
<label for="appPass" class="pl-1 mb-1">Password</label>
<input type="password" class="form-control select" id="appPass" autocomplete="current-password">
</div>
<div class="d-flex justify-content-end mt-4">
<button id="submitConfirm" type="button" class="col-8 justify-content-center fs15 bg2 selected">Register</button>
</div>
<div class="fs15 pt-3 text-center d-hide errcolor" id="regErr"></div>
</div>
{{template "confirmRegistrationForm" .}}
</form>

{{- /* registration failed low balance. */ -}}
Expand Down
2 changes: 1 addition & 1 deletion client/webserver/site/src/html/settings.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@
</form>

{{- /* CONFIRM REGISTRATION */ -}}
<form class="card bg1 d-hide" id="confirmRegForm">
<form class="card mx-auto my-5 bg1 text-left d-hide" id="confirmRegForm">
{{template "confirmRegistrationForm" .}}
</form>

Expand Down
83 changes: 83 additions & 0 deletions client/webserver/site/src/js/forms.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import Doc from './doc'
import { postJSON } from './http'
import State from './state'
import { feeSendErr } from './constants'

let app

Expand Down Expand Up @@ -291,6 +292,88 @@ export class WalletConfigForm {
}
}

/*
* ConfirmRegistrationForm should be used with the "confirmRegistrationForm" template.
*/
export class ConfirmRegistrationForm {
constructor (application, form, { getDexAddr, getCertFile }, success, insufficientFundsFail) {
this.fields = Doc.parsePage(form, [
'feeDisplay', 'marketRowTemplate', 'marketsTableRows', 'appPass', 'appPassBox',
'submitConfirm', 'regErr'
])
app = application
this.getDexAddr = getDexAddr
this.getCertFile = getCertFile
this.success = success
this.insufficientFundsFail = insufficientFundsFail
this.form = form
bind(form, this.fields.submitConfirm, () => this.submitForm())
}

/*
* setExchange populates the form with the details of an exchange.
*/
setExchange (xc) {
const fields = this.fields
this.fee = xc.feeAsset.amount
fields.feeDisplay.textContent = Doc.formatCoinValue(this.fee / 1e8)
while (fields.marketsTableRows.firstChild) {
fields.marketsTableRows.removeChild(fields.marketsTableRows.firstChild)
}
const markets = Object.values(xc.markets)
markets.sort((m1, m2) => {
const compareBase = m1.basesymbol.localeCompare(m2.basesymbol)
const compareQuote = m1.quotesymbol.localeCompare(m2.quotesymbol)
return compareBase === 0 ? compareQuote : compareBase
})
markets.forEach((market) => {
const tr = fields.marketRowTemplate.cloneNode(true)
Doc.tmplElement(tr, 'baseicon').src = Doc.logoPath(market.basesymbol)
Doc.tmplElement(tr, 'quoteicon').src = Doc.logoPath(market.quotesymbol)
Doc.tmplElement(tr, 'base').innerText = market.basesymbol.toUpperCase()
Doc.tmplElement(tr, 'quote').innerText = market.quotesymbol.toUpperCase()
Doc.tmplElement(tr, 'lotsize').innerText = `${market.lotsize / 1e8} ${market.basesymbol.toUpperCase()}`
fields.marketsTableRows.appendChild(tr)
})
}

/*
* submitForm is called when the form is submitted.
*/
async submitForm () {
const fields = this.fields
Doc.hide(fields.regErr)
const cert = await this.getCertFile()
const dexAddr = this.getDexAddr()
const registration = {
addr: dexAddr,
pass: fields.appPass.value,
fee: this.fee,
cert: cert
}
fields.appPass.value = ''
const loaded = app.loading(this.form)
const res = await postJSON('/api/register', registration)
if (!app.checkResponse(res)) {
// This form is used both in the register workflow and the
// settings page. The register workflow handles a failure
// where the user does not have enough funds to pay for the
// registration fee in a different way.
if (res.code === feeSendErr && this.insufficientFundsFail) {
loaded()
this.insufficientFundsFail(res.msg)
return
}
fields.regErr.textContent = res.msg
Doc.show(fields.regErr)
loaded()
return
}
loaded()
this.success()
}
}

export class UnlockWalletForm {
constructor (application, form, success, pwCache) {
this.fields = Doc.parsePage(form, [
Expand Down
97 changes: 37 additions & 60 deletions client/webserver/site/src/js/register.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
import Doc from './doc'
import BasePage from './basepage'
import { postJSON } from './http'
import { NewWalletForm, UnlockWalletForm, DEXAddressForm, bind as bindForm } from './forms'
import { feeSendErr } from './constants'
import State from './state'
import { NewWalletForm, UnlockWalletForm, DEXAddressForm, ConfirmRegistrationForm, bind as bindForm } from './forms'

const DCR_ID = 42
const animationLength = 300
Expand All @@ -26,10 +24,10 @@ export default class RegistrationPage extends BasePage {
// Form 3: Unlock Decred wallet
'unlockWalletForm',
// Form 4: Configure DEX server
'dexAddrForm',
'dexAddrForm', 'dexAddr',
// Form 5: Confirm DEX registration and pay fee
'confirmRegForm', 'feeDisplay', 'dcrBaseMarketName', 'dexDCRLotSize', 'appPass', 'submitConfirm', 'regErr',
'dexCertBox', 'failedRegForm', 'regFundsErr', 'appPassBox'
'dexCertBox', 'failedRegForm', 'regFundsErr'
])

// Hide the form closers for the registration process.
Expand Down Expand Up @@ -58,38 +56,33 @@ export default class RegistrationPage extends BasePage {

// ADD DEX
this.dexAddrForm = new DEXAddressForm(app, page.dexAddrForm, async (xc) => {
this.fee = xc.feeAsset.amount
const fee = xc.feeAsset.amount
const balanceFeeRegistration = app.user.assets[DCR_ID].wallet.balance.available
if (balanceFeeRegistration < this.fee) {
await this.changeForm(page.dexAddrForm, page.failedRegForm)
page.regFundsErr.textContent = `Looks like there is not enough funds for
if (balanceFeeRegistration < fee) {
const errorMsg = `Looks like there is not enough funds for
paying the registration fee. Amount needed:
${Doc.formatCoinValue(this.fee / 1e8)} Amount available:
${Doc.formatCoinValue(fee / 1e8)} Amount available:
${Doc.formatCoinValue(balanceFeeRegistration / 1e8)}.
Deposit funds and try again.`
page.regFundsErr.textContent = errorMsg
Doc.show(page.regFundsErr)
await this.changeForm(page.dexAddrForm, page.failedRegForm)
return
}

page.feeDisplay.textContent = Doc.formatCoinValue(this.fee / 1e8)
// Assume there is at least one DCR base market since we're assuming DCR for
// registration anyway.
for (const market of Object.values(xc.markets)) {
if (market.baseid === 42) {
page.dexDCRLotSize.textContent = Doc.formatCoinValue(market.lotsize / 1e8)
page.dcrBaseMarketName.textContent = market.name.toUpperCase()
if (market.quoteid === 0) break // prefer dcr-btc
}
}
if (State.passwordIsCached()) Doc.hide(page.appPassBox)
else Doc.show(page.appPassBox)
this.confirmRegisterForm.setExchange(xc)
await this.changeForm(page.dexAddrForm, page.confirmRegForm)
}, this.pwCache)

// SUBMIT DEX REGISTRATION
bindForm(page.confirmRegForm, page.submitConfirm, () => this.registerDEX())

this.confirmRegisterForm = new ConfirmRegistrationForm(app,
page.confirmRegForm,
{
getCertFile: () => this.getCertFile(),
getDexAddr: () => this.getDexAddr()
},
() => this.registerDEXSuccess(),
(msg) => this.registerDEXFundsFail(msg))
// Attempt to load the dcrwallet configuration from the default location.
if (app.user.authed) this.auth()
}
Expand Down Expand Up @@ -171,46 +164,30 @@ export default class RegistrationPage extends BasePage {
await this.changeForm(page.appPWForm, page.newWalletForm)
}

/* Authorize DEX registration. */
async registerDEX () {
const page = this.page
const pw = page.appPass.value || this.pwCache.pw
if (!pw && !State.passwordIsCached()) {
page.regErr.textContent = 'password required'
Doc.show(page.regErr)
return
}

Doc.hide(page.regErr)
/* gets the contents of the cert file */
async getCertFile () {
let cert = ''
if (this.dexAddrForm.page.certFile.value) {
cert = await this.dexAddrForm.page.certFile.files[0].text()
}
const registration = {
addr: this.dexAddrForm.page.dexAddr.value,
pass: pw,
fee: this.fee,
cert: cert
}
page.appPass.value = ''
const loaded = app.loading(page.confirmRegForm)
const res = await postJSON('/api/register', registration)
loaded()
if (!app.checkResponse(res)) {
// show different form with no passphrase input in case of no funds.
if (res.code === feeSendErr) {
await this.changeForm(page.confirmRegForm, page.failedRegForm)
page.regFundsErr.textContent = res.msg
Doc.show(page.regFundsErr)
return
}
return cert
}

page.regErr.textContent = res.msg
Doc.show(page.regErr)
return
}
// Need to get a fresh market list. May consider handling this with a
// websocket update instead.
/* gets the dex address inputted by the user */
getDexAddr () {
return this.page.dexAddr.value
}

/* Called when dex registration failed due to insufficient funds. */
async registerDEXFundsFail (msg) {
const page = this.page
page.regFundsErr.textContent = msg
Doc.show(page.regFundsErr)
await this.changeForm(page.confirmRegForm, page.failedRegForm)
}

/* Called after successful registration to a DEX. */
async registerDEXSuccess () {
await app.fetchUser()
app.loadPage('markets')
}
Expand Down

0 comments on commit 96d12e4

Please sign in to comment.