Skip to content

Commit

Permalink
Repo structure
Browse files Browse the repository at this point in the history
  • Loading branch information
lealobanov committed Dec 12, 2024
1 parent 5a68a0a commit a5d50a0
Show file tree
Hide file tree
Showing 8 changed files with 348 additions and 60 deletions.
29 changes: 25 additions & 4 deletions .github/workflows/cadence_lint.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
name: Run Cadence Lint
name: Run Cadence Contract Compilation, Deployment, Transaction Execution, and Lint
on: push

jobs:
Expand All @@ -9,7 +9,7 @@ jobs:
uses: actions/checkout@v3
with:
submodules: 'true'

- name: Install Flow CLI
run: |
brew update
Expand All @@ -23,8 +23,29 @@ jobs:
else
echo "Flow project already initialized."
fi
flow dependencies install
- name: Start Flow Emulator
run: |
echo "Starting Flow emulator in the background..."
nohup flow emulator start > emulator.log 2>&1 &
sleep 5 # Wait for the emulator to start
flow project deploy --network=emulator # Deploy the recipe contracts indicated in flow.json
- name: Run All Transactions
run: |
echo "Running all transactions in the transactions folder..."
for file in ./cadence/transactions/*.cdc; do
echo "Running transaction: $file"
TRANSACTION_OUTPUT=$(flow transactions send "$file" --signer emulator-account)
echo "$TRANSACTION_OUTPUT"
if echo "$TRANSACTION_OUTPUT" | grep -q "Transaction Error"; then
echo "Transaction Error detected in $file, failing the action..."
exit 1
fi
done
- name: Run Cadence Lint
run: |
echo "Running Cadence linter on all .cdc files in the current repository"
flow cadence lint **/*.cdc
echo "Running Cadence linter on .cdc files in the current repository"
flow cadence lint ./cadence/**/*.cdc
19 changes: 0 additions & 19 deletions cadence/contract.cdc

This file was deleted.

1 change: 1 addition & 0 deletions cadence/contract.cdc
187 changes: 187 additions & 0 deletions cadence/contracts/Recipe.cdc
Original file line number Diff line number Diff line change
@@ -0,0 +1,187 @@
/// ExampleToken.cdc
///
/// The ExampleToken contract is a sample implementation of a fungible token on Flow.
///
/// Fungible tokens behave like everyday currencies -- they can be minted, transferred or
/// traded for digital goods.
///
/// This is a basic implementation of a Fungible Token and is NOT meant to be used in production
/// See the Flow Fungible Token standard for real examples: https://github.com/onflow/flow-ft
access(all) contract ExampleToken {

access(all) entitlement Withdraw

access(all) let VaultStoragePath: StoragePath
access(all) let VaultPublicPath: PublicPath

access(all) var totalSupply: UFix64

/// Balance
///
/// The interface that provides a standard field
/// for representing balance
///
access(all) resource interface Balance {
access(all) var balance: UFix64
}

/// Provider
///
/// The interface that enforces the requirements for withdrawing
/// tokens from the implementing type.
///
/// It does not enforce requirements on `balance` here,
/// because it leaves open the possibility of creating custom providers
/// that do not necessarily need their own balance.
///
access(all) resource interface Provider {

/// withdraw subtracts tokens from the implementing resource
/// and returns a Vault with the removed tokens.
///
/// The function's access level is `access(Withdraw)`
/// So in order to access it, one would either need the object itself
/// or an entitled reference with `Withdraw`.
///
/// @param amount the amount of tokens to withdraw from the resource
/// @return The Vault with the withdrawn tokens
///
access(Withdraw) fun withdraw(amount: UFix64): @Vault {
post {
// `result` refers to the return value
result.balance == amount:
"ExampleToken.Provider.withdraw: Cannot withdraw tokens!"
.concat("The balance of the withdrawn tokens (").concat(result.balance.toString())
.concat(") is not equal to the amount requested to be withdrawn (")
.concat(amount.toString()).concat(")")
}
}
}

/// Receiver
///
/// The interface that enforces the requirements for depositing
/// tokens into the implementing type.
///
/// We do not include a condition that checks the balance because
/// we want to give users the ability to make custom receivers that
/// can do custom things with the tokens, like split them up and
/// send them to different places.
///
access(all) resource interface Receiver {

/// deposit takes a Vault and deposits it into the implementing resource type
///
/// @param from the Vault that contains the tokens to deposit
///
access(all) fun deposit(from: @Vault)
}

/// Vault
///
/// Each user stores an instance of only the Vault in their storage
/// The functions in the Vault are governed by the pre and post conditions
/// in the interfaces when they are called.
/// The checks happen at runtime whenever a function is called.
///
/// Resources can only be created in the context of the contract that they
/// are defined in, so there is no way for a malicious user to create Vaults
/// out of thin air. A special Minter resource or constructor function needs to be defined to mint
/// new tokens.
///
access(all) resource Vault: Balance, Provider, Receiver {

/// keeps track of the total balance of the account's tokens
access(all) var balance: UFix64

/// initialize the balance at resource creation time
init(balance: UFix64) {
self.balance = balance
}

/// withdraw
///
/// Function that takes an integer amount as an argument
/// and withdraws that amount from the Vault.
///
/// It creates a new temporary Vault that is used to hold
/// the money that is being transferred. It returns the newly
/// created Vault to the context that called so it can be deposited
/// elsewhere.
///
access(Withdraw) fun withdraw(amount: UFix64): @Vault {
pre {
self.balance >= amount:
"ExampleToken.Vault.withdraw: Cannot withdraw tokens! "
.concat("The amount requested to be withdrawn (").concat(amount.toString())
.concat(") is greater than the balance of the Vault (")
.concat(self.balance.toString()).concat(").")
}
self.balance = self.balance - amount
return <-create Vault(balance: amount)
}

/// deposit
///
/// Function that takes a Vault object as an argument and adds
/// its balance to the balance of the owners Vault.
///
/// It is allowed to destroy the sent Vault because the Vault
/// was a temporary holder of the tokens. The Vault's balance has
/// been consumed and therefore can be destroyed.
access(all) fun deposit(from: @Vault) {
self.balance = self.balance + from.balance
destroy from
}
}

/// createEmptyVault
///
access(all) fun createEmptyVault(): @Vault {
return <-create Vault(balance: 0.0)
}

// VaultMinter
//
// Resource object that an admin can control to mint new tokens
access(all) resource VaultMinter {

// Function that mints new tokens and deposits into an account's vault
// using their `{Receiver}` reference.
// We say `&{Receiver}` to say that the recipient can be any resource
// as long as it implements the Receiver interface
access(all) fun mintTokens(amount: UFix64, recipient: Capability<&{Receiver}>) {
let recipientRef = recipient.borrow()
?? panic("ExampleToken.VaultMinter.mintTokens: Could not borrow a receiver reference to "
.concat("the specified recipient's ExampleToken.Vault")
.concat(". Make sure the account has set up its account ")
.concat("with an ExampleToken Vault and valid capability."))

ExampleToken.totalSupply = ExampleToken.totalSupply + UFix64(amount)
recipientRef.deposit(from: <-create Vault(balance: amount))
}
}

/// The init function for the contract. All fields in the contract must
/// be initialized at deployment. This is just an example of what
/// an implementation could do in the init function. The numbers are arbitrary.
init() {
self.VaultStoragePath = /storage/CadenceFungibleTokenTutorialVault
self.VaultPublicPath = /public/CadenceFungibleTokenTutorialReceiver

self.totalSupply = 30.0

// create the Vault with the initial balance and put it in storage
// account.save saves an object to the specified `to` path
// The path is a literal path that consists of a domain and identifier
// The domain must be `storage`, `private`, or `public`
// the identifier can be any name
let vault <- create Vault(balance: self.totalSupply)
self.account.storage.save(<-vault, to: self.VaultStoragePath)

// Create a new VaultMinter resource and store it in account storage
self.account.storage.save(<-create VaultMinter(), to: /storage/CadenceFungibleTokenTutorialMinter)

}
}
6 changes: 6 additions & 0 deletions cadence/tests/Recipe_test.cdc
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import Test

access(all) fun testExample() {
let array = [1, 2, 3]
Test.expect(array.length, Test.equal(3))
}
34 changes: 0 additions & 34 deletions cadence/transaction.cdc

This file was deleted.

1 change: 1 addition & 0 deletions cadence/transaction.cdc
34 changes: 34 additions & 0 deletions cadence/transactions/deposit_to_vault.cdc
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import ExampleToken from 0x01

// This transaction mints tokens and deposits them into account 0x02's vault
transaction {

// Local variable for storing the reference to the minter resource
let mintingRef: auth(MintEntitlement) &ExampleToken.VaultMinter

// Local variable for storing the reference to the Vault of
// the account that will receive the newly minted tokens
var receiver: Capability<&ExampleToken.Vault{ExampleToken.Receiver}>

prepare(acct: auth(Storage, Capabilities) &Account) {
// Borrow a reference to the stored, private minter resource
self.mintingRef = acct.capabilities.storage.borrow<&ExampleToken.VaultMinter>(
from: /storage/MainMinter
) ?? panic("Could not borrow a reference to the minter")

// Get the public account object for account 0x02
let recipient = getAccount(0x02)

// Get their public receiver capability
self.receiver = recipient.capabilities.borrow<&ExampleToken.Vault{ExampleToken.Receiver}>(
/public/MainReceiver
) ?? panic("Could not borrow the receiver capability from account 0x02")
}

execute {
// Mint 30 tokens and deposit them into the recipient's Vault
self.mintingRef.mintTokens(amount: 30.0, recipient: self.receiver)

log("30 tokens minted and deposited to account 0x02")
}
}
1 change: 1 addition & 0 deletions emulator-account.pkey
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
0xdc07d83a937644ff362b279501b7f7a3735ac91a0f3647147acf649dda804e28
Loading

0 comments on commit a5d50a0

Please sign in to comment.