Skip to content

Commit

Permalink
feat: Add implicit create methods to contracts which don't have an ex…
Browse files Browse the repository at this point in the history
…plicit one
  • Loading branch information
tristanmenzel committed Oct 24, 2024
1 parent 32ac667 commit dc95de6
Show file tree
Hide file tree
Showing 2 changed files with 64 additions and 2 deletions.
44 changes: 42 additions & 2 deletions src/awst_build/contract-visitor.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import ts from 'typescript'
import { ContractReference } from '../awst/models'
import { ARC4BareMethodConfig, ARC4CreateOption, ContractReference, OnCompletionAction } from '../awst/models'
import { nodeFactory } from '../awst/node-factory'
import type * as awst from '../awst/nodes'
import type { ContractMethod } from '../awst/nodes'
Expand All @@ -9,7 +9,7 @@ import { voidWType } from '../awst/wtypes'
import { Constants } from '../constants'
import { AwstBuildFailureError, NotSupported, TodoError } from '../errors'
import { logger } from '../logger'
import { codeInvariant, invariant } from '../util'
import { codeInvariant, invariant, isIn } from '../util'
import type { ClassElements } from '../visitor/syntax-names'
import type { Visitor } from '../visitor/visitor'
import { accept } from '../visitor/visitor'
Expand Down Expand Up @@ -58,6 +58,25 @@ export class ContractVisitor extends BaseVisitor implements Visitor<ClassElement
this.acceptAndIgnoreBuildErrors(member)
}
}
const hasCreateMethod = this._subroutines.some((s) =>
isIn(s.arc4MethodConfig?.create, [ARC4CreateOption.Require, ARC4CreateOption.Allow]),
)
const hasBareNoopMethod = this._subroutines.some(
(s) => s.arc4MethodConfig?.isBare && isIn(OnCompletionAction.NoOp, s.arc4MethodConfig.allowedCompletionTypes),
)
if (!isAbstract && !hasCreateMethod) {
if (hasBareNoopMethod) {
logger.error(
sourceLocation,
`Non-abstract ARC4 contract has no methods which can be called to create the contract. ` +
`An implicit one could not be inserted as there is already a bare method handling the NoOp on completion action. ` +
`In order to allow creating the contract specify { onCreate: 'allow' } or { onCreate: 'require' } in an @abimethod or @baremethod decorator above the chosen method.`,
)
} else {
// TODO: This should check base classes
this._subroutines.push(this.makeDefaultCreate(sourceLocation))
}
}
const cref = ContractReference.fromPType(this._contractPType)
this.result = new ContractFragment({
name: this._className,
Expand Down Expand Up @@ -118,6 +137,27 @@ export class ContractVisitor extends BaseVisitor implements Visitor<ClassElement
})
}

private makeDefaultCreate(sourceLocation: SourceLocation) {
return nodeFactory.contractMethod({
memberName: '__algots__.defaultCreate',
cref: ContractReference.fromPType(this._contractPType),
args: [],
arc4MethodConfig: new ARC4BareMethodConfig({
allowedCompletionTypes: [OnCompletionAction.NoOp],
create: ARC4CreateOption.Require,
sourceLocation,
}),
synthetic: true,
returnType: voidWType,
inheritable: false,
documentation: nodeFactory.methodDocumentation(),
sourceLocation,
body: nodeFactory.block({
sourceLocation,
}),
})
}

private getBaseContracts(contractType: ContractClassPType): ContractReference[] {
return contractType.baseTypes.flatMap((baseType) => {
return [
Expand Down
22 changes: 22 additions & 0 deletions tests/expected-output/cant-create.algo.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { abimethod, Contract } from '@algorandfoundation/algorand-typescript'
import { baremethod } from '@algorandfoundation/algorand-typescript/arc4'

// @expect-error Non-abstract ARC4 contract has no methods which can be called to create the contract...
export class CantCreate extends Contract {
@baremethod({ allowActions: 'NoOp' })
public handleBare() {}
}

export abstract class CantCreateAbstract extends Contract {
@baremethod({ allowActions: 'NoOp' })
public handleBare() {}
}

export abstract class NoBare extends Contract {
@abimethod({ allowActions: 'NoOp' })
public handleNoop() {}
}
export abstract class NoNoOp extends Contract {
@baremethod({ allowActions: 'UpdateApplication' })
public handleUpdate() {}
}

0 comments on commit dc95de6

Please sign in to comment.