Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

XERC20 token implementation #124

Merged
merged 3 commits into from
Dec 17, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
61 changes: 53 additions & 8 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
@@ -1,33 +1,78 @@
name: contracts-tests

on:
push:
pull_request:

jobs:
contracts:
contracts-cairo:
runs-on: ubuntu-latest
env:
working-directory: ./cairo
SCARB_VERSION: "2.6.5"
SNFOUNDRY_VERSION: "0.22.0"
steps:
- uses: actions/checkout@v3

- uses: software-mansion/setup-scarb@v1
with:
scarb-version: "2.6.5"
scarb-version: ${{ env.SCARB_VERSION }}

- uses: foundry-rs/setup-snfoundry@v3
with:
starknet-foundry-version: "0.22.0"
- working-directory: ${{ env.working-directory}}
starknet-foundry-version: ${{ env.SNFOUNDRY_VERSION }}

- name: Format check
working-directory: ${{ env.working-directory }}
run: scarb fmt --check

- name: Cache contracts
id: cache-contracts
uses: actions/cache@v3
with:
path: ./target
key: ${{ runner.os }}-contracts-${{ hashFiles('./src', 'Scarb.lock') }}
path: ${{ env.working-directory }}/target
key: ${{ runner.os }}-contracts-${{ env.working-directory }}-${{ hashFiles(format('{0}/src/**', env.working-directory), format('{0}/Scarb.lock', env.working-directory)) }}

- working-directory: ${{ env.working-directory}}
- name: Build
working-directory: ${{ env.working-directory }}
run: scarb build
- working-directory: ${{ env.working-directory}}

- name: Test
working-directory: ${{ env.working-directory }}
run: snforge test

contracts-xerc20:
runs-on: ubuntu-latest
env:
working-directory: ./xerc20
SCARB_VERSION: "2.9.2"
SNFOUNDRY_VERSION: "0.34.0"
steps:
- uses: actions/checkout@v3

- uses: software-mansion/setup-scarb@v1
with:
scarb-version: ${{ env.SCARB_VERSION }}

- uses: foundry-rs/setup-snfoundry@v3
with:
starknet-foundry-version: ${{ env.SNFOUNDRY_VERSION }}

- name: Format check
working-directory: ${{ env.working-directory }}
run: scarb fmt --check

- name: Cache contracts
id: cache-contracts
uses: actions/cache@v3
with:
path: ${{ env.working-directory }}/target
key: ${{ runner.os }}-contracts-${{ env.working-directory }}-${{ hashFiles(format('{0}/src/**', env.working-directory), format('{0}/Scarb.lock', env.working-directory)) }}

- name: Build
working-directory: ${{ env.working-directory }}
run: scarb build

- name: Test
working-directory: ${{ env.working-directory }}
run: snforge test
5 changes: 5 additions & 0 deletions xerc20/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
target
.snfoundry_cache/

.env
deployments/
2 changes: 2 additions & 0 deletions xerc20/.tool-versions
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
scarb 2.9.2
starknet-foundry 0.34.0
71 changes: 71 additions & 0 deletions xerc20/Scarb.lock
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
# Code generated by scarb DO NOT EDIT.
version = 1

[[package]]
name = "openzeppelin_access"
version = "0.20.0"
source = "git+https://github.com/OpenZeppelin/cairo-contracts.git?tag=v0.20.0#7756fd1de2b4ebd239fa6e372d75535cea02e5e5"
dependencies = [
"openzeppelin_introspection",
]

[[package]]
name = "openzeppelin_account"
version = "0.20.0"
source = "git+https://github.com/OpenZeppelin/cairo-contracts.git?tag=v0.20.0#7756fd1de2b4ebd239fa6e372d75535cea02e5e5"
dependencies = [
"openzeppelin_introspection",
"openzeppelin_utils",
]

[[package]]
name = "openzeppelin_introspection"
version = "0.20.0"
source = "git+https://github.com/OpenZeppelin/cairo-contracts.git?tag=v0.20.0#7756fd1de2b4ebd239fa6e372d75535cea02e5e5"

[[package]]
name = "openzeppelin_token"
version = "0.20.0"
source = "git+https://github.com/OpenZeppelin/cairo-contracts.git?tag=v0.20.0#7756fd1de2b4ebd239fa6e372d75535cea02e5e5"
dependencies = [
"openzeppelin_access",
"openzeppelin_account",
"openzeppelin_introspection",
"openzeppelin_utils",
]

[[package]]
name = "openzeppelin_upgrades"
version = "0.20.0"
source = "git+https://github.com/OpenZeppelin/cairo-contracts.git?tag=v0.20.0#7756fd1de2b4ebd239fa6e372d75535cea02e5e5"

[[package]]
name = "openzeppelin_utils"
version = "0.20.0"
source = "git+https://github.com/OpenZeppelin/cairo-contracts.git?tag=v0.20.0#7756fd1de2b4ebd239fa6e372d75535cea02e5e5"

[[package]]
name = "snforge_scarb_plugin"
version = "0.34.0"
source = "git+https://github.com/foundry-rs/starknet-foundry?tag=v0.34.0#d6976d4635cbe69bd199fd502788c469d408ed2d"

[[package]]
name = "snforge_std"
version = "0.34.0"
source = "git+https://github.com/foundry-rs/starknet-foundry?tag=v0.34.0#d6976d4635cbe69bd199fd502788c469d408ed2d"
dependencies = [
"snforge_scarb_plugin",
]

[[package]]
name = "xerc20"
version = "0.1.0"
dependencies = [
"openzeppelin_access",
"openzeppelin_account",
"openzeppelin_introspection",
"openzeppelin_token",
"openzeppelin_upgrades",
"openzeppelin_utils",
"snforge_std",
]
33 changes: 33 additions & 0 deletions xerc20/Scarb.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
[package]
name = "xerc20"
version = "0.1.0"
edition = "2024_07"
cairo-version = "2.9.2"

# See more keys and their definitions at https://docs.swmansion.com/scarb/docs/reference/manifest.html

[dependencies]
starknet = "2.9.2"
openzeppelin_access = { git = "https://github.com/OpenZeppelin/cairo-contracts.git", tag = "v0.20.0" }
openzeppelin_token = { git = "https://github.com/OpenZeppelin/cairo-contracts.git", tag = "v0.20.0" }
openzeppelin_utils = { git = "https://github.com/OpenZeppelin/cairo-contracts.git", tag = "v0.20.0" }
openzeppelin_account = { git = "https://github.com/OpenZeppelin/cairo-contracts.git", tag = "v0.20.0" }
openzeppelin_upgrades = { git = "https://github.com/OpenZeppelin/cairo-contracts.git", tag = "v0.20.0" }
openzeppelin_introspection = { git = "https://github.com/OpenZeppelin/cairo-contracts.git", tag = "v0.20.0" }

[dev-dependencies]
snforge_std = { git = "https://github.com/foundry-rs/starknet-foundry", tag = "v0.34.0" }

[[target.starknet-contract]]
sierra = true

[tool.fmt]
sort-module-level-items = true

[scripts]
test = "snforge test"

[[tool.snforge.fork]]
name = "mainnet"
url = "https://free-rpc.nethermind.io/mainnet-juno"
block_id.tag = "latest"
4 changes: 4 additions & 0 deletions xerc20/scripts/.env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
FEE_TOKEN="strk"
SALT=0xff00ff
STARKNET_NETWORK="dev"
PROFILE="default"
66 changes: 66 additions & 0 deletions xerc20/scripts/declare.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
#!/bin/bash

# Function to declare the contract and extract hashes
declare_contract() {
local contract_name="$1" # Take the contract name as a parameter
local profile="$2"
local fee_token="$3"

echo "Executing sncast command to declare the contract '$contract_name'..."

# Run the sncast command and capture the output
output=$(sncast --profile $profile --wait declare \
--fee-token $fee_token \
--contract-name "$contract_name")

echo "Command executed successfully."

# Check if output is not empty
if [[ -z "$output" ]]; then
echo "Error: No output received from sncast command."
echo "Output: $output" # Show output
return 1 # Changed from exit to return
fi

# Extract class_hash
class_hash=$(echo "$output" | grep -E "class_hash[:=]" | awk -F '[:=]' '{gsub(/ /, "", $2); print $2}')

# Validate extraction
if [[ -z "$class_hash" ]]; then
echo "Error: class_hash not found in the output."
echo "Output: $output" # Show output
return 1 # Changed from exit to return
fi
# Output the extracted hashes
echo "$contract_name: $class_hash" >> "deployments/$STARKNET_NETWORK/declared-classes.txt"
echo "Class hash for $contract_name saved to deployments/$STARKNET_NETWORK/declared-classes.txt"
}

if [[ -z "$STARKNET_NETWORK" ]]; then
echo "Error: STARKNET_NETWORK is not set."
return 1 # Changed from exit to return
fi
# Determine the file path based on the STARKNET_NETWORK environment variable
output_dir="deployments/$STARKNET_NETWORK"
output_file="$output_dir/declared-classes.txt"

local profile=$PROFILE
if [[ -z "$profile" ]]; then
profile="default"
fi

local fee_token=$FEE_TOKEN
if [[ -z "$fee_token" ]]; then
fee_token="strk"
fi

# Create the directory if it doesn't exist
mkdir -p "$output_dir"

# Remove existing declared-classes.txt file if it exists
rm -f "$output_file"

# Call the function with the provided contract name
declare_contract "XERC20Factory" $profile $fee_token
declare_contract "XERC20" $profile $fee_token
declare_contract "XERC20Lockbox" $profile $fee_token
95 changes: 95 additions & 0 deletions xerc20/scripts/deploy_factory.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
# Read class hashes from deployments/declared-classes.txt and store them in a local mapping

deploy_factory() {
local factory_class_hash="$1"
local xerc20_class_hash="$2"
local lockbox_class_hash="$3"
local profile="$4"
local fee_token="$5"
local salt="$6"

echo "Deploying contract factory with class hash '$factory_class_hash'..."
# Capture the output of the deployment command
output=$(sncast --profile $profile --wait \
deploy \
--fee-token $fee_token \
--class-hash $factory_class_hash\
--constructor-calldata $xerc20_class_hash $lockbox_class_hash\
--salt $SALT\
--unique
)

echo "Deployment command executed."

# Check if output is not empty
if [[ -z "$output" ]]; then
echo "Error: No output received from deployment command."
return 1
fi

# Extract transaction_hash and contract_address
transaction_hash=$(echo "$output" | grep -E "transaction_hash[:=]" | awk -F '[:=]' '{gsub(/ /, "", $2); print $2}')
contract_address=$(echo "$output" | grep -E "contract_address[:=]" | awk -F '[:=]' '{gsub(/ /, "", $2); print $2}')

# Validate extraction
if [[ -z "$transaction_hash" ]]; then
echo "Error: transaction_hash not found in the output."
return 1
fi

if [[ -z "$contract_address" ]]; then
echo "Error: contract_address not found in the output."
return 1
fi

# Output the extracted hashes
echo "Transaction Hash: $transaction_hash"
echo "Contract Address: $contract_address"

echo "XERC20Factory: $contract_address" >> "deployments/$STARKNET_NETWORK/deployed-contracts.txt"
echo "XERC20Factory deployed to $contract_address in tx_hash: $transaction_hash"
}

declare -A class_hashes

if [[ -z "$STARKNET_NETWORK" ]]; then
echo "Error: STARKNET_NETWORK is not set."
return 1 # Changed from exit to return
fi

if [[ -z "$SALT" ]]; then
echo "Error: SALT is not set."
return 1 # Changed from exit to return
fi

local profile=$PROFILE
if [[ -z "$profile" ]]; then
profile="default"
fi

local fee_token=$FEE_TOKEN
if [[ -z "$fee_token" ]]; then
fee_token="strk"
fi

input_file="deployments/$STARKNET_NETWORK/declared-classes.txt"

if [[ -f "$input_file" ]]; then
while IFS= read -r line; do
# Extract the class name and hash
class_name=$(echo "$line" | awk -F ': ' '{print $1}') # Remove trailing colon and whitespace
class_hash=$(echo "$line" | awk -F ': ' '{print $2}') # Remove leading/trailing whitespace
class_hashes[$class_name]=$class_hash
done < "$input_file"
else
echo "Input file not found: $input_file"
return 1
fi

deploy_factory \
"${class_hashes[XERC20Factory]}" \
"${class_hashes[XERC20]}" \
"${class_hashes[XERC20Lockbox]}" \
$profile \
$fee_token \
$SALT
11 changes: 11 additions & 0 deletions xerc20/snfoundry.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
[sncast.default]
# change here with the account name you use
account = "user"

# change this line with the path to your accounts.json
# see how to import your account if you already have one
# {https://foundry-rs.github.io/starknet-foundry/appendix/sncast/account/import.html}
accounts-file = ".starknet_accounts/starknet_open_zeppelin_accounts.json"

# node url
url = "http://127.0.0.1:5050"
Loading
Loading