This audit was performed upon the commit 9ff9deb by Dean Eigenmann, it was done as part of the ZK Labs community audit initiative.
The code is kept simple & concise, there is no unnecessary complexity found in the smart contract.
The Token Subscription (MetaTx) project enables applications to create a trustless subscription model without their users needing to constantly and manually transfer tokens. It consists of one contract, the Subscription contract, which is created with the parameters for a subscription including destination address, token address, token amount, and period of recurrence. The publisher then supplies a link to the subscriber that is presented with the terms of the subscription to sign an off-chain meta transaction that is replayed on the defined period. The subscriber controls the flow of the tokens (starting, stopping, pausing, etc) using the ERC20 standard approve() function.
More information can be found through the website.
There does not seem to be any tests covering the smart contracts, these types of tests should be created.
ECDSA is used for all bytes32 variables.SafeMath is used for all uint256 variables.L72 to there where rest of the variables are defined.constructor to the rest of the function definitions.external.nonce field to subscription signatures. Making it possible to reopen cancelled subscriptions.This function sets various fields: - requiredToAddress - requiredTokenAddress - requiredTokenAmount - requiredPeriodSeconds - requiredGasPrice - author
This function returns whether the nextValidTimestamp for a given subscription with a gracePeriod added to it is smaller than or equal to the current timestamp.
This function packs the passed variables using the abi.encodePacked function and then proceeds to hashing those bytes using the keccak256 function.
This function recovers the signer of a given message using the recover function found in the ECDSA library.
This function checks multiple things, such as: - That the signer of the message is equal to the from address. - That the from address is not equal to the to address. - That the current time is greater than or equal to the nextValidTimestamp for the given subscription. - Ensures that the token allowance is greater than the tokenAmount added with the gasPrice. - Ensures that the token balance is greater than the tokenAmount added with the gasPrice.
First the subscription hash is generated by the passed variables using the getSubscriptionHash function. The signer is then recovered using the recover function found in the ECDSA library. It is then ensured that the signer is equal to the value of the passed from variable. Finally the nextValidTimestamp for the given subscription is set to 2**256 - 1.
recover call, the getSubscriptionSigner function can be called as it has been in other functions.Initially the subscription hash is generated using the getSubscriptionHash function. Then the signer is recovered using the getSubscriptionSigner function. Next it is ensured that the signer is equal to the passed from address. It is then ensured that the current timestamp is greater than or equal to the value of the nextValidTimestamp for the given subscription.
Several checks are then run: - It is ensured that the requiredToAddress is either equal to 0x0 or the passed to variable. - It is ensured that the requiredTokenAddress is either equal to 0x0 or the passed tokenAddress variable. - It is ensured that the requiredTokenAmount is either equal to 0 or the passed tokenAmount variable. - It is ensured that the requiredPeriodSeconds is either equal to 0 or the passed periodSeconds variable. - It is ensured that the requiredGasPrice is either equal to 0 or the passed gasPrice variable.
The value of the nextValidTimestamp for the given subscription is then set to the current timestamp added to the periodSeconds variable.
Tokens are then transfered from the from address to the passed to address using the transferFrom function. It is ensured that tokens were transfered successfully by adding the balance of the to address before the transfer to the transfered amount and ensuring that said value is equal to the new balance of the to address. The ExecuteSubscription event is then emitted.
Finally is the value of gasPrice is greater than zero, the value is transfered to the function caller from the from address.
require on L233-236 will not work for every token. See here.isSubscriptionReady?