implement plasma erc20
MODIFY
src/enums/log_event_signature.ts
src/enums/log_event_signature.ts
export enum Log_Event_Signature {
+ PlasmaErc20WithdrawEventSig = '0xebff2602b3f468259e1e99f613fed6691f3a6526effe6ef3e768ba7ae7a36c4f',
+ PlasmaErc721WithdrawEventSig = '0x9b1bfa7fa9ee420a16e124f794c35ac9f90472acc99140eb2f6447c714cad8eb',
Erc20Transfer = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef',
Erc721Transfer = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef',
Erc721BatchTransfer = '0xf871896b17e9cb7a64941c62c188a4f5c621b86800e3d15452ece01ce56073df',

MODIFY
src/interfaces/index.ts
src/interfaces/index.ts
@@ -16,3 +16,4 @@ export * from "./rpc_response_payload";
export * from "./map_promise_option";
export * from "./base_client_config";
export * from "./error";
+export * from "./plasma_helper_contract";
\ No newline at end of file

MODIFY
src/interfaces/plasma_client_config.ts
src/interfaces/plasma_client_config.ts
@@ -3,5 +3,7 @@ import { IBaseClientConfig } from "./base_client_config";
export interface IPlasmaClientConfig extends IBaseClientConfig {
depositManager?: string;
+ withdrawManager?: string;
registry?: string;
+ rootChain?: string;
}
\ No newline at end of file

ADD
src/interfaces/plasma_helper_contract.ts
+import { RegistryContract } from "../plasma/registry";
+import { WithdrawManager } from "../plasma/withdraw_manager";
+import { ExitManager } from "../pos/exit_manager";
+import { DepositManager } from "../plasma/deposit_manager";
+
+export interface IPlasmaContracts {
+ depositManager: DepositManager;
+ registry: RegistryContract;
+ exitManager: ExitManager;
+ withdrawManager: WithdrawManager;
+}
\ No newline at end of file

MODIFY
src/plasma/erc20.ts
src/plasma/erc20.ts
-import BN from "bn.js";
-import { ITransactionOption } from "../interfaces";
-import { BaseToken, Converter, Web3SideChainClient } from "../utils";
-import { DepositManager } from "./deposit_manager";
+import { TYPE_AMOUNT } from "../types";
+import { Log_Event_Signature } from "../enums";
+import { BaseContract } from "../abstracts";
+import { IPlasmaContracts, ITransactionOption } from "../interfaces";
+import { BaseToken, Converter, promiseResolve, Web3SideChainClient } from "../utils";
+import { Erc20Predicate } from "./erc20_predicate";
+
+
+
export class ERC20 extends BaseToken {
+ private predicate_: BaseContract;
+
+
constructor(
tokenAddress: string,
isParent: boolean,
client: Web3SideChainClient,
- public depositManager: DepositManager) {
+ private contracts_: IPlasmaContracts
+ ) {
super({
isParent,
tokenAddress,
@@ -17,6 +26,20 @@ export class ERC20 extends BaseToken {
}, client);
}
+ getPredicate(): Promise<BaseContract> {
+ if (this.predicate_) {
+ return promiseResolve(this.predicate_);
+ }
+ return this.contracts_.registry.getContract().then(contract => {
+ return contract.method("erc20Predicate").read<string>();
+ }).then(predicateAddress => {
+ return new Erc20Predicate(this.client, predicateAddress).getContract();
+ }).then(contract => {
+ this.predicate_ = contract;
+ return contract;
+ });
+ }
+
getBalance(userAddress: string, option: ITransactionOption = {}) {
return this.getContract().then(contract => {
const method = contract.method(
@@ -27,11 +50,11 @@ export class ERC20 extends BaseToken {
});
}
- approve(amount: BN | string | number, option: ITransactionOption = {}) {
+ approve(amount: TYPE_AMOUNT, option: ITransactionOption = {}) {
return this.getContract().then(contract => {
const method = contract.method(
"approve",
- this.depositManager.contract.address,
+ this.contracts_.depositManager.contract.address,
Converter.toHex(amount)
);
return this.processWrite(method, option);
@@ -46,9 +69,9 @@ export class ERC20 extends BaseToken {
);
}
- deposit(amount: BN | string | number, userAddress: string, option: ITransactionOption = {}) {
+ deposit(amount: TYPE_AMOUNT, userAddress: string, option: ITransactionOption = {}) {
return this.getContract().then(tokenContract => {
- const contract = this.depositManager.contract;
+ const contract = this.contracts_.depositManager.contract;
const method = contract.method(
"depositERC20ForUser",
tokenContract.address,
@@ -58,4 +81,34 @@ export class ERC20 extends BaseToken {
return this.processWrite(method, option);
});
}
+
+ withdrawStart(amount: TYPE_AMOUNT, option?: ITransactionOption) {
+ return this.getContract().then(tokenContract => {
+ const method = tokenContract.method(
+ "withdraw",
+ Converter.toHex(amount)
+ );
+ return this.processWrite(method, option);
+ });
+ }
+
+ withdrawChallenge(burnTxHash: string, option?: ITransactionOption) {
+ return Promise.all([
+ this.getPredicate(),
+ this.contracts_.exitManager.buildPayloadForExit(burnTxHash, Log_Event_Signature.PlasmaErc20WithdrawEventSig, false)
+ ]).then(result => {
+ const [predicate, payload] = result;
+ const method = predicate.method(
+ "startExitWithBurntTokens",
+ payload
+ );
+ return this.processWrite(method, option);
+ });
+ }
+
+ withdrawExit(tokens: string | string[], option?: ITransactionOption) {
+ return this.contracts_.withdrawManager.withdrawExit(tokens, option);
+ }
+
+
}
\ No newline at end of file

ADD
src/plasma/erc20_predicate.ts
+import { BaseToken, Web3SideChainClient } from "../utils";
+
+export class Erc20Predicate extends BaseToken {
+
+ constructor(client: Web3SideChainClient, address: string) {
+ super(
+ {
+ isParent: true,
+ tokenAddress: address,
+ tokenContractName: "ERC20Predicate"
+ },
+ client
+ );
+ }
+
+}
\ No newline at end of file

MODIFY
src/plasma/ether.ts
src/plasma/ether.ts
-import BN from "bn.js";
-import { TYPE_AMOUNT } from "src";
-import { ITransactionOption } from "../interfaces";
+import { TYPE_AMOUNT } from "../types";
+import { IPlasmaContracts, ITransactionOption } from "../interfaces";
import { Web3SideChainClient, Converter, BaseToken } from "../utils";
import { DepositManager } from "./deposit_manager";
import { ERC20 } from "./erc20";
import { RegistryContract } from "./registry";
+import { ExitManager } from "../pos";
+import { WithdrawManager } from "./withdraw_manager";
export class Ether extends BaseToken {
@@ -12,9 +13,7 @@ export class Ether extends BaseToken {
constructor(
isParent: boolean,
client: Web3SideChainClient,
- public depositManager: DepositManager,
- public registry: RegistryContract,
-
+ private contracts_: IPlasmaContracts
) {
super({
@@ -31,7 +30,7 @@ export class Ether extends BaseToken {
}
deposit(amount: TYPE_AMOUNT, option: ITransactionOption = {}) {
- const contract = this.depositManager.contract;
+ const contract = this.contracts_.depositManager.contract;
option.value = Converter.toHex(amount);
const method = contract.method(
"depositEther",
@@ -46,8 +45,15 @@ export class Ether extends BaseToken {
option.value = Converter.toHex(amount);
return this.sendTransaction(option);
}
- return this.registry.contract.method("getWethTokenAddress").read<string>().then(ethAddress => {
- const erc20 = new ERC20(ethAddress, false, this.client, this.depositManager);
+ return this.contracts_.registry.getContract().then(contract => {
+ return contract.method("getWethTokenAddress").read<string>();
+ }).then(ethAddress => {
+ const erc20 = new ERC20(
+ ethAddress,
+ false,
+ this.client,
+ this.contracts_
+ );
return erc20['getContract']();
}).then(contract => {
const method = contract.method(

MODIFY
src/plasma/index.ts
src/plasma/index.ts
import { ERC20 } from "./erc20";
import { ERC721 } from "./erc721";
import { Web3SideChainClient } from "../utils";
-import { IPlasmaClientConfig } from "../interfaces";
+import { IPlasmaClientConfig, IPlasmaContracts } from "../interfaces";
import { DepositManager } from "./deposit_manager";
import { LOGGER } from "../constant";
import { RegistryContract } from "./registry";
+import { Ether } from "./ether";
+import { ExitManager, RootChain } from "../pos";
+import { WithdrawManager } from "./withdraw_manager";
export class PlasmaClient {
private client_: Web3SideChainClient;
- withdrawManager;
+ withdrawManager: WithdrawManager;
+ exitManager: ExitManager;
depositManager: DepositManager;
registry: RegistryContract;
+ rootChain: RootChain;
+
+ private getContracts_() {
+ return {
+ depositManager: this.depositManager,
+ exitManager: this.exitManager,
+ registry: this.registry,
+ withdrawManager: this.withdrawManager
+ } as IPlasmaContracts;
+ }
erc20(tokenAddress: string, isParent?: boolean) {
return new ERC20(
tokenAddress,
isParent,
this.client_,
- this.depositManager
+ this.getContracts_()
);
}
@@ -34,43 +48,49 @@ export class PlasmaClient {
}
constructor(config: IPlasmaClientConfig) {
- this.client_ = new Web3SideChainClient(config);
+ const client = this.client_ = new Web3SideChainClient(config);
LOGGER.enableLog(config.log);
}
init() {
const client = this.client_;
let config: IPlasmaClientConfig = client.config;
- const mainContracts = this.client_.mainPlasmaContracts;
- config = Object.assign(
- config,
+ return client.init().then(_ => {
+ const mainContracts = client.mainPlasmaContracts;
+ client.config = config = Object.assign(
{
+ rootChain: mainContracts.RootChainProxy,
registry: mainContracts.Registry,
depositManager: mainContracts.DepositManagerProxy,
withdrawManager: mainContracts.WithdrawManagerProxy,
},
+ config
);
+ this.rootChain = new RootChain(
+ client,
+ config.rootChain
+ );
- return client.init().then(_ => {
- return Promise.all([
- this.client_.getABI("DepositManager").then(abi => {
+ this.registry = new RegistryContract(
+ client,
+ client.config.registry,
+ );
+
+ return this.client_.getABI("DepositManager").then(abi => {
this.depositManager = new DepositManager(
client.parent,
client.config.depositManager,
abi
);
- }),
- this.client_.getABI("Registry").then(abi => {
- this.registry = new RegistryContract(
- client.parent,
- client.config.registry,
- abi
- );
- })
- ]);
+ return this;
+ });
});
}
+ ether(isParent?) {
+ return new Ether(isParent, this.client_, this.getContracts_());
+ }
+
}

MODIFY
src/plasma/registry.ts
src/plasma/registry.ts
-import { BaseWeb3Client, BaseContract } from "../abstracts";
+import { BaseToken, Web3SideChainClient } from "../utils";
-export class RegistryContract {
- contract: BaseContract;
+export class RegistryContract extends BaseToken {
- constructor(private client_: BaseWeb3Client, address: string, abi) {
- this.contract = this.client_.getContract(
- address,
- abi
+ constructor(client: Web3SideChainClient, address: string) {
+ super(
+ {
+ isParent: true,
+ tokenAddress: address,
+ tokenContractName: "Registry"
+ },
+ client
);
}

ADD
src/plasma/withdraw_manager.ts
+import { BaseContractMethod } from "../abstracts";
+import { ITransactionOption } from "../interfaces";
+import { BaseToken, Web3SideChainClient } from "../utils";
+
+export class WithdrawManager extends BaseToken {
+
+ constructor(client: Web3SideChainClient, address: string) {
+ super(
+ {
+ isParent: true,
+ tokenAddress: address,
+ tokenContractName: "WithdrawManager"
+ },
+ client
+ );
+ }
+
+ withdrawExit(tokens: string | string[], option?: ITransactionOption) {
+ return this.getContract().then(contract => {
+ let method: BaseContractMethod;
+ if (Array.isArray(tokens)) {
+ method = contract.method("processExitsBatch", tokens);
+ }
+ else {
+ method = contract.method("processExits", tokens);
+ }
+ return this.processWrite(method, option);
+ });
+ }
+
+}
\ No newline at end of file

MODIFY
src/pos/exit_manager.ts
src/pos/exit_manager.ts
@@ -3,7 +3,7 @@ import { Converter, ProofUtil } from "../utils";
import assert from "assert";
import BN from "bn.js";
import ethUtils from "ethereumjs-util";
-import { ITransactionReceipt } from "src/interfaces";
+import { ITransactionReceipt } from "../interfaces";
import { service } from "../services";
import { BaseWeb3Client } from "../abstracts";

MODIFY
src/pos/index.ts
src/pos/index.ts
@@ -31,13 +31,13 @@ export class POSClient {
return client.init().then(_ => {
const mainPOSContracts = this.client_.mainPOSContracts;
- config = Object.assign(
- config,
+ client.config = config = Object.assign(
{
rootChainManager: mainPOSContracts.RootChainManagerProxy,
rootChain: this.client_.mainPlasmaContracts.RootChainProxy
} as IPOSClientConfig,
+ config
);
this.rootChainManager = new RootChainManager(

MODIFY
src/tsconfig.json
src/tsconfig.json
{
"compilerOptions": {
- "baseUrl": "../",
"noImplicitAny": false,
"noEmitOnError": false,
"removeComments": false,

MODIFY
src/utils/proof_util.ts
src/utils/proof_util.ts
import { BaseWeb3Client } from "../abstracts";
import { MerkleTree } from "./merkle_tree";
import ethUtils from "ethereumjs-util";
-import { ITransactionReceipt, IBlock, IBlockWithTransaction } from "src/interfaces";
+import { ITransactionReceipt, IBlock, IBlockWithTransaction } from "../interfaces";
import { mapPromise } from "./map_promise";
const TRIE = require('merkle-patricia-tree');
const rlp = ethUtils.rlp;

implement plasma erc20