5 func checkRecursive(contract *Contract) bool {
6 for _, clause := range contract.Clauses {
7 for _, stmt := range clause.statements {
8 if l, ok := stmt.(*lockStatement); ok {
9 if c, ok := l.program.(*callExpr); ok {
10 if references(c.fn, contract.Name) {
20 func prohibitSigParams(contract *Contract) error {
21 for _, p := range contract.Params {
22 if p.Type == sigType {
23 return fmt.Errorf("contract parameter \"%s\" has type Signature, but contract parameters cannot have type Signature", p.Name)
29 func requireAllParamsUsedInClauses(params []*Param, clauses []*Clause) error {
30 for _, p := range params {
32 for _, c := range clauses {
33 err := requireAllParamsUsedInClause([]*Param{p}, c)
40 return fmt.Errorf("parameter \"%s\" is unused", p.Name)
46 func requireAllParamsUsedInClause(params []*Param, clause *Clause) error {
47 for _, p := range params {
49 for _, stmt := range clause.statements {
50 switch s := stmt.(type) {
51 case *verifyStatement:
52 used = references(s.expr, p.Name)
54 used = references(s.lockedAmount, p.Name) || references(s.lockedAsset, p.Name) || references(s.program, p.Name)
55 case *unlockStatement:
56 used = references(s.unlockedAmount, p.Name) || references(s.unlockedAsset, p.Name)
64 return fmt.Errorf("parameter \"%s\" is unused in clause \"%s\"", p.Name, clause.Name)
70 func references(expr expression, name string) bool {
71 switch e := expr.(type) {
73 return references(e.left, name) || references(e.right, name)
75 return references(e.expr, name)
77 if references(e.fn, name) {
80 for _, a := range e.args {
81 if references(a, name) {
87 return string(e) == name
89 for _, elt := range []expression(e) {
90 if references(elt, name) {
99 func requireAllValuesDisposedOnce(contract *Contract, clause *Clause) error {
100 err := valueDisposedOnce(contract.Value, clause)
107 func valueDisposedOnce(value ValueInfo, clause *Clause) error {
109 for _, s := range clause.statements {
110 switch stmt := s.(type) {
111 case *unlockStatement:
112 if references(stmt.unlockedAmount, value.Amount) && references(stmt.unlockedAsset, value.Asset) {
116 if references(stmt.lockedAmount, value.Amount) && references(stmt.lockedAsset, value.Asset) {
123 return fmt.Errorf("valueAmount \"%s\" or valueAsset \"%s\" not disposed in clause \"%s\"", value.Amount, value.Asset, clause.Name)
127 return fmt.Errorf("valueAmount \"%s\" or valueAsset \"%s\" disposed multiple times in clause \"%s\"", value.Amount, value.Asset, clause.Name)
131 func referencedBuiltin(expr expression) *builtin {
132 if v, ok := expr.(varRef); ok {
133 for _, b := range builtins {
134 if string(v) == b.name {
142 func assignIndexes(clause *Clause) {
144 for _, s := range clause.statements {
145 switch stmt := s.(type) {
147 stmt.index = nextIndex
150 case *unlockStatement:
156 func typeCheckClause(contract *Contract, clause *Clause, env *environ) error {
157 for _, s := range clause.statements {
158 switch stmt := s.(type) {
159 case *verifyStatement:
160 if t := stmt.expr.typ(env); t != boolType {
161 return fmt.Errorf("expression in verify statement in clause \"%s\" has type \"%s\", must be Boolean", clause.Name, t)
165 if t := stmt.lockedAmount.typ(env); !(t == intType || t == amountType) {
166 return fmt.Errorf("lockedAmount expression \"%s\" in lock statement in clause \"%s\" has type \"%s\", must be Integer", stmt.lockedAmount, clause.Name, t)
168 if t := stmt.lockedAsset.typ(env); t != assetType {
169 return fmt.Errorf("lockedAsset expression \"%s\" in lock statement in clause \"%s\" has type \"%s\", must be Asset", stmt.lockedAsset, clause.Name, t)
171 if t := stmt.program.typ(env); t != progType {
172 return fmt.Errorf("program in lock statement in clause \"%s\" has type \"%s\", must be Program", clause.Name, t)
175 case *unlockStatement:
176 if t := stmt.unlockedAmount.typ(env); !(t == intType || t == amountType) {
177 return fmt.Errorf("unlockedAmount expression \"%s\" in unlock statement of clause \"%s\" has type \"%s\", must be Integer", stmt.unlockedAmount, clause.Name, t)
179 if t := stmt.unlockedAsset.typ(env); t != assetType {
180 return fmt.Errorf("unlockedAsset expression \"%s\" in unlock statement of clause \"%s\" has type \"%s\", must be Asset", stmt.unlockedAsset, clause.Name, t)
182 if stmt.unlockedAmount.String() != contract.Value.Amount || stmt.unlockedAsset.String() != contract.Value.Asset {
183 return fmt.Errorf("amount \"%s\" of asset \"%s\" expression in unlock statement of clause \"%s\" must be the contract valueAmount \"%s\" of valueAsset \"%s\"",
184 stmt.unlockedAmount.String(), stmt.unlockedAsset.String(), clause.Name, contract.Value.Amount, contract.Value.Asset)