# Predicates in Matic Plasma This post highlights the implementation details of our predicate design. Our predicate design is heavily inspired from [Understanding the Generalized Plasma Architecture](https://medium.com/plasma-group/plapps-and-predicates-understanding-the-generalized-plasma-architecture-fc171b25741) and we thank the plasma group for the same. We recently published our [Account based MoreVP](https://ethresear.ch/t/account-based-plasma-morevp/5480) specification. The linked post is a pre-requisite to understanding this post. Note: `withdrawManager` is our term for what plasma group calls the _commitment contract_. ### Predicate for ERC20/721 token transfer The most relevant function in the ERC20/721 predicates are `startExit` and `verifyDeprecation`. See [IPredicate.sol](https://github.com/maticnetwork/contracts/blob/dev-morevp/contracts/root/predicates/IPredicate.sol#L11). The `startExit` function will be invoked when an exitor wants to start a MoreVP style exit (referencing the preceding reference transactions). ``` function startExit(bytes calldata data, bytes calldata exitTx) external { referenceTxData = decode(data) // Verify inclusion of reference tx in checkpoint / commitment // returns priority which is something like that defined in minimum viable plasma (blknum * 1000000000 + txindex * 10000 + logIndex) // Here, logIndex is the index of the log in the tx receipt. priority = withdrawManager.verifyInclusion(referenceTxData) // validate exitTx - This may be an in-flight tx, so inclusion will not be checked exitAmount = processExitTx(exitTx) // returns the balance of the party at the end of referenceTx - this is the "youngest input" to the exitTx closingBalance = processReferenceTx(referenceTxData) // The closing balance of the exitTx should be <= the referenced balance require( closingBalance >= exitAmount, "Exiting with more tokens than referenced" ); withdrawManager.addExitToQueue(msg.sender, token, exitAmount, priority) } ``` For challenging older state transitions, the predicate exposes a `verifyDeprecation` function. ``` function verifyDeprecation(bytes calldata exit, bytes calldata challengeData) external returns (bool) { referenceTxData = decode(challengeData) Verify sign on the referenceTxData.rawTx and that the rawTx calls some function in the associated contract on plasma chain that deprecates the state // Verify inclusion of challenge tx in checkpoint / commitment priorityOfChallengeTx = withdrawManager.verifyInclusion(referenceTxData) return priorityOfChallengeTx > exit.priority } ``` Finally, the `challengeExit` function in `withdrawManager` is resposible for calling `predicate.verifyDeprecation` and cancel the exit if it returns true. See [WithdrawManager.sol](https://github.com/maticnetwork/contracts/blob/dev-morevp/contracts/root/withdrawManager/WithdrawManager.sol). ``` function challengeExit(uint256 exitId, uint256 inputId, bytes calldata challengeData) external { PlasmaExit storage exit = exits[exitId]; Input storage input = exit.inputs[inputId]; require( exit.token != address(0x0) && input.signer != address(0x0), "Invalid exit or input id" ); bool isChallengeValid = IPredicate(exit.predicate).verifyDeprecation( encodeExit(exit), encodeInputUtxo(inputId, input), challengeData ); if (isChallengeValid) { deleteExit(exitId); emit ExitCancelled(exitId); } } ``` While this makes up the crux of our [ERC20Predicate.sol](https://github.com/maticnetwork/contracts/blob/dev-morevp/contracts/root/predicates/ERC20Predicate.sol) logic, the actual implementation is much more involved and can be found in this [pull request](https://github.com/maticnetwork/contracts/pull/78). We invite the plasma community to review the same and leave their precious feedback here or on the PR.