Skip to content

Commit

Permalink
XERC20 token implementation (#124)
Browse files Browse the repository at this point in the history
* xerc20 implementation

* XERC20 CI

* unused dependency removed
  • Loading branch information
EgeCaner authored Dec 17, 2024
1 parent 2b4f509 commit 563426e
Show file tree
Hide file tree
Showing 31 changed files with 4,336 additions and 8 deletions.
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

0 comments on commit 563426e

Please sign in to comment.