Skip to content

Commit

Permalink
feat: adding latest changes from beaker template (debugger, typed sim…
Browse files Browse the repository at this point in the history
…ulate) (#2)

* feat: adding latest changes from beaker template (debugger, typed simulate)

* chore: minor tweaks

* refactor: simplifying configuration and test variations

* chore: fixing typos

* feat: Update contract.py.j2 templates

- Updated the `hello` method in the `contract.py.j2` template files to return a modified greeting message.
- The greeting message now includes a comma after "Hello" for better readability and clarity.
  • Loading branch information
aorumbayev authored Dec 19, 2023
1 parent a8c9a1b commit ee81044
Show file tree
Hide file tree
Showing 198 changed files with 3,050 additions and 243 deletions.
37 changes: 32 additions & 5 deletions copier.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,13 @@ author_name:
type: str
help: Package author name
placeholder: "Your Name"
default: "Your Name"

author_email:
type: str
help: Package author email
placeholder: "[email protected]"
default: "[email protected]"

ide_vscode:
type: bool
Expand All @@ -55,9 +57,33 @@ deployment_language:
TypeScript: "typescript"
default: "python"

use_python_pytest:
type: bool
when: false
help: Do you want to include unit tests (via pytest)?
# deployment_language is empty when using the default_language
default: |-
{% if deployment_language|length == 0 or deployment_language == 'python' -%}
yes
{%- else -%}
no
{%- endif %}
use_typescript_jest:
type: bool
when: false
help: Do you want to include unit tests (via jest)?
default: |-
{% if deployment_language == 'typescript' -%}
yes
{%- else -%}
no
{%- endif %}
python_linter:
type: str
help: Do you want to use a Python linter?
when: false
choices:
Ruff: "ruff"
Flake8: "flake8"
Expand All @@ -67,39 +93,40 @@ python_linter:
use_python_black:
type: bool
when: false
help: Do you want to use a Python formatter (via Black)?
default: yes

use_python_mypy:
type: bool
when: false
help: Do you want to use a Python type checker (via mypy)?
default: |-
yes
use_python_pytest:
type: bool
help: Do you want to include unit tests (via pytest)?
default: yes

use_python_pip_audit:
type: bool
when: false
help: Do you want to include Python dependency vulnerability scanning (via pip-audit)?
default: yes

use_github_actions:
type: bool
when: false
help: Do you want to include Github Actions workflows for build and testnet deployment?
default: |-
yes
use_pre_commit:
type: bool
when: false
help: Do you want to include pre-commit for linting, type checking and formatting?
default: |-
yes
use_dispenser:
type: bool
when: false
help: Do you want to fund your deployment account using an optional dispenser account?
default: no

Expand Down
1 change: 1 addition & 0 deletions includes/contract_name_kebab.jinja
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{{- contract_name.split('_')|join('-') -}}
1 change: 1 addition & 0 deletions includes/contract_name_pascal.jinja
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{{- contract_name.split('_')|map('capitalize')|join -}}
2 changes: 1 addition & 1 deletion template_content/.algokit.toml.jinja
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
[algokit]
min_version = "v1.7.3"
min_version = "v1.8.0"

[deploy]
{%- if deployment_language == 'python' %}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,4 @@ from puyapy.arc4 import String, abimethod
class {{ contract_name.split('_')|map('capitalize')|join }}(ARC4Contract):
@abimethod()
def hello(self, name: String) -> String:
return String.encode(Bytes(b"Hello ") + name.decode())
return String.encode(Bytes(b"Hello, ") + name.decode())
4 changes: 4 additions & 0 deletions template_content/.gitignore.jinja
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ coverage.xml
.hypothesis/
.pytest_cache/
cover/
coverage/

# Translations
*.mo
Expand Down Expand Up @@ -172,3 +173,6 @@ cython_debug/

# NPM
node_modules

# AlgoKit
debug_traces/
13 changes: 13 additions & 0 deletions template_content/README.md.jinja
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,19 @@ This project has been generated using AlgoKit. See below for default getting sta

This project uses [GitHub Actions](https://docs.github.com/en/actions/learn-github-actions/understanding-github-actions) to define CI/CD workflows, which are located in the [`.github/workflows`](./.github/workflows) folder.

### Debugging Smart Contracts

This project is optimized to work with AlgoKit AVM Debugger extension. To activate it:
{%- if deployment_language == 'python' %}
Refer to the commented header in the `__main__.py` file in the `smart_contracts` folder.
{%- elif deployment_language == 'typescript' %}
Refer to the commented header in the `index.ts` file in the `smart_contracts` folder.
{%- endif %}

If you have opted in to include VSCode launch configurations in your project, you can also use the `Debug TEAL via AlgoKit AVM Debugger` launch configuration to interactively select an available trace file and launch the debug session for your smart contract.

For information on using and setting up the `AlgoKit AVM Debugger` VSCode extension refer [here](https://github.com/algorandfoundation/algokit-avm-vscode-debugger). To install the extension from the VSCode Marketplace, use the following link: [AlgoKit AVM Debugger extension](https://marketplace.visualstudio.com/items?itemName=algorandfoundation.algokit-avm-vscode-debugger).

#### Setting up GitHub for CI/CD workflow and TestNet deployment

1. Every time you have a change to your smart contract, and when you first initialize the project you need to [build the contract](#initial-setup) and then commit the `smart_contracts/artifacts` folder so the [output stability](https://github.com/algorandfoundation/algokit-cli/blob/main/docs/articles/output_stability.md) tests pass
Expand Down
4 changes: 2 additions & 2 deletions template_content/pyproject.toml.jinja
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@ readme = "README.md"

[tool.poetry.dependencies]
python = "^3.12"
algokit-utils = "^2.0.1"
algokit-utils = "^2.2.0"
python-dotenv = "^1.0.0"
puya = "^0.1.3"
puya = "^0.2.0"

[tool.poetry.group.dev.dependencies]
{% if use_python_black -%}
Expand Down
11 changes: 7 additions & 4 deletions template_content/smart_contracts/__main__.py.jinja
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,16 @@ from pathlib import Path
from dotenv import load_dotenv

from smart_contracts.config import contracts
{% if deployment_language == 'python' -%}
from smart_contracts.helpers.build import build
{% if deployment_language == 'python' -%}
from smart_contracts.helpers.deploy import deploy
{%- elif deployment_language == 'typescript' -%}
from smart_contracts.helpers.build import build
{%- endif %}

# Uncomment the following lines to enable auto generation of AVM Debugger compliant sourcemap and simulation trace file.
# Learn more about using AlgoKit AVM Debugger to debug your TEAL source codes and inspect various kinds of
# Algorand transactions in atomic groups -> https://github.com/algorandfoundation/algokit-avm-vscode-debugger
# from algokit_utils.config import config
# config.configure(debug=True, trace_all=True)
{%- endif %}
logging.basicConfig(
level=logging.DEBUG, format="%(asctime)s %(levelname)-10s: %(message)s"
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,13 @@ import * as path from 'path'
import { consoleLogger } from '@algorandfoundation/algokit-utils/types/logging'
import * as algokit from '@algorandfoundation/algokit-utils'

// Uncomment the debug and traceAll options to enable auto generation of AVM Debugger compliant sourceMap and simulation trace file.
// Learn more about using AlgoKit AVM Debugger to debug your TEAL source codes and inspect various kinds of Algorand transactions in atomic groups -> https://github.com/algorandfoundation/algokit-avm-vscode-Debugger

algokit.Config.configure({
logger: consoleLogger,
// debug: true,
// traceAll: true,
})

// base directory
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,4 @@ from puyapy.arc4 import String, abimethod
class {{ contract_name.split('_')|map('capitalize')|join }}(ARC4Contract):
@abimethod()
def hello(self, name: String) -> String:
return String.encode(Bytes(b"Hello ") + name.decode())
return String.encode(Bytes(b"Hello, ") + name.decode())
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,15 @@ def deploy(
deployer: algokit_utils.Account,
) -> None:
from smart_contracts.artifacts.{{ contract_name }}.client import (
{{ contract_name.split('_')|map('capitalize')|join }}Client,
{% include pathjoin('includes', 'contract_name_pascal.jinja') %}Client,
)

app_client = {{ contract_name.split('_')|map('capitalize')|join }}Client(
app_client = {% include pathjoin('includes', 'contract_name_pascal.jinja') %}Client(
algod_client,
creator=deployer,
indexer_client=indexer_client,
)

app_client.deploy(
on_schema_break=algokit_utils.OnSchemaBreak.AppendApp,
on_update=algokit_utils.OnUpdate.AppendApp,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ export async function deploy() {
},
algod,
)
const appClient = new {{ contract_name.split('_')|map('capitalize')|join }}Client(
const appClient = new {% include pathjoin('includes', 'contract_name_pascal.jinja') %}Client(
{
resolveBy: 'creatorAndName',
findExistingUsing: indexer,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
{
"name": "smart_contracts",
"version": "1.0.0",
"description": "Smart contract deployer",
"main": "index.ts",
"scripts": {
"deploy": "ts-node-dev --transpile-only --watch .env -r dotenv/config smart_contracts/index.ts",
"deploy:ci": "ts-node --transpile-only -r dotenv/config smart_contracts/index.ts",
{%- if use_typescript_jest %}
"test": "jest --coverage",
{%- endif %}
"format": "prettier --write ."
},
"engines": {
"node": ">=18.0"
},
"dependencies": {
"@algorandfoundation/algokit-utils": "^5.1.0",
"algosdk": "^2.5.0"
},
"devDependencies": {
{%- if use_typescript_jest %}
"@types/jest": "^29.5.11",
{%- endif %}
"dotenv": "^16.0.3",
"prettier": "^2.8.4",
{%- if use_typescript_jest %}
"ts-jest": "^29.1.1",
{%- endif %}
"ts-node-dev": "^2.0.0",
"typescript": "^4.9.5"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
{
"compilerOptions": {
"target": "ES2020",
"declaration": true,
"declarationMap": true,
"sourceMap": true,
"strict": true,
"noImplicitReturns": true,
"noFallthroughCasesInSwitch": true,
"esModuleInterop": true,
"experimentalDecorators": true,
"emitDecoratorMetadata": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true,
"allowJs": false,
"allowSyntheticDefaultImports": true,
"moduleResolution": "Node",
"resolveJsonModule": true,
"isolatedModules": true,
"noEmit": true
},
"include": ["src/**/*.ts"],
"exclude": ["node_modules", "dist", "coverage"]
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
"esbenp.prettier-vscode",
{% endif -%}
"tamasfe.even-better-toml",
"editorconfig.editorconfig"
"editorconfig.editorconfig",
"algorandfoundation.algokit-avm-vscode-debugger"
]
}
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,13 @@
"module": "smart_contracts",
"args": ["build"],
"cwd": "${workspaceFolder}"
},
{
"type": "avm",
"request": "launch",
"name": "Debug TEAL via AlgoKit AVM Debugger",
"simulateTraceFile": "${workspaceFolder}/${command:PickSimulateTraceFile}",
"stopOnEntry": true
}
]
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,11 @@
import pytest
from algokit_utils import (
get_algod_client,
get_indexer_client,
is_localnet,
)
from algosdk.v2client.algod import AlgodClient
from algosdk.v2client.indexer import IndexerClient
from dotenv import load_dotenv


Expand All @@ -23,3 +25,8 @@ def algod_client() -> AlgodClient:
# included here to prevent accidentally running against other networks
assert is_localnet(client)
return client


@pytest.fixture(scope="session")
def indexer_client() -> IndexerClient:
return get_indexer_client()
Original file line number Diff line number Diff line change
@@ -1,32 +1,48 @@
import algokit_utils
import pytest
from algokit_utils import get_localnet_default_account
from algokit_utils.config import config
from algosdk.v2client.algod import AlgodClient
from algosdk.v2client.indexer import IndexerClient

from smart_contracts.artifacts.{{ contract_name }}.client import {{ contract_name.split('_')|map('capitalize')|join }}Client
from smart_contracts.artifacts.{{ contract_name }}.client import {% include pathjoin('includes', 'contract_name_pascal.jinja') %}Client


@pytest.fixture(scope="session")
def {{ contract_name }}_client(
algod_client: AlgodClient, indexer_client: IndexerClient
) -> {{ contract_name.split('_')|map('capitalize')|join }}Client:
client = {{ contract_name.split('_')|map('capitalize')|join }}Client(
) -> {% include pathjoin('includes', 'contract_name_pascal.jinja') %}Client:
config.configure(
debug=True,
# trace_all=True,
)

client = {% include pathjoin('includes', 'contract_name_pascal.jinja') %}Client(
algod_client,
creator=get_localnet_default_account(algod_client),
indexer_client=indexer_client,
)

client.deploy(
on_schema_break=algokit_utils.OnSchemaBreak.ReplaceApp,
on_update=algokit_utils.OnUpdate.UpdateApp,
allow_delete=True,
allow_update=True,
on_schema_break=algokit_utils.OnSchemaBreak.AppendApp,
on_update=algokit_utils.OnUpdate.AppendApp,
)
return client


def test_says_hello({{ contract_name }}_client: {{ contract_name.split('_')|map('capitalize')|join }}Client) -> None:
def test_says_hello({{ contract_name }}_client: {% include pathjoin('includes', 'contract_name_pascal.jinja') %}Client) -> None:
result = {{ contract_name }}_client.hello(name="World")

assert result.return_value == "Hello, World"


def test_simulate_says_hello_with_correct_budget_consumed(
{{ contract_name }}_client: {% include pathjoin('includes', 'contract_name_pascal.jinja') %}Client, algod_client: AlgodClient
) -> None:
result = (
{{ contract_name }}_client.compose().hello(name="World").hello(name="Jane").simulate()
)

assert result.abi_results[0].return_value == "Hello, World"
assert result.abi_results[1].return_value == "Hello, Jane"
assert result.simulate_response["txn-groups"][0]["app-budget-consumed"] < 100
Loading

0 comments on commit ee81044

Please sign in to comment.