mirror of
https://github.com/logos-blockchain/lez-programs.git
synced 2026-08-25 06:01:11 +00:00
feat(apps/amm): create pools via the new createPool op; drop the pool-watch poll
Route pool creation through the redesigned createPool op and retire the old
create-flow machinery. Add-liquidity stays on the legacy submitNewPosition.
Module (amm_module):
- createPool becomes a single-param envelope: it reads the caller-provided
lpHoldingId from the request (a new pool has no pre-existing LP holding),
dropping the requires-fresh-lp handshake — the module never creates wallet
accounts. Returns { status, error, transactionId }; unlike the swaps, a
submit failure carries a code so the UI can explain why.
Backend (AmmUiBackend):
- Expose liquidityQuote (read-only preview) and createPool slots. createPool
guards on the app's wallet-open state, forwards the request, and refreshes
balances on success. No account creation here.
UI (liquidity flow/form):
- NewPositionFlow.confirm() branches on the missing-pool signal: create ->
createPool (mint a fresh public LP account via createAccountPublic, then
submit); add -> unchanged submitNewPosition. Hex transactionId accepted.
- submissionSnapshot supplies canonical-order holdingAId/holdingBId.
- (liquidityQuote is wired to the backend but the create preview still rides
the legacy quote for now.)
Cleanup: the pool-creation confirmation poll is orphaned now that create no
longer submits via submitNewPosition. It polled the pool account by re-quoting
until poolStatus flipped to active_pool — a stopgap for the missing
transactionStatus/poll_tx on the lez module. Removed pendingPoolProbes,
poolPoller, watchPoolCreation, pollPendingPool, finishPoolProbe,
rotate/removePendingPool, pairKey, matchesSelectedPair,
selectedPoolCreationPending, poolActivated, the poolCreationPending state,
acceptPoolActivation, and their now-obsolete tests.
This commit is contained in:
@@ -48,7 +48,6 @@ AmmActionCard {
|
||||
readonly property bool quoteLoading: root.flowState.quoteLoading === true
|
||||
readonly property bool submitting: root.flowState.submitting === true
|
||||
readonly property bool quoteStale: root.flowState.quoteStale === true
|
||||
readonly property bool poolCreationPending: root.flowState.poolCreationPending === true
|
||||
readonly property string submitError: root.flowState.errorCode
|
||||
? root.issueText(root.flowState.errorCode) : ""
|
||||
readonly property string transactionId: String(root.flowState.transactionId || "")
|
||||
@@ -95,7 +94,11 @@ AmmActionCard {
|
||||
&& !root.quoteLoading
|
||||
&& !root.quoteStale
|
||||
&& !root.submitting
|
||||
&& !root.poolCreationPending
|
||||
// A create-pool tx for this pair is already in flight
|
||||
// (transactionId set) but the pool still reads missing until
|
||||
// the chain processes it — block confirm so a stale
|
||||
// missing_pool quote can't submit a duplicate NewDefinition.
|
||||
&& !(root.missingPool && root.transactionId.length > 0)
|
||||
|
||||
signal quoteRequested(bool immediate, var quoteRequest)
|
||||
signal confirmationRequested(var snapshot)
|
||||
@@ -600,7 +603,6 @@ AmmActionCard {
|
||||
text: root.submitting
|
||||
? qsTr("Submitting…")
|
||||
: root.contextLoading ? qsTr("Loading…")
|
||||
: root.poolCreationPending ? qsTr("Waiting for pool")
|
||||
: root.missingPool ? qsTr("Create pool") : qsTr("Add liquidity")
|
||||
enabled: root.canConfirm
|
||||
onClicked: root.confirmationRequested(root.submissionSnapshot())
|
||||
@@ -856,22 +858,6 @@ AmmActionCard {
|
||||
root.requestQuote(true)
|
||||
}
|
||||
|
||||
function acceptPoolActivation(quote) {
|
||||
if (!quote || quote.status !== "ok"
|
||||
|| quote.poolStatus !== "active_pool"
|
||||
|| !root.quoteMatchesSelectedPair(quote)) {
|
||||
return false
|
||||
}
|
||||
root.confirmedPoolStatus = "active_pool"
|
||||
root.activePoolQuote = quote
|
||||
root.amountA = ""
|
||||
root.amountB = ""
|
||||
root.minimumAmountARaw = ""
|
||||
root.minimumAmountBRaw = ""
|
||||
root.localErrors = []
|
||||
return true
|
||||
}
|
||||
|
||||
function noteDraftChanged() {
|
||||
root.draftChanged()
|
||||
}
|
||||
@@ -1449,8 +1435,12 @@ AmmActionCard {
|
||||
var built = root.buildQuoteRequest()
|
||||
return {
|
||||
"request": built.request,
|
||||
"poolProbeRequest": root.poolProbeRequest(built.request),
|
||||
"quoteHash": String(root.quotePayload.quoteHash || ""),
|
||||
// Canonical-order holdings for the create path's createPool call: the
|
||||
// request's tokenAId/amountARaw are canonical, so holdingAId must be the
|
||||
// canonical token A's holding too (createPool re-canonicalizes as a no-op).
|
||||
"holdingAId": String((root.displayIsCanonical ? root.tokenA : root.tokenB).holdingId || ""),
|
||||
"holdingBId": String((root.displayIsCanonical ? root.tokenB : root.tokenA).holdingId || ""),
|
||||
"pairText": qsTr("%1 / %2").arg(root.shortTokenName(root.tokenA)).arg(root.shortTokenName(root.tokenB)),
|
||||
"feeText": root.feeLabel(root.selectedFeeBps),
|
||||
"depositAText": root.quoteAmount("actualAmountARaw", "actualAmountBRaw", "A"),
|
||||
|
||||
@@ -248,10 +248,6 @@ Item {
|
||||
form.failTokenResolution(code)
|
||||
}
|
||||
|
||||
function onPoolActivated(quote) {
|
||||
form.acceptPoolActivation(quote)
|
||||
}
|
||||
|
||||
function onQuoteRefreshRequested(immediate) {
|
||||
form.requestQuote(immediate)
|
||||
}
|
||||
|
||||
@@ -20,7 +20,6 @@ QtObject {
|
||||
"quoteLoading": root.quoteLoading,
|
||||
"quoteStale": root.quoteStale,
|
||||
"submitting": root.submitting,
|
||||
"poolCreationPending": root.selectedPoolCreationPending(),
|
||||
"transactionId": root.transactionId,
|
||||
"errorCode": root.flowErrorCode || root.contextErrorCode
|
||||
|| root.quoteErrorCode
|
||||
@@ -39,12 +38,9 @@ QtObject {
|
||||
property string contextErrorCode: ""
|
||||
property string quoteErrorCode: ""
|
||||
property var pendingQuoteRequest: ({ "ok": false, "request": ({}) })
|
||||
property var pendingPoolProbes: []
|
||||
property bool poolProbeInFlight: false
|
||||
|
||||
signal tokenResolutionFinished(bool finalResponse)
|
||||
signal tokenResolutionFailed(string code)
|
||||
signal poolActivated(var quote)
|
||||
signal quoteRefreshRequested(bool immediate)
|
||||
signal submitSucceeded
|
||||
signal submitFailed
|
||||
@@ -57,13 +53,6 @@ QtObject {
|
||||
onTriggered: root.requestQuoteNow(root.quoteSerial)
|
||||
}
|
||||
|
||||
property Timer poolPoller: Timer {
|
||||
interval: 5000
|
||||
repeat: true
|
||||
running: root.pendingPoolProbes.length > 0
|
||||
onTriggered: root.pollPendingPool()
|
||||
}
|
||||
|
||||
onNewPositionContextChanged: root.invalidateQuote()
|
||||
|
||||
onWalletStateReadyChanged: {
|
||||
@@ -207,13 +196,19 @@ QtObject {
|
||||
return
|
||||
}
|
||||
|
||||
// Pool creation (initialPriceRealRaw is set only on the missing-pool path) goes
|
||||
// through the new createPool op — hex ids, caller-provided accounts. Add-liquidity
|
||||
// keeps the legacy submitNewPosition.
|
||||
if (snapshot.request.initialPriceRealRaw !== undefined) {
|
||||
root.createPool(snapshot)
|
||||
return
|
||||
}
|
||||
|
||||
root.runtime.watch(root.backend.submitNewPosition(snapshot.request, snapshot.quoteHash),
|
||||
function(result) {
|
||||
if (result && result.status === "submitted"
|
||||
&& /^[1-9A-HJ-NP-Za-km-z]{32,44}$/.test(
|
||||
String(result.transactionId || ""))) {
|
||||
if (snapshot.request.initialPriceRealRaw !== undefined)
|
||||
root.watchPoolCreation(snapshot.poolProbeRequest, result.deadlineMs)
|
||||
root.submitting = false
|
||||
root.transactionId = result.transactionId
|
||||
root.flowErrorCode = ""
|
||||
@@ -230,6 +225,58 @@ QtObject {
|
||||
})
|
||||
}
|
||||
|
||||
// Create a pool via the new createPool op. A new pool has no pre-existing LP
|
||||
// holding, so the caller provides a fresh account: create one, then submit. No
|
||||
// confirmation poll yet (transactionStatus is pending an upstream dependency).
|
||||
function createPool(snapshot) {
|
||||
root.runtime.watch(root.backend.createAccountPublic(),
|
||||
function(lpId) {
|
||||
if (!lpId || String(lpId).length === 0) {
|
||||
root.finishSubmitFailure(root.quoteError("wallet_submission_failed"))
|
||||
return
|
||||
}
|
||||
root.submitCreatePool(snapshot, String(lpId))
|
||||
},
|
||||
function(error) {
|
||||
root.finishSubmitFailure(root.quoteError("wallet_submission_failed"))
|
||||
})
|
||||
}
|
||||
|
||||
function submitCreatePool(snapshot, lpHoldingId) {
|
||||
var request = {
|
||||
"tokenAId": snapshot.request.tokenAId,
|
||||
"tokenBId": snapshot.request.tokenBId,
|
||||
"holdingAId": snapshot.holdingAId,
|
||||
"holdingBId": snapshot.holdingBId,
|
||||
"lpHoldingId": lpHoldingId,
|
||||
"amountARaw": snapshot.request.amountARaw,
|
||||
"amountBRaw": snapshot.request.amountBRaw,
|
||||
"feeBps": snapshot.request.feeBps,
|
||||
// u64-max sentinel = no deadline, same as the swap submits.
|
||||
"deadlineMs": "18446744073709551615"
|
||||
}
|
||||
root.runtime.watch(root.backend.createPool(request),
|
||||
function(result) {
|
||||
if (result && result.status === "ok"
|
||||
&& String(result.transactionId || "").length > 0) {
|
||||
root.submitting = false
|
||||
root.transactionId = String(result.transactionId)
|
||||
root.flowErrorCode = ""
|
||||
root.contextErrorCode = ""
|
||||
root.quoteErrorCode = ""
|
||||
root.invalidateQuote()
|
||||
root.submitSucceeded()
|
||||
return
|
||||
}
|
||||
var code = result && result.error ? String(result.error)
|
||||
: "wallet_submission_failed"
|
||||
root.finishSubmitFailure(root.quoteError(code))
|
||||
},
|
||||
function(error) {
|
||||
root.finishSubmitFailure(root.quoteError("wallet_submission_failed"))
|
||||
})
|
||||
}
|
||||
|
||||
function finishSubmitFailure(result) {
|
||||
root.submitting = false
|
||||
const hasFreshQuote = result && result.quote
|
||||
@@ -247,89 +294,6 @@ QtObject {
|
||||
root.scheduleQuote(true, root.pendingQuoteRequest)
|
||||
}
|
||||
|
||||
function watchPoolCreation(request, deadlineMs) {
|
||||
const key = root.pairKey(request)
|
||||
let deadline = Number(deadlineMs)
|
||||
if (!isFinite(deadline) || deadline <= 0)
|
||||
deadline = 0
|
||||
const pending = root.pendingPoolProbes.filter(function(item) {
|
||||
return item.key !== key
|
||||
})
|
||||
pending.push({
|
||||
"key": key,
|
||||
"request": request,
|
||||
"deadlineMs": deadline
|
||||
})
|
||||
root.pendingPoolProbes = pending
|
||||
Qt.callLater(root.pollPendingPool)
|
||||
}
|
||||
|
||||
function pollPendingPool() {
|
||||
if (root.poolProbeInFlight || root.pendingPoolProbes.length === 0
|
||||
|| !root.walletStateReady || root.runtime === null) {
|
||||
return
|
||||
}
|
||||
const pending = root.pendingPoolProbes[0]
|
||||
root.poolProbeInFlight = true
|
||||
root.runtime.watch(root.backend.quoteNewPosition(pending.request),
|
||||
function(quote) {
|
||||
root.finishPoolProbe(pending, quote)
|
||||
},
|
||||
function(error) {
|
||||
root.finishPoolProbe(pending, null)
|
||||
})
|
||||
}
|
||||
|
||||
function finishPoolProbe(pending, quote) {
|
||||
root.poolProbeInFlight = false
|
||||
if (quote && quote.poolStatus === "active_pool") {
|
||||
root.removePendingPool(pending.key)
|
||||
if (root.matchesSelectedPair(pending.request)) {
|
||||
root.poolActivated(quote)
|
||||
root.invalidateQuote()
|
||||
root.refreshContext(true)
|
||||
}
|
||||
return
|
||||
}
|
||||
if (pending.deadlineMs > 0 && Date.now() >= pending.deadlineMs) {
|
||||
root.removePendingPool(pending.key)
|
||||
return
|
||||
}
|
||||
root.rotatePendingPool()
|
||||
}
|
||||
|
||||
function pairKey(request) {
|
||||
return String(request.tokenAId || "") + ":" + String(request.tokenBId || "")
|
||||
}
|
||||
|
||||
function matchesSelectedPair(request) {
|
||||
return root.pairKey(root.pendingQuoteRequest.request || {}) === root.pairKey(request)
|
||||
}
|
||||
|
||||
function selectedPoolCreationPending() {
|
||||
const request = root.pendingQuoteRequest.request || {}
|
||||
if (!request.tokenAId || !request.tokenBId)
|
||||
return false
|
||||
const selected = root.pairKey(request)
|
||||
return root.pendingPoolProbes.some(function(item) {
|
||||
return item.key === selected
|
||||
})
|
||||
}
|
||||
|
||||
function removePendingPool(key) {
|
||||
root.pendingPoolProbes = root.pendingPoolProbes.filter(function(item) {
|
||||
return item.key !== key
|
||||
})
|
||||
}
|
||||
|
||||
function rotatePendingPool() {
|
||||
if (root.pendingPoolProbes.length < 2)
|
||||
return
|
||||
const pending = root.pendingPoolProbes.slice(1)
|
||||
pending.push(root.pendingPoolProbes[0])
|
||||
root.pendingPoolProbes = pending
|
||||
}
|
||||
|
||||
function draftChanged() {
|
||||
root.invalidateQuote()
|
||||
root.transactionId = ""
|
||||
|
||||
@@ -271,3 +271,30 @@ QVariantList AmmUiBackend::tokenList()
|
||||
{
|
||||
return m_logos->amm_module.tokenList();
|
||||
}
|
||||
|
||||
QVariantMap AmmUiBackend::liquidityQuote(QVariantMap request)
|
||||
{
|
||||
// Read-only create-pool preview — no wallet guard. The module prices the opening
|
||||
// LP and price server-side from the two deposit amounts.
|
||||
return m_logos->amm_module.liquidityQuote(request);
|
||||
}
|
||||
|
||||
QVariantMap AmmUiBackend::createPool(QVariantMap request)
|
||||
{
|
||||
// Same connected-state submit guard as the swaps — this app's lock is
|
||||
// authoritative even though the shared wallet may remain open elsewhere.
|
||||
if (!isWalletOpen())
|
||||
return QVariantMap {
|
||||
{ QStringLiteral("status"), QStringLiteral("error") },
|
||||
{ QStringLiteral("error"), QStringLiteral("wallet_unavailable") },
|
||||
};
|
||||
|
||||
// The caller supplies the fresh LP holding in the request; the backend forwards to
|
||||
// the module (it creates no wallet accounts) and refreshes balances on a successful
|
||||
// submit.
|
||||
const QVariantMap result = m_logos->amm_module.createPool(request);
|
||||
if (result.value(QStringLiteral("status")).toString() == QStringLiteral("ok")
|
||||
&& !result.value(QStringLiteral("transactionId")).toString().isEmpty())
|
||||
refreshBalances();
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -71,6 +71,12 @@ public slots:
|
||||
// Reads the token list from TOKENS_CONFIG (via the module) so the Swap UI's
|
||||
// token picker is config-driven instead of hardcoded.
|
||||
QVariantList tokenList() override;
|
||||
// Create-pool preview (liquidityQuote, read-only) and submit (createPool). The caller
|
||||
// supplies lpHoldingId in the request — a fresh account it created via
|
||||
// createAccountPublic() — so createPool forwards to the module and creates no wallet
|
||||
// accounts here.
|
||||
QVariantMap liquidityQuote(QVariantMap request) override;
|
||||
QVariantMap createPool(QVariantMap request) override;
|
||||
|
||||
private:
|
||||
void syncWalletState();
|
||||
|
||||
@@ -92,4 +92,26 @@ class AmmUiBackend
|
||||
// a QVariantList of QVariantMap entries. Returns an empty list if
|
||||
// TOKENS_CONFIG is unset/unreadable/invalid.
|
||||
SLOT(QVariantList tokenList())
|
||||
|
||||
// Server-side create-pool preview from the two deposit amounts. `request`
|
||||
// carries { tokenAId, tokenBId, amountARaw, amountBRaw } (ids hex or base58;
|
||||
// amounts decimal-string base units). Returns { status:"ok", error:"",
|
||||
// amountARaw, amountBRaw, expectedLpRaw, lockedLpRaw, initialPriceRaw } — the
|
||||
// LP the creator receives and the opening price, via the shared on-chain math.
|
||||
// On failure { status:"error", error:<code> } — invalid_token_id,
|
||||
// same_token_pair, amount_too_low, amount_required, bad_amount, backend_error.
|
||||
// Read-only, no submission (the fee is not needed — it isn't part of the pool
|
||||
// PDA nor the pricing).
|
||||
SLOT(QVariantMap liquidityQuote(QVariantMap request))
|
||||
// Submits a NewDefinition transaction creating the pool for the request's pair.
|
||||
// `request` carries { tokenAId, tokenBId, holdingAId, holdingBId, lpHoldingId,
|
||||
// amountARaw, amountBRaw, feeBps, deadlineMs } (ids hex or base58; amounts/deadline
|
||||
// decimal strings). A new pool has no existing LP holding, so the caller supplies
|
||||
// lpHoldingId — a fresh account it created via createAccountPublic(); the backend
|
||||
// just forwards to the module and creates no wallet accounts here. Returns
|
||||
// { status:"ok", error:"", transactionId:<hex tx hash> } on success, else
|
||||
// { status:"error", error:<code> } (wallet_unavailable, config_missing,
|
||||
// invalid_account_id, bad_amount, bad_fee_bps_amount, invalid_fee_tier,
|
||||
// wallet_submission_failed, backend_error).
|
||||
SLOT(QVariantMap createPool(QVariantMap request))
|
||||
}
|
||||
|
||||
@@ -191,44 +191,6 @@ TestCase {
|
||||
compare(page.flow.submitting, false)
|
||||
}
|
||||
|
||||
function test_base58MissingPoolSubmissionStartsPoolWatch() {
|
||||
var backend = createTemporaryObject(backendComponent, testCase, {
|
||||
"walletStateReady": true,
|
||||
"submitResult": {
|
||||
"status": "submitted",
|
||||
"transactionId": submittedTransactionId,
|
||||
"deadlineMs": String(Date.now() + 60000)
|
||||
}
|
||||
})
|
||||
var runtime = createTemporaryObject(runtimeComponent, testCase)
|
||||
var page = createTemporaryObject(pageComponent, testCase, {
|
||||
"backend": backend,
|
||||
"runtime": runtime
|
||||
})
|
||||
verify(backend)
|
||||
verify(runtime)
|
||||
verify(page)
|
||||
|
||||
var probe = {
|
||||
"tokenAId": "22222222222222222222222222222222",
|
||||
"tokenBId": "33333333333333333333333333333333"
|
||||
}
|
||||
page.flow.pendingQuoteRequest = { "ok": true, "request": probe }
|
||||
page.flow.confirm({
|
||||
"request": {
|
||||
"initialPriceRealRaw": "18446744073709551616"
|
||||
},
|
||||
"poolProbeRequest": probe,
|
||||
"quoteHash": "sha256:expected"
|
||||
})
|
||||
wait(0)
|
||||
|
||||
compare(page.flow.transactionId, submittedTransactionId)
|
||||
compare(page.flow.pendingPoolProbes.length, 1)
|
||||
compare(page.flow.selectedPoolCreationPending(), true)
|
||||
compare(page.flow.poolProbeInFlight, false)
|
||||
}
|
||||
|
||||
function test_nativeHexSubmittedResultDoesNotEnterSuccessState() {
|
||||
var backend = createTemporaryObject(backendComponent, testCase, {
|
||||
"walletStateReady": true,
|
||||
@@ -257,70 +219,4 @@ TestCase {
|
||||
compare(page.flow.submitting, false)
|
||||
}
|
||||
|
||||
function test_poolProbeDoesNotPublishProbeAmountsAsCurrentQuote() {
|
||||
var backend = createTemporaryObject(backendComponent, testCase, {
|
||||
"walletStateReady": true
|
||||
})
|
||||
var page = createTemporaryObject(pageComponent, testCase, {
|
||||
"backend": backend
|
||||
})
|
||||
verify(backend)
|
||||
verify(page)
|
||||
|
||||
var request = {
|
||||
"tokenAId": "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz",
|
||||
"tokenBId": "22222222222222222222222222222222"
|
||||
}
|
||||
var pending = { "key": page.flow.pairKey(request), "request": request }
|
||||
page.flow.pendingQuoteRequest = { "ok": true, "request": request }
|
||||
page.flow.pendingPoolProbes = [pending]
|
||||
page.flow.newPositionQuote = {
|
||||
"status": "ok",
|
||||
"poolStatus": "missing_pool",
|
||||
"tokenAId": request.tokenAId,
|
||||
"tokenBId": request.tokenBId
|
||||
}
|
||||
page.flow.quoteStale = false
|
||||
|
||||
page.flow.finishPoolProbe(pending, {
|
||||
"status": "ok",
|
||||
"poolStatus": "active_pool",
|
||||
"tokenAId": request.tokenAId,
|
||||
"tokenBId": request.tokenBId
|
||||
})
|
||||
|
||||
compare(page.flow.pendingPoolProbes.length, 0)
|
||||
compare(page.flow.newPositionQuote.poolStatus, "missing_pool")
|
||||
verify(page.flow.quoteStale)
|
||||
}
|
||||
|
||||
function test_poolProbeStopsBlockingAfterTransactionDeadline() {
|
||||
var backend = createTemporaryObject(backendComponent, testCase, {
|
||||
"walletStateReady": true
|
||||
})
|
||||
var page = createTemporaryObject(pageComponent, testCase, {
|
||||
"backend": backend
|
||||
})
|
||||
verify(backend)
|
||||
verify(page)
|
||||
|
||||
var request = {
|
||||
"tokenAId": "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz",
|
||||
"tokenBId": "22222222222222222222222222222222"
|
||||
}
|
||||
var pending = {
|
||||
"key": page.flow.pairKey(request),
|
||||
"request": request,
|
||||
"deadlineMs": Date.now() - 1
|
||||
}
|
||||
page.flow.pendingQuoteRequest = { "ok": true, "request": request }
|
||||
page.flow.pendingPoolProbes = [pending]
|
||||
page.flow.poolProbeInFlight = true
|
||||
|
||||
page.flow.finishPoolProbe(pending, null)
|
||||
|
||||
compare(page.flow.pendingPoolProbes.length, 0)
|
||||
compare(page.flow.poolProbeInFlight, false)
|
||||
verify(!page.flow.selectedPoolCreationPending())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -345,36 +345,6 @@ TestCase {
|
||||
compare(form.amountA, "2")
|
||||
}
|
||||
|
||||
function test_poolActivationClearsCreationDraftWithoutPublishingProbeAmounts() {
|
||||
var form = createForm()
|
||||
form.confirmedPoolStatus = "missing_pool"
|
||||
form.amountA = "3"
|
||||
form.amountB = "2"
|
||||
form.minimumAmountARaw = "3"
|
||||
form.minimumAmountBRaw = "2000000"
|
||||
|
||||
verify(form.acceptPoolActivation({
|
||||
"status": "ok",
|
||||
"tokenAId": tokenHigh,
|
||||
"tokenBId": tokenLow,
|
||||
"poolStatus": "active_pool",
|
||||
"reserveARaw": "3000000",
|
||||
"reserveBRaw": "2"
|
||||
}))
|
||||
|
||||
verify(form.activePool)
|
||||
compare(form.activePoolQuote.poolStatus, "active_pool")
|
||||
compare(form.amountA, "")
|
||||
compare(form.amountB, "")
|
||||
compare(form.minimumAmountARaw, "")
|
||||
compare(form.minimumAmountBRaw, "")
|
||||
quoteRequestedSpy.target = form
|
||||
quoteRequestedSpy.clear()
|
||||
form.requestQuote(true)
|
||||
compare(quoteRequestedSpy.count, 0)
|
||||
compare(form.localErrors.length, 0)
|
||||
}
|
||||
|
||||
function test_staleQuoteErrorsDoNotMarkCurrentDraft() {
|
||||
var quote = {
|
||||
"status": "ok",
|
||||
|
||||
Reference in New Issue
Block a user