Here we will build on the previous tutorial and sign the quote we got from the quote tutorial, so that we can place an order on CoW Protocol.
Intents and signatures
CoW Protocol uses intents to represent orders. An intent is a signed message. Most intents are signed using the EIP-712 signing scheme, and this is what we will use in this tutorial.
Signing an order
In the previous tutorial, we received an OrderQuoteResponse
object. This object contains all the data that we need to sign an order.
Types and utilities
For signing, we will use the UnsignedOrder
type from the SDK
, along with the OrderSigningUtils
utility.
import type { Web3Provider } from '@ethersproject/providers';
import { OrderBookApi, SupportedChainId, OrderQuoteRequest, OrderQuoteSideKindSell, OrderSigningUtils, UnsignedOrder } from '@cowprotocol/cow-sdk';
import { BigNumber } from 'ethers';
export async function run(provider: Web3Provider): Promise<unknown> {
// ...
const order: UnsignedOrder = {
...quote,
sellAmount: BigNumber.from(quote.sellAmount).add(BigNumber.from(quote.feeAmount)).toString(), // Quoted sellAmount must be added to quoted feeAmount
feeAmount: '0', // and feeAmount must be set to 0
receiver: ownerAddress, // required due type mismatch
}
}
The
OrderQuoteResponse
type contains areceiver
field, however the type of this field is not compatible with theUnsignedOrder
type. This is why we need to override thereceiver
field with theownerAddress
(which is the address of the wallet we are using).
Sign the order
Now that we have the UnsignedOrder
, we can sign it:
import type { Web3Provider } from '@ethersproject/providers';
import { OrderBookApi, SupportedChainId, OrderQuoteRequest, OrderQuoteSideKindSell, OrderSigningUtils, UnsignedOrder } from '@cowprotocol/cow-sdk';
export async function run(provider: Web3Provider): Promise<unknown> {
// ...
return OrderSigningUtils.signOrder(order, chainId, signer);
}
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.
- Accept the connection request in Rabby
- Press the "Run" button again
- Observe the
SigningResult
object returned to the output panel
An example signing result should look like:
{
"signature": "0x98ac143acad82e3908489ac8ca3f908cb49b0a861f15a51fc0a79bdea6dcca0212403f419ed8b022881a7cecf7358a69c2cfa9596e877fc67bea5be6d9981cf51b",
"signingScheme": "eip712"
}
In the above case, we can see the signature
returned is the ECDSA
signature of the EIP-712
hash of the UnsignedOrder
. Now this can be used to place an order on CoW Protocol.
import type { Web3Provider } from '@ethersproject/providers'
import { OrderBookApi, SupportedChainId, OrderQuoteRequest, OrderQuoteSideKindSell } from '@cowprotocol/cow-sdk'
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 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);
return quote
}