From 0b5bfff7f40efbf69c41493bc3261776e1da1f70 Mon Sep 17 00:00:00 2001 From: Elton Baidoo Date: Sat, 6 Sep 2025 15:29:28 -0400 Subject: [PATCH 1/7] Git CI workflow for file tests --- .github/workflows/ci.yml | 65 ++++++++++++++++++ .python-version | 1 + ogc-contracts/projects/ogc-contracts/Makefile | 33 +++++++++ .../projects/ogc-contracts/README.md | 35 ++++++++++ .../__pycache__/simple_vault.cpython-313.pyc | Bin 0 -> 4414 bytes .../__pycache__/working_vault.cpython-313.pyc | Bin 0 -> 5248 bytes .../projects/ogc-contracts/ogc_demo.py | 64 +++++++++++++++++ .../projects/ogc-contracts/pyproject.toml | 32 +++++++++ .../__pycache__/__init__.cpython-313.pyc | Bin 0 -> 184 bytes .../__pycache__/__main__.cpython-313.pyc | Bin 0 -> 8711 bytes .../__pycache__/contract.cpython-313.pyc | Bin 0 -> 7694 bytes .../__pycache__/deploy_config.cpython-313.pyc | Bin 0 -> 1637 bytes .../projects/ogc-contracts/test_vault.py | 62 +++++++++++++++++ .../projects/ogc-contracts/working_vault.py | 59 ++++++++++++++++ 14 files changed, 351 insertions(+) create mode 100644 .github/workflows/ci.yml create mode 100644 .python-version create mode 100644 ogc-contracts/projects/ogc-contracts/Makefile create mode 100644 ogc-contracts/projects/ogc-contracts/README.md create mode 100644 ogc-contracts/projects/ogc-contracts/__pycache__/simple_vault.cpython-313.pyc create mode 100644 ogc-contracts/projects/ogc-contracts/__pycache__/working_vault.cpython-313.pyc create mode 100644 ogc-contracts/projects/ogc-contracts/ogc_demo.py create mode 100644 ogc-contracts/projects/ogc-contracts/pyproject.toml create mode 100644 ogc-contracts/projects/ogc-contracts/smart_contracts/__pycache__/__init__.cpython-313.pyc create mode 100644 ogc-contracts/projects/ogc-contracts/smart_contracts/__pycache__/__main__.cpython-313.pyc create mode 100644 ogc-contracts/projects/ogc-contracts/smart_contracts/ogc_vault/__pycache__/contract.cpython-313.pyc create mode 100644 ogc-contracts/projects/ogc-contracts/smart_contracts/ogc_vault/__pycache__/deploy_config.cpython-313.pyc create mode 100644 ogc-contracts/projects/ogc-contracts/test_vault.py create mode 100644 ogc-contracts/projects/ogc-contracts/working_vault.py diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..39f21bf --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,65 @@ +name: OGC CI + +on: + push: + branches: [ main, develop, ci-runner ] + pull_request: + branches: [ main, develop ] + +jobs: + test: + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Setup Python 3.13 + uses: actions/setup-python@v5 + with: + python-version: '3.13' + + - name: Install pipx and AlgoKit + run: | + python -m pip install --user pipx + python -m pipx ensurepath + pipx install algokit==2.9.0 + echo "$HOME/.local/bin" >> $GITHUB_PATH + + - name: Verify AlgoKit installation + run: algokit --version + + - name: Start LocalNet + run: | + algokit localnet start + sleep 10 # Give LocalNet time to fully start + + - name: Install Poetry + run: | + python -m pip install poetry==1.8.3 + poetry --version + + - name: Install dependencies + working-directory: ogc-contracts/projects/ogc-contracts + run: | + poetry install --no-interaction --no-root + + - name: Build contracts + working-directory: ogc-contracts/projects/ogc-contracts + run: | + poetry run python working_vault.py + ls -la artifacts/working_vault/ || echo "Artifacts directory not found" + + - name: Run tests + working-directory: ogc-contracts/projects/ogc-contracts + run: | + poetry run python test_vault.py + + - name: Run OGC demo + working-directory: ogc-contracts/projects/ogc-contracts + run: | + poetry run python ogc_demo.py + + - name: Stop LocalNet + if: always() + run: algokit localnet stop \ No newline at end of file diff --git a/.python-version b/.python-version new file mode 100644 index 0000000..7acdc73 --- /dev/null +++ b/.python-version @@ -0,0 +1 @@ +3.13.7 \ No newline at end of file diff --git a/ogc-contracts/projects/ogc-contracts/Makefile b/ogc-contracts/projects/ogc-contracts/Makefile new file mode 100644 index 0000000..3a16316 --- /dev/null +++ b/ogc-contracts/projects/ogc-contracts/Makefile @@ -0,0 +1,33 @@ +.PHONY: help install build deploy test demo clean + +help: ## Show this help message + @grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-20s\033[0m %s\n", $$1, $$2}' + +install: ## Install dependencies + poetry install --no-interaction + +build: ## Build smart contracts + poetry run python working_vault.py + @echo "✅ Contracts built in artifacts/" + +deploy: ## Deploy to LocalNet + poetry run python deploy_working.py + +test: ## Run test suite + poetry run python test_vault.py + +demo: ## Run OGC demo + poetry run python ogc_demo.py + +clean: ## Clean artifacts + rm -rf artifacts/ + rm -rf __pycache__/ + rm -rf .pytest_cache/ + +localnet-start: ## Start LocalNet + algokit localnet start + +localnet-stop: ## Stop LocalNet + algokit localnet stop + +ci: install build test demo ## Run full CI pipeline \ No newline at end of file diff --git a/ogc-contracts/projects/ogc-contracts/README.md b/ogc-contracts/projects/ogc-contracts/README.md new file mode 100644 index 0000000..0e659a5 --- /dev/null +++ b/ogc-contracts/projects/ogc-contracts/README.md @@ -0,0 +1,35 @@ +# OGC Smart Contracts + +Smart contracts for the OGC (Out The Groupchat) project. + +## Quick Start + +```bash +# Install dependencies +make install + +# Build contracts +make build + +# Run tests +make test + +# Run demo +make demo +``` + +## CI/CD + +This project uses GitHub Actions for continuous integration: +- ✅ Builds contracts on every push +- ✅ Runs test suite +- ✅ Validates demo scenarios +- ✅ Uses pinned dependencies for reproducibility + +## Dependencies + +All dependencies are pinned in `pyproject.toml` for reproducible builds: +- `beaker-pyteal==1.1.1` +- `pyteal==0.24.1` +- `py-algorand-sdk==2.10.0` +- `algokit-utils==2.4.0` \ No newline at end of file diff --git a/ogc-contracts/projects/ogc-contracts/__pycache__/simple_vault.cpython-313.pyc b/ogc-contracts/projects/ogc-contracts/__pycache__/simple_vault.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f9b31b9ee6b3f00c22237df4b918f67d764ce067 GIT binary patch literal 4414 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 icRX`>Z};Eoe|IqJs?l6E%iH$= goal: + print("🎉 Goal reached!") + else: + print(f"⏳ Need {(goal-total)/1_000_000} more ALGO") + + return {"app_id": app_id, "total": total, "goal": goal} + +if __name__ == "__main__": + result = ogc_demo() + print(f"🏁 Demo complete: {result['total']/1_000_000} ALGO raised") \ No newline at end of file diff --git a/ogc-contracts/projects/ogc-contracts/pyproject.toml b/ogc-contracts/projects/ogc-contracts/pyproject.toml new file mode 100644 index 0000000..1d46d84 --- /dev/null +++ b/ogc-contracts/projects/ogc-contracts/pyproject.toml @@ -0,0 +1,32 @@ +[tool.poetry] +name = "ogc-contracts" +version = "0.1.0" +description = "OGC - Out The Groupchat: Decentralized group funding on Algorand" +authors = ["OGC Team"] +readme = "README.md" + +[tool.poetry.dependencies] +python = "^3.13" +beaker-pyteal = "1.1.1" +pyteal = "0.24.1" +py-algorand-sdk = "2.10.0" +algokit-utils = "2.4.0" +python-dotenv = "1.1.1" +setuptools = "80.9.0" + +[tool.poetry.group.dev.dependencies] +pytest = "^8.0.0" +black = "^24.0.0" +isort = "^5.13.0" + +[build-system] +requires = ["poetry-core"] +build-backend = "poetry.core.masonry.api" + +[tool.black] +line-length = 88 +target-version = ['py313'] + +[tool.isort] +profile = "black" +line_length = 88 \ No newline at end of file diff --git a/ogc-contracts/projects/ogc-contracts/smart_contracts/__pycache__/__init__.cpython-313.pyc b/ogc-contracts/projects/ogc-contracts/smart_contracts/__pycache__/__init__.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..ebf031b2a6bfce9e343df4f50d60cf80fea902e2 GIT binary patch literal 184 zcmey&%ge<81oMmbWPs?$AOZ#$p^VQgK*m&tbOudEzm*I{OhDdekkqYk{m|mnqGJ8j zoRa*!q{PgW{Cs_XcW3?l^km)S{JfH)#N?7<{eq(WtW*#KRk%1ev8W^-p)5W=GcU6w lK3=b&@)n0pZhlH>PO4oIE6^U0JBmS!kIamWj77{q765|gF@yjB literal 0 HcmV?d00001 diff --git a/ogc-contracts/projects/ogc-contracts/smart_contracts/__pycache__/__main__.cpython-313.pyc b/ogc-contracts/projects/ogc-contracts/smart_contracts/__pycache__/__main__.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..45e3fa55a76ed862d92673b3c27549d73dce9968 GIT binary patch literal 8711 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 KN}h+?;rZX{Fk)-~ literal 0 HcmV?d00001 diff --git a/ogc-contracts/projects/ogc-contracts/smart_contracts/ogc_vault/__pycache__/contract.cpython-313.pyc b/ogc-contracts/projects/ogc-contracts/smart_contracts/ogc_vault/__pycache__/contract.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..3d235bee3f0bac4a94896c4cff44318080df5914 GIT binary patch literal 7694 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 literal 0 HcmV?d00001 diff --git a/ogc-contracts/projects/ogc-contracts/test_vault.py b/ogc-contracts/projects/ogc-contracts/test_vault.py new file mode 100644 index 0000000..d2272bf --- /dev/null +++ b/ogc-contracts/projects/ogc-contracts/test_vault.py @@ -0,0 +1,62 @@ +#!/usr/bin/env python3 +"""Test suite for OGC Vault""" + +from beaker import sandbox, client +from working_vault import app +from algosdk import transaction as tx +from algosdk.atomic_transaction_composer import TransactionWithSigner + +def test_vault_basic(): + print("🧪 Testing OGC Vault Basic Flow") + + algod_client = sandbox.get_algod_client() + creator = sandbox.get_accounts().pop() + contributor = sandbox.get_accounts().pop() + + goal = 1_000_000 # 1 ALGO + current_round = algod_client.status()["last-round"] + deadline_round = current_round + 100 + + # Deploy + app_client = client.ApplicationClient( + client=algod_client, + app=app, + signer=creator.signer, + ) + + app_id, app_addr, _ = app_client.create( + goal_amount=goal, + deadline_round=deadline_round, + receiver_addr=creator.address, + ) + + print(f"✅ Deployed: APP_ID {app_id}") + + # Fund app + sp = algod_client.suggested_params() + fund_txn = tx.PaymentTxn(creator.address, sp, app_addr, 2_000_000) + algod_client.send_transaction(fund_txn.sign(creator.private_key)) + + # Test contribution + contrib_amount = 500_000 + pmt = tx.PaymentTxn(contributor.address, sp, app_addr, contrib_amount) + pmt_with_signer = TransactionWithSigner(pmt, contributor.signer) + + app_client_contrib = client.ApplicationClient( + client=algod_client, app=app, app_id=app_id, signer=contributor.signer + ) + app_client_contrib.call("contribute", payment=pmt_with_signer) + + # Verify + total = app_client.call("get_total").return_value + goal_check = app_client.call("get_goal").return_value + + assert total == contrib_amount, f"Expected {contrib_amount}, got {total}" + assert goal_check == goal, f"Expected {goal}, got {goal_check}" + + print(f"✅ Contribution test passed: {total/1_000_000} ALGO") + return True + +if __name__ == "__main__": + success = test_vault_basic() + print(f"🏁 Tests {'PASSED' if success else 'FAILED'}") \ No newline at end of file diff --git a/ogc-contracts/projects/ogc-contracts/working_vault.py b/ogc-contracts/projects/ogc-contracts/working_vault.py new file mode 100644 index 0000000..0f8d0ec --- /dev/null +++ b/ogc-contracts/projects/ogc-contracts/working_vault.py @@ -0,0 +1,59 @@ +#!/usr/bin/env python3 +"""Working vault with proper schema""" + +from pyteal import * +from beaker import * + +class VaultState: + goal = GlobalStateValue(stack_type=TealType.uint64, key=Bytes("goal"), default=Int(0)) + deadline = GlobalStateValue(stack_type=TealType.uint64, key=Bytes("deadline"), default=Int(0)) + receiver = GlobalStateValue(stack_type=TealType.bytes, key=Bytes("receiver"), default=Bytes("")) + total = GlobalStateValue(stack_type=TealType.uint64, key=Bytes("total"), default=Int(0)) + +app = Application("WorkingVault", state=VaultState) + +@app.create +def create(goal_amount: abi.Uint64, deadline_round: abi.Uint64, receiver_addr: abi.Address, *, output: abi.Uint64): + return Seq( + app.state.goal.set(goal_amount.get()), + app.state.deadline.set(deadline_round.get()), + app.state.receiver.set(receiver_addr.get()), + app.state.total.set(Int(0)), + output.set(Global.current_application_id()), + ) + +@app.external +def contribute(payment: abi.PaymentTransaction): + return Seq( + Assert(And( + payment.get().receiver() == Global.current_application_address(), + payment.get().amount() > Int(0), + )), + app.state.total.set(app.state.total.get() + payment.get().amount()), + ) + +@app.external +def release(): + now = Global.round() + bal = Balance(Global.current_application_address()) + return Seq( + Assert(And(now >= app.state.deadline.get(), bal >= app.state.goal.get())), + InnerTxnBuilder.Begin(), + InnerTxnBuilder.SetFields({ + TxnField.type_enum: TxnType.Payment, + TxnField.receiver: app.state.receiver.get(), + TxnField.amount: bal - Int(1_000_000), + }), + InnerTxnBuilder.Submit(), + ) + +@app.external(read_only=True) +def get_goal(*, output: abi.Uint64): + return output.set(app.state.goal.get()) + +@app.external(read_only=True) +def get_total(*, output: abi.Uint64): + return output.set(app.state.total.get()) + +if __name__ == "__main__": + app.build().export("./artifacts/working_vault") \ No newline at end of file From 1540a00ecc5275d9f7003cbc8d45000228f159a4 Mon Sep 17 00:00:00 2001 From: Elton Baidoo Date: Sat, 6 Sep 2025 15:38:03 -0400 Subject: [PATCH 2/7] Update CI runner to be more flexible with file structure naming --- .github/workflows/ci.yml | 73 ++++++++++++++++--- ogc-contracts/projects/ogc-contracts/Makefile | 34 +++++++-- 2 files changed, 91 insertions(+), 16 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 39f21bf..267c81c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -39,26 +39,79 @@ jobs: python -m pip install poetry==1.8.3 poetry --version + - name: Find project directory + id: find-project + run: | + # Find directory with pyproject.toml + PROJECT_DIR=$(find . -name "pyproject.toml" -type f | head -1 | xargs dirname) + if [ -z "$PROJECT_DIR" ]; then + echo "No pyproject.toml found, trying common patterns..." + for pattern in "*contracts*/projects/*" "*contracts*" "contracts" "."; do + if find $pattern -name "*.py" -path "*/smart_contracts/*" 2>/dev/null | head -1; then + PROJECT_DIR=$(find $pattern -name "*.py" -path "*/smart_contracts/*" 2>/dev/null | head -1 | xargs dirname | xargs dirname) + break + fi + done + fi + echo "PROJECT_DIR=$PROJECT_DIR" >> $GITHUB_OUTPUT + echo "Found project directory: $PROJECT_DIR" + - name: Install dependencies - working-directory: ogc-contracts/projects/ogc-contracts + working-directory: ${{ steps.find-project.outputs.PROJECT_DIR }} run: | - poetry install --no-interaction --no-root + if [ -f "pyproject.toml" ]; then + poetry install --no-interaction --no-root + else + echo "No pyproject.toml found, installing with pip" + pip install beaker-pyteal pyteal py-algorand-sdk algokit-utils python-dotenv setuptools + fi - name: Build contracts - working-directory: ogc-contracts/projects/ogc-contracts + working-directory: ${{ steps.find-project.outputs.PROJECT_DIR }} run: | - poetry run python working_vault.py - ls -la artifacts/working_vault/ || echo "Artifacts directory not found" + # Find and build any vault/contract files + for contract in *vault*.py *contract*.py; do + if [ -f "$contract" ]; then + echo "Building $contract..." + if [ -f "pyproject.toml" ]; then + poetry run python "$contract" + else + python "$contract" + fi + fi + done + # List any artifacts created + find . -name "artifacts" -type d -exec ls -la {} \; 2>/dev/null || echo "No artifacts directory found" - name: Run tests - working-directory: ogc-contracts/projects/ogc-contracts + working-directory: ${{ steps.find-project.outputs.PROJECT_DIR }} run: | - poetry run python test_vault.py + # Find and run test files + for test in test_*.py *_test.py; do + if [ -f "$test" ]; then + echo "Running $test..." + if [ -f "pyproject.toml" ]; then + poetry run python "$test" + else + python "$test" + fi + fi + done - - name: Run OGC demo - working-directory: ogc-contracts/projects/ogc-contracts + - name: Run demos + working-directory: ${{ steps.find-project.outputs.PROJECT_DIR }} run: | - poetry run python ogc_demo.py + # Find and run demo files + for demo in *demo*.py demo_*.py; do + if [ -f "$demo" ]; then + echo "Running $demo..." + if [ -f "pyproject.toml" ]; then + poetry run python "$demo" + else + python "$demo" + fi + fi + done - name: Stop LocalNet if: always() diff --git a/ogc-contracts/projects/ogc-contracts/Makefile b/ogc-contracts/projects/ogc-contracts/Makefile index 3a16316..4f9b9c6 100644 --- a/ogc-contracts/projects/ogc-contracts/Makefile +++ b/ogc-contracts/projects/ogc-contracts/Makefile @@ -7,17 +7,39 @@ install: ## Install dependencies poetry install --no-interaction build: ## Build smart contracts - poetry run python working_vault.py + @echo "🔨 Building contracts..." + @for contract in *vault*.py *contract*.py; do \ + if [ -f "$$contract" ]; then \ + echo "Building $$contract..."; \ + poetry run python "$$contract"; \ + fi; \ + done @echo "✅ Contracts built in artifacts/" deploy: ## Deploy to LocalNet - poetry run python deploy_working.py + @for deploy in deploy_*.py *_deploy.py; do \ + if [ -f "$$deploy" ]; then \ + echo "Running $$deploy..."; \ + poetry run python "$$deploy"; \ + break; \ + fi; \ + done test: ## Run test suite - poetry run python test_vault.py - -demo: ## Run OGC demo - poetry run python ogc_demo.py + @for test in test_*.py *_test.py; do \ + if [ -f "$$test" ]; then \ + echo "Running $$test..."; \ + poetry run python "$$test"; \ + fi; \ + done + +demo: ## Run demos + @for demo in *demo*.py demo_*.py; do \ + if [ -f "$$demo" ]; then \ + echo "Running $$demo..."; \ + poetry run python "$$demo"; \ + fi; \ + done clean: ## Clean artifacts rm -rf artifacts/ From 086102e31a7bb61e8431ddd3f7a8841623e23969 Mon Sep 17 00:00:00 2001 From: Elton Baidoo Date: Sat, 6 Sep 2025 15:58:34 -0400 Subject: [PATCH 3/7] Add setup markdown file --- SETUP.md | 122 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 122 insertions(+) create mode 100644 SETUP.md diff --git a/SETUP.md b/SETUP.md new file mode 100644 index 0000000..63663ae --- /dev/null +++ b/SETUP.md @@ -0,0 +1,122 @@ +# OGC Development Setup + +## 🚀 Fresh AlgoKit Setup + +If you just installed AlgoKit and want to start: + +### 1. Install AlgoKit +```bash +# Install AlgoKit +pipx install algokit + +# Verify installation +algokit --version +algokit doctor # Check system health +``` + +### 2. Start LocalNet +```bash +# Start Algorand LocalNet +algokit localnet start + +# Check status +algokit localnet status +``` + +### 3. Navigate to Project +```bash +cd ~/OGC/ogc-contracts/projects/ogc-contracts +``` + +### 4. Activate Environment +```bash +# Activate Poetry virtualenv +source "$(poetry env info --path)/bin/activate" + +# Verify Python version +python --version # Should be 3.13.x +``` + +### 5. Install Dependencies +```bash +# Install with Poetry +poetry install + +# Or manually with pip +pip install beaker-pyteal pyteal py-algorand-sdk algokit-utils +``` + +### 6. Build & Test +```bash +# Build contracts +python working_vault.py + +# Run tests +python test_vault.py + +# Run demo +python ogc_demo.py +``` + +### 7. Stop When Done +```bash +# Stop LocalNet +algokit localnet stop +``` + +## 🔄 Quick Reset Script + +If you need to reset your environment: + +```bash +# One-liner to get back into dev mode +cd ~/OGC/ogc-contracts/projects/ogc-contracts && source "$(poetry env info --path)/bin/activate" && python --version +``` + +Or use the Makefile: +```bash +make dev # Activates environment and drops into shell +``` + +## 🛠️ Development Commands + +```bash +make install # Install dependencies +make build # Build contracts +make test # Run tests +make demo # Run demo +make ci # Full CI pipeline +``` + +## 🔍 Troubleshooting + +**LocalNet not starting?** +```bash +algokit localnet reset # Reset LocalNet +algokit doctor # Check system health +``` + +**Python version issues?** +```bash +poetry env info # Check Poetry environment +poetry shell # Alternative to source activation +``` + +**Dependencies not found?** +```bash +poetry install --no-cache # Reinstall dependencies +``` + +## 📁 Project Structure + +``` +OGC/ +├── SETUP.md # This file +├── .github/workflows/ci.yml # CI configuration +└── ogc-contracts/projects/ogc-contracts/ + ├── pyproject.toml # Dependencies + ├── Makefile # Build commands + ├── working_vault.py # Main contract + ├── test_vault.py # Tests + └── ogc_demo.py # Demo +``` \ No newline at end of file From 50b639e6dfee4e287ac4b5b7aae92d7e0a531114 Mon Sep 17 00:00:00 2001 From: Elton Baidoo <146414760+eltonbaidoo@users.noreply.github.com> Date: Sat, 6 Sep 2025 16:00:20 -0400 Subject: [PATCH 4/7] Update directory structure instructions in SETUP.md --- SETUP.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/SETUP.md b/SETUP.md index 63663ae..b5bfcd2 100644 --- a/SETUP.md +++ b/SETUP.md @@ -27,6 +27,7 @@ algokit localnet status ```bash cd ~/OGC/ogc-contracts/projects/ogc-contracts ``` +any directory name is fine but it should have the \/projects/\ ### 4. Activate Environment ```bash @@ -119,4 +120,4 @@ OGC/ ├── working_vault.py # Main contract ├── test_vault.py # Tests └── ogc_demo.py # Demo -``` \ No newline at end of file +``` From 3a5f32ad17cc3f4d4481440b91be46a02a9f4b50 Mon Sep 17 00:00:00 2001 From: Elton Baidoo <146414760+eltonbaidoo@users.noreply.github.com> Date: Sat, 6 Sep 2025 16:01:43 -0400 Subject: [PATCH 5/7] Update Build & Test section in SETUP.md --- SETUP.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SETUP.md b/SETUP.md index b5bfcd2..77603bd 100644 --- a/SETUP.md +++ b/SETUP.md @@ -47,7 +47,7 @@ poetry install pip install beaker-pyteal pyteal py-algorand-sdk algokit-utils ``` -### 6. Build & Test +### 6. Build & Test (Have to write it or pull it) ```bash # Build contracts python working_vault.py From f21de4dd760bd22a1b9a71e681e1c44d05b3be06 Mon Sep 17 00:00:00 2001 From: Elton Baidoo Date: Sat, 6 Sep 2025 16:34:39 -0400 Subject: [PATCH 6/7] ADD tangible set up --- DEMO.md | 127 ++++++++++++++++++ TANGIBLE_DEMO.md | 127 ++++++++++++++++++ .../__pycache__/working_vault.cpython-313.pyc | Bin 5248 -> 5248 bytes .../projects/ogc-contracts/asa_vault.py | 66 +++++++++ .../ogc-contracts/create_ogc_token.py | 48 +++++++ .../projects/ogc-contracts/test_token.py | 54 ++++++++ .../projects/ogc-contracts/verify_token.py | 33 +++++ 7 files changed, 455 insertions(+) create mode 100644 DEMO.md create mode 100644 TANGIBLE_DEMO.md create mode 100644 ogc-contracts/projects/ogc-contracts/asa_vault.py create mode 100644 ogc-contracts/projects/ogc-contracts/create_ogc_token.py create mode 100644 ogc-contracts/projects/ogc-contracts/test_token.py create mode 100644 ogc-contracts/projects/ogc-contracts/verify_token.py diff --git a/DEMO.md b/DEMO.md new file mode 100644 index 0000000..64f3c54 --- /dev/null +++ b/DEMO.md @@ -0,0 +1,127 @@ +# OGC Demo Commands + +## 📍 Where to Run Commands + +**All commands must be run from:** +```bash +/Users/eltonbaidoo/OGC/ogc-contracts/projects/ogc-contracts/ +``` + +## 🚀 Quick Start + +### 1. Navigate & Activate +```bash +cd ~/OGC/ogc-contracts/projects/ogc-contracts +source "$(poetry env info --path)/bin/activate" +python --version # Should show 3.13.x +``` + +### 2. Create OGC Token +```bash +python create_ogc_token.py +``` +**Expected Output:** +``` +🪙 Creating OGC Token... +✅ OGC Token Created! + Asset ID: 1033 + Total Supply: 1,000,000,000 OGC + Creator: VYXZFE4BGH... +``` + +### 3. Verify Token +```bash +python verify_token.py +``` +**Expected Output:** +``` +🔍 Verifying OGC Token... +✅ OGC Token Found! + Asset ID: 1033 + Name: OGC Token + Unit: OGC + Total: 1,000,000,000 +``` + +### 4. Demo ALGO Vault +```bash +python ogc_demo.py +``` +**Expected Output:** +``` +🚀 OGC - Out The Groupchat Demo +🎯 Goal: 2.0 ALGO +✅ Fund Created: APP_ID 1036 +💰 Total: 1.5 ALGO +⏳ Need 0.5 more ALGO +``` + +### 5. Run Tests +```bash +python test_vault.py +``` +**Expected Output:** +``` +🧪 Testing OGC Vault Basic Flow +✅ Deployed: APP_ID 1037 +✅ Contribution test passed: 0.5 ALGO +🏁 Tests PASSED +``` + +## 🎯 One-Liner Commands + +### Full Demo Sequence +```bash +cd ~/OGC/ogc-contracts/projects/ogc-contracts && source "$(poetry env info --path)/bin/activate" && python create_ogc_token.py && python verify_token.py && python ogc_demo.py +``` + +### Quick Token Demo +```bash +python create_ogc_token.py && python verify_token.py +``` + +### Quick Vault Demo +```bash +python ogc_demo.py && python test_vault.py +``` + +## 🛠️ Makefile Commands + +```bash +make demo # Run ogc_demo.py +make test # Run test_vault.py +make build # Build working_vault.py +make ci # Run full pipeline +``` + +## 📊 What Each Command Does + +| Command | Purpose | Output | +|---------|---------|---------| +| `create_ogc_token.py` | Mints OGC token on LocalNet | Asset ID number | +| `verify_token.py` | Confirms token exists | Token details | +| `ogc_demo.py` | Shows group funding scenario | ALGO vault demo | +| `test_vault.py` | Tests contract functions | Test results | +| `working_vault.py` | Builds smart contract | Artifacts created | + +## 🎤 For Hackathon Presentation + +**Run in this order:** +1. `python create_ogc_token.py` - "We minted OGC token" +2. `python verify_token.py` - "Token verified on Algorand" +3. `python ogc_demo.py` - "Group funding demo" +4. `python test_vault.py` - "All tests pass" + +## 🔧 Troubleshooting + +**If commands fail:** +```bash +# Check you're in right directory +pwd # Should show: /Users/eltonbaidoo/OGC/ogc-contracts/projects/ogc-contracts + +# Check environment is active +which python # Should show venv path + +# Reactivate if needed +source "$(poetry env info --path)/bin/activate" +``` \ No newline at end of file diff --git a/TANGIBLE_DEMO.md b/TANGIBLE_DEMO.md new file mode 100644 index 0000000..2b7d75f --- /dev/null +++ b/TANGIBLE_DEMO.md @@ -0,0 +1,127 @@ +# OGC Tangible Demo Commands + +## 📍 Where to Run Commands + +**All commands must be run from:** +```bash +/Users/eltonbaidoo/OGC/ogc-contracts/projects/ogc-contracts/ +``` + +## 🚀 Quick Start + +### 1. Navigate & Activate +```bash +cd ~/OGC/ogc-contracts/projects/ogc-contracts +source "$(poetry env info --path)/bin/activate" +python --version # Should show 3.13.x +``` + +### 2. Create OGC Token +```bash +python create_ogc_token.py +``` +**Expected Output:** +``` +🪙 Creating OGC Token... +✅ OGC Token Created! + Asset ID: 1033 + Total Supply: 1,000,000,000 OGC + Creator: VYXZFE4BGH... +``` + +### 3. Verify Token +```bash +python verify_token.py +``` +**Expected Output:** +``` +🔍 Verifying OGC Token... +✅ OGC Token Found! + Asset ID: 1033 + Name: OGC Token + Unit: OGC + Total: 1,000,000,000 +``` + +### 4. Demo ALGO Vault +```bash +python ogc_demo.py +``` +**Expected Output:** +``` +🚀 OGC - Out The Groupchat Demo +🎯 Goal: 2.0 ALGO +✅ Fund Created: APP_ID 1036 +💰 Total: 1.5 ALGO +⏳ Need 0.5 more ALGO +``` + +### 5. Run Tests +```bash +python test_vault.py +``` +**Expected Output:** +``` +🧪 Testing OGC Vault Basic Flow +✅ Deployed: APP_ID 1037 +✅ Contribution test passed: 0.5 ALGO +🏁 Tests PASSED +``` + +## 🎯 One-Liner Commands + +### Full Demo Sequence +```bash +cd ~/OGC/ogc-contracts/projects/ogc-contracts && source "$(poetry env info --path)/bin/activate" && python create_ogc_token.py && python verify_token.py && python ogc_demo.py +``` + +### Quick Token Demo +```bash +python create_ogc_token.py && python verify_token.py +``` + +### Quick Vault Demo +```bash +python ogc_demo.py && python test_vault.py +``` + +## 🛠️ Makefile Commands + +```bash +make demo # Run ogc_demo.py +make test # Run test_vault.py +make build # Build working_vault.py +make ci # Run full pipeline +``` + +## 📊 What Each Command Does + +| Command | Purpose | Output | +|---------|---------|---------| +| `create_ogc_token.py` | Mints OGC token on LocalNet | Asset ID number | +| `verify_token.py` | Confirms token exists | Token details | +| `ogc_demo.py` | Shows group funding scenario | ALGO vault demo | +| `test_vault.py` | Tests contract functions | Test results | +| `working_vault.py` | Builds smart contract | Artifacts created | + +## 🎤 For Hackathon Presentation + +**Run in this order:** +1. `python create_ogc_token.py` - "We minted OGC token" +2. `python verify_token.py` - "Token verified on Algorand" +3. `python ogc_demo.py` - "Group funding demo" +4. `python test_vault.py` - "All tests pass" + +## 🔧 Troubleshooting + +**If commands fail:** +```bash +# Check you're in right directory +pwd # Should show: /Users/eltonbaidoo/OGC/ogc-contracts/projects/ogc-contracts + +# Check environment is active +which python # Should show venv path + +# Reactivate if needed +source "$(poetry env info --path)/bin/activate" +``` \ No newline at end of file diff --git a/ogc-contracts/projects/ogc-contracts/__pycache__/working_vault.cpython-313.pyc b/ogc-contracts/projects/ogc-contracts/__pycache__/working_vault.cpython-313.pyc index c2cfc1c946002a05ee40fd3e25cf674a3c0a4b2a..ba728485a9fd32d8e13b68303d6b5d3ffa32190c 100644 GIT binary patch delta 19 YcmZqBY|!NT%*)Hg00gGp8@b9v050zYc>n+a delta 19 YcmZqBY|!NT%*)Hg00b_z8@b9v051asdH?_b diff --git a/ogc-contracts/projects/ogc-contracts/asa_vault.py b/ogc-contracts/projects/ogc-contracts/asa_vault.py new file mode 100644 index 0000000..6282eb8 --- /dev/null +++ b/ogc-contracts/projects/ogc-contracts/asa_vault.py @@ -0,0 +1,66 @@ +#!/usr/bin/env python3 +"""ASA-compatible vault contract""" + +from pyteal import * +from beaker import * + +class ASAVaultState: + goal = GlobalStateValue(stack_type=TealType.uint64, key=Bytes("goal"), default=Int(0)) + deadline = GlobalStateValue(stack_type=TealType.uint64, key=Bytes("deadline"), default=Int(0)) + receiver = GlobalStateValue(stack_type=TealType.bytes, key=Bytes("receiver"), default=Bytes("")) + asset_id = GlobalStateValue(stack_type=TealType.uint64, key=Bytes("asset_id"), default=Int(0)) + total = GlobalStateValue(stack_type=TealType.uint64, key=Bytes("total"), default=Int(0)) + +app = Application("ASAVault", state=ASAVaultState) + +@app.create +def create(goal_amount: abi.Uint64, deadline_round: abi.Uint64, receiver_addr: abi.Address, asset: abi.Asset, *, output: abi.Uint64): + return Seq( + app.state.goal.set(goal_amount.get()), + app.state.deadline.set(deadline_round.get()), + app.state.receiver.set(receiver_addr.get()), + app.state.asset_id.set(asset.asset_id()), + app.state.total.set(Int(0)), + output.set(Global.current_application_id()), + ) + +@app.external +def contribute_asa(*, axfer: abi.AssetTransferTransaction): + return Seq( + Assert(And( + axfer.get().xfer_asset() == app.state.asset_id.get(), + axfer.get().asset_receiver() == Global.current_application_address(), + axfer.get().asset_amount() > Int(0), + )), + app.state.total.set(app.state.total.get() + axfer.get().asset_amount()), + ) + +@app.external +def release_asa(): + now = Global.round() + return Seq( + Assert(And(now >= app.state.deadline.get(), app.state.total.get() >= app.state.goal.get())), + InnerTxnBuilder.Begin(), + InnerTxnBuilder.SetFields({ + TxnField.type_enum: TxnType.AssetTransfer, + TxnField.xfer_asset: app.state.asset_id.get(), + TxnField.asset_receiver: app.state.receiver.get(), + TxnField.asset_amount: app.state.total.get(), + }), + InnerTxnBuilder.Submit(), + ) + +@app.external(read_only=True) +def get_goal(*, output: abi.Uint64): + return output.set(app.state.goal.get()) + +@app.external(read_only=True) +def get_total(*, output: abi.Uint64): + return output.set(app.state.total.get()) + +@app.external(read_only=True) +def get_asset_id(*, output: abi.Uint64): + return output.set(app.state.asset_id.get()) + +if __name__ == "__main__": + app.build().export("./artifacts/asa_vault") \ No newline at end of file diff --git a/ogc-contracts/projects/ogc-contracts/create_ogc_token.py b/ogc-contracts/projects/ogc-contracts/create_ogc_token.py new file mode 100644 index 0000000..e51456f --- /dev/null +++ b/ogc-contracts/projects/ogc-contracts/create_ogc_token.py @@ -0,0 +1,48 @@ +#!/usr/bin/env python3 +"""Create OGC Token (ASA) for demo""" + +from beaker import sandbox +from algosdk import transaction as tx + +def create_ogc_token(): + print("🪙 Creating OGC Token...") + + algod = sandbox.get_algod_client() + creator = sandbox.get_accounts().pop() + sp = algod.suggested_params() + + # Create ASA + txn = tx.AssetCreateTxn( + sender=creator.address, + sp=sp, + total=1_000_000_000, # 1 billion tokens + decimals=6, # 6 decimal places + default_frozen=False, + unit_name="OGC", + asset_name="OGC Token", + url="https://ogc.example.com", + manager=creator.address, + reserve=creator.address, + freeze=None, + clawback=None, + ) + + stx = txn.sign(creator.private_key) + txid = algod.send_transaction(stx) + + # Wait for confirmation + import time + time.sleep(2) # Simple wait + confirmed = algod.pending_transaction_info(txid) + asset_id = confirmed["asset-index"] + + print(f"✅ OGC Token Created!") + print(f" Asset ID: {asset_id}") + print(f" Total Supply: 1,000,000,000 OGC") + print(f" Creator: {creator.address}") + + return asset_id, creator + +if __name__ == "__main__": + asset_id, creator = create_ogc_token() + print(f"\n💡 Use Asset ID {asset_id} in your demos!") \ No newline at end of file diff --git a/ogc-contracts/projects/ogc-contracts/test_token.py b/ogc-contracts/projects/ogc-contracts/test_token.py new file mode 100644 index 0000000..57706cf --- /dev/null +++ b/ogc-contracts/projects/ogc-contracts/test_token.py @@ -0,0 +1,54 @@ +#!/usr/bin/env python3 +"""Test OGC token transfers""" + +from beaker import sandbox +from algosdk import transaction as tx + +def test_token_transfer(): + print("🧪 Testing OGC Token Transfer...") + + algod = sandbox.get_algod_client() + creator, alice = sandbox.get_accounts()[:2] + sp = algod.suggested_params() + + # Get asset ID from user + asset_id = int(input("Enter Asset ID from create_ogc_token.py: ")) + + # Alice opts into the token + print("📝 Alice opting into OGC token...") + optin = tx.AssetTransferTxn( + sender=alice.address, + sp=sp, + receiver=alice.address, + amt=0, + index=asset_id + ) + algod.send_transaction(optin.sign(alice.private_key)) + import time + time.sleep(2) # Wait for opt-in to confirm + print("✅ Alice opted in") + + # Creator sends tokens to Alice + print("💸 Sending 1000 OGC to Alice...") + transfer = tx.AssetTransferTxn( + sender=creator.address, + sp=sp, + receiver=alice.address, + amt=1000_000_000, # 1000 OGC (6 decimals) + index=asset_id + ) + algod.send_transaction(transfer.sign(creator.private_key)) + print("✅ Transfer complete!") + + # Check Alice's balance + alice_info = algod.account_info(alice.address) + for asset in alice_info.get("assets", []): + if asset["asset-id"] == asset_id: + balance = asset["amount"] / 1_000_000 # Convert from micro-units + print(f"💰 Alice's OGC balance: {balance} OGC") + break + + print("🎉 Token test successful!") + +if __name__ == "__main__": + test_token_transfer() \ No newline at end of file diff --git a/ogc-contracts/projects/ogc-contracts/verify_token.py b/ogc-contracts/projects/ogc-contracts/verify_token.py new file mode 100644 index 0000000..ed983c3 --- /dev/null +++ b/ogc-contracts/projects/ogc-contracts/verify_token.py @@ -0,0 +1,33 @@ +#!/usr/bin/env python3 +"""Verify OGC token exists""" + +from beaker import sandbox + +def verify_token(): + print("🔍 Verifying OGC Token...") + + algod = sandbox.get_algod_client() + asset_id = 1033 # From create_ogc_token.py output + + try: + # Get asset info + asset_info = algod.asset_info(asset_id) + params = asset_info["params"] + + print(f"✅ OGC Token Found!") + print(f" Asset ID: {asset_id}") + print(f" Name: {params['name']}") + print(f" Unit: {params['unit-name']}") + print(f" Total: {params['total']:,}") + print(f" Decimals: {params['decimals']}") + print(f" Creator: {params['creator']}") + + return True + + except Exception as e: + print(f"❌ Token not found: {e}") + return False + +if __name__ == "__main__": + success = verify_token() + print(f"🏁 Verification {'PASSED' if success else 'FAILED'}") \ No newline at end of file From c08512360d45a67a99f43f91b09219e1d8ff8199 Mon Sep 17 00:00:00 2001 From: Elton Baidoo Date: Sat, 6 Sep 2025 17:00:36 -0400 Subject: [PATCH 7/7] eb-main --- ogc-contracts/projects/ogc-contracts/asa_vault.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ogc-contracts/projects/ogc-contracts/asa_vault.py b/ogc-contracts/projects/ogc-contracts/asa_vault.py index 6282eb8..9ba08b0 100644 --- a/ogc-contracts/projects/ogc-contracts/asa_vault.py +++ b/ogc-contracts/projects/ogc-contracts/asa_vault.py @@ -25,7 +25,7 @@ def create(goal_amount: abi.Uint64, deadline_round: abi.Uint64, receiver_addr: a ) @app.external -def contribute_asa(*, axfer: abi.AssetTransferTransaction): +def contribute_asa(axfer: abi.AssetTransferTransaction): return Seq( Assert(And( axfer.get().xfer_asset() == app.state.asset_id.get(),