Start and confirm withdraw
MODIFY
examples/node/confirm-withdraw.js
examples/node/confirm-withdraw.js
-const Matic = require('maticjs').default
+const Matic = require('../../dist/index').default
+
const config = require('./config')
const from = config.FROM_ADDRESS // from address
+
+var transactionHash = '0x03042186456e1ca3843c0eed088acba8fc56c3687d26ad028f0f1d1ad450647d' // Insert txHash generated from initiate-withdraw.js
+
// Create object of Matic
const matic = new Matic({
maticProvider: config.MATIC_PROVIDER,
parentProvider: config.PARENT_PROVIDER,
- rootChainAddress: config.ROOTCHAIN_ADDRESS,
- syncerUrl: config.SYNCER_URL,
- watcherUrl: config.WATCHER_URL,
- withdrawManagerAddress: config.WITHDRAWMANAGER_ADDRESS,
+ rootChain: config.ROOTCHAIN_ADDRESS,
+ registry: config.REGISTRY_ADDRESS,
+ depositManager: config.DEPOSITMANAGER_ADDRESS,
+ withdrawManager: config.WITHDRAWMANAGER_ADDRESS,
})
-matic.wallet = config.PRIVATE_KEY // prefix with `0x`
-
-var transactionHash = 'Paste txHash here ...' // Insert txHash generated from initiate-withdraw.js
-
-//Wait for 5 mins till the checkpoint is submitted, then run the confirm withdraw
+matic.initialize().then(() => {
+ matic.wallet(config.PRIVATE_KEY)
matic.withdraw(transactionHash, {
from,
- onTransactionHash: (hash) => {
- // action on Transaction success
- console.log(hash) // eslint-disable-line
- // Withdraw process is completed, funds will be transfer to your account after challege period is over.
- },
+ }).then((res) => {
+ console.log(res) // eslint-disable-line
+
})
+})
+//Wait for 5 mins till the checkpoint is submitted, then run the confirm withdraw

MODIFY
examples/node/initiate-withdraw-ERC20.js
examples/node/initiate-withdraw-ERC20.js
-const Matic = require('maticjs').default
+const bn = require('bn.js')
+
+const Matic = require('../../dist/index').default
+
const config = require('./config')
const token = config.MATIC_TEST_TOKEN // test token address
-const amount = '1000000000000000000' // amount in wei
+const amount = new bn(100000000) // amount in wei
+
const from = config.FROM_ADDRESS // from address
// Create object of Matic
const matic = new Matic({
maticProvider: config.MATIC_PROVIDER,
parentProvider: config.PARENT_PROVIDER,
- rootChainAddress: config.ROOTCHAIN_ADDRESS,
- syncerUrl: config.SYNCER_URL,
- watcherUrl: config.WATCHER_URL,
- withdrawManagerAddress: config.WITHDRAWMANAGER_ADDRESS,
+ rootChain: config.ROOTCHAIN_ADDRESS,
+ registry: config.REGISTRY_ADDRESS,
+ depositManager: config.DEPOSITMANAGER_ADDRESS,
+ withdrawManager: config.WITHDRAWMANAGER_ADDRESS,
})
-matic.wallet = config.PRIVATE_KEY // prefix with `0x`
-
-// NOTE: Initiate the withdraw on the Matic chain, and wait for ~5 minutes for
-// the checkpoint (refer https://whitepaper.matic.network/#checklayer for technical details)
-// before confirming the withdraw by executing `confirm-withdraw.js`.
-// The txHash from the output needs to be copied to the `confirm-withdraw.js` file before executing
+matic.initialize().then(() => {
+ matic.wallet(config.PRIVATE_KEY)
matic
.startWithdraw(token, amount, {
from,
- onTransactionHash: (hash) => {
- // console.log("Withdraw Initiated")
- console.log(hash) // eslint-disable-line
- },
+ }).then((res) => {
+ console.log(res) // eslint-disable-line
+ })
+
})
\ No newline at end of file

MODIFY
src/index.ts
src/index.ts
@@ -78,7 +78,7 @@ export default class Matic extends ContractsBase {
return this.web3Client.send(txObject, _options)
}
- async approveERC20TokensForDeposit(
+ approveERC20TokensForDeposit(
token: address,
amount: BN | string,
options?: SendOptions,
@@ -101,4 +101,15 @@ export default class Matic extends ContractsBase {
}
return this.depositManager.depositERC20ForUser(token, amount, user, options)
}
+
+ startWithdraw(token: address, amount: BN | string, options?: SendOptions) {
+ if (options && (!options.from || !amount || !token)) {
+ throw new Error(`options.from, amount or token is missing`)
+ }
+ return this.withdrawManager.burnERC20Tokens(token, amount, options)
+ }
+
+ withdraw(txHash: string, options?: SendOptions) {
+ return this.withdrawManager.startExitWithBurntERC20Tokens(txHash, options)
+ }
}

MODIFY
src/root/WithdrawManager.ts
src/root/WithdrawManager.ts
@@ -24,64 +24,114 @@ export default class WithdrawManager extends ContractsBase {
private rootChain: RootChain
private registry: Registry
- constructor(withdrawManager: address, rootChain: RootChain, web3Client: Web3Client, registry: Registry) {
+ constructor(
+ withdrawManager: address,
+ rootChain: RootChain,
+ web3Client: Web3Client,
+ registry: Registry,
+ ) {
super(web3Client)
- this.withdrawManager = new this.web3Client.parentWeb3.eth.Contract(WithdrawManagerArtifact.abi, withdrawManager)
+ this.withdrawManager = new this.web3Client.parentWeb3.eth.Contract(
+ WithdrawManagerArtifact.abi,
+ withdrawManager,
+ )
this.rootChain = rootChain
this.registry = registry
}
async initialize() {
- const erc20PredicateAddress = await this.registry.registry.methods.erc20Predicate().call()
- const erc721PredicateAddress = await this.registry.registry.methods.erc721Predicate().call()
- this.erc20Predicate = new this.web3Client.parentWeb3.eth.Contract(ERC20PredicateArtifact.abi, erc20PredicateAddress)
- this.erc721Predicate = new this.web3Client.parentWeb3.eth.Contract(ERC721PredicateArtifact.abi, erc721PredicateAddress)
+ const erc20PredicateAddress = await this.registry.registry.methods
+ .erc20Predicate()
+ .call()
+ const erc721PredicateAddress = await this.registry.registry.methods
+ .erc721Predicate()
+ .call()
+ this.erc20Predicate = new this.web3Client.parentWeb3.eth.Contract(
+ ERC20PredicateArtifact.abi,
+ erc20PredicateAddress,
+ )
+ this.erc721Predicate = new this.web3Client.parentWeb3.eth.Contract(
+ ERC721PredicateArtifact.abi,
+ erc721PredicateAddress,
+ )
}
- burnERC20Tokens(token: address, amount: BN | string, options?: SendOptions) {
- return this.wrapWeb3Promise(
- this.getERC20TokenContract(token).methods
- .withdraw(this.encode(amount))
- .send(options),
- options
+ async burnERC20Tokens(
+ token: address,
+ amount: BN | string,
+ options?: SendOptions,
+ ) {
+ const txObject = this.getERC20TokenContract(token).methods.withdraw(
+ this.encode(amount),
)
+
+ const _options = await this._fillOptions(
+ options,
+ txObject,
+ this.web3Client.getMaticWeb3(),
+ )
+
+ if (options.encodeAbi) {
+ _options.data = txObject.encodeABI()
+ _options.to = token
+ return _options
+ }
+
+ return this.web3Client.send(txObject, _options)
}
burnERC721Token(token: address, tokenId: BN | string, options?: SendOptions) {
return this.wrapWeb3Promise(
- this.getERC721TokenContract(token).methods
- .withdraw(this.encode(tokenId))
+ this.getERC721TokenContract(token)
+ .methods.withdraw(this.encode(tokenId))
.send(options),
- options
+ options,
)
}
processExits(token: address, options?: SendOptions) {
options = options || {}
if (!options || !options.gas || options.gas < 2000000) {
- console.log('processExits can be gas expensive, sending in 2000000 gas but even this might not be enough')
+ console.log(
+ 'processExits can be gas expensive, sending in 2000000 gas but even this might not be enough',
+ )
options.gas = 2000000
}
return this.web3Client.send(
this.withdrawManager.methods.processExits(token),
- options
+ options,
)
}
async startExitWithBurntERC20Tokens(burnTxHash, options?) {
const payload = await this._buildPayloadForExit(burnTxHash)
- return this.web3Client.send(
- this.erc20Predicate.methods.startExitWithBurntTokens(payload),
- options
+ const txObject = this.erc20Predicate.methods.startExitWithBurntTokens(
+ payload,
)
+
+ const _options = await this._fillOptions(
+ options,
+ txObject,
+ this.web3Client.getParentWeb3(),
+ )
+
+ if (options.encodeAbi) {
+ _options.data = txObject.encodeABI()
+ return _options
+ }
+ return this.web3Client.send(txObject, _options)
}
async startExitForMintWithTokenURITokens(burnERC20TxHash, options?) {
- const { payload, mint } = await this._startExitForMintWithTokenURITokens(burnERC20TxHash)
+ const { payload, mint } = await this._startExitForMintWithTokenURITokens(
+ burnERC20TxHash,
+ )
return this.web3Client.send(
- this.erc721Predicate.methods
- .startExitForMintWithTokenURITokens(payload, mint),
- options
+ this.erc721Predicate.methods.startExitForMintWithTokenURITokens(
+ payload,
+ mint,
+ ),
+ options,
)
}
@@ -90,29 +140,43 @@ export default class WithdrawManager extends ContractsBase {
const mints = []
// note that these calls will be simultaneous
await bluebird.map(burnTxs, async tx => {
- const { payload, mint } = await this._startExitForMintWithTokenURITokens(tx)
+ const { payload, mint } = await this._startExitForMintWithTokenURITokens(
+ tx,
+ )
payloads.push(payload)
mints.push(mint)
})
return this.web3Client.send(
- this.erc721Predicate.methods
- .startBulkExitForMintWithTokenURITokens(ethUtils.rlp.encode(payloads), ethUtils.rlp.encode(mints)),
- options
+ this.erc721Predicate.methods.startBulkExitForMintWithTokenURITokens(
+ ethUtils.rlp.encode(payloads),
+ ethUtils.rlp.encode(mints),
+ ),
+ options,
)
}
private async _startExitForMintWithTokenURITokens(burnTxHash, options?) {
const payload = await this._buildPayloadForExit(burnTxHash)
- const burnReceipt = await this.web3Client.getMaticWeb3().eth.getTransactionReceipt(burnTxHash)
- const withdrawEvent = burnReceipt.logs.find(l => l.topics[0].toLowerCase() === WithdrawManager.WITHDRAW_EVENT_SIG)
+ const burnReceipt = await this.web3Client
+ .getMaticWeb3()
+ .eth.getTransactionReceipt(burnTxHash)
+ const withdrawEvent = burnReceipt.logs.find(
+ l => l.topics[0].toLowerCase() === WithdrawManager.WITHDRAW_EVENT_SIG,
+ )
const tokenId = withdrawEvent.data
- const mintEvents = await this.getERC721TokenContract(burnReceipt.to)
- .getPastEvents('Transfer', { filter: { tokenId }, fromBlock: 0, toBlock: 'latest' })
- const mintTxHash = mintEvents
- .find(event => event.raw.topics[3] === tokenId)
+ const mintEvents = await this.getERC721TokenContract(
+ burnReceipt.to,
+ ).getPastEvents('Transfer', {
+ filter: { tokenId },
+ fromBlock: 0,
+ toBlock: 'latest',
+ })
+ const mintTxHash = mintEvents.find(event => event.raw.topics[3] === tokenId)
.transactionHash
console.log('mintTxHash', mintTxHash)
- let mint: any = await this.web3Client.getMaticWeb3().eth.getTransaction(mintTxHash)
+ let mint: any = await this.web3Client
+ .getMaticWeb3()
+ .eth.getTransaction(mintTxHash)
mint = ethUtils.bufferToHex(await Proofs.getTxBytes(mint))
return { payload, mint }
}
@@ -120,29 +184,53 @@ export default class WithdrawManager extends ContractsBase {
private async _buildPayloadForExit(burnERC20TxHash) {
// check checkpoint
const lastChildBlock = await this.rootChain.getLastChildBlock()
- const burnTx = await this.web3Client.getMaticWeb3().eth.getTransaction(burnERC20TxHash)
- const receipt = await this.web3Client.getMaticWeb3().eth.getTransactionReceipt(burnERC20TxHash)
- const block: any = await this.web3Client.getMaticWeb3().eth.getBlock(burnTx.blockNumber, true /* returnTransactionObjects */)
+ const burnTx = await this.web3Client
+ .getMaticWeb3()
+ .eth.getTransaction(burnERC20TxHash)
+ const receipt = await this.web3Client
+ .getMaticWeb3()
+ .eth.getTransactionReceipt(burnERC20TxHash)
+ const block: any = await this.web3Client
+ .getMaticWeb3()
+ .eth.getBlock(burnTx.blockNumber, true /* returnTransactionObjects */)
- console.log('burnTx.blockNumber', burnTx.blockNumber, 'lastChildBlock', lastChildBlock)
+ console.log(
+ 'burnTx.blockNumber',
+ burnTx.blockNumber,
+ 'lastChildBlock',
+ lastChildBlock,
+ )
assert.ok(
new BN(lastChildBlock).gte(new BN(burnTx.blockNumber)),
- 'Burn transaction has not been checkpointed as yet'
+ 'Burn transaction has not been checkpointed as yet',
+ )
+ const headerBlockNumber = await this.rootChain.findHeaderBlockNumber(
+ burnTx.blockNumber,
)
- const headerBlockNumber = await this.rootChain.findHeaderBlockNumber(burnTx.blockNumber)
const headerBlock = await this.web3Client.call(
- this.rootChain.getRawContract().methods.headerBlocks(this.encode(headerBlockNumber))
+ this.rootChain
+ .getRawContract()
+ .methods.headerBlocks(this.encode(headerBlockNumber)),
+ )
+ console.log(
+ 'headerBlockNumber',
+ headerBlockNumber.toString(),
+ 'headerBlock',
+ headerBlock,
)
- console.log('headerBlockNumber', headerBlockNumber.toString(), 'headerBlock', headerBlock)
// build block proof
const blockProof = await Proofs.buildBlockProof(
this.web3Client.getMaticWeb3(),
headerBlock.start,
headerBlock.end,
- burnTx.blockNumber
+ burnTx.blockNumber,
)
// console.log('blockProof', blockProof)
- const receiptProof = await Proofs.getReceiptProof(receipt, block, this.web3Client.getMaticWeb3())
+ const receiptProof = await Proofs.getReceiptProof(
+ receipt,
+ block,
+ this.web3Client.getMaticWeb3(),
+ )
return this._encodePayload(
headerBlockNumber,
blockProof,
@@ -154,13 +242,24 @@ export default class WithdrawManager extends ContractsBase {
receiptProof.parentNodes,
receiptProof.path,
// @todo logIndex can vary
- 1 // logIndex
+ 1, // logIndex
)
}
private _encodePayload(
- headerNumber, buildBlockProof, blockNumber, timestamp, transactionsRoot, receiptsRoot, receipt, receiptParentNodes, path, logIndex) {
- return ethUtils.bufferToHex(ethUtils.rlp.encode([
+ headerNumber,
+ buildBlockProof,
+ blockNumber,
+ timestamp,
+ transactionsRoot,
+ receiptsRoot,
+ receipt,
+ receiptParentNodes,
+ path,
+ logIndex,
+ ) {
+ return ethUtils.bufferToHex(
+ ethUtils.rlp.encode([
headerNumber,
buildBlockProof,
blockNumber,
@@ -170,7 +269,8 @@ export default class WithdrawManager extends ContractsBase {
ethUtils.bufferToHex(receipt),
ethUtils.bufferToHex(ethUtils.rlp.encode(receiptParentNodes)),
ethUtils.bufferToHex(ethUtils.rlp.encode(path)),
- logIndex
- ]))
+ logIndex,
+ ]),
+ )
}
}

Start and confirm withdraw