Page MenuHomePhabricator

[Cashtab] Prevent agora buys of offers above spot
ClosedPublic

Authored by bytesofman on Sun, Jan 5, 15:30.

Details

Reviewers
emack
Group Reviewers
Restricted Project
Commits
rABC2249c7452dc0: [Cashtab] Prevent agora buys of offers above spot
Summary

Current incentive structure is leading scammers to create offers above spot. These are apparently being bought by mistake.

Disable buys above spot in Cashtab. Show an alert explaining.

Test Plan

npm test

image.png (460×297 px, 64 KB)

Diff Detail

Repository
rABC Bitcoin ABC
Lint
Lint Not Applicable
Unit
Tests Not Applicable

Event Timeline

Failed tests logs:

====== CashTab Unit Tests: <OrderBook /> We can buy an offer ======
Error: Unable to find an element with the text: Error: Insufficient utxos to accept this offer. This could be because the text is broken up by multiple elements. In this case, you can provide a function for your text matcher to make your matcher more flexible.

Ignored nodes: comments, script, style
<body>
  <div>
    <div
      class="Toastify"
    />
    <div
      class="sc-jDwBTQ fQGJyM"
      height="470"
      width="320"
    >
      <button
        class="sc-hzDkRC cGiRCv"
      >
        X
      </button>
      <div
        class="sc-iRbamj diDrvR"
        height="470"
      >
        <div
          class="sc-gPEVay kKfQpa"
        >
          Execute this trade?
        </div>
        <img
          alt="icon for aed861a31b96934b88c0252ede135cb9700d7649f69191235087a3030e553cb1"
          height="128"
          src="https://icons.etokens.cash/128/aed861a31b96934b88c0252ede135cb9700d7649f69191235087a3030e553cb1.png"
          width="128"
        />
        <p
          class="sc-cLQEGU gJBEYV"
        >
          Agora offers must be accepted at specific quantities.
        </p>
        <p
          class="sc-cLQEGU gJBEYV"
        >
          Review and confirm.
        </p>
        <div
          class="sc-gqPbQI liNowb"
        >
          <div
            class="sc-hORach gtKEVB"
          >
            <div
              class="sc-bAeIUo fMAOJA"
            >
              Target qty:
               
            </div>
            <div
              class="sc-bMVAic gmHHif"
            >
              55.55
            </div>
          </div>
          <div
            class="sc-hORach gtKEVB"
          >
            <div
              class="sc-bAeIUo fMAOJA"
            >
              Actual qty:
               
            </div>
            <div
              class="sc-bMVAic gmHHif"
            >
              55.55
            </div>
          </div>
          <div
            class="sc-hORach gtKEVB"
          >
            <div
              class="sc-bAeIUo fMAOJA"
            >
              Price XEC:
               
            </div>
            <div
              class="sc-bMVAic gmHHif"
            >
              666,636.8 XEC
            </div>
          </div>
          <div
            class="sc-hORach gtKEVB"
          >
            <div
              class="sc-bAeIUo fMAOJA"
            >
              Price
               
              USD
              :
               
            </div>
            <div
              class="sc-bMVAic gmHHif"
            >
              $20.00 USD
            </div>
          </div>
          <div
            class="sc-hORach gtKEVB"
          >
            <div
              class="sc-eerKOB fBIFrm"
            >
              This offer is
               
              9.0004
              % above spot
            </div>
          </div>
          <div
            class="sc-iAyFgw frsajd"
          >
            Cashtab does not support buying offers above spot.
          </div>
        </div>
      </div>
      <div
        class="sc-gipzik iYsHQe"
      >
        <button
          class="sc-csuQGl sc-Rmtcm iTahgD"
          disabled=""
        >
          OK
        </button>
        <button
          class="sc-csuQGl sc-bRBYWo eDDpPR"
        >
          Cancel
        </button>
      </div>
    </div>
    <div
      class="sc-jhAzac gewYLf"
    />
    <div
      class="sc-exAgwC ddRUma"
    >
      <div
        class="sc-cQFLBn kypZyy"
      >
        <button
          aria-label="View larger icon for Cachet"
          class="sc-daURTG fPWbQp"
          size="64"
          title="aed861a31b96934b88c0252ede135cb9700d7649f69191235087a3030e553cb1"
        />
        <div
          class="sc-gojNiO ilHQCd"
        >
          <a
            href="#/token/aed861a31b96934b88c0252ede135cb9700d7649f69191235087a3030e553cb1"
          >
            Cachet
             (CACHET)
          </a>
          <div
            class="sc-jAaTju eAHIQS"
          >
            aed
            ...
            cb1
            <button
              aria-label="Copy Token ID"
              class="sc-kGXeez fWkUYs"
            >
              <svg
                title="copy-paste"
              />
            </button>
          </div>
          <div
            class="sc-jwKygS heRPdH"
          >
            <div
              class="sc-btzYZH ehlgNP"
            >
              <input
                class="sc-jtRfpW imHqoI"
                id="Toggle price for aed861a31b96934b88c0252ede135cb9700d7649f69191235087a3030e553cb1"
                name="Toggle price for aed861a31b96934b88c0252ede135cb9700d7649f69191235087a3030e553cb1"
                title="Toggle price for aed861a31b96934b88c0252ede135cb9700d7649f69191235087a3030e553cb1"
                type="checkbox"
              />
              <label
                class="sc-lhVmIH caWsiU"
                for="Toggle price for aed861a31b96934b88c0252ede135cb9700d7649f69191235087a3030e553cb1"
              >
                <span
                  class="sc-bYSBpT dLassW"
                  data-off="XEC"
                  data-on="usd"
                />
                <span
                  class="sc-elJkPf cgAGSi"
                />
              </label>
            </div>
          </div>
        </div>
      </div>
      <div
        class="sc-bXGyLb BQzWg"
      >
        <div
          class="sc-lkqHmb huZDAu"
        >
          <button
            class="sc-eLExRp faQCXg"
          >
            <div
              class="sc-krvtoX bmBvvu"
            />
            <div
              class="sc-cbkKFq euhrBi"
            >
              $0.03600 USD
            </div>
          </button>
          <button
            class="sc-eLExRp faQCXg"
          >
            <div
              class="sc-krvtoX enwGeT"
            />
            <div
              class="sc-cbkKFq euhrBi"
            >
              $0.3000 USD
            </div>
          </button>
          <button
            class="sc-eLExRp fLqsTw"
          >
            <div
              class="sc-krvtoX dmFTyi"
            />
            <div
              class="sc-fYiAbW ggDOwK"
            />
            <div
              class="sc-cbkKFq euhrBi"
            >
              $0.3600 USD
            </div>
          </button>
        </div>
        <div
          class="sc-fOKMvo efpinN"
        >
          <span>
            Buy
          </span>
          <div
            class="sc-dVhcbM jfavMR"
          >
            <input
              aria-labelledby="Select buy qty aed861a31b96934b88c0252ede135cb9700d7649f69191235087a3030e553cb1"
              class="sc-bbmXgH fZGsZp"
              max="300.00"
              min=".30"
              name="Select buy qty aed861a31b96934b88c0252ede135cb9700d7649f69191235087a3030e553cb1"
              step="0.01"
              type="range"
              value="55.55"
            />
            <div
              class="sc-fYxtnH eXvWCD"
            >
              <input
                class="sc-gGBfsJ bdyaWr"
                name="Select buy qty aed861a31b96934b88c0252ede135cb9700d7649f69191235087a3030e553cb1-typed"
                placeholder="Select buy qty aed861a31b96934b88c0252ede135cb9700d7649f69191235087a3030e553cb1"
                value="55.55"
              />
            </div>
            <div
              class="sc-kvZOFW doyTlY"
            />
          </div>
        </div>
        <div
          class="sc-dUjcNx koWWgJ"
        >
          <div>
            55.55
             
            CACHET
          </div>
          <h3>
            $20.00 USD
          </h3>
          <button
            class="sc-fjdhpX sc-cSHVUG gODvHf"
          >
            Buy 
            Cachet
             (CACHET)
          </button>
        </div>
      </div>
    </div>
  </div>
</body>
    at waitForWrapper (/work/cashtab/node_modules/@testing-library/dom/dist/wait-for.js:163:27)
    at /work/cashtab/node_modules/@testing-library/dom/dist/query-helpers.js:86:33
    at Object.findByText (/work/cashtab/src/components/Agora/OrderBook/__tests__/index.test.js:618:26)
====== CashTab Unit Tests: <Agora /> We can buy an offer ======
Error: Unable to find an element with the text: Bought .30 Cachet (CACHET) for 3,601.92 XEC ($0.1081 USD). This could be because the text is broken up by multiple elements. In this case, you can provide a function for your text matcher to make your matcher more flexible.

Ignored nodes: comments, script, style
<body>
  <div>
    <div
      class="sc-eitiEO jtKsEs"
    >
      <div
        class="Toastify"
      />
      <div
        class="sc-bhlBdH kUtPuC"
      >
        <div
          class="sc-AnqlK jwdJGM"
        >
          <div
            class="sc-hycgNl fMlaSZ"
          >
            <img
              alt="cashtab"
              class="sc-chAAoq dvNFPG"
              src="test-file-stub"
            />
          </div>
          <div
            class="sc-cCbXAZ hWVbsV"
          >
            <div
              class="sc-gGCbJM jirjPV"
            >
              <select
                class="sc-lcpuFF ixVLGq"
                data-testid="wallet-select"
                id="wallets"
                name="wallets"
              >
                <option
                  class="sc-bqjOQT hQomri"
                  value="Agora Partial Alpha"
                >
                  Agora Partial Alpha
                </option>
                <option
                  class="sc-bqjOQT hQomri"
                  value="Agora Partial Beta"
                >
                  Agora Partial Beta
                </option>
              </select>
              <div
                class="sc-ciodno khxwxx"
              >
                <button
                  aria-label="Copy ecash:qqpmsv8yh8wwx3lnf92rrc0e6yq97j6zqs8av8vx8h"
                  class="sc-kgAjT dOXpmg"
                >
                  <svg
                    title="copy-paste"
                  />
                </button>
                <div
                  class="sc-eilVRo kNDvpj"
                >
                  <div
                    class="sc-eerKOB VCLyQ"
                  >
                    <input
                      checked=""
                      class="sc-bnXvFD clpqCe"
                      id="show-hide-balance"
                      name="show-hide-balance"
                      title="show-hide-balance"
                      type="checkbox"
                    />
                    <label
                      class="sc-emmjRN bKoUpK"
                      for="show-hide-balance"
                    >
                      <span
                        class="sc-cpmLhU prmji"
                        data-off=""
                        data-on=""
                      />
                      <span
                        class="sc-dymIpo kCLFY"
                      />
                    </label>
                  </div>
                </div>
              </div>
            </div>
            <div
              class="sc-fHSTwm exyNVL"
              title="Wallet Info"
            >
              <div
                class="sc-jkCMRl bMctXd"
                title="Balance in XEC"
              >
                4,200.00
                 
                XEC
                 
              </div>
              <div
                class="sc-crNyjn hVKMSK"
                title="Balance in Local Currency"
              >
                $
                0.13
                 
                USD
              </div>
              <p
                class="sc-cpHetk cyTyLD"
                title="Price in Local Currency"
              >
                1 
                XEC
                 = 
                0.00003000
                 
                USD
              </p>
            </div>
          </div>
          <div
            class="sc-jvEmr ePAtrN"
          >
            <h2
              class="sc-tilXH fKCONc"
            >
              Agora 
              <svg
                title="Meme Agora"
              />
            </h2>
            <div
              class="sc-dEfkYy goEHKM"
              title="Active Offers"
            >
              <div
                class="sc-bmyXtO iISewh"
              >
                <div
                  class="sc-eilVRo kNDvpj"
                >
                  <div
                    class="sc-eerKOB eKNDhC"
                  >
                    <input
                      class="sc-bnXvFD clpqCe"
                      id="Toggle Active Offers"
                      name="Toggle Active Offers"
                      title="Toggle Active Offers"
                      type="checkbox"
                    />
                    <label
                      class="sc-emmjRN bKoUpK"
                      for="Toggle Active Offers"
                    >
                      <span
                        class="sc-cpmLhU bOTgFW"
                        data-off=""
                        data-on=""
                      />
                      <span
                        class="sc-dymIpo bAUpOn"
                      />
                    </label>
                  [...
    at waitForWrapper (/work/cashtab/node_modules/@testing-library/dom/dist/wait-for.js:163:27)
    at /work/cashtab/node_modules/@testing-library/dom/dist/query-helpers.js:86:33
    at Object.findByText (/work/cashtab/src/components/Agora/__tests__/index.test.js:863:26)
====== CashTab Unit Tests: <Agora /> We get expected error if we try to buy an offer we cannot afford ======
Error: Unable to find an element with the text: Error: Insufficient utxos to accept this offer. This could be because the text is broken up by multiple elements. In this case, you can provide a function for your text matcher to make your matcher more flexible.

Ignored nodes: comments, script, style
<body>
  <div>
    <div
      class="sc-eitiEO jtKsEs"
    >
      <div
        class="Toastify"
      />
      <div
        class="sc-bhlBdH kUtPuC"
      >
        <div
          class="sc-AnqlK jwdJGM"
        >
          <div
            class="sc-hycgNl fMlaSZ"
          >
            <img
              alt="cashtab"
              class="sc-chAAoq dvNFPG"
              src="test-file-stub"
            />
          </div>
          <div
            class="sc-cCbXAZ hWVbsV"
          >
            <div
              class="sc-gGCbJM jirjPV"
            >
              <select
                class="sc-lcpuFF ixVLGq"
                data-testid="wallet-select"
                id="wallets"
                name="wallets"
              >
                <option
                  class="sc-bqjOQT hQomri"
                  value="Agora Partial Alpha"
                >
                  Agora Partial Alpha
                </option>
                <option
                  class="sc-bqjOQT hQomri"
                  value="Agora Partial Beta"
                >
                  Agora Partial Beta
                </option>
              </select>
              <div
                class="sc-ciodno khxwxx"
              >
                <button
                  aria-label="Copy ecash:qqpmsv8yh8wwx3lnf92rrc0e6yq97j6zqs8av8vx8h"
                  class="sc-kgAjT dOXpmg"
                >
                  <svg
                    title="copy-paste"
                  />
                </button>
                <div
                  class="sc-eilVRo kNDvpj"
                >
                  <div
                    class="sc-eerKOB VCLyQ"
                  >
                    <input
                      checked=""
                      class="sc-bnXvFD clpqCe"
                      id="show-hide-balance"
                      name="show-hide-balance"
                      title="show-hide-balance"
                      type="checkbox"
                    />
                    <label
                      class="sc-emmjRN bKoUpK"
                      for="show-hide-balance"
                    >
                      <span
                        class="sc-cpmLhU prmji"
                        data-off=""
                        data-on=""
                      />
                      <span
                        class="sc-dymIpo kCLFY"
                      />
                    </label>
                  </div>
                </div>
              </div>
            </div>
            <div
              class="sc-fHSTwm exyNVL"
              title="Wallet Info"
            >
              <div
                class="sc-jkCMRl bMctXd"
                title="Balance in XEC"
              >
                0.00
                 
                XEC
                 
              </div>
              <div
                class="sc-crNyjn hVKMSK"
                title="Balance in Local Currency"
              >
                $
                0.00
                 
                USD
              </div>
              <p
                class="sc-cpHetk cyTyLD"
                title="Price in Local Currency"
              >
                1 
                XEC
                 = 
                0.00003000
                 
                USD
              </p>
            </div>
          </div>
          <div
            class="sc-jvEmr ePAtrN"
          >
            <h2
              class="sc-tilXH fKCONc"
            >
              Agora 
              <svg
                title="Meme Agora"
              />
            </h2>
            <div
              class="sc-dEfkYy goEHKM"
              title="Active Offers"
            >
              <div
                class="sc-bmyXtO iISewh"
              >
                <div
                  class="sc-eilVRo kNDvpj"
                >
                  <div
                    class="sc-eerKOB eKNDhC"
                  >
                    <input
                      class="sc-bnXvFD clpqCe"
                      id="Toggle Active Offers"
                      name="Toggle Active Offers"
                      title="Toggle Active Offers"
                      type="checkbox"
                    />
                    <label
                      class="sc-emmjRN bKoUpK"
                      for="Toggle Active Offers"
                    >
                      <span
                        class="sc-cpmLhU bOTgFW"
                        data-off=""
                        data-on=""
                      />
                      <span
                        class="sc-dymIpo bAUpOn"
                      />
                    </label>
                  <...
    at waitForWrapper (/work/cashtab/node_modules/@testing-library/dom/dist/wait-for.js:163:27)
    at /work/cashtab/node_modules/@testing-library/dom/dist/query-helpers.js:86:33
    at Object.findByText (/work/cashtab/src/components/Agora/__tests__/index.test.js:1028:26)

Each failure log is accessible here:
CashTab Unit Tests: <OrderBook /> We can buy an offer
CashTab Unit Tests: <Agora /> We can buy an offer
CashTab Unit Tests: <Agora /> We get expected error if we try to buy an offer we cannot afford

patch bug in getting fuel inputs, update tests, better formatting of delta from spot

back out unrelated changes, improve formatting of spot price delta with dedicated function and tests

bytesofman published this revision for review.Sun, Jan 5, 23:52
bytesofman added inline comments.
cashtab/src/components/Agora/OrderBook/__tests__/index.test.js
482 ↗(On Diff #51969)

somewhat useful though also annoying -- this test was buying an offer above spot. we can't do that now. so we need to buy the spot offer.

cashtab/src/components/Agora/OrderBook/index.tsx
851 ↗(On Diff #51969)

implementation is all in this modal

we disable the "ok" button if the price of this offer is above spot

this means the user can preview the buy, but buying is disabled, and we show them a msg for why

because only the "buy" modal is impacted, users can still cancel any offer they created

cashtab/src/components/Agora/__tests__/index.test.js
691 ↗(On Diff #51969)

this was duplicating the test in OrderBook, which is where it should be tested. Duplicated because agora tests are older than OrderBook.

No point in refactoring this test in two places

871 ↗(On Diff #51969)

this was buying a non-spot offer, so had to be refactored

cashtab/src/components/Common/Atoms.tsx
74 ↗(On Diff #51969)

we break all by default as this component often shows addresses or other stuff that must wrap

but for this diff, we have a case where we do not want to break normal words, hardcoded with no params

cashtab/src/components/Common/Modal.tsx
134 ↗(On Diff #51969)

I didn't realize we already had disabled supported here so went about converting to ts

no point in backing out this conversion, we do use the modified modal in this diff

emack requested changes to this revision.Mon, Jan 6, 01:48
emack added a subscriber: emack.
emack added inline comments.
cashtab/src/components/Agora/OrderBook/index.tsx
853–854 ↗(On Diff #51970)

so it's not even a threshold anymore? In which case it's more an enforced market buy rather than spot, the spot terminology may need to be adjusted.

what if the liquidity at the spot price can only cover 50% of the user's purchase quantity? wouldn't that need to purchase the balance quantity at above spot?

This revision now requires changes to proceed.Mon, Jan 6, 01:48
bytesofman marked an inline comment as done.
bytesofman added inline comments.
cashtab/src/components/Agora/OrderBook/index.tsx
853–854 ↗(On Diff #51970)

yes.

the ultimate plan is to completely duplicate exchange experience, i.e. you can slide to the full amount offered, and this will build a tx accepting all the partials of your order (mb, say, 3 full offers, and then half of another one).

This will take some more thought and more work in the libs though. It's not a trivial implementation.

I was not planning to do this kind of "enforce spot" -- though it is an important first step in our ultimate UX goal. However we are seeing users buy the wrong offers by mistake and then get upset about it. We are also seeing on many (most?) agora listings people creating ridiculous "Hail mary" offers, sometimes asking for more than the total supply of all eCash.

imo fixing the incentives to correct these problems is more important than the inconvenience this might impose on people who want to buy above spot.

If someone really wants to buy the more expensive offers (and not the less expensive offers0 they are available on the blockchain. I'm not sure what the use case is though.

what if the liquidity at the spot price can only cover 50% of the user's purchase quantity?

buy the spot then buy the next one. tx fees are basically zero, so I don't see this as some kind of major UX downgrade. For the UX we are going for, this is what will happen behind the scenes anyway.

people can still make sell orders above spot, so the "limit order" ux is the same.

I don't think it's possible to buy "only above spot" and not spot on any crypto exchange. No need to support that in Cashtab, esp given the behavior it is causing.

This revision is now accepted and ready to land.Mon, Jan 6, 03:46
This revision was automatically updated to reflect the committed changes.
bytesofman marked an inline comment as done.

If it is for newbies, I would suggest to say "market rate" instead of "spot" because that's trader talk. Or maybe spot price at least. Also I would add "Recommended to chose cheaper offers instead".