Skip to main content

Now, from the previous tutorial we have created a simple app data document. We will now use this document to create an order.

In doing so, we will be making use of:

Instantiate the SDK

We will start from the basic setup from the submit order tutorial and the simple app data tutorial. This has been populated in the code editor for you.

Quoting with app data

The keen eye-ed among you will notice that appDataHex and appDataContent are not used. Let's fix that. When we request a quote, we will pass appDataHex and appDataContent to the API. This allows the API to:

  • validate the app data document and its hash (appDataHex)
  • wrap the app data into the response object
  • determine any additional fees that may be required (if the app data document contains hooks)
run.ts
// ...
export async function run(provider: Web3Provider): Promise<unknown> {
	// ...

	const quoteRequest: OrderQuoteRequest = {
		sellToken,
		buyToken,
		from: ownerAddress,
		receiver: ownerAddress,
		sellAmountBeforeFee: sellAmount,
		kind: OrderQuoteSideKindSell.SELL,
		appData: appDataContent,
		appDataHash: appDataHex,
	};

	// ...
}

Signing with app data

When signing an order, we need to make sure that we have set the appData correctly. In this case, the UnsignedOrder used by the OrderSigningUtils class has an appData field which should be set to the appDataHex value.

run.ts
// ...
export async function run(provider: Web3Provider): Promise<unknown> {
	// ...
	const order: UnsignedOrder = {
		...quote,
		receiver: ownerAddress,
		appData: appDataHex,
	}
	// ...
}

Run the code

To run the code, we can press the "Run" button in the bottom right panel (the web container).

When running the script, we may be asked to connect a wallet. We can use Rabby for this.

  1. Accept the connection request in Rabby
  2. Press the "Run" button again
  3. Observe the orderId returned to the output panel

You can now use the orderId to check the status of the order on CoW Explorer. Within the order details page, you can also see the app data document that was used to create the order.

Errors

The usual API errors from the submit order tutorial may occur. In addition, the following errors may occur:

  • InvalidAppData: The app data passed to the API is not either bytes32 or a stringified JSON object.
  • AppDataHashMismatch: The hash of the app data document doesn't match the appDataHash field provided in the order. This may be due to the app data document being modified after the order was signed.

Next: Upload to the API

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
import type { Web3Provider } from '@ethersproject/providers'
import {
  OrderBookApi,
  SupportedChainId,
  OrderQuoteRequest,
  OrderQuoteSideKindSell,
  OrderSigningUtils,
  UnsignedOrder,
  SigningScheme
} from '@cowprotocol/cow-sdk'
import { MetadataApi, latest } from '@cowprotocol/app-data'
 
export async function run(provider: Web3Provider): Promise<unknown> {
  const chainId = +(await provider.send('eth_chainId', []));
  if (chainId !== SupportedChainId.GNOSIS_CHAIN) {
    throw new Error(`Please connect to the Gnosis chain. ChainId: ${chainId}`);
  }
 
  const orderBookApi = new OrderBookApi({ chainId: SupportedChainId.GNOSIS_CHAIN });
  const metadataApi = new MetadataApi()
 
  const appCode = 'Decentralized CoW'
  const environment = 'production'
  const referrer = { address: `0xcA771eda0c70aA7d053aB1B25004559B918FE662` }
 
  const quoteAppDoc: latest.Quote = { slippageBips: '50' }
  const orderClass: latest.OrderClass = { orderClass: 'market' }
 
  const appDataDoc = await metadataApi.generateAppDataDoc({
    appCode,
    environment,
    metadata: {
      referrer,
      quote: quoteAppDoc,
      orderClass
    },
  })
 
  const { appDataHex, appDataContent } = await metadataApi.appDataToCid(appDataDoc)
 
  const signer = provider.getSigner();
  const ownerAddress = await signer.getAddress();
 
  const sellToken = '0xe91d153e0b41518a2ce8dd3d7944fa863463a97d'; // wxDAI
  const buyToken = '0x177127622c4A00F3d409B75571e12cB3c8973d3c'; // COW
  const sellAmount = '1000000000000000000'; // 1 wxDAI
 
  const quoteRequest: OrderQuoteRequest = {
    sellToken,
    buyToken,
    from: ownerAddress,
    receiver: ownerAddress,
    sellAmountBeforeFee: sellAmount,
    kind: OrderQuoteSideKindSell.SELL,
  };
 
  const { quote } = await orderBookApi.getQuote(quoteRequest);
 
  const order: UnsignedOrder = {
    ...quote,
    receiver: ownerAddress,
  }
 
  const orderSigningResult = await OrderSigningUtils.signOrder(
    order,
    chainId,
    signer
  )
 
  try {
    const orderId = await orderBookApi.sendOrder({
      ...quote,
      ...orderSigningResult,
      signingScheme: orderSigningResult.signingScheme as unknown as SigningScheme
    })
 
    return {
      orderId,
    }
  } catch (e) {
    return e
  }
}
 
initialising