Skip to the content.

Validate all contract parameters

Intent

Verifying whether the information provided by the user is as expected.

Consequences

Context

Smart contracts can receive user input. An example is via methods, where the user input is passed as an argument to the method. It should not be assumed by the smart contract developer that all user input will be as expected. It is possible that an attacker provides malicious user input on purpose in order to bring the smart contract in an inconsistent state, or to let the smart contract execute unexpected behavior. To avoid this, checks should be done whenever user input is received. Note that once again, this pattern is related to the "checks effects interactions" pattern in Solidity [1]. This is because this pattern, just as the "checks effects interactions" pattern, suggests to first perform all checks on the input parameters updating the contract state.

Example

const start = zcf => {
  let naturalNumbersList = [];
  const getNaturalNumbersList = () => {
    return naturalNumbersList;
  }
  const addToNaturalNumbersList = value => {
    naturalNumbersList.push(value);
  };
  const creatorFacet = Far('creatorFacet', {
    getNaturalNumbersList
  });
  const publicFacet = Far('publicFacet', {
    addToNaturalNumbersList
  });
  return harden({ creatorFacet, publicFacet });
};
harden(start);
export { start };

The code above shows a smart contract in which any entity with the publicFacet can add numbers to the naturalNumbersList using the addToNaturalNumbersList method. The creator of the smart contract can retrieve the natural numbers list using the getNaturalNumbersList method, provided by the creatorFacet.

//Alice starts an instance of the smart contract
const { creatorFacet, publicFacet } = await E(zoe).startInstance(installation);
//Alice shares the publicFacet
//Bob adds natural number 8 to the naturalNumberList
await E(publicFacet).addToNaturalNumbersList(8);
//Carol wrongfully adds number -11 to the naturalNumberList
await E(publicFacet).addToNaturalNumbersList(-11);
//The naturalNumberList is now in an invalid state, since -11 is not a natural number
t.deepEqual(
  await E(creatorFacet).getNaturalNumbersList(),
  [8, -11]
);

As shown in this test code, Carol is able to add a negative number to the naturalNumbersList. This brings the smart contract into an invalid state, since there should only be natural numbers in the naturalNumbersList.

const start = zcf => {
  let naturalNumbersList = [];
  const getNaturalNumbersList = () => {
    return naturalNumbersList;
  }
  const addToNaturalNumbersList = value => {
    Nat(value);
    naturalNumbersList.push(value);
  };
  const creatorFacet = Far('creatorFacet', {
    getNaturalNumbersList
  });
  const publicFacet = Far('publicFacet', {
    addToNaturalNumbersList
  });
  return harden({ creatorFacet, publicFacet });
};
harden(start);
export { start };

The flaw in the original smart contract is resolved by performing user input validation, as seen in the code above. Here, the addToNaturalNumbersList first verifies whether the input is indeed a natural number. If this is the case, the code will execute as usual. If this is not the case, an exception is thrown [2].

//Alice starts an instance of the smart contract
const { creatorFacet, publicFacet } = await E(zoe).startInstance(installation);
//Alice shares the publicFacet
//Bob adds natural number 8 to the naturalNumberList
await E(publicFacet).addToNaturalNumbersList(8);
//Carol wrongfully adds number -11 to the naturalNumberList
await t.throwsAsync(async () =>
  {
    await E(publicFacet).addToNaturalNumbersList(-11);
  },
  {
    instanceOf: RangeError,
    message: '-11 is negative'
  }
);
//The naturalNumberList remains in a valid state
t.deepEqual(
  await E(creatorFacet).getNaturalNumbersList(),
  [8]
);

The above test shows that it has become impossible to pass anything but a natural number to addToNaturalNumbersList method. The contract can no longer be brought into an inconsistent state via the addToNaturalNumbersList method.

General rule

If the user provides any form of input, then it should be verified whether this given input is indeed as expected.

Known uses

References

[1] F. Volland, Checks effects interactions

[2] Agoric, Nat