Skip to content

Instantly share code, notes, and snippets.

@probablyangg
Last active November 23, 2019 18:12
Show Gist options
  • Save probablyangg/1c5e1eae196261d52e0e0f433e8113bb to your computer and use it in GitHub Desktop.
Save probablyangg/1c5e1eae196261d52e0e0f433e8113bb to your computer and use it in GitHub Desktop.
The three contracts used to enable PoS enabled asset deposit and withdraw from Matic chain. Manager contract emits events `deposit` and `withdraw`, the bridge listens to these events and invokes relevant functions on RootToken and ChildToken, depending upon the request. Both Deposits and Transfers start from `Manager` contract. There will be a s…
pragma solidity ^0.5.11;
import "github.com/OpenZeppelin/openzeppelin-solidity/contracts/token/ERC20/ERC20Detailed.sol";
import "github.com/OpenZeppelin/openzeppelin-solidity/contracts/token/ERC20/ERC20.sol";
contract ChildToken is ERC20, ERC20Detailed {
constructor (
string memory _name,
string memory _symbol,
uint8 _decimals
) public
ERC20Detailed(_name, _symbol, _decimals) {}
// function caller gets specified amount of tokens
function mintTokens (uint256 amount) public {
_mint (msg.sender, amount);
}
// invoked by bridge
// mints tokens to user's account
function deposit(address user, uint256 amount) public {
// check for amount and user
require(amount > 0 && user != address(0x0));
_mint(user, amount);
}
// invoked by bridge
// burns tokens
function withdraw(address user, uint256 amount) public {
require(amount > 0 && user != address(0x0));
_burn(user, amount);
}
}
pragma solidity ^0.5.11;
// import { SafeMath } from "github.com/OpenZeppelin/openzeppelin-solidity/contracts/math/SafeMath.sol";
import './RootToken.sol';
contract Manager {
// using SafeMath for uint256;
address internal _rootToken;
bool deposited;
event Deposit (
address user, // user invoking deposit
uint256 amountOrTokenId // amount of token to be deposited
);
event Withdraw (
address user,
uint256 amountOrTokenId, // amount of token to be withdrawn
bool deposited
);
constructor(address rootToken) public {
_rootToken = rootToken;
}
function updateRootToken (address newRoot) public {
_rootToken = newRoot;
}
// owned token amount of an address
mapping (address => uint256) public ownedTokens;
// emits deposit event
// bridge listens this event and invokes `deposit` in childtoken
function deposit (uint256 _tokenAmt) public {
ownedTokens[msg.sender] += _tokenAmt;
RootToken(_rootToken).transferFrom(msg.sender, address(this), _tokenAmt); // manager contract has to be approved from the user
emit Deposit (msg.sender, _tokenAmt);
}
// emits withdraw event
// bridge listens this event and invokes withdraw in childtoken (burn on child)
// and if deposited = false => invokes withdraw in roottoken
function withdraw (uint256 _tokenAmt) public {
if (ownedTokens[msg.sender] != 0) {
// the token was deposited
deposited = true;
require (_tokenAmt <= ownedTokens[msg.sender],
"trying to withdraw more than what was deposited by the user");
RootToken(_rootToken).transfer(msg.sender, _tokenAmt);
ownedTokens[msg.sender] -= _tokenAmt;
emit Withdraw(msg.sender, _tokenAmt, deposited); // burns on child
} else {
deposited = false;
emit Withdraw(msg.sender, _tokenAmt, deposited); // burns on child and mints on root
}
}
}
pragma solidity ^0.5.11;
import "github.com/OpenZeppelin/openzeppelin-solidity/contracts/token/ERC20/ERC20Detailed.sol";
import "github.com/OpenZeppelin/openzeppelin-solidity/contracts/token/ERC20/ERC20.sol";
contract RootToken is ERC20, ERC20Detailed {
constructor (
string memory _name,
string memory _symbol,
uint8 _decimals
) public
ERC20Detailed(_name, _symbol, _decimals) {}
// function caller gets specified amount of tokens
function mintTokens (uint256 amount) public {
_mint (msg.sender, amount);
}
// invoked by bridge for tokens that were minted on child chain
function withdraw(address user, uint256 amount) public {
_mint(user, amount);
}
}
@probablyangg
Copy link
Author

probablyangg commented Nov 22, 2019

Alternative for deposits:
bridge listens to Transfer event with recipient as Manager contract's address and mints on child
(wont require prior approval)
user simply transfers to Manager smart contract, and the token is minted on child
(possible when dealing with only one pair of contracts - (root, child))

@probablyangg
Copy link
Author

probablyangg commented Nov 23, 2019

Not sure what is the best way to go for withdrawals
if user invokes withdrawal from rootchain contract, there is no proof of their balance on child chain until an event is emitted and bridge invokes a burn on child, and in case that was a malicious transaction, the tokens would have already been transferred

easier way would be to initiate withdrawal from child chain, but then there would need to be two bridges listening on both networks ..

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment