Skip to content

Commit 4d67606

Browse files
authored
[Lightcone2.js] modify exchange for issue: https://github.com/Loopring/lightcone2/issues/345 (#285)
* modify * Update comments in MetaMask * Add @types/ethereumjs-abi, and fix an bug when importing ethereumjs-abi in Typescript * Add error handling in createAccount in lightcone_v2.js/src/sign/exchange.ts * Switch using Async/Await, rather than using a Promise in another Promise.
1 parent 4a682fc commit 4d67606

File tree

8 files changed

+75
-56
lines changed

8 files changed

+75
-56
lines changed

packages/lightcone_v2.js/package.json

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,12 +24,13 @@
2424
"main": "dist/index.js",
2525
"license": "ISC",
2626
"dependencies": {
27+
"@types/ethereumjs-abi": "^0.6.3",
2728
"async-validator": "1.8.2",
2829
"bignumber.js": "^9.0.0",
2930
"bip39": "2.5.0",
3031
"blake-hash": "^1.1.0",
3132
"bn.js": "^4.11.8",
32-
"ethereumjs-abi": "0.6.5",
33+
"ethereumjs-abi": "0.6.7",
3334
"ethereumjs-tx": "1.3.3",
3435
"ethereumjs-util": "5.2.0",
3536
"ethereumjs-wallet": "0.6.0",
@@ -38,11 +39,11 @@
3839
"grpc-loader": "^2.0.1",
3940
"grpc-web": "^1.0.4",
4041
"hdkey": "0.7.1",
42+
"isomorphic-fetch": "2.2.1",
4143
"nodeunit": "^0.11.3",
4244
"snarkjs": "0.1.11",
4345
"socket.io-client": "2.0.4",
44-
"web3": "^1.0.0-beta.36",
45-
"whatwg-fetch": "^3.0.0"
46+
"web3": "^1.0.0-beta.36"
4647
},
4748
"devDependencies": {
4849
"@types/chai": "^4.1.7",

packages/lightcone_v2.js/src/lib/wallet/ethereum/contracts/AbiFunction.ts

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
import {methodID, rawDecode, rawEncode} from 'ethereumjs-abi';
1+
// Using import {*} from 'ethereumjs-abi'; failed to import ethereumjs-abi
2+
var abi = require('ethereumjs-abi')
23
import {addHexPrefix, clearHexPrefix, toBuffer, toHex} from '../../common/formatter';
34
import BN from 'bn.js';
45

@@ -19,7 +20,7 @@ export default class AbiFunction {
1920
this.outputTypes = outputs.map(({type}) => type);
2021
this.outputs = outputs;
2122
this.constant = constant;
22-
this.methodAbiHash = toHex(methodID(name, this.inputTypes));
23+
this.methodAbiHash = toHex(abi.methodID(name, this.inputTypes));
2324
}
2425

2526
/**
@@ -29,7 +30,7 @@ export default class AbiFunction {
2930
*/
3031
encodeInputs(inputs) {
3132
const abiInputs = this.parseInputs(inputs);
32-
return this.methodAbiHash + clearHexPrefix(toHex(rawEncode(this.inputTypes, abiInputs)));
33+
return this.methodAbiHash + clearHexPrefix(toHex(abi.rawEncode(this.inputTypes, abiInputs)));
3334
}
3435

3536
/**
@@ -38,7 +39,7 @@ export default class AbiFunction {
3839
* @returns {*}
3940
*/
4041
decodeOutputs(outputs) {
41-
return this.parseOutputs(rawDecode(this.outputTypes, toBuffer(outputs)));
42+
return this.parseOutputs(abi.rawDecode(this.outputTypes, toBuffer(outputs)));
4243
}
4344

4445
/**
@@ -47,7 +48,7 @@ export default class AbiFunction {
4748
* @returns {*}
4849
*/
4950
decodeEncodedInputs(encoded) {
50-
return this.parseOutputs(rawDecode(this.inputTypes, toBuffer(addHexPrefix(encoded))));
51+
return this.parseOutputs(abi.rawDecode(this.inputTypes, toBuffer(addHexPrefix(encoded))));
5152
}
5253

5354
parseInputs(inputs = {}) {

packages/lightcone_v2.js/src/lib/wallet/ethereum/utils.ts

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,11 @@
11
import validator from '../common/validator'
22
import request from '../common/request'
33

4-
// FIXME: abi is not included in the project.
5-
// import {generateAbiData} from './abi';
6-
import {configs} from "../config/data";
7-
import {toBuffer} from "../common/formatter";
8-
import {rawDecode} from 'ethereumjs-abi'
94
import {sha3} from 'ethereumjs-util'
105

116
// HACK: What is the host in wallet/ethereum?
12-
const host = 'host';
7+
// const host = 'localhost:8545';
8+
const host = 'http://localhost:8545';
139

1410
export async function getTransactionCount(address, tag) {
1511
try {

packages/lightcone_v2.js/src/lib/wallet/ethereum/walletAccount.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -200,7 +200,7 @@ export class WalletAccount {
200200
// Hack: We don't need this one?
201201
export class KeyAccount extends WalletAccount {
202202

203-
privateKey: any
203+
privateKey: any;
204204

205205
/**
206206
* @property

packages/lightcone_v2.js/src/sign/exchange.ts

Lines changed: 40 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,8 @@ export class Exchange {
3636
private readonly accounts: Map<WalletAccount, DexAccount>;
3737

3838
public constructor() {
39-
this.exchangeID = 0; // TODO: config
40-
this.exchangeAddr = '0x'; // TODO: config
39+
this.exchangeID = 2; // TODO: config
40+
this.exchangeAddr = '0x3d88d9C4adC342cEff41855CF540844268390BE6'; // TODO: config
4141
this.walletAccountID = 0; // TODO: config
4242
this.accounts = new Map<WalletAccount, DexAccount>();
4343
}
@@ -47,7 +47,6 @@ export class Exchange {
4747
for (let i = 0; i < length; i++) {
4848
res[i] = value.testn(i) ? 1 : 0;
4949
}
50-
5150
return res;
5251
}
5352

@@ -99,42 +98,52 @@ export class Exchange {
9998

10099
public flattenList = (l: any[]) => {
101100
return [].concat.apply([], l);
102-
}
101+
};
103102

103+
// JavaScript: Promises and Why Async/Await Wins the Battle
104+
// https://hackernoon.com/javascript-promises-and-why-async-await-wins-the-battle-4fc9d15d509f
105+
// ES7 async error handling: do it right or die
106+
// https://medium.com/@giovannipinto/async-error-handling-forced-to-do-it-right-2817cf9e8b43
104107
public async createAccount(wallet: WalletAccount, gasPrice: number) {
105-
// TODO: need to check if gasPrice is a reasonable value
106-
if (this.accounts.get(wallet) == null) {
107-
const keyPair = generateKeyPair();
108-
console.log(keyPair)
109-
this.createOrUpdateAccount(keyPair.publicKeyX, keyPair.publicKeyY, gasPrice).then((rawTx: Transaction) => {
110-
const signedTx = wallet.signEthereumTx(rawTx);
111-
wallet.sendTransaction(new Eth(''), signedTx).then(() => { // TODO: config
112-
grpcClientService.getAccount(wallet.getAddress()).then((account: Account) => {
113-
const dexAccount = new DexAccount();
114-
dexAccount.nonce = 0;
115-
dexAccount.owner = wallet.getAddress();
116-
dexAccount.accountID = account.getAccountId().getValue();
117-
dexAccount.publicKeyX = keyPair.publicKeyX;
118-
dexAccount.publicKeyY = keyPair.publicKeyY;
119-
dexAccount.secretKey = keyPair.secretKey;
120-
this.accounts.set(wallet, dexAccount);
121-
this.currentDexAccount = dexAccount;
122-
this.currentWalletAccount = wallet;
123-
});
108+
try {
109+
// TODO: need to check if gasPrice is a reasonable value
110+
if (this.accounts.get(wallet) == null) {
111+
const keyPair = generateKeyPair();
112+
this.currentWalletAccount = wallet;
113+
let rawTx: Transaction = await this.createOrUpdateAccount(keyPair.publicKeyX, keyPair.publicKeyY, gasPrice)
114+
const signedTx = wallet.signEthereumTx(rawTx);
115+
116+
// TODO: Let's avoid using Promises. Change this part to await.
117+
// At least, avoid using a Promise in another Promise.
118+
wallet.sendTransaction(new Eth('localhost:8545'), signedTx).then(() => { // TODO: config
119+
grpcClientService.getAccount(wallet.getAddress()).then((account: Account) => {
120+
const dexAccount = new DexAccount();
121+
dexAccount.nonce = 0;
122+
dexAccount.owner = wallet.getAddress();
123+
dexAccount.accountID = account.getAccountId().getValue();
124+
dexAccount.publicKeyX = keyPair.publicKeyX;
125+
dexAccount.publicKeyY = keyPair.publicKeyY;
126+
dexAccount.secretKey = keyPair.secretKey;
127+
this.accounts.set(wallet, dexAccount);
128+
this.currentDexAccount = dexAccount;
124129
});
125-
}
126-
);
130+
});
131+
}
132+
} catch(err) {
133+
console.error('Failed to create.', err);
134+
throw err;
127135
}
128136
}
129137

130138
public async createOrUpdateAccount(publicX: string, publicY: string, gasPrice: number) {
131139
// FIXME: ethereum.abi.Contracts.ExchangeContract.encodeInputs returns error
132140
// Unhandled Rejection (TypeError): name.startsWith is not a function
141+
console.log('Start encode input of createOrUpdateAccount')
133142
const data = ethereum.abi.Contracts.ExchangeContract.encodeInputs('createOrUpdateAccount', {
134-
pubKeyX: publicX,
135-
pubKeyY: publicY
143+
pubKeyX: fm.toBN(publicX),
144+
pubKeyY: fm.toBN(publicY)
136145
});
137-
146+
console.log('End encode input of createOrUpdateAccount')
138147
return new Transaction({
139148
to: this.exchangeAddr,
140149
value: '0x0',
@@ -259,9 +268,9 @@ export class Exchange {
259268
order.rebateBips = (order.rebateBips !== undefined) ? order.rebateBips : 0;
260269
order.walletAccountID = (order.walletAccountID !== undefined) ? order.walletAccountID : this.walletAccountID;
261270

262-
assert(order.maxFeeBips < 64, 'maxFeeBips >= 64');
263-
assert(order.feeBips < 64, 'feeBips >= 64');
264-
assert(order.rebateBips < 64, 'rebateBips >= 64');
271+
// assert(order.maxFeeBips < 64, 'maxFeeBips >= 64');
272+
// assert(order.feeBips < 64, 'feeBips >= 64');
273+
// assert(order.rebateBips < 64, 'rebateBips >= 64');
265274

266275
// Sign the order
267276
this.signOrder(order);

packages/lightcone_v2.js/src/wallet/metaMask.ts

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ import {MetaMaskAccount} from '../lib/wallet/ethereum/walletAccount';
66
import { fromMetaMask } from '../lib/wallet/WalletUtils';
77
import {exchange} from '../sign/exchange';
88

9-
// TODO: implement callback to integrate MetaMask
109
export class MetaMask {
1110

1211
public web3: Web3;
@@ -15,10 +14,10 @@ export class MetaMask {
1514
public account: MetaMaskAccount;
1615

1716
public constructor() {
18-
this.web3 = new Web3(Web3.givenProvider || 'http://localhost:8545'); // TODO: replace for ruby
17+
this.web3 = new Web3('http://localhost:8545'); // TODO: replace for ruby
1918
this.account = fromMetaMask(this.web3);
2019
this.address = this.account.getAddress();
21-
this.ethNode = new Eth(''); // TODO: config
20+
this.ethNode = new Eth('http://localhost:8545'); // TODO: config
2221
}
2322

2423
public async createOrUpdateAccount(publicX: string, publicY: string, gasPrice: number) {
@@ -45,6 +44,3 @@ export class MetaMask {
4544
});
4645
}
4746
}
48-
49-
// Avoid to use metaMask because MetaMask is not ready when the website is loaded.
50-
// export const metaMask: MetaMask = new MetaMask();
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
const BN = require("bn.js");
2+
3+
describe("generate key_pair test", function () {
4+
this.timeout(100000);
5+
before( async () => {
6+
});
7+
8+
it("send tx using metamask", async () => {
9+
let bn = new BN(20);
10+
console.log(bn.toString(16))
11+
});
12+
});

packages/lightcone_v2.js/test/sign.ts

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,16 @@
1-
const BN = require("bn.js");
1+
import {exchange} from "../src";
2+
import {KeyAccount} from "../src/lib/wallet/ethereum/walletAccount";
3+
24

35
describe("generate key_pair test", function () {
46
this.timeout(100000);
5-
before( async () => {
7+
before(async () => {
68
});
79

810
it("send tx using metamask", async () => {
9-
let bn = new BN(20);
10-
console.log(bn.toString(16))
11+
let keyAccount = new KeyAccount('ffd9b73fa766fe3a69d139c2cc39dfbb171d680222f07196a2c7b088e4139d75');
12+
exchange.createAccount(keyAccount, 100000).then(() => {
13+
console.log()
14+
});
1115
});
1216
});

0 commit comments

Comments
 (0)