A common pattern we see in smart contracts is where a trait is passed in to a function, and then inside the function, this trait is checked to make sure that it matches some principal defined in a data-var or map. This check is then needed in many functions and can be easily forgotten. In place of this error-prone behavior, we could allow developers to define refinement types, which enforce a check as a sort of pre-check before executing the function body.
I'm picturing something like this:
(define-refined-type (CheckedToken <sip-010>)
(if (is-eq (contract-of CheckedToken) (var-get expected-token))
(ok true)
(err u1)
))
(define-public (do-something (token CheckedToken))
...
)
When do-something is called directly by a transaction or a contract-call?, the check is performed and will exit immediately if it returns an error. Otherwise, the function body is executed as usual. In this example, token could be passed into another local function specifying the CheckedToken type and the check does not need to be repeated.
What I don't like about it:
- The error type needs to match all functions that use this type
A common pattern we see in smart contracts is where a trait is passed in to a function, and then inside the function, this trait is checked to make sure that it matches some principal defined in a data-var or map. This check is then needed in many functions and can be easily forgotten. In place of this error-prone behavior, we could allow developers to define refinement types, which enforce a check as a sort of pre-check before executing the function body.
I'm picturing something like this:
When
do-somethingis called directly by a transaction or acontract-call?, the check is performed and will exit immediately if it returns an error. Otherwise, the function body is executed as usual. In this example,tokencould be passed into another local function specifying theCheckedTokentype and the check does not need to be repeated.What I don't like about it: