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
?