📱Interfaces & Modules

So far we’ve been writing code at the top level. Code at the top level is ordinary Pact that NuChain VM can execute. However, when you are defining a new smart contract, you need to organize your Pact code into interfaces and/or modules so that it can be referenced later from other contracts or via a NuChain Node node’s Pact API. NuChain node will store your interfaces and modules within the namespace you’ve entered.

Interfaces and modules are both units for organizing Pact code, but they serve different purposes. An interface describes the API that a module will implement and can supply constants and models for formal verification to aid in that implementation, but it doesn’t contain any implementations itself and cannot be executed on NuChain.

Interfaces purely exist as a method of abstraction. An interface can be implemented by multiple modules (that means that the module provides an implementation for every function included in the interface), so it serves as a blueprint for implementers. Also, Pact functions take a reference to module as an argument so long as the module implements a specific interface. That means you can write a function that can be used with any module that implements the given interface — a powerful form of abstraction.

We don’t use interfaces in our contract because it’s quite small and no one else is expected to provide another implementation for its API. Instead, we skip straight to the implementation: the ‘nucredit-faucet-faucet’ module.

A module in Pact is the primary unit of organization for Pact code. Modules can contain functions, pacts, capabilities, tables, and other Pact code.

Let’s define a Pact module with the code for our faucet. To define a module we must provide a module name, a module governance function, and then the module body containing the implementation.

The module name is used to refer to the module from other modules (or in the REPL). For example, coin.transfer refers to the transfer function defined in the coin module. To refer to a module it must have been deployed to Nuchain Node (or loaded into the REPL). We’ll name our module nucredit-faucet-faucet.

Since we’re within the free namespace, that means we can refer to our module on NuChain with the prefix free.nucredit-faucet-faucet. The module governance function restricts how the contract can be upgraded.

Governance functions can be a keyset reference, which means that the contract can be upgraded so long as the upgrade transaction satisfies the keyset, or they can be a “capability” defined in the module. We’ll learn a lot more about capabilities later and will use a keyset reference as our governance.

// pact

(module nucredit-faucet-faucet "free.nucredit-faucet-faucet-keyset"  @doc  
"'nucredit-faucet-faucet' represents the nucredit-faucet Faucet Contract. \  \ This contract  provides a small number of NCH to any 
\  \ NuChain user who needs some. To request funds for        \  \ yourself (Chain 0 only):                                \  \                                                         \  \ > (free.nucredit-faucet-faucet.request-funds …)                 \  \                                                         \  \ To check your account’s request and total limits:       \  \ > (free.nucredit-faucet-faucet.get-limits …)                    \  \                                                         \  \ To return funds to the faucet account (Chain 0 only):   \  \ > (free.nucredit-faucet-faucet.return-funds …)"

Now, let’s implement the body of our module. We’ll begin with the two forms of metadata we can use to annotate our modules, interfaces, functions, table schemas, and other Pact code. The @doc metadata field is for documentation strings, and the @model metadata field is for formal verification.

Last updated