Syntax overview¶
Contract Templates¶
A contract template in Spedn represents a template for generating a P2SH address and corresponding redeem script. It can be parametrized. Contract parameters have to be specified to instantiate it, that is - to generate a particular contract with an address.
You can perceive a contract template as a specification of a pin tumbler lock mechanism while a contract is a particular lock and parameters are pin lengths in it.
Syntax:
contract ContractName ( [type paramName [, …]] ) { }
Example:
contract SomeContract(Ripemd160 pubKeyHash, int x) {
// challenges
}
Challenges¶
A challenge is a set of conditions that have to be met to redeem a coin locked in a contract.
Challenges specify arguments that will be expected to be provided in scriptSig
when redeeming the coin.
A contract must contain at least one challenge and a challenge must define at least one argument.
Challenges must have unique names.
A challenge introduces a lexical scope so two different challenges can define an argument with the same name.
When redeeming a coin, a redeemer must choose one of the challenges and satisfy its conditions.
You can perceive a challenge as a keyhole in a lock and arguments as keys.
Syntax:
challenge name ( type argName [, …] **) statement **
Example:
challenge someChallenge(PubKey pubKey, Sig signature) {
// statements...
}
Statements¶
A challenge can contain any number of statements. To be precise - it contains a single statement but this can be a block statement which can contain any number of statements.
There are the following kinds of statements:
Verification¶
The most important statement and often the only one needed. It evaluates an expression and fails the script if the result is false.
Syntax:
verify expr ;
Example:
verify hash1 == hash2;
Variable binding¶
You can define a local variable that will be accessible down in the same lexical scope and nested scopes.
Syntax:
type name = expr ;
Example:
int a = b + c;
There is also a possibility to define 2 variables in case of using the split operator. If one of the results is unnecessary, you can ignore it with a low dash operator.
Syntax:
type [ leftName , rightName ] = expr1 @ expr2 ;
type [ _, rightName ] = expr1 @ expr2 ;
type [ leftName , _ ] = expr1 @ expr2 ;
Example:
bin [prefix, _] = secret @ 4;
Conditional¶
You can conditionaly execute a branch of code. A branch introduces a new lexical scope and it can be a verification, block or another conditional.
Syntax:
if ( condition ) statement [ else statement ]
Example:
if (num % 2 == 1)
verify checkSig(sig, alice);
else
verify checkSig(sig, bob);
Block¶
A block is a statement that groups several statements for sequential execution. A block introduces a lexical scope. The last statement must be a verification or conditional.
Syntax:
{ [ statements… ] }
Example:
if (num % 2 = 1) {
verify checkSig(sig, alice);
} else {
verify checkSig(sig, bob);
verify checkSequence(5d);
}
Loop¶
There are no loops, it’s Bitcoin.
Lexical scopes¶
Spedn creates common, nested lexical scopes for parameters, arguments, variables and functions. There can be no 2 identical names within the same scope. Also - name shadowing is prohibited so a nested scope cannot redefine a name present in its parent scope.
There are following scopes in the nesting order:
- Global scope - contains predefined functions and type constructors
- Contract scope - introduced by the contract, contains contract parameters
- Challenge scope - introduced by the challenge, contains challenge arguments and local variables
- Local scope - introduced by if/else/block statements, contains local variables
Exhaustive example:
// a global scope, names like checkSig, min, max are reserved.
// contract scope begins
contract X(int a, int b) { // names a, b are defined
// challenge scope begins
challenge a( // it's OK for the challenge to be named a because challenge names don't occupy the name table.
int c // name c is defined
/* int a // BAD - already defined in contract scope */)
{
verify a >= b;
/* verify a == d // BAD - d is not yet defined */
int d = a + b; // name d is defined
if (d > 0)
// if scope begins
{
int e = d % c;
verify e == 0;
}
// if scope ends; e is gone.
else
// else scope begins
verify a == b;
// else scope ends
/* verify e == 1 // BAD - e is gone */
}
// challenge scope ends; c, d are gone
// challenge scope begins
challenge b(int c, int d) // names c, d are defined
{
verify c == d;
}
// challenge scope ends; c, d are gone
}
// contract scope ends; a, b are gone