Entrypoints

In Tezos there are two different types of accounts: implicit and originated. The latter is an account with Michelson code attached to it and is basically known as smart contract. It can be seen as a collection of functions that share and manipulate the same storage. Different to implicit accounts, originated accounts can receive more than just ꜩ in a transaction, namely parameters that are consumed when executing the code. Those parameters always first arrive at the main function of the code.

The challenge is how to address specific functions from the "outside", while parameters are always passed to the main function? That's why we have so called entrypoints that work like the following: variants of parameters get matched and routed to the functions we want to address. In this way, entrypoints make functions explicitly callable from the outside of the smart contract.

Remember

Entrypoints make functions explicitly callable from the outside of a smart contract.

Example from the workshop

In the notarization workshop the smart contract has two functions exposed with the help of entrypoints:

  1. NotarizeDocument(notarizeParameter): It takes a new document hash to notarize and a list of signees.
  2. SignDocument(signParameter): This signs an existing document for a given document hash.

The chart below shows how both variants of the parameters are matched in the main function of the smart contract. The variants are notarizeParameter with (documentHash, signees) and for signParameter with documentHash. Depending on which parameter is passed in the transaction, one of the two functions notarizeDocument and signDocument is called. As you can see, the exposed functions are calling other functions that are within the smart contract, which are not exposed to the outside.

graph TD transaction["Transaction with parameters targets main function"] transaction-->entrypoints{"Main entrypoint <br> matches varying <br> parameters <br>to function"} entrypoints-->|"notarizeParameter: (documentHash, signees)"|NotarizeDocument entrypoints-->|signParameter: documentHash|SignDocument SignDocument-.->signDocument NotarizeDocument-.->notarizeDocument subgraph smart contract notarizeDocument["notarizeDocument(documentHash, signees)"] getEmpty["getEmptydocumentSignatures()"] addDocument["addDocumentHashWithSigneesToNotary()"] notarizeDocument-->|calls internally|addDocument addDocument-->|calls internally|getEmpty addSign["addSignatureToDocumentSignaturesOrFail()"] signDocument["signDocument(documentHash)"] signDocument -->|calls internally|addSign end

We can also look at the code that does this matching. It is written in Ligo in the ReasonLIGO flavor.

workshop-notarization/smart-contracts/contracts/main/notary.religo and contracts/partials/notary/action/action.religo
/**
* Unique set of addresses which will be able
* to co-sign the document.
*/
type signees = set(signee);
/**
* Parameter for the `NotarizeDocument` entrypoint,
* accepting a hash to be notarized along with a set of signees.
*/
type notarizeParameter = {
documentHash: documentHash,
signees: signees
};
/**
* Parameter for the `SignDocument` entrypoint,
* accepting a single document hash to be signed.
*/
type signParameter = documentHash;
type action =
/**
* Propose a new document hash to notarize
*/
| NotarizeDocument(notarizeParameter)
/**
* Sign an existing document with a new signature
*/
| SignDocument(signParameter);
/**
* Main function representing the Notary contract
*/
let main = ((action, storage): (action, storage)) : entrypointReturn =>
/**
* Entrypoint routing
*/
switch (action) {
| NotarizeDocument(notarizeParameter) => notarizeDocument(notarizeParameter, storage);
| SignDocument(signParameter) => signDocument(signParameter, storage);
}