new: users: add getTransferSignature method
MODIFY
package-lock.json
package-lock.json
}
}
},
+ "browserify-sha3": {
+ "version": "0.0.4",
+ "resolved": "https://registry.npmjs.org/browserify-sha3/-/browserify-sha3-0.0.4.tgz",
+ "integrity": "sha1-CGxHuMgjFsnUcCLCYYWVRXbdjiY=",
+ "requires": {
+ "js-sha3": "^0.6.1",
+ "safe-buffer": "^5.1.1"
+ },
+ "dependencies": {
+ "js-sha3": {
+ "version": "0.6.1",
+ "resolved": "https://registry.npmjs.org/js-sha3/-/js-sha3-0.6.1.tgz",
+ "integrity": "sha1-W4n3enR3Z5h39YxKB1JAk0sflcA="
+ }
+ }
+ },
"browserify-sign": {
"version": "4.0.4",
"resolved": "https://registry.npmjs.org/browserify-sign/-/browserify-sign-4.0.4.tgz",
}
}
},
+ "eth-sig-util": {
+ "version": "2.5.3",
+ "resolved": "https://registry.npmjs.org/eth-sig-util/-/eth-sig-util-2.5.3.tgz",
+ "integrity": "sha512-KpXbCKmmBUNUTGh9MRKmNkIPietfhzBqqYqysDavLseIiMUGl95k6UcPEkALAZlj41e9E6yioYXc1PC333RKqw==",
+ "requires": {
+ "buffer": "^5.2.1",
+ "elliptic": "^6.4.0",
+ "ethereumjs-abi": "0.6.5",
+ "ethereumjs-util": "^5.1.1",
+ "tweetnacl": "^1.0.0",
+ "tweetnacl-util": "^0.15.0"
+ },
+ "dependencies": {
+ "bn.js": {
+ "version": "4.11.8",
+ "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.8.tgz",
+ "integrity": "sha512-ItfYfPLkWHUjckQCk8xC+LwxgK8NYcXywGigJgSwOP8Y2iyWT4f2vsZnoOXTTbo+o5yXmIUJ4gn5538SO5S3gA=="
+ },
+ "ethereumjs-abi": {
+ "version": "0.6.5",
+ "resolved": "https://registry.npmjs.org/ethereumjs-abi/-/ethereumjs-abi-0.6.5.tgz",
+ "integrity": "sha1-WmN+8Wq0NHP6cqKa2QhxQFs/UkE=",
+ "requires": {
+ "bn.js": "^4.10.0",
+ "ethereumjs-util": "^4.3.0"
+ },
+ "dependencies": {
+ "ethereumjs-util": {
+ "version": "4.5.0",
+ "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-4.5.0.tgz",
+ "integrity": "sha1-PpQosxfuvaPXJg2FT93alUsfG8Y=",
+ "requires": {
+ "bn.js": "^4.8.0",
+ "create-hash": "^1.1.2",
+ "keccakjs": "^0.2.0",
+ "rlp": "^2.0.0",
+ "secp256k1": "^3.0.1"
+ }
+ }
+ }
+ },
+ "tweetnacl": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-1.0.3.tgz",
+ "integrity": "sha512-6rt+RN7aOi1nGMyC4Xa5DdYiukl2UWCbcJft7YhxReBGQD7OAM8Pbxw6YMo4r2diNEA8FEmu32YOn9rhaiE5yw=="
+ }
+ }
+ },
"ethereum-bloom-filters": {
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/ethereum-bloom-filters/-/ethereum-bloom-filters-1.0.6.tgz",
},
"ansi-regex": {
"version": "2.1.1",
- "bundled": true
+ "bundled": true,
+ "optional": true
},
"aproba": {
"version": "1.2.0",
},
"balanced-match": {
"version": "1.0.0",
- "bundled": true
+ "bundled": true,
+ "optional": true
},
"brace-expansion": {
"version": "1.1.11",
"bundled": true,
+ "optional": true,
"requires": {
"balanced-match": "^1.0.0",
"concat-map": "0.0.1"
},
"code-point-at": {
"version": "1.1.0",
- "bundled": true
+ "bundled": true,
+ "optional": true
},
"concat-map": {
"version": "0.0.1",
- "bundled": true
+ "bundled": true,
+ "optional": true
},
"console-control-strings": {
"version": "1.1.0",
- "bundled": true
+ "bundled": true,
+ "optional": true
},
"core-util-is": {
"version": "1.0.2",
},
"inherits": {
"version": "2.0.4",
- "bundled": true
+ "bundled": true,
+ "optional": true
},
"ini": {
"version": "1.3.5",
"is-fullwidth-code-point": {
"version": "1.0.0",
"bundled": true,
+ "optional": true,
"requires": {
"number-is-nan": "^1.0.0"
}
"minimatch": {
"version": "3.0.4",
"bundled": true,
+ "optional": true,
"requires": {
"brace-expansion": "^1.1.7"
}
},
"minimist": {
"version": "0.0.8",
- "bundled": true
+ "bundled": true,
+ "optional": true
},
"minipass": {
"version": "2.9.0",
"bundled": true,
+ "optional": true,
"requires": {
"safe-buffer": "^5.1.2",
"yallist": "^3.0.0"
"mkdirp": {
"version": "0.5.1",
"bundled": true,
+ "optional": true,
"requires": {
"minimist": "0.0.8"
}
},
"number-is-nan": {
"version": "1.0.1",
- "bundled": true
+ "bundled": true,
+ "optional": true
},
"object-assign": {
"version": "4.1.1",
"once": {
"version": "1.4.0",
"bundled": true,
+ "optional": true,
"requires": {
"wrappy": "1"
}
},
"safe-buffer": {
"version": "5.1.2",
- "bundled": true
+ "bundled": true,
+ "optional": true
},
"safer-buffer": {
"version": "2.1.2",
"string-width": {
"version": "1.0.2",
"bundled": true,
+ "optional": true,
"requires": {
"code-point-at": "^1.0.0",
"is-fullwidth-code-point": "^1.0.0",
"strip-ansi": {
"version": "3.0.1",
"bundled": true,
+ "optional": true,
"requires": {
"ansi-regex": "^2.0.0"
}
},
"wrappy": {
"version": "1.0.2",
- "bundled": true
+ "bundled": true,
+ "optional": true
},
"yallist": {
"version": "3.1.1",
- "bundled": true
+ "bundled": true,
+ "optional": true
}
}
},
"safe-buffer": "^5.1.0"
}
},
+ "keccakjs": {
+ "version": "0.2.3",
+ "resolved": "https://registry.npmjs.org/keccakjs/-/keccakjs-0.2.3.tgz",
+ "integrity": "sha512-BjLkNDcfaZ6l8HBG9tH0tpmDv3sS2mA7FNQxFHpCdzP3Gb2MVruXBSuoM66SnVxKJpAr5dKGdkHD+bDokt8fTg==",
+ "requires": {
+ "browserify-sha3": "^0.0.4",
+ "sha3": "^1.2.2"
+ }
+ },
"keyv": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/keyv/-/keyv-3.1.0.tgz",
"safe-buffer": "^5.0.1"
}
},
+ "sha3": {
+ "version": "1.2.6",
+ "resolved": "https://registry.npmjs.org/sha3/-/sha3-1.2.6.tgz",
+ "integrity": "sha512-KgLGmJGrmNB4JWVsAV11Yk6KbvsAiygWJc7t5IebWva/0NukNrjJqhtKhzy3Eiv2AKuGvhZZt7dt1mDo7HkoiQ==",
+ "requires": {
+ "nan": "2.13.2"
+ },
+ "dependencies": {
+ "nan": {
+ "version": "2.13.2",
+ "resolved": "https://registry.npmjs.org/nan/-/nan-2.13.2.tgz",
+ "integrity": "sha512-TghvYc72wlMGMVMluVo9WRJc0mB8KxxF/gZ4YYFy7V2ZQX9l7rgbPg7vjS9mt6U5HXODVFVI2bOduCzwOMv/lw=="
+ }
+ }
+ },
"shebang-command": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz",
"resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz",
"integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q="
},
+ "tweetnacl-util": {
+ "version": "0.15.1",
+ "resolved": "https://registry.npmjs.org/tweetnacl-util/-/tweetnacl-util-0.15.1.tgz",
+ "integrity": "sha512-RKJBIj8lySrShN4w6i/BonWp2Z/uxwC3h4y7xsRrpP59ZboCd0GpEVsOnMDYLMmKBpYhb5TgHzZXy7wTfYFBRw=="
+ },
"type": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/type/-/type-1.2.0.tgz",
"requires": {
"underscore": "1.9.1",
"web3-core-helpers": "1.2.1",
- "websocket": "github:web3-js/WebSocket-Node#905deb4812572b344f5801f8c9ce8bb02799d82e"
+ "websocket": "github:web3-js/WebSocket-Node#polyfill/globalThis"
},
"dependencies": {
"websocket": {

MODIFY
package.json
package.json
"bluebird": "^3.7.1",
"bn.js": "5.0.0",
"debug": "^4.1.1",
+ "eth-sig-util": "^2.5.3",
"ethereumjs-block": "2.2.0",
"ethereumjs-tx": "1.3.7",
- "ethereumjs-util": "5.2.0",
+ "ethereumjs-util": "^5.2.0",
"isomorphic-fetch": "2.2.1",
"matic-protocol": "github:maticnetwork/contracts#fa6862dc6ddae97351aa1b4d16c087861b5a489e",
"merkle-patricia-tree": "2.3.2",

ADD
src/common/Utils.ts
+import { signTypedData } from 'eth-sig-util'
+import EthUtil from 'ethereumjs-util'
+
+export class Utils {
+ getOrderHash(order) {
+ const orderData = Buffer.concat([
+ EthUtil.toBuffer(order.id),
+ EthUtil.toBuffer(order.token),
+ EthUtil.setLengthLeft(order.amount, 32),
+ ])
+ return EthUtil.keccak256(orderData)
+ }
+ // @todo take chain id as a param
+ getTypedData({ token, spender, tokenIdOrAmount, data, expiration }) {
+ return {
+ types: {
+ EIP712Domain: [
+ { name: 'name', type: 'string' },
+ { name: 'version', type: 'string' },
+ { name: 'chainId', type: 'uint256' },
+ { name: 'contract', type: 'address' },
+ ],
+ TokenTransferOrder: [
+ { name: 'spender', type: 'address' },
+ { name: 'tokenIdOrAmount', type: 'uint256' },
+ { name: 'data', type: 'bytes32' },
+ { name: 'expiration', type: 'uint256' },
+ ],
+ },
+ domain: {
+ name: 'Matic Network',
+ version: '1',
+ chainId: 15001,
+ contract: token,
+ },
+ primaryType: 'TokenTransferOrder',
+ message: {
+ spender,
+ tokenIdOrAmount,
+ data,
+ expiration,
+ },
+ }
+ }
+
+ signEIP712TypedData(data, privateKey) {
+ return signTypedData(EthUtil.toBuffer(privateKey), {
+ data: data,
+ })
+ }
+}

MODIFY
src/index.ts
src/index.ts
@@ -5,8 +5,9 @@ import RootChain from './root/RootChain'
import Registry from './root/Registry'
import WithdrawManager from './root/WithdrawManager'
import Web3Client from './common/Web3Client'
-import { address, SendOptions } from './types/Common'
+import { address, SendOptions, order } from './types/Common'
import ContractsBase from './common/ContractsBase'
+import { Utils } from './common/Utils'
export default class Matic extends ContractsBase {
public web3Client: Web3Client
@@ -14,6 +15,7 @@ export default class Matic extends ContractsBase {
public rootChain: RootChain
public withdrawManager: WithdrawManager
public registry: Registry
+ public utils: Utils
constructor(options: any = {}) {
const web3Client = new Web3Client(
@@ -28,6 +30,7 @@ export default class Matic extends ContractsBase {
this.rootChain = new RootChain(options.rootChain, this.web3Client)
this.depositManager = new DepositManager(options.depositManager, this.web3Client, this.registry)
this.withdrawManager = new WithdrawManager(options.withdrawManager, this.rootChain, this.web3Client, this.registry)
+ this.utils = new Utils()
}
initialize() {
@@ -165,6 +168,33 @@ export default class Matic extends ContractsBase {
return this.depositManager.approveERC20(token, amount, options)
}
+ getTransferSignature(sellOrder: order, buyOrder: order, options: SendOptions) {
+ if (!sellOrder.orderId || !sellOrder.spender) {
+ throw new Error('orderId or spender missing from sell order')
+ }
+ if (!options.from) {
+ throw new Error('options.from is missing')
+ }
+
+ const orderObj = {
+ token: buyOrder.token,
+ amount: buyOrder.amount,
+ id: sellOrder.orderId,
+ expiration: sellOrder.expiry,
+ }
+ const orderHash = this.utils.getOrderHash(orderObj)
+ const dataToSign = {
+ token: sellOrder.token,
+ tokenIdOrAmount: sellOrder.amount,
+ spender: sellOrder.spender,
+ data: orderHash,
+ expiration: sellOrder.expiry,
+ }
+ const typedData = this.utils.getTypedData(dataToSign)
+ const wallet = this.web3Client.getWallet()
+ return this.utils.signEIP712TypedData(typedData, wallet[options.from].privateKey)
+ }
+
depositERC20ForUser(token: address, user: address, amount: BN | string, options?: SendOptions) {
if (options && (!options.from || !amount || !token)) {
throw new Error('options.from, token or amount is missing')

MODIFY
src/types/Common.ts
src/types/Common.ts
@@ -9,3 +9,11 @@ export declare interface SendOptions {
parent?: boolean
to?: string
}
+
+export declare interface order {
+ token: string
+ amount: string | number
+ expiry?: string | number
+ orderId?: string
+ spender?: string
+}

new: users: add getTransferSignature method