Skip to content

Commit 5cce24d

Browse files
committed
client: Allow force-disable of DEX account.
If a DEX server goes offline permanently, users are stuck unable to disable the account because active orders can't be cancelled. Add a force option to ToggleAccountStatus that revokes unfilled orders to allow disabling. Matches with on-chain swaps in progress continue to settle independently. The UI automatically retries with force when the initial disable fails due to active orders.
1 parent fc94268 commit 5cce24d

8 files changed

Lines changed: 27 additions & 10 deletions

File tree

client/core/account.go

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -47,8 +47,10 @@ func (c *Core) disconnectDEX(dc *dexConnection) {
4747
}
4848

4949
// ToggleAccountStatus is used to disable or enable an account by given host and
50-
// application password.
51-
func (c *Core) ToggleAccountStatus(pw []byte, host string, disable bool) error {
50+
// application password. If force is true and disable is true, active orders
51+
// will be revoked to allow disabling. Matches with on-chain swaps in progress
52+
// will continue to settle (refund/redeem) independently.
53+
func (c *Core) ToggleAccountStatus(pw []byte, host string, disable, force bool) error {
5254
// Validate password.
5355
crypter, err := c.encryptionKey(pw)
5456
if err != nil {
@@ -69,7 +71,15 @@ func (c *Core) ToggleAccountStatus(pw []byte, host string, disable bool) error {
6971
if disable {
7072
// Check active orders or bonds.
7173
if dc.hasActiveOrders() {
72-
return errors.New("cannot disable account with active orders")
74+
if !force {
75+
return errors.New("cannot disable account with active orders")
76+
}
77+
c.log.Warnf("Force-disabling account on %s with active orders. Revoking unfilled orders.", host)
78+
dc.tradeMtx.RLock()
79+
for _, trade := range dc.trades {
80+
trade.revoke()
81+
}
82+
dc.tradeMtx.RUnlock()
7383
}
7484

7585
if dc.hasUnspentBond() {

client/core/account_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,7 @@ func TestToggleAccountStatus(t *testing.T) {
132132
}
133133
tCore.connMtx.Unlock()
134134

135-
err := tCore.ToggleAccountStatus(tPW, test.host, test.wantDisable)
135+
err := tCore.ToggleAccountStatus(tPW, test.host, test.wantDisable, false)
136136
if test.wantErr {
137137
if err == nil {
138138
t.Fatalf("expected error for test %v", test.name)

client/webserver/api.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -887,7 +887,7 @@ func (s *WebServer) apiToggleAccountStatus(w http.ResponseWriter, r *http.Reques
887887
return
888888
}
889889
// Disable account.
890-
err = s.core.ToggleAccountStatus(appPW, form.Host, form.Disable)
890+
err = s.core.ToggleAccountStatus(appPW, form.Host, form.Disable, form.Force)
891891
if err != nil {
892892
s.writeAPIError(w, fmt.Errorf("error updating account status: %w", err))
893893
return

client/webserver/live_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -771,7 +771,7 @@ func (c *TCore) AccountExport(pw []byte, host string) (*core.Account, []*db.Bond
771771
func (c *TCore) AccountImport(pw []byte, account *core.Account, bond []*db.Bond) error {
772772
return nil
773773
}
774-
func (c *TCore) ToggleAccountStatus(pw []byte, host string, disable bool) error { return nil }
774+
func (c *TCore) ToggleAccountStatus(pw []byte, host string, disable, force bool) error { return nil }
775775

776776
func (c *TCore) TxHistory(uint32, *asset.TxHistoryRequest) (*asset.TxHistoryResponse, error) {
777777
return nil, nil

client/webserver/site/src/js/dexsettings.ts

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -315,16 +315,22 @@ export default class DexSettingsPage extends BasePage {
315315

316316
// toggleAccountStatus enables or disables the account associated with the
317317
// provided host.
318-
async toggleAccountStatus (disable:boolean) {
318+
async toggleAccountStatus (disable:boolean, force?: boolean): Promise<void> {
319319
const page = this.page
320320
Doc.hide(page.errMsg)
321321
let host: string|null = this.host
322322
if (disable) host = page.disableAccountHost.textContent
323-
const req = { host, disable: disable }
323+
const req = { host, disable: disable, force: force || false }
324324
const loaded = app().loading(this.body)
325325
const res = await postJSON('/api/toggleaccountstatus', req)
326326
loaded()
327327
if (!app().checkResponse(res)) {
328+
// If disabling fails because of active orders, retry with force
329+
// to revoke unfilled orders. The user already confirmed the
330+
// disable via the form.
331+
if (disable && !force && res.msg && res.msg.includes('active orders')) {
332+
return this.toggleAccountStatus(true, true)
333+
}
328334
if (disable) {
329335
page.disableAccountErr.textContent = res.msg
330336
Doc.show(page.disableAccountErr)

client/webserver/types.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,7 @@ type updateAccountStatusForm struct {
137137
Pass encode.PassBytes `json:"pw"`
138138
Host string `json:"host"`
139139
Disable bool `json:"disable"`
140+
Force bool `json:"force"`
140141
}
141142

142143
type deleteRecordsForm struct {

client/webserver/webserver.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,7 @@ type clientCore interface {
147147
MaxSell(host string, base, quote uint32) (*core.MaxOrderEstimate, error)
148148
AccountExport(pw []byte, host string) (*core.Account, []*db.Bond, error)
149149
AccountImport(pw []byte, account *core.Account, bonds []*db.Bond) error
150-
ToggleAccountStatus(pw []byte, host string, disable bool) error
150+
ToggleAccountStatus(pw []byte, host string, disable, force bool) error
151151
IsInitialized() bool
152152
ExportSeed(pw []byte) (string, error)
153153
PreOrder(*core.TradeForm) (*core.OrderEstimate, error)

client/webserver/webserver_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -250,7 +250,7 @@ func (c *TCore) AccountExport(pw []byte, host string) (*core.Account, []*db.Bond
250250
func (c *TCore) AccountImport(pw []byte, account *core.Account, bonds []*db.Bond) error {
251251
return nil
252252
}
253-
func (c *TCore) ToggleAccountStatus(pw []byte, host string, disable bool) error { return nil }
253+
func (c *TCore) ToggleAccountStatus(pw []byte, host string, disable, force bool) error { return nil }
254254

255255
func (c *TCore) ExportSeed(pw []byte) (string, error) {
256256
return "seed words here", nil

0 commit comments

Comments
 (0)