Code Monkey home page Code Monkey logo

simple-exchange's Introduction

SimpleExchange dApp

Description

The SimpleExchange contract was written with simplicity in mind. It allows the exchange of two predefined assets, and it holds an order book which is filled when users make an offer, describing what asset they give and what asset they want in return. As soon as a user creates an offer that matches one of the existing ones, the contract will execute the exchange and the counterparts will receive their desired assets.

Documentation

You can find a detailed description of the SimpleExchange contract in the components page, as well as a guide on how to interact, test and deploy the contract in the tutorial page.
For the contracts and tests we included in-line comments to facilitate the understatement of the logic implemented and methods used.

Repository Contents

  • Contracts:
    • Basic version
    • Upgradable version
  • Tests:
    • Unit tests (both versions)
    • Integration tests
    • Swingset tests
    • Smoke tests
    • testing helpers
  • Core-eval proposals
  • Documentation
    • Component
    • Tutorial
  • UI

Community

Any feedback is welcome, so feel free to share your ideas or improvements, by opening an issue or pull request.

simple-exchange's People

Contributors

jorge-lopes avatar grigorigrigoryanbytepitch avatar alexanderem49 avatar anilhelvaci avatar

Watchers

 avatar

Forkers

jorge-lopes

simple-exchange's Issues

Display Orders

image
  • Can we align "No Data" card with the "Order Book"
  • We should use useState( state => state.XX) inside components => getDisplayInfo - Trade.jsx
  • I think only Give and Want is enough for the table column headers instead of Give (Value - Brand) and Want (Value - Brand) => renderTableContent

Integration test failure

The integration test is failing with error Promise returned by test never resolved

yarn run v1.22.5
$ cd contract && yarn test test/integrationTests
$ ava --verbose test/integrationTests

Removing intrinsics.Symbol.dispose
Removing intrinsics.Symbol.asyncDispose
[bundleTool] bundles/ bundle-walletFactory.js valid: 148 files bundled at 2023-10-26T09:03:15.545Z 
----- WltFct.4  2 makeAssetRegistry Object [Alleged: Bank] {}
  ✖ test make sell offer Promise returned by test never resolved
  ─

  test make sell offer

  Error: Promise returned by test never resolved
    at process.emit (node:events:517:28)

  ─

  1 test failed
error Command failed with exit code 1.
info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.
error Command failed with exit code 1.
info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.

Debugging shows that error happens at this line, inside setupFakeAgoricNamesWithAssets function.

Constant agoricNamesAdmin at this line is a promise in pending state. Awaiting this promise immediately throws an error, seems like this is the promise that never resolves

Inside setupFakeAgoricNamesWithAssets it fails when awaiting Promise.all with 2 promises inside.

Smoke tests error: Cannot initialize @agoric/assert

When the offer build script imports import { AmountMath } from '@agoric/ertp'; it will trigger the following error:
Cannot initialize @agoric/assert, missing globalThis.assert methods Fail

Complete error message:

jorgelopes@Jorges-MBP smokeTests % ./buyOffer.sh
(Error#1)
Error#1: Cannot initialize @agoric/assert, missing globalThis.assert methods Fail

  at packages/assert/src/assert.js:48:9
  at async Promise.all (index 0)

Executing  [
  '--node=http://0.0.0.0:26657',
  '--chain-id=agoriclocal',
  '--keyring-backend=test',
  '--from=agoric1dvk4vr2ss65zcls9qdf0ntcaaaunw3cyn6l8e8',
  'tx',
  'swingset',
  'wallet-action',
  '--allow-spend',
  '',
  '--yes'
]
Error: Spend action cannot be empty: unknown request
Usage:
  agd tx swingset wallet-action [json string] [flags]

Flags:
  -a, --account-number uint      The account number of the signing account (offline mode only)
      --allow-spend              Allow the WalletAction to spend assets
  -b, --broadcast-mode string    Transaction broadcasting mode (sync|async|block) (default "sync")
      --dry-run                  ignore the --gas flag and perform a simulation of a transaction, but don't broadcast it (when enabled, the local Keybase is not accessible)
      --fee-account string       Fee account pays fees for the transaction instead of deducting from the signer
      --fees string              Fees to pay along with transaction; eg: 10uatom
      --from string              Name or address of private key with which to sign
      --gas string               gas limit to set per-transaction; set to "auto" to calculate sufficient gas automatically (default 200000)
      --gas-adjustment float     adjustment factor to be multiplied against the estimate returned by the tx simulation; if the gas limit is set manually this flag is ignored  (default 1)
      --gas-prices string        Gas prices in decimal format to determine the transaction fee (e.g. 0.1uatom)
      --generate-only            Build an unsigned transaction and write it to STDOUT (when enabled, the local Keybase is not accessible)
  -h, --help                     help for wallet-action
      --keyring-backend string   Select keyring's backend (os|file|kwallet|pass|test|memory) (default "os")
      --keyring-dir string       The client Keyring directory; if omitted, the default 'home' directory will be used
      --ledger                   Use a connected Ledger device
      --node string              <host>:<port> to tendermint rpc interface for this chain (default "tcp://localhost:26657")
      --note string              Note to add a description to the transaction (previously --memo)
      --offline                  Offline mode (does not allow any online functionality
  -o, --output string            Output format (text|json) (default "json")
  -s, --sequence uint            The sequence number of the signing account (offline mode only)
      --sign-mode string         Choose sign mode (direct|amino-json), this is an advanced feature
      --timeout-height uint      Set a block timeout height to prevent the tx from being committed past a certain height
  -y, --yes                      Skip tx broadcasting prompt confirmation

Global Flags:
      --chain-id string     The network chain ID
      --home string         directory for config and data (default "/Users/jorgelopes/.agoric")
      --log_format string   The logging format (json|plain) (default "plain")
      --log_level string    The logging level (trace|debug|info|warn|error|fatal|panic) (default "info")
      --trace               print out full stack trace on errors

agoric: (Error#1)
Error#1: Command failed: agd --node=http://0.0.0.0:26657 --chain-id=agoriclocal --keyring-backend=test --from=agoric1dvk4vr2ss65zcls9qdf0ntcaaaunw3cyn6l8e8 tx swingset wallet-action --allow-spend  --yes

  at checkExecSyncError (node:child_process:861:11)
  at execFileSync (node:child_process:896:15)
  at execSwingsetTransaction (packages/agoric-cli/src/lib/chain.js:78:12)
  at Command.<anonymous> (packages/agoric-cli/src/commands/wallet.js:125:7)
  at main (packages/agoric-cli/src/main.js:400:19)

Issue related to 'makeAgoricWalletConnection'

Context

When running the UI, no error is triggered in the console after executing yarn run dev but the browser window stays empty with the following error being printed in the browser console:

NavBar.jsx:3 Uncaught SyntaxError: The requested module '/@fs/Users/jorgelopes/Documents/GitHub/Agoric/agoric-sdk/packages/web-components/index.js' does not provide an export named 'makeAgoricWalletConnection' (at NavBar.jsx:3:10)

On the Agoric client terminal, the following message was logged:

outbound: eek, no delivery method for target 5b65c040719bf5385448437e9e65e12c6fc5e3260db12527cd687326156076e8

Displaying an Agoric Amount Correctly

Context

The UI component that handles sending offers to the contract must work as a bridge between human readable input values and Agoric amounts. For that @agoric/ui-kit has two complementary methods that handles this problem:

Problem

These two methods above need the displayInfo whichever amount they're displaying/parsing at any point in time. This displayInfo has the following properties;

  • AssetKind = nat or set
  • decimalPlaces = {number}

We need a dynamic way to keep track of these information in our UI app.

Solution

vstorage has this information in three separate paths;

  • boardAux
  • vbankAsset
  • vbankPurses

For the purposes of this project vbankAsset is the easiest place to fetch displayInfo when the ease of creating testing environment is considered.

Storage Watcher

storageWatcher works with paths to indicate the location of the required data. For the current problem at hand, here's the path to fetch vbankAsset data:

published.agoricNames.vbankAsset 

Remember that we're interested in the actual data and not child nodes of the path specified. So the method to add in the storageWatcher.js would look like this:

const watchVbankAsset = () => {
        watcher.watchLatest(
            [AgoricChainStoragePathKind.Data, 'published.agoricNames.vbankAsset'],
            vbankAssets => {
                console.log('VBankAsset Update', vbankAssets);
                // Call your zustand parser method here
            }
        );
    };

Using displayInfo in the store

Now that we've the displayInfo in the zustand, it's time to use it in our UI components. here are some key assumptions about consuming displayInfo data;

  • There's a method called getDisplayInfo(amount) that accepts an amount and returns the displayInfo

Here's an example method for displaying an agoric amount

const displayAmount = amount => {
    const { brand, value } = amount;
    const { getDisplayInfo } = useStore.getState();
    const displayInfo = getDisplayInfo(brand);

    if (!displayInfo) return '';

    const { assetKind, decimalPlaces } = displayInfo;
    return stringifyValue(value, assetKind, decimalPlaces);
};

Parsing User Input

When the user types a number in the text field, we should call a method similar to the example below in the onChange(or whatever is fired on user input) callback;

const parseUserInput = (brand, ev, setUserInput) => {
  const { getDisplayInfo } = useStore.getState();
  const displayInfo = getDisplayInfo(brand);
  
  if (!displayInfo) return AmountMath.makeEmpty(brand);

  const { assetKind, decimalPlaces } = displayInfo;
  const str = ev.target?.value
                ?.replace('-', '')
                .replace('e', '')
                .replace('E', '');

  const parsed = parseAsAmount(str, brand, assetKind, decimalPlaces);
  setUserInput(parsed);
};

User flow

Scenarios to describe:

  • Instantiate a new contract
  • Get order books
  • Make sell/buy offer
  • Offer is registered on order book
  • Trade is executed

Terminology

Verify the correct use of the terms order, offer and seat

Smoke tests error: No inbound handler for wallet

Context

When executing one of the smoke tests offer script, the chain logs will output the following error message:
Error#5: No inbound handler for wallet

Full error logs:

2023-10-23T14:36:25.626Z block-manager: block 691 begin
2023-10-23T14:36:25.633Z SwingSet: xsnap: v10: UnhandledPromiseRejectionWarning: (Error#5)
2023-10-23T14:36:25.634Z SwingSet: xsnap: v10: Error#5: No inbound handler for wallet
2023-10-23T14:36:25.634Z SwingSet: xsnap: v10: Error: No inbound handler for (a string)
 at construct ()
 at Error (/bundled-source/.../node_modules/ses/src/error/tame-error-constructor.js:56)
 at makeError (/bundled-source/.../node_modules/ses/src/error/assert.js:243)
 at fail (/bundled-source/.../node_modules/ses/src/error/assert.js:357)
 at baseAssert (/bundled-source/.../node_modules/ses/src/error/assert.js:377)
 at fromBridge (.../vats/src/bridge.js:62)
 at apply ()
 at apply ()
 at In "fromBridge" method of (BridgeScopedManager) (/bundled-source/.../node_modules/@endo/exo/src/exo-tools.js:42)
 at inbound (.../vats/src/bridge.js:151)
 at apply ()
 at apply ()
 at In "inbound" method of (BridgeManagerKit privateInbounder) (/bundled-source/.../node_modules/@endo/exo/src/exo-tools.js:42)
 at apply ()
 at apply ()
 at dispatchToHandler (/bundled-source/.../node_modules/@endo/eventual-send/src/handled-promise.js:163)
 at win (/bundled-source/.../node_modules/@endo/eventual-send/src/handled-promise.js:511)
 at ()

test-upgradableSimpleExchange

The second make sell offer and make buy offer tests are failing

  ─

  make sell offer

  test/test-upgradableSimpleExchange.js:307

   306:   t.deepEqual(buys, [], 'buys list should be empty');
   307:   t.deepEqual(                                       
   308:     sells,                                           

  sells list should NOT be empty

  Difference:

    [
  +   {
  +     give: {
  +       Asset: {
  +         brand: Object @Alleged: moola brand {},
  +         value: 3n,
  +       },
  +     },
  +     want: {
  +       Price: {
  +         brand: Object @Alleged: simoleans brand {},
  +         value: 4n,
  +       },
  +     },
  +   },
    ]

  › file://test/test-upgradableSimpleExchange.js:307:5



  make buy offer

  test/test-upgradableSimpleExchange.js:386

   385:   t.deepEqual(sells, [], 'sells list should be empty');                       
   386:   t.deepEqual(buys, [aliceBuyOrderProposal], 'buys list should NOT be empty');
   387: });                                                                           

  buys list should NOT be empty

  Difference:

    [
  +   {
  +     give: {
  +       Price: {
  +         brand: Object @Alleged: simoleans brand {},
  +         value: 4n,
  +       },
  +     },
  +     want: {
  +       Asset: {
  +         brand: Object @Alleged: moola brand {},
  +         value: 3n,
  +       },
  +     },
  +   },
    ]

  › file://test/test-upgradableSimpleExchange.js:386:5

  ─

Refine Simple Exchange to not clone Agoric SDK

Today [SimpleExchange sample dapp] checks out an Agoric SDK branch to deploy and test their SimpleExchange sample dapp.

Dan and co have successfully created a Game Place Dapp. As shown in the accompanying draft getting started documentation, agoric-sdk packages are installed from NPM (using yarn) rather than by cloning the agoric-sdk repo.

We would like BytePitch to ditch cloning Agoric SDK and instead use the NPM package.

This would create a familiar dev experience from when they test the Game dapp and graduate to SimpleExchange.

Description of the Design
Use the same SimpleExchange but it is deployed and launched on Local Chain in Docker.
Security Considerations
Scaling Considerations
Test Plan

We don't test our NPM packages as much as we would like, so we would love for BytePitch to test creation of smart contracts using these packages and outline what capabilities are hindered as a developer.

Two particularly relevant changes to get the game places dapp to work without cloning and agoric install:

build(contract): update @agoric/* deps to match npm
build(contract): update endo deps to match agoric-sdk
I gather @mhofman has a suggestion to refine these slightly.

cc @michaelfig

Unit tests

  • Refactor unit tests of both contract versions by using the testing tools (setup, assertions and helpers) methods 6cfdc0f
  • Add test that execute offers with non-fungible tokens
  • Fix issue #3
  • Test the scenario where a trade is executed with surplus

Edge cases

Each one of these edge cases should be addressed on an individual unit test

  • Alice makes a sell offer
  • Bob makes a buy offer
  • Alice and Bod make offers that should result in an exchange
  • Bob makes offer with wrong issuers (you need to create a third issuerKit)
  • Bob makes offer with offerProposal missing attribute (try both Asset and Price)
  • Bob makes offer without offerProposal
  • Bob makes offer with null or invalid shapes on the proposals
  • Alice and Bob make exchange that result in excess of either Asset or Price for Bob or Alice (this edge case can be configured for multiple scenarios/tests)
  • Test flows with more than 2 users
  • Test with non-fungible tokens assets

Notes:

  • verify payouts and notifier state updates for each test
  • see test-simpleExchange for more scenarios

Update Documentation

Since the contract to be deployed on Devnet will be the upgradable version, the component page needs to be consistent. This means that we need to update the document.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.