aboutsummaryrefslogtreecommitdiffstats
path: root/packages/contracts/util/order.ts
blob: 635999348e52b8204fab113738045a0958a2f6a4 (plain) (blame)
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
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
import {BigNumber} from 'bignumber.js';
import promisify = require('es6-promisify');
import ethUtil = require('ethereumjs-util');
import * as _ from 'lodash';
import Web3 = require('web3');

import {crypto} from './crypto';
import {OrderParams} from './types';

// In order to benefit from type-safety, we re-assign the global web3 instance injected by Truffle
// with type `any` to a variable of type `Web3`.
const web3: Web3 = (global as any).web3;

export class Order {
  public params: OrderParams;
  constructor(params: OrderParams) {
    this.params = params;
  }
  public isValidSignature() {
    const {v, r, s} = this.params;
    if (_.isUndefined(v) || _.isUndefined(r) || _.isUndefined(s)) {
      throw new Error('Cannot call isValidSignature on unsigned order');
    }
    const orderHash = this.getOrderHash();
    const msgHash = ethUtil.hashPersonalMessage(ethUtil.toBuffer(orderHash));
    try {
      const pubKey = ethUtil.ecrecover(msgHash, v, ethUtil.toBuffer(r), ethUtil.toBuffer(s));
      const recoveredAddress = ethUtil.bufferToHex(ethUtil.pubToAddress(pubKey));
      return recoveredAddress === this.params.maker;
    } catch (err) {
      return false;
    }
  }
  public async signAsync() {
    const orderHash = this.getOrderHash();
    const signature = await promisify(web3.eth.sign)(this.params.maker, orderHash);
    const {v, r, s} = ethUtil.fromRpcSig(signature);
    this.params = _.assign(this.params, {
      orderHashHex: orderHash,
      v,
      r: ethUtil.bufferToHex(r),
      s: ethUtil.bufferToHex(s),
    });
  }
  public createFill(shouldThrowOnInsufficientBalanceOrAllowance?: boolean, fillTakerTokenAmount?: BigNumber) {
    const fill = {
      orderAddresses: [
        this.params.maker,
        this.params.taker,
        this.params.makerToken,
        this.params.takerToken,
        this.params.feeRecipient,
      ],
      orderValues: [
        this.params.makerTokenAmount,
        this.params.takerTokenAmount,
        this.params.makerFee,
        this.params.takerFee,
        this.params.expirationTimestampInSec,
        this.params.salt,
      ],
      fillTakerTokenAmount: fillTakerTokenAmount || this.params.takerTokenAmount,
      shouldThrowOnInsufficientBalanceOrAllowance: !!shouldThrowOnInsufficientBalanceOrAllowance,
      v: this.params.v,
      r: this.params.r,
      s: this.params.s,
    };
    return fill;
  }
  public createCancel(cancelTakerTokenAmount?: BigNumber) {
    const cancel = {
      orderAddresses: [
        this.params.maker,
        this.params.taker,
        this.params.makerToken,
        this.params.takerToken,
        this.params.feeRecipient,
      ],
      orderValues: [
        this.params.makerTokenAmount,
        this.params.takerTokenAmount,
        this.params.makerFee,
        this.params.takerFee,
        this.params.expirationTimestampInSec,
        this.params.salt,
      ],
      cancelTakerTokenAmount: cancelTakerTokenAmount || this.params.takerTokenAmount,
    };
    return cancel;
  }
  private getOrderHash(): string {
    const orderHash = crypto.solSHA3([
      this.params.exchangeContractAddress,
      this.params.maker,
      this.params.taker,
      this.params.makerToken,
      this.params.takerToken,
      this.params.feeRecipient,
      this.params.makerTokenAmount,
      this.params.takerTokenAmount,
      this.params.makerFee,
      this.params.takerFee,
      this.params.expirationTimestampInSec,
      this.params.salt,
    ]);
    const orderHashHex = ethUtil.bufferToHex(orderHash);
    return orderHashHex;
  }
}