Resource-Aware Session Types for Digital Contracts

—Programming digital contracts comes with unique challenges, which include (i) expressing and enforcing protocols of interaction, (ii) controlling resource usage, and (iii) preventing the duplication or deletion of a contract’s assets. This article presents the design and type-theoretic foundation of Nomos , a programming language for digital contracts that addresses these challenges. To express and enforce protocols, Nomos is based on shared binary session types . To control resource usage, Nomos employs automatic amortized resource analysis . To prevent the duplication or deletion of assets, Nomos uses a linear type system . A monad integrates the effectful session-typed language with a general-purpose functional language. Nomos’ prototype implementation features linear-time type checking and efﬁcient type reconstruction that includes automatic inference of resource bounds via off-the-shelf linear optimization. The effectiveness of the language is evaluated with case studies on implementing common smart contracts such as auctions, elections, and currencies. Nomos is completely formalized, including the type system, a cost semantics, and a transactional semantics to deploy Nomos contracts on a blockchain. The type soundness proof ensures that protocols are followed at run-time and that types establish sound upper bounds on the resource consumption, ruling out re-entrancy and out-of-gas vulnerabilities.


I. INTRODUCTION
Digital contracts are programs that implement and enforce the execution of a contract.With the rise of blockchains and cryptocurrencies such as Bitcoin [1], Ethereum [2], and Tezos [3], digital contracts have become popular in the form of smart contracts, which provide potentially distrusting parties with programmable money and a distributed consensus mechanism.Smart contracts are used to implement auctions [4], investment instruments [5], insurance agreements [6], supply chain management [7], and mortgage loans [8].They hold the promise to lower cost, increase fairness, and expand access to the financial infrastructure.
Many of today's prominent smart contract languages suffer from security vulnerabilities, which have severe financial consequences.A well-known example is the attack on The DAO [5], resulting in a $60 million theft by exploiting a contract re-entrancy vulnerability.Smart contract languages have been typically derived from existing general-purpose This article is based on research supported by the National Science Foundation under SaTC Award 1801369, CAREER Award 1845514 and Grant No. 1718276.Any opinions, findings, and conclusions contained in this document are those of the authors and do not necessarily reflect the views of the sponsoring organizations.languages [4], [9], [10] and fail to accommodate the domainspecific requirements of digital contracts.These requirements are: (i) expressing and enforcing protocols of interaction, (ii) controlling and computing resource (or gas) usage, and (iii) preventing duplication or deletion of a contract's assets.
This article presents the design and type-theoretic foundation of Nomos, a language for digital contracts accommodating these requirements by construction.
To express and enforce the protocols underlying a contract, Nomos is based on binary session types [11]- [17].Session types capture the protocols of interactions in the type, rather than the implementation code, and type-checking guarantees protocol adherence at run-time.Delimiting the sequences of actions that must be executed atomically, session types also prevent re-entrance into a contract in an inconsistent state.To control resource usage, Nomos employs automatic amortized resource analysis (AARA), a type-based technique for automatically inferring symbolic resource bounds [18]- [22].AARA is parametric in the cost model, allowing instantiation to track gas usage.As a result, Nomos contracts mitigate denial-ofservice attacks without being vulnerable to out-of-gas exceptions.Moreover, resource bounds are integrated with sessiontyped protocols and enable precise path-sensitive descriptions of cost that avoid gaps between worst-case and average-case cost.To prevent duplication or deletion of assets, Nomos uses a linear type system [23].The effectful session-typed language, which implements contract interfaces and contract-to-contract communication, is integrated with a strict, general-purpose functional language using a contextual monad.
Integrating these seemingly disparate approaches (session types, resource analysis, linearity, and functional programming) and combining them with the different roles that arise in a digital contract (contract, asset, transaction) in a way that the result remains consistent, presents unique challenges.For one, both the functional as well as session-typed language use potential annotations to bound the resource consumption, which requires care when functional values are exchanged as messages between processes.For another, prior work on integrating shared and linear session types [24] preclude contracts from persisting their linear assets across transactions, a feature essential to digital contract development; a restriction that we lift in this work.Fundamental is the use of different forms of typing judgments for expressions and processes along with judgmental modes to distinguish the different roles in a digital contract.The modes are essential in ensuring type safety, as they allow the expression of mode-indexed invariants on the typing contexts and their enforcement by the typing rules.
Nomos is completely formalized, including the type system, a cost semantics, and a transactional semantics to instantiate Nomos contracts on a blockchain.A type soundness proof ensures that protocols are followed at run-time and that types establish sound upper bounds on the resource consumption.
The soundness guarantees are meaningful in a restricted attacker model in which even the adversary cannot execute ill-typed code.Such a model is justified in a decentralized consensus setting such as a blockchain, where transactions and contracts are publicly type checked, thwarting attacks from adversaries intending to damage the blockchain state by submitting malformed code.In this setting, transaction validation and thus type checking are part of the attack surface and can be used by an adversary for denial-of-service attacks.To mitigate such attacks, we have carefully designed the Nomos type system that integrates its various features in a way that type checking is linear-time in the size of the program.
To evaluate Nomos, we implemented a publicly available open-source prototype [25] and conducted 8 case studies implementing common smart contracts such as auctions, elections, and currencies.Our experiments show that typechecking overhead is less than 0.7 ms for each contract and bound inference (can be performed off-chain) takes less than 10 ms.Moreover, gas bounds are tight for most contracts.To the best of our knowledge, this is the first implementation to integrate shared binary session types into a functional language with support for resource analysis.
To simplify programming and make Nomos accessible to digital contract developers, we (i) developed an intuitive surface syntax particularly related to the contextual monad integrating session types into a functional core; (ii) used a bidirectional type checker with a particular focus on improving the quality of error messages to guide the programmer to locate the source of the error; (iii) used an off-the-shelf LP solver to automatically infer channel modes and potential annotations so that the burden of inference does not fall on the programmer.
Our main technical contributions are: • design of Nomos, a language that addresses the domainspecific requirements of digital contracts by construction; • a fine-tuned system of typing judgments (Section IV) that uses modes to orchestrate the sound integration of session types (Section III), functions (Section V), and resource analysis (Section VI); • extension of shared session types to store linear assets; • resource cost amortization by allowing gas storage in internal data structures (Section VI); • type safety proof of Nomos using a novel asynchronous cost semantics (Section VII); • a prototype implementation and case study of prominent blockchain applications (Section VIII); • a transactional semantics to deploy and execute Nomos contracts and transactions on a blockchain (Section IX).In addition, the technical report [26] details the technical development, provides additional explanations and the full implementation of the blockchain applications.

II. NOMOS BY EXAMPLE
This section provides an overview of the main features of Nomos based on a simple auction contract.
Explicit Protocols of Interaction: Digital contracts, like traditional contracts, follow a predefined protocol.For instance, an auction contract distinguishes a bidding phase, where bidders submit their bids, possibly multiple times, from a subsequent collection phase, where the highest bidder receives the lot while all other bidders receive their bids back.In Solidity [4], the bidding phase of an auction is typically implemented as the bid function below.This function receives a bid (msg.value)from a bidder (msg.sender) and adds it to the bidder's total previous bids (bidValue).To guarantee that a bid can only be placed in the bidding phase, the contract uses the state variable status to track the different phases of a contract.The require statement tests whether the auction is still running and thus accepts bids.It is checked at run-time and aborts the execution if the condition is not met.It is the responsibility of the programmer to define state variables, update them, and introduce guards.
Rather than burying the contract's interaction protocol in implementation code by means of state variables and runtime checks, Nomos allows the explicit expression and static enforcement of protocols with session types.The auction's protocol amounts to the following recursive session type: L auction}} We first focus on how the session type defines the main interactions of a contract with a bidder and ignore the operators ↑ S L , ↓ S L , , and for now.To distinguish the two main phases an auction can be in, the session type uses an internal choice (⊕), leading the contract to either send the label running or ended, depending on whether the auction still accepts bids or not, respectively.Dual to an internal choice is an external choice ( ), which leaves the choice to the client (i.e., bidder) rather than the provider (i.e., contract).For example, in case the auction is running, the client can choose between placing a bid (label bid) or backing out (cancel).In the former case, the client indicates their identifier (type id), followed by a payment (type money).Nomos session types allow transfer of both non-linear (e.g., id) and linear assets (e.g., money), using the operators arrow (→) and ( ), respectively.Should the auction have ended, the client can choose to check their outcome (label collect) or back out (cancel).In the case of collect, the auction will answer with either won or lost.In the former case, the auction will send the lot, in the latter case, it will return the client's bid.The linear product (⊗) is dual to and denotes the transfer of a linear value from the contract to the client.The auction type guarantees that a client cannot collect during the running phase, while they cannot bid during the ended phase.
Nomos uses shared session types [24] to guarantee that bidders interact with the auction in mutual exclusion from each other and that the sequences of actions are executed atomically.To demarcate the parts of the protocol that become a critical section, the above session type uses the ↑ S L and ↓ S L modalities.The ↑ S L modality denotes the beginning of a critical section, the ↓ S L modality denotes its end.Programmatically, ↑ S L translates into an acquire of the auction session and ↓ S L into its release, which is only sound if the protocol behaves like an auction afterwards (equi-synchronizing type).
Contracts are implemented by processes, revealing the concurrent, message-passing nature of session-typed languages.The process run below implements the auction's running phase.Line 3 gives the process' signature, indicating that it offers a shared session of type auction along the channel sa and uses a linear hash map b : hashmap id, bid of bids indexed by id and a linear lot l.Line 5 onward list the process body.Lines 1,2 define session types bid and bids, respectively.The contract process first accepts an acquire request by a bidder (line 5) and then sends the message running (line 6), indicating the auction status and waiting for the bidder's choice.Should the bidder choose to make a bid, the process waits to receive the bidder's identifier (line 7) followed by money equivalent to the bidder's bid (line 8).Internally, the process stores the pair of the bidder's identifier and bid in the data structure bids (line 10).After this linear exchange, the process leaves the critical section by issuing a detach (line 9), matching the bidder's release request, and tail calls the check process (line 11) that compares the number of bidders with a threshold.If the threshold is exceeded, the contract transitions to the ended phase implemented by a different process, otherwise the run process is called again.
Linear Assets: Nomos integrates a linear type system that tracks the assets stored in a process.The type system enforces that assets are never duplicated, but only exchanged between processes.Moreover, the type system prevents a process from terminating while it holds linear assets.For example, the auction contract treats money and lot as linear assets, which is witnessed by the use of the linear operators and ⊗ for their exchange.In contrast, no provisions to handle assets linearly exist in Solidity, allowing such assets to be created out of thin air, duplicated, or discarded.In the above bid function, for instance, the language does not prevent the programmer from writing bidValue[bidder] = bid instead, losing the bidder's previous bid.
Re-Entrancy Vulnerabilities: A contract function is reentrant if, once called by a user, it can potentially be called again before the previous call has completed.As an illustration, consider the below collect function of the auction contract in Solidity where the funds are transferred to the bidder before the hash map is updated to reflect this change.A bidder can now cause re-entrancy by creating a dummy contract with an unnamed fallback function (line 9) that calls the auction's collect function.This call is triggered when collect calls send (line 5), leading to an infinite recursive call to collect, depleting all funds from the auction.The message-passing framework of session types eliminates this vulnerability.While session types provide multiple clients access to a contract, the acquire-release discipline ensures that clients interact with the contract in mutual exclusion.To attempt re-entrancy, a bidder will need to acquire the auction contract twice without releasing it, but the second acquire would fail to execute.
Resource Cost: Another important aspect of digital contracts is their resource usage.On a blockchain, executing a contract function, or transaction, requires new blocks to be added to the blockchain.In existing blockchains like Ethereum, this is done by miners who charge a fee based on the gas usage of the transaction, indicating the cost of its execution.Precisely computing this cost is important because the sender of a transaction must pay this fee to the miners.If the sender does not pay a sufficient amount, the transaction will be aborted by the miners and the sender's fee is lost!Nomos uses resource-aware session types [27] to statically analyze the resource cost of a transaction.They operate by assigning an initial potential to each process.This potential is consumed by each operation that the process executes or can be transferred between processes to share and amortize cost.The cost of each operation is defined by a cost model.If the cost model assigns a cost to each operation equivalent to their gas cost during execution, the potential consumed during a transaction reflects an upper bound on the gas usage.
Resource-aware session types express the potential as part of the session type using the operators and .The operator prescribes that the client must send potential to the contract, with the amount of potential indicated as a superscript.Dually, prescribes that the contract must send potential to the client.In case of the auction contract, we require the client to pay potential for the operations that the contract must execute, both while placing and collecting their bids.If the cost model assigns a cost of 1 to each contract operation, then the maximum cost of an auction session is 22 (taking the max number of operations in all branches).Thus, we require the client to send 22 units of potential at the start of the auction session type using 22 .In the lost branch of the auction type, on the other hand, the contract returns 7 units of potential to the client using 7 .This mirrors gas usage in smart contracts, where the sender initiates a transaction with some initial gas, and the leftover gas at the end of the transaction is returned to the sender.In contrast to existing smart contract languages like Solidity, which provide no support for analyzing the cost of a transaction, Nomos' type checker has automatically inferred these potential annotations and guarantees that well-typed transactions cannot run out of gas.Thus, Nomos enforces static gas bounds on transactions without burdening the programmer to infer them.
Bringing It All Together: Combining all these features soundly in one language is challenging.In Nomos, we achieve this by using different typing judgments and channel modes, identifying the role of the process offered along that channel.The mode R denotes purely linear processes for linear assets or private data structures, such as b and l in the auction.The modes S and L denote sharable processes, i.e., contracts, that are either in their shared or linear phase such as sa and la, respectively.The mode T denotes a transaction process that can refer to shared and linear processes and is issued by a user, such as bidder in the auction.Modes are assigned to each channel and are carried over into the process typing judgments imposing invariants (Definition 1) that are key to type safety.To simplify programming, Nomos' inference engine automatically infers the channel modes, thus relieving the programmer from the burden of annotating each channel with its respective mode.

III. BASE SYSTEM OF SESSION TYPES
Nomos builds on linear session types for message-passing concurrency [11]- [14], [17] and, in particular, on the line of works that have a logical foundation due to the existence of a Curry-Howard correspondence between linear logic [23] and the session-typed π-calculus [14], [17].Linear propositions can be viewed as resources that must be used exactly once in a proof.Under the Curry-Howard correspondence, an intuitionistic linear sequent A 1 , A 2 , . . ., A n C can be interpreted as the offer of a session C by a process P using the sessions A 1 , A 2 , . . ., A n (x 1 : A 1 ), (x 2 : A 2 ), . . ., (x n : A n ) P :: (z : C) We label each antecedent as well as the conclusion with the name of the channel along which the session is provided.The x i 's correspond to channels used by P , and z is the channel provided by P .As is standard, we use the linear context ∆ to combine multiple assumptions.
For the typing of processes in Nomos, we extend the above judgment with two additional contexts (Ψ and Γ), a resource annotation q, and a mode m of the offered channel: Ψ ; Γ ; ∆ q P :: (x m : A) We will gradually introduce each concept in the remainder of this article.For future reference, we show the complete typing rules, with additional contexts, resource annotations, and modes henceforth, but highlight the parts that will be discussed in later sections in blue.
The Curry-Howard correspondence gives each linear logic connective an interpretation as a session type: Each type prescribes the kind of message that must be sent or received along a channel of that type and at which type the session continues after the exchange.Types are defined mutually recursively in a global signature.Following previous work on session types [15], [16], the process expressions of Nomos are defined as follows.
Because we adopt the intuitionistic version of linear logic, session types are expressed from the point of view of the provider.Table I provides the viewpoint of the provider in the first line, and that of the client in the second line for each connective.Columns 1 and 3 describe the session type and process term before the interaction.Columns 2 and 4 describe the type and term after the interaction.The last column describes the provider and client action.Figure 1 provides selected typing rules.As an illustration of the statics and semantics, we explain the internal choice (⊕) connective.
Internal Choice: The linear logic connective A ⊕ B has been generalized to n-ary labeled sum ⊕{ : A } ∈K .A process that provides x : ⊕{ : A } ∈K can send any label l ∈ K along x and then continues by providing x : A l .The corresponding process term is written as (x.l ; P ), where P is the continuation.A client branches on the label received along x using the term case x ( ⇒ Q ) ∈K .The typing rules for the provider and client are ⊕R and ⊕L, respectively, in Figure 1.
The operational semantics is formalized as a system of multiset rewriting rules [28].We introduce semantic objects proc(c m , w, P ) and msg(c m , w, N ) denoting process P and message N , respectively, being provided along channel c at mode m.The resource annotation w indicates the work performed so far, the discussion of which we defer to Section VI.Communication is asynchronous, allowing the sender (c m .l; P ) to continue with P without waiting for l to be received.As a technical device to ensure that consecutive messages arrive in the order they were sent, the sender also creates a fresh continuation channel c + m so that the message TABLE I: Overview of binary session types with their operational description Ψ ; Γ ; ∆ q P :: (xm : A) Process P uses linear channels in ∆, and provides type A along x.
Ψ ; Γ ; ∆ q P :: ) is just a particular form of process.Therefore, no separate typing rules for messages are needed; they can be typed as processes [24].
Channel Passing.: Nomos allows the exchange of channels over channels, also referred to as higher-order channels.A process providing A n B can receive a channel of type A at mode n and then continue with providing B. The provider process term is (y n ← recv x m ; P ), where P is the continuation.The corresponding client sends this channel using (send x m w n ; Q).The dual type operator A ⊗ n B requires the provider to send a channel of type A at mode n and then continue with providing B. The client receives this channel and continues to use B. An important distinction from standard session types is that the and ⊗ types are decorated with the mode m of the channel exchanged.Since modes distinguish the status of the channels in Nomos, this mode decoration is necessary to ensure type safety.
Forwarding: A forwarding process x m ← y m (which provides channel x) identifies channels x and y (both at mode m) so that any further communication along x or y occurs on the unified channel.The typing rule fwd is given in Figure 1 and corresponds to the logical rule of identity.
Operationally, a process c ← d forwards any message N that arrives along d to c and vice versa.Since linearity ensures that every process has a unique client, forwarding results in terminating the forwarding process and corresponding renaming of the channel in the client process.
Process and Type Definitions: Process definitions have the form Ψ ; Γ ; ∆ q f = P :: (x m : A) where f is the name of the process and P its definition.All definitions are collected in a fixed global signature Σ.We require well-typedness, i.e., Ψ ; Γ ; ∆ q f = P :: (x m : A) for every definition, which allows the definitions to be mutually recursive.For readability of the examples, we break a definition into two declarations, one providing the type (top) and the other the process definition (bottom) binding the variables x m and those in Ψ, Γ and ∆ (omitting their types): A new instance of a defined process f can be spawned with the expression x m ← f y 1 ← y 2 ; Q where y 1 is a sequence of functional variables matching the antecedents Ψ and y 2 is a sequence of channels matching the antecedents Γ ; ∆.
The newly spawned process will use all variables in y 1 and channels in y 2 and provide x m to the continuation Q.The operational semantics is defined by where a m is a fresh channel.Here we write [d/Ψ] and [e/Γ ∆] to denote substitution of the variables in d and e for the corresponding variables in Ψ and Γ ; ∆ respectively in that order.Sometimes a process invocation is a tail call, written without a continuation as x m ← f y 1 ← y 2 .This is a shorthand for x m ← f y 1 ← y 2 ; x m ← x m for a fresh variable x m , that is, we create a fresh channel and immediately identify it with x m (although it is implemented more efficiently).Session types can be naturally extended to include recursive types.For this purpose we allow (possibly mutually recursive) type definitions X = A in the signature, where we require A to be contractive [29].This means here that A should not itself be a type name.Our type definitions are equi-recursive so we can silently replace X by A during type checking, and no explicit rules for recursive types are needed.

IV. SHARING CONTRACTS
Multi-user support is fundamental to digital contract development.Linear session types, as defined in Section III, unfortunately preclude such sharing because they restrict processes to exactly one client; only one bidder for the auction, for instance (who will always win!).To support multi-user contracts, we base Nomos on shared session types [24].Shared session types impose an acquire-release discipline on shared processes to guarantee that multiple clients interact with a contract in mutual exclusion of each other.When a client acquires a shared contract, it obtains a private linear channel along which it can communicate with the contract undisturbed by any other clients.Once the client releases the contract, it loses its private linear channel and only retains a shared reference to the contract.
A key idea of shared session types is to lift the acquirerelease discipline to the type level.Generalizing the idea of type stratification [16], [30], [31], session types are stratified into a linear and shared layer with two adjoint modalities going back and forth between them:

session types
The ↑ S L type modality translates into an acquire, while the dual ↓ S L type modality into a release.Whereas mutual exclusion is one key ingredient to guarantee type preservation for shared session types, the other key ingredient is the requirement that a session type is equi-synchronizing.A session type is equisynchronizing if it imposes the invariant on a process to be released back to the same type at which the process was previously acquired.This is the key behind eliminating reentrancy attacks since it prevents a user from interrupting an ongoing session in the middle and initiating a new one.In the Nomos typing judgment Ψ ; Γ ; ∆ q P :: (x m : A), the contexts Γ and ∆ store the shared and linear channels that P can refer to, respectively.The stratification of channels into layers arises from a difference in structural properties that exist for types at a mode.Shared propositions exhibit weakening, Allowing Contracts to Rely on Linear Assets: As exemplified by the auction contract, a digital contract typically amounts to a process that is shared at the outset, but oscillates between shared and linear to interact with clients, one at a time.Crucial for this pattern is the ability of a contract to maintain its linear assets (e.g., money or lot for the auction) regardless of its mode.Unfortunately, current shared session types [24] do not allow a shared process to rely on any linear channels, requiring any linear assets to be consumed before becoming shared.This precaution was logically motivated [32] and also crucial for type preservation.
A key novelty of our work is to lift this restriction while maintaining type preservation.To this end, we factorize the process typing judgment according to the three roles that arise in digital contract programs: contracts, transactions, and linear assets.Since contracts oscillate between shared and linear modes (due to acquire/release), we get 4 sub-judgments for typing processes, each characterized by the mode of the channel being offered.
Definition 1 (Process Typing).The judgment Ψ ; Γ ; ∆ q P :: (x m : A) is categorized according to mode m imposing certain invariants on the judgment.L(A) denotes the language generated by the grammar of A.
Figure 2 shows the session type grammar in Nomos.The first sub-judgment in Definition 1 is for typing linear assets.These type a purely linear process P using a purely linear context ∆ (channels at mode R and types belonging to grammar A R in Figure 2) and offering a purely linear type A along channel x R .The mode R of the channel indicates that a purely linear session is offered.The second and third sub-judgments are for typing contracts.The second sub-judgment shows the type of a contract process P using a shared context Γ and a purely linear channel context ∆ and offering shared type A on the shared channel x S .Once this shared channel is acquired by a user, the shared process transitions to its linear phase, whose Ψ ; Γ ; ∆ q P :: (xm : A) Process P uses shared channels in Γ and offers A along x.
Fig. 3: Typing rules corresponding to the shared layer.
typing is governed by the third sub-judgment.The offered channel transitions to linear mode L, while the linear context may now contain channels at modes R or L. Finally, the fourth typing judgment types a linear process, corresponding to a transaction holding access to shared channels Γ and linear channels ∆, and offering at mode T. This novel factorization upholds preservation while allowing shared contract processes to rely on linear resources.The modes impose the ordering R < S < L < T among the channels in the configuration.A process (offering a channel) at a certain mode is allowed to rely only on processes at the same or lower mode.These are exactly the conditions imposed by Definition 1.This introduces an implicit ordering among the linear processes depending on their mode, ensuring that no cyclic dependencies can arise among processes and imposing a tree structure on the process configuration.Relatedly, shared processes can only refer to shared channels (at mode S) or purely linear channels (at mode R) as exemplified by the judgment ∆ purelin in Figure 3. Formally, ∆ purelin denotes that for all d k ∈ ∆ =⇒ k = R.This ensures that a shared contract must release all processes it has acquired before itself being released.This further enforces an ordering in which the channels are acquired and released, thus allowing contracts to interact with other contracts without compromising type safety.
Shared session types introduce new typing rules into our system, concerning the acquire-release constructs (see Figure 3).An acquire is applied to the shared channel x S along which the shared process offers and yields a linear channel x L when successful.A contract process can accept an acquire request along its offering shared channel x S .After the accept is successful, the shared contract process transitions to its linear phase, now offering along the linear channel x L .To accept an acquire request, the contract must only contain channels at mode R (indicated by ∆ purelin), in accordance with Definition 1.This premise is crucial to type preservation, since it ensures that a contract has not acquired another contract while it is accepting an acquire request itself.Implicitly, this imposes an order on the acquire of contracts, and the inverse order is followed for their release.The dual to acquire-accept is release-detach.A client can release linear access to a contract process, while the contract process detaches from the client.

V. ADDING A FUNCTIONAL LAYER
To support general-purpose programming patterns, Nomos combines linear channels with conventional data structures, such as integers, lists, or dictionaries.To reflect and track different classes of data in the type system, we take inspiration from prior work [15], [16] and incorporate processes into a functional core via a linear contextual monad that isolates session-based concurrency.To this end, we introduce a separate functional context to the typing of a process.The linear contextual monad encapsulates open concurrent computations, which can be passed in functional computations but also transferred between processes in the form of higher-order processes, providing a uniform integration of higher-order functions and processes.
The types are separated into a functional and concurrent part, mutually dependent on each other.The functional types τ are given by the type grammar below.
The types are standard, except for the potential annotation q ∈ N in list type L q (τ ), which we explain in Section VI, and the contextual monadic types in the last line, which are the topic of this section.The expressivity of the types and terms in the functional layer are not important for the development in this paper.Thus, we do not formally define functional terms M but assume that they have the expected term formers such as function abstraction and application, type constructors, and pattern matching.We define a standard judgment for the functional part of the language.
The main novelty in the functional types are the three type formers for contextual monads, denoting the type of a process expression.The type {A R ← A R } R denotes a process offering a purely linear session type A R and using the purely linear vector of types A R .The corresponding introduction form in the functional language is the monadic value constructor {c R ← P ← d R }, denoting a runnable process offering along channel c R that uses channels d R , all at mode R. The corresponding typing rule for the monad is {}I R in Figure 4 (ignore the blue portions).
The monadic bind operation implements process composition and acts as the elimination form for values of type {A R ← A R } R .The bind operation, written as c R ← M ← d R ; Q c , composes the process underlying the monadic term M , which offers along channel c R and uses channels d R , with Q c , which uses c R .The typing rule for the monadic bind is rule {}E RR in Figure 4.The context ∆ is split between the monad M and continuation Q, enforcing linearity.Similarly, the potential in the functional context is split using the sharing judgment ( ), explained in Section VI.The shared context Γ is empty in accordance with the invariants established in Definition 1 (i), since the mode of offered channel z is R.The effect of executing a bind is the spawn of the purely linear process corresponding to the monad M , and the parent process continuing with Q.
Ψ ; Γ ; ∆ q P :: (xm : A) Process P uses functional values in Ψ, and provides A along x.
The above rule spawns the process P offering along a globally fresh channel c R , and using channels a.The continuation process Q acts as a client for this fresh channel c R .The other two monadic types correspond to spawning a shared process {A S ← A S ; A R } S and a transaction process {A T ← A S ; A} T at mode S and T, respectively.Their rules are analogous to {}I R and {}E RR and described in the technical report [26].
Value Communication: Communicating a value of the functional fragment along a channel is expressed at the type level by adding the following two session types.
The type τ → A prescribes receiving a value of type τ with continuation type A, while its dual τ ∧ A prescribes sending a value of type τ with continuation A. The corresponding typing rules for arrow (→ R, → L) are given in Figure 4 (rules for ∧ are inverse).As indicated in the → R rule, receiving a value y : τ on a channel x : τ → A adds it to the functional context Ψ.On the other hand, sending M on channel x : τ → A requires that M has type τ (third premise).
Tracking Linear Assets: As an illustration, consider the type money introduced in the auction example (Section II).The type is an abstraction over funds stored in a process and is described as The type supports querying for value, and addition and subtraction.The type also expresses insufficiency of funds in the case of subtraction.The provider process only supplies money to the client if the requested amount is less than the current balance, as depicted in the sufficient label.The type is implemented by a wallet process that internally stores a linear list of coins and an integer representing its value.The technical report [26] contains its code and explanation.

VI. TRACKING RESOURCE USAGE
The predominant approach for tracking resource cost on blockchains like Ethereum is to introduce a cost model that defines the gas consumption of low level operations.A transaction needs to be executed and validated before adding it to the global distributed ledger, i.e., blockchain.This validation is performed by miners, who charge fees based on the gas consumption of the transaction.This fee has to be estimated and provided by the sender prior to the transaction.
It is not trivial to decide on the right amount for the fee since the gas cost of the contract does not only depend on the requested transaction but also on the (a priori unknown) state of the blockchain.Thus, precise and static estimation of gas cost facilitates transactions and reduces risks.We discuss our approach of tracking resource usage, both at the functional and process layer.Our technique is parametric in the cost model applied by the programmer, thus making it directly applicable for gas cost analysis.The programmer only needs to specify the gas cost of each primitive operation, and our type system infers the corresponding gas bound of a transaction.
Functional Layer: Numerous techniques have been proposed to statically derive resource bounds for functional programs [33]- [37].In Nomos, we adapt the work on automatic amortized resource analysis (AARA) [18], [20] that has been implemented in Resource Aware ML (RaML) [21].RaML can automatically derive worst-case resource bounds for higherorder polymorphic programs with user-defined inductive types.The derived bounds are multivariate resource polynomials of the size parameters of the arguments.
As an illustration, consider the function apply that iterates over a list of balances and applies interest on each element, multiplying them by a constant c.We use tick annotations to define the resource usage of an expression in this article.One tick operation realizes a cost of 1.We have annotated the code to count the number of multiplications.The resource usage of an evaluation of apply b is len(b).The idea of AARA is to decorate base types with potential annotations that define a potential function as in amortized analysis.The typing rules ensure that the potential before evaluating an expression is sufficient to cover the cost of the evaluation and the potential defined by the return type.This posterior potential can then be used to pay for resource usage in the continuation of the program.For example, we can derive the following resource-annotated type.
The type L 1 (int) denotes a list of integers assigning a unit potential to each element in the list.The return value, on the other hand, has no potential.The annotation on the function arrow indicates that we do not need any potential to call the function and that no constant potential is left after the function call has returned.These annotations need not be provided by the programmer and can be inferred automatically by an off-the-shelf LP solver, even if the potential functions are polynomial [20], [21].
In Nomos, we simply adopt the standard typing judgment of AARA for functional programs: Ψ q M : τ .It states that under the resource-annotated functional context Ψ, with constant potential q, the expression M has the resource-aware type τ .The operational cost semantics is defined by M ⇓ V | µ which states that the closed expression M evaluates to the value V with cost µ.More details about AARA can be found in the literature [18], [21] and the technical report [26].
Process Layer: To bound the resource usage of a process, Nomos features resource-aware session types [27] for work analysis.Resource-aware session types describe resource contracts for inter-process communication.The type system supports amortized analysis by assigning potential to both messages and processes.As an illustration, consider the following resource-aware list interface from prior work [27].
The type prescribes that the provider of list A must send one unit of potential with every cons message that it sends.Dually, a client of this list will receive a unit potential with every cons message.All other type constructors are marked with potential 0, and exchanging the corresponding messages does not lead to transfer of potential.
While resource-aware session types in Nomos are equivalent to the existing formulation [27], our version is simpler and more streamlined.Instead of requiring every message to carry a potential (and potentially tagging several messages with 0 potential), we introduce two new type constructors for exchanging potential.
The type r A requires the provider to pay r units of potential which are transferred to the client.Dually, the type r A requires the client to pay r units of potential that are received by the provider.Thus, the reformulated list type becomes With all aspects introduced, the process typing judgment Ψ ; Γ ; ∆ q P :: (x m : A) denotes a process P accessing functional variables in Ψ, shared channels in Γ, linear channels in ∆, offers service of type A along channel x at mode m and stores a non-negative constant potential q.The expressing typing judgment denotes that expression M has type τ in the presence of functional context Ψ and potential p.
Figure 5 shows the rules that interact with the potential annotations.In the rule R, process P storing potential q Ψ ; Γ ; ∆ q P :: (xm : A) Process P has potential q and provides type A along channel x.
receives r units along the offered channel x m : r A using the get construct and the continuation executes with p = q+r units of potential.In the dual rule L, a process storing potential q = p+r sends r units along the channel x m : r A in ∆ using the pay construct, and the continuation remains with p units of potential.The typing rules for the dual constructor r A are the exact inverse.Finally, executing the tick (r) construct consumes r potential from the stored process potential q, and the continuation remains with p = q − r units, as described in the tick rule.
The tick construct is used to simulate a cost model in Nomos.If an operation (e.g., sending a message, calling a function, etc.) has a cost of r, this cost is simulated by inserting tick (r) just before the operation.Then, the tick operations are the only ones that cost potential, thus simplifying the type system.These tick operations are automatically inserted by the Nomos type checker, using a predefined cost model that assigns a constant cost to each operation.The programmer is not allowed to insert their own tick operations, and cannot maliciously change the gas cost.In addition, our implementation provides some standard cost models that, for instance, assign a unit cost to each operation.
Integration: Since both AARA for functional programs and resource-aware session types are based on the integration of the potential method into their type systems, their combination is natural.The two points of integration of the functional and process layer are (i) spawning a process, and (ii) sending/receiving a value from the functional layer.Recall the spawn rule {}E RR from Figure 4.A process storing potential r = p + q can spawn a process corresponding to the monadic value M , if M needs p units of potential to evaluate, while the continuation needs q units of potential to execute.Moreover, the functional context Ψ is shared in the two premises as Ψ 1 and Ψ 2 using the judgment Ψ (Ψ 1 , Ψ 2 ).This judgment, explored in prior work [21] describes that the base types in Ψ are copied to both Ψ 1 and Ψ 2 , but the potential is split up.For instance, L q1+q2 (τ ) (L q1 (τ ), L q2 (τ )).The rule →L follows a similar pattern.Thus, the combination of the two type systems is smooth, assigning a uniform meaning to potential, both for the functional and process layer.Remarkably, this technical device of exchanging functional values can be used to exchange non-constant potential with messages.
Operational Cost Semantics: The resource usage of a process (or message) is tracked in semantic objects proc(c, w, P ) and msg(c, w, N ) using the local counters w.This signifies that the process P (or message N ) has performed work w so far.The rules of that explicitly affect the work counter are This rule describes that if an expression M evaluates to V with cost µ, then the process P [M ] depending on monadic expression M steps to P [V ], while the work counter increments by µ, denoting the total number of internal steps taken by the process.At the process layer, the work increments on executing a tick operation.
proc(c m , w, tick (µ) ; P ) → proc(c m , w + µ, P ) A new process (or message) is spawned with w = 0, and a terminating process transfers its work to the corresponding message it interacts with before termination, thus preserving the total work performed by the system.

VII. TYPE SOUNDNESS
The main theorems that exhibit the connections between our type system and the operational cost semantics are the usual type preservation and progress.First, Definition 1 asserts certain invariants on process typing judgment depending on the mode of the channel offered by a process.This mode, remains invariant, as the process evolves.This is ensured by the process typing rules, which remarkably preserve these invariants despite being parametric in the mode.
Lemma 1 (Invariants).The typing rules on the judgment Ψ ; Γ ; ∆ q (x m : A) preserve the invariants outlined in Definition 1, i.e., if the conclusion satisfies the invariant, so do all the premises.
Configuration Typing: At run-time, a program evolves into a number of processes and messages, represented by proc and msg predicates.This multiset of predicates is referred to as a configuration (abbreviated as Ω).
A key question is how to type these configurations because a configuration both uses and provides a number of channels.The solution is to have the typing impose a partial order among the processes and messages, requiring the provider of a channel to appear before its client.We stipulate that no two distinct processes or messages in a well-formed configuration provide the same channel c.
The typing judgment for configurations has the form Σ ; Γ 0 E Ω :: (Γ ; ∆) defining a configuration Ω providing shared channels in Γ and linear channels in ∆.Additionally, we need to track the mapping between the shared channels and their linear counterparts offered by a contract process, switching back and forth between them when the channel is acquired or released respectively.This mapping, along with the type of the shared channels, is stored in Γ 0 .E is a natural number and stores the sum of the total potential and work as recorded in each process and message.We call E the energy of the configuration.The technical report [26] details the configuration typing rules.
Finally, Σ denotes a signature storing the type and function definitions.A signature is well-formed if (i) every type definition V = A V is contractive [29] (A V cannot be a type name) allowing an equi-recursive treatment [38] and (ii) every function definition f = M : τ is well-typed according to the expression typing judgment Σ ; • p M : τ .The signature does not contain process definitions; every process is encapsulated inside a function using the contextual monad.
The preservation theorem is standard for expressions [21].For processes, we proceed by induction on the operational cost semantics and inversion on the configuration and process typing judgment.
To state progress, we need the notion of a poised process [16].A process proc(c m , w, P ) is poised if it is trying to receive a message on c m .Dually, a message msg(c m , w, N ) is poised if it is sending along c m .A configuration is poised if every message or process in the configuration is poised.Intuitively, this means that the configuration is trying to interact with the outside world along a channel in Γ or ∆.Additionally, a process can be blocked [24] if it is trying to acquire a contract process that has already been acquired by some process.This can lead to the possibility of deadlocks.
Either Ω is poised, or it can take a step, i.e., Ω → Ω , or some process in Ω is blocked along a S for some shared channel a S and there is a process proc(a L , w, P ) ∈ Ω.
The progress theorem is weaker than that for binary linear session types, where progress guarantees deadlock freedom.

VIII. IMPLEMENTATION AND EVALUATION
We have developed an open-source prototype implementation [25] of Nomos in OCaml.This prototype contains a lexer and parser (929 lines of code), a type checker (2388 lines of code), a pretty printer (451 lines of code), an LP solver interface (915 lines of code) and an interpreter (1286 lines of code) for implementing, type checking and executing Nomos programs.We also describe our efforts to simplify programming and improve accessiblity of Nomos to developers.

Syntax:
The lexer and parser for Nomos have been implemented in Menhir [39], an LR(1) parser generator for OCaml.A Nomos program is a list of mutually recursive type and process definitions.To visually separate out functional variables from session-typed channels, we require that shared channels are prefixed by #, while linear channels are prefixed by $.This avoids confusion between the two, both for the programmer and the parser.We also require the programmer to indicate the mode of the process being defined: asset, contract or transaction, assigning the respective modes R, S and T to the offered channel.The modes for all other channels are inferred automatically (explained later).The initial potential {q} of a process is marked on the turnstile in the declaration.The syntax for definitions is In the context, T is the functional type for variable x1, while A is the session type for channel $c2 and M is a functional expression implementing the process.We add syntactic sugar, such as the forms let x = M; P and if M then P 1 else P 2 , to the process layer to ease programming.Finally, a functional expression can enter the session type monad using {}, i.e., M = {P} where P is a session-typed expression.
Type Checking: We implemented a bi-directional [40] type checker with a specific focus on the quality of error messages, which include, for example, extent (source code location) information for each definition and expression.The programmer provides the initial type of each variable and channel in the declaration and the definition is checked against it, while reconstructing the intermediate types.This helps localize the source of a type error as the point where type reconstruction fails.Type equality is restricted to reflexivity (constant time), although we have also implemented the standard co-inductive algorithm [29] which is quadratic in the size of type definitions.For all our examples, the reflexive notion of equality was sufficient.Type checking is linear time in the size of the program, which is important in the blockchain domain where type checking can be part of the attack surface.
Potential and Mode Inference: The potential and mode annotations are the most interesting aspects of the Nomos type system.Since modes are associated with each channel, they are tedious to write.Similarly, the exact potential annotations depend on the cost assigned to each operation and is difficult to predict statically.Thus, we implemented an automatic inference algorithm for both these annotations by relying on an off-the-shelf LP solver.
Using ideas from existing techniques for type inference for AARA [18], [21], we reduce the reconstruction of potential annotations to linear optimization.To this end, Nomos' inference engine uses the Coin-Or LP solver.In a Nomos program, the programmer can indicate unknown potential using * .Thus, resource-aware session types can be marked with * and * , list types can be marked as L * (τ ) and process definitions can be marked with |{ * }− on the turnstile.The mode of all the channels is marked as 'unknown' while parsing.
The inference engine iterates over the program and substitutes the star annotations with potential variables and 'unknown' with mode variables.Then, the bidirectional typing rules are applied, approximately checking the program (modulo potential and mode annotations) while also generating linear constraints for potential annotations (see Figure 4).and mode annotations (see Definition 1 and Figure 3).Finally, these constraints are shipped to the LP solver, which minimizes the value of the potential annotations to achieve tight bounds.The LP solver either returns that the constraints are infeasible, or returns a satisfying assignment, which is then substituted into the program.The final program is pretty printed for the programmer to view and verify the potential and mode annotations.

A. Case Studies
We evaluate the design of Nomos by implementing several smart contract applications and discussing the typical issues that arise.All the contracts are implemented and type checked in the prototype implementation and the potential and mode annotations are derived automatically by the inference engine.The cost model used for these examples assigns 1 unit of cost to every atomic internal computation and sending of a message.We show the contract types from the implementation with the following ASCII format: ERC-20 Token Standard: ERC-20 [41] is a technical standard for smart contracts on the Ethereum blockchain that defines a common list of standard functions that a token contract has to implement.The majority of tokens on the Ethereum blockchain are ERC-20 compliant.
The ERC-20 token contract implements the following session type in Nomos: stype erc20token = /\ <{11}| &{ totalSupply : int ˆ|{9}> \/ erc20token, balanceOf : id -> int ˆ|{8}> \/ erc20token, transfer : id -> id -> int -> |{0}> \/ erc20token, approve : id -> id -> int -> |{6}> \/ erc20token, allowance : id -> id -> int ˆ|{6}> \/ erc20token } The type ensures that the token implements the protocol underlying the ERC-20 standard.To query the total number of tokens in supply, a client sends the totalSupply label, and the contract sends back an integer.If the contract receives the balanceOf label followed by the owner's identifier, it sends back an integer corresponding to the owner's balance.A balance transfer can be initiated by sending the transfer label to the contract followed by sender's and receiver's identifier, and the amount to be transferred.If the contract receives approve, it receives the two identifiers and the value, and updates the allowance internally.Finally, this allowance can be checked by issuing the allowance label, and sending the owner's and spender's identifier.The design of Nomos is orthogonal to the concrete representation of money or currency in the language.The Nomos implementation provides a simple built-in abstract coin type of a unit value.Our implementation of the erc20token session type relies on these abstract coins used exclusively for exchanges among the private accounts.Coins are treated linearly as no operations are allowed on primitive types.As a result, coins cannot be created or discarded.
It is straightforward to add features by using more sophisticated abstract coin types or by providing built-in operations that are executed by the runtime system.For example, we can add coins with unique identifiers or coins of different denominations by changing the underlying session type of coins.Similarly, we can add operations for minting (creating) or burning (discarding) coins if users have the respective privileges.Such operations could be, for instance, implemented in an abstract contract that is an interface to the runtime system.Finally, there can be operations for exchanging coins and gas at rates that are fixed when type-checking transactions.
It is also possible to allow programmers to define their own abstract types with their individual introduction and elimination forms to use them in an implementation of a session type like erc20token.
Hacker Gold (HKG) Token: The HKG token is one particular implementation of the ERC-20 token specification.Recently, a vulnerability was discovered in the HKG token smart contract based on a typographical error leading to a reissuance of the entire token [42].When updating the receiver's balance during a transfer, instead of writing balance+=value, the programmer mistakenly wrote balance=+value (semantically meaning balance=value).Nomos' type system would have caught the linearity violation in the latter statement that drops the existing balance in the recipient's account.
Puzzle Contract: This contract, taken from prior work [43] rewards users who solve a computational puzzle and submit the solution.The contract allows two functions, one that allows the owner to update the reward, and the other that allows a user to submit their solution and collect the reward.
In Nomos, this contract is implemented to offer the type The contract still supports the two transactions.To update the reward, it receives the update label and an identifier, verifies that the sender is the owner, receives money from the sender, and acts like a puzzle again.The transaction to submit a solution has a guard associated with it.First, the contract sends an integer corresponding to the reward amount, the user then verifies that the reward matches the expected reward (the guard condition).If this check succeeds, the user sends the success label, followed by the solution, receives the winnings, and the session terminates.If the guard fails, the user issues the failure label and immediately terminates the session.Thus, the contract implementation guarantees that the user submitting the solution receives their expected winnings.

Voting:
The voting contract provides a ballot type.Once the election closes, the contract can be acquired to check the winner.We use two implementations for the contract: the first stores a counter for each candidate that is updated after each vote is cast (voting in Table II); the second does not use a counter but stores potential inside the vote list that is consumed for counting the votes at the end (voting-aa in Table II).This stored potential is provided by the voter to amortize the cost of counting.The type above shows the potential annotations corresponding to the latter.
Insurance: Nomos has been carefully designed to allow inter-contract communication without compromising type safety.We illustrate this feature using an insurance contract that processes flight delay insurance claims after verifying them with a trusted third party.The insurer and third party verifier are implemented as separate contracts providing the following session types.The insurer type provides the option to submit a claim by receiving it and responds with success or failure depending upon verification of the claim.If the claim is successful, the insurer sends over the reimbursement in the form of money.
The verifier type provides the option to verify a claim by receiving it and responding with valid or invalid depending on the validity of the claim.The insurer, upon receiving a claim, acquires the verifier and sends it the claim details.If the claim is valid, then it responds with success, sends the money and detaches from its client.If the claim is invalid, it responds with failure and immediately detaches from its client.
Experimental Evaluation: We describe the 8 case studies we implemented in Nomos.We have already discussed auction (Section II), ERC 20, puzzle, voting, and insurance.The other case studies are: • A bank account that allows users to register, make deposits and withdrawals and check the balance.• An escrow to exchange bonds between two parties.
• A wallet allowing users to store money on the blockchain.Table II  The evaluation shows that the type-checking overhead is less than a millisecond for case studies.This indicates that Nomos is applicable to settings like distributed blockchains in which type checking could add significant overhead and could be part of the attack surface.Type inference is also efficient but an order of magnitude slower than type checking.This is acceptable since inference is only performed once during deployment and can be carried out off-chain.Gas bounds are tight in most cases.Loose gas bounds are caused by conditional branches with different gas cost.In practice, this is not a major concern since the Nomos semantics tracks the exact gas cost, and a user will not be overcharged for their transaction.However, Nomos' type system can be easily modified to only allow contracts with tight bounds.
Our implementation experience revealed that describing the session type of a contract crystallizes the important aspects of its protocol.Often, subtle aspects of a contract are revealed while defining the protocol as a session type.Once the type is defined, the implementation simply follows the type protocol.The error messages from the type checker were helpful in ensuring linearity of assets and adherence to the protocol.Using * for potential annotations meant we could remain unaware of the exact gas cost of operations.The syntactic sugar constructs reduced the programming overhead and the size of the contract implementations.

IX. BLOCKCHAIN INTEGRATION
To integrate Nomos with a blockchain, we need a mechanism to (i) represent contracts and their addresses in the current blockchain state, (ii) create and execute transactions, and (iii) construct the global distributed ledger.
Nomos on a Blockchain: We assume a blockchain like Ethereum that contains a set of Nomos contracts C 1 , . . ., C n together with their type information • ; Γ i ; ∆ i R qi C i :: (x i S : A i S ).The shared context Γ i types the shared contracts that C i refers to, and the linear context ∆ i R types the contract's linear assets.The channel name x i S of a contract is its address and has to be globally unique.We allow contracts to carry potential given by the annotation q i and the potential defined by the annotations in ∆ i R but the type system could easily be altered to suppress the potential.
These contracts form a stuck configuration (a valid virtual blockchain state) typed as ) and E = Σ n i=1 q i + w i is the total energy, that is, the sum of the stored potential and previously performed work.To perform a transaction with a contract, a user submits a transaction script Q (a process) that is well-typed with respect to the existing contracts: We mandate that the transaction offers along a channel of type 1 and terminates by sending a close message on its offered channel.This enforces that the transaction, at termination, leaves the blockchain in a well-formed state.This script process is added to the set of contracts and the new (closed) configuration is typed as )) This configuration then steps according to the Nomos semantics, ending with the termination of the script Q, leaving the configuration in a stuck state again to start a new transaction.If type checking were too costly here, that can lead to yet another source of denial-of-service attacks.In Nomos however, type checking is linear time in the size of the script.
A transaction can either create new contracts, or update the state of existing contracts.In the former case, new contracts are added to the blockchain state, making them visible in the type of the configuration for subsequent transactions to access.In the latter case, it acquires the contracts it wishes to interact with, followed by an update in the contracts' internal state and releases them.Since the contract types are equisynchronizing, they remain unchanged at the end of transaction execution.This ensures that the subsequent transactions can access the same contracts at the same type.In the future we plan to allow sub-synchronizing types that enable a client to release a contract channel not at the same type, but a subtype.The subtype can then describe the phase of the contract.For instance, the ended phase of auction contract will be a subtype of the running phase.The technical report [26] details the technique for serialized execution of transactions.
Deterministic Execution: Since blockchains rely on consensus among the miners, it is important to ensure deterministic execution of transactions.However, Nomos semantics has one source of non-determinism: the acquire-accept rule where an accepting contract latches on to any acquiring transaction.Our approach to resolve this non-determinism is to determinize the process scheduler based on some heuristics.Another promising approach is record-and-replay [44], [45].The miner records the order in which the contracts are acquired in the ledger, which is then replayed by others to compute the current blockchain state.
Interpreter: The Nomos implementation provides two functionalities: (i) inference: takes a program as input, infers the potential and mode annotations and outputs a well-typed program (discussed in Section VIII), and (ii) execution: which takes a well-typed transaction program and a valid blockchain state as input, executes the transaction against the state and outputs a valid blockchain state.Internally, the blockchain state is represented as a configuration, i.e. set of contracts and linear assets stored inside them.Our implementation serializes the configuration using OCaml S-expressions so that their snapshots can be written to and read from a file.This makes the blockchain state persistent through transactions.
Attacker Model: Our blockchain model requires that all code submitted for execution is well-typed.The soundness theorem of Nomos (Theorem 1) then guarantees that execution of well-typed code cannot damage the blockchain state, or render it unusable.Thus, we capitalize on the restriction requiring adversarial code to be type correct.Furthemore, the Nomos type checker is carefully implemented to be linear-time in the size of the program.Thus, an adversary cannot cause denial-of-service by submitting programs that take too long to typecheck!Deadlocks: The only language specific reason a transaction can fail is a deadlock in the transaction code.Our progress theorem accounts for this possibility of deadlocks.Since a valid blockchain state represents a stuck configuration of a particular form (only shared contracts in the configuration), we verify at the end of the transaction execution if the new configuration has this form.If not, we conclude that a deadlock occurred during the execution, and we simply abort the whole transaction.We maintain snapshots of the configuration after every transaction execution, so we simply revert to the previous valid blockchain state.It is the user's responsibility to issue a new transaction that does not deadlock.In the future, we also plan to employ deadlock prevention techniques [46] to statically rule out deadlocks.

X. OTHER RELATED WORK
We classify the related work into 3 categories -i) new programming languages for smart contracts, ii) static analysis techniques for existing languages and bytecode, and iii) session-typed and type-based resource analysis systems technically related to Nomos.
Smart Contract Languages: Existing smart contracts on Ethereum are predominantly implemented in Solidity [4], a statically typed object-oriented language influenced by Python and JavaScript.Languages like Vyper [47] address resource usage by disallowing recursion and infinite-length loops, thus making estimation of gas usage decidable.However, both languages still suffer from re-entrancy vulnerabilities.Bamboo [48], on the other hand, makes state transitions explicit and avoids re-entrance by design.In contrast to our work, none of these languages use linear type systems to track assets stored in a contract.Domain specific languages have also been designed for other blockchains apart from Ethereum.Typecoin [49] uses affine logic to solve the peer-to-peer affine commitment problem using a generalization of Bitcoin where transactions deal in types rather than numbers.Although Typecoin does not provide a mechanism for expressing protocols, it also uses a linear type system to prevent resources from being discarded or duplicated.Rholang [50] is formally modeled by the ρ-calculus, a reflective higher-order extension of the π-calculus.Michelson [51] is a purely functional stack-based language that has no side effects.However, none of these languages describe and enforce communication protocols statically.Scilla [52] is an intermediate-level language where contracts are structured as communicating automata providing a continuation-passing style computational model to the language semantics.Scilla does not use session types or linearity but features static gas bounds.A difference is that Nomos' bounds are not asymptotic and are proved sound with respect to a cost semantics.The Move programming language [53] is a flexible language based on Rust [54] to implement contracts on the Libra blockchain.Similar to Nomos, it provides the ability to define custom linear types to represent assets.However, it does not provide support to express contract protocols or gas usage.
Static Analysis: Analysis of smart contracts has received substantial attention [55], [56] recently due to their security vulnerabilities [57], [58].KEVM [59] creates a program verifier based on reachability logic that given an EVM program and specification, tries to automatically prove the corresponding reachability theorems.However, the verifier requires significant manual intervention, both in specification and proof construction.Oyente [43] is a symbolic execution tool that checks for 4 kinds of security bugs in smart contracts, transaction-order dependence, timestamp dependence, mishandled exceptions and re-entrancy vulnerabilities.MadMax [60] automatically detects gas-focused vulnerabilities with high confidence.The analysis is based on a decompiler that extracts control and data flow information from EVM bytecode, and a logic-based analysis specification that produces a highlevel program model.Ethereum contracts are also translated to F* [61] to prove runtime safety and functional correctness, although they do not support all syntactic features.VERISOL [62] is a highly-automated formal verifier for Solidity that can produce proofs as well as counterexamples and proves semantic conformance of smart contracts against a state machine model with access-control policy.However, in contrast to Nomos, where guarantees are proved by a soundness proof of the type system, static analysis techniques often do not explore all program paths, can report false positives that need to be manually filtered, and miss bugs due to timeouts and other sources of incompleteness.
Session types and Resource analysis: Session types were introduced by Honda [11] as a typed formalism for inter-process dyadic interaction.They have been integrated into a functional language in prior work [15].However, this integration does not account for resource usage or sharing.Sharing in session types has also been explored in prior work [24], but with the strong restriction that shared processes cannot rely on linear resources that we lift in Nomos.Shared session types were also never integrated with a functional layer or tracked for resource usage.While we consider binary session types that express local interactions, global protocols can be expressed using multi-party session types [13], [63].Automatic amortized resource analysis (AARA) has been introduced as a type system to derive linear [18] and polynomial bounds [21] for functional programming languages.Resource usage has also previously been explored separately for the purely linear process layer [27], but were never combined with shared session types or integrated with the functional layer.

XI. CONCLUSION
We have described the programming language Nomos, its type-theoretic foundation, a prototype implementation and evaluated its feasibility on several real world smart contract applications.Nomos builds on linear logic, shared session types, and automatic amortized resource analysis to address the challenges that programmers are faced with when implementing digital contracts.Our main contributions are the design and implementation of Nomos' multi-layered resource-aware type system and its type soundness proof.
In future work, we plan to explore refinement session types [64], [65] for expressing and verifying functional correctness of contracts against their specifications and to target open questions regarding a blockchain integration.These include the exact cost model, fluctuation of gas prices, and potential compilation to a lower-level language.Since Nomos has a concurrent semantics, we also plan to support parallel execution of transactions using speculation techniques [66].
contains a compilation of our experiments with the case studies and the prototype implementation.The experiments were run on an Intel Core i5 2.7 GHz processor with 16 GB 1867 MHz DDR3 memory.It presents the contract name, its lines of code (LOC), the type checking time (T (ms)), number of potential and mode variables introduced (Vars), number of potential and mode constraints that were generated while type checking (Cons) and the time the LP solver took The last column describes the maximal gap between the static gas bound inferred and the actual runtime gas cost.It accounts for the difference in the gas cost in different program paths.However, this waste is clearly marked in the program by explicit tick instructions so the programmer is aware of this runtime gap, based on the program path executed.