Skip to content

Commit

Permalink
Merge pull request #125 from CirclesUBI/20240328-deployment-gc
Browse files Browse the repository at this point in the history
20240328 deployment gc
  • Loading branch information
jaensen authored Apr 2, 2024
2 parents 8571c0a + b996e30 commit fca18a8
Show file tree
Hide file tree
Showing 48 changed files with 942 additions and 150 deletions.
3 changes: 3 additions & 0 deletions example.env → .env.example
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
PRIVATE_KEY_CHIADO='YOUR_PRIVATE_KEY'
PRIVATE_KEY_GNOSIS='YOUR_PRIVATE_KEY'
RPC_URL_CHIADO='https://rpc.chiadochain.net'
RPC_URL_GNOSIS='https://rpc.gnosischain.com'
BLOCKSCOUT_API_KEY='YOUR_API_KEY'
BLOCKSCOUT_URL_CHIADO='https://gnosis-chiado.blockscout.com/api?'
BLOCKSCOUT_URL_GNOSIS='https://gnosis.blockscout.com/api?'
BLOCKSCOUT_VERIFIER='blockscout'
GNOSISSCAN_API_KEY='YOUR_API_KEY'
GNOSISSCAN_URL='https://api.gnosisscan.io/api?'
Expand Down
1 change: 1 addition & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@
[submodule "lib/openzeppelin-contracts"]
path = lib/openzeppelin-contracts
url = https://github.com/OpenZeppelin/openzeppelin-contracts
branch = v5.0.2
9 changes: 9 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,15 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

# v0.3.1

- [PR ]
- temporarilly rename "Circles" to "Rings" and "CRC" to "RING", so that pre-release deployments are easily recognizable from the later production deployment
- [PR 123]
- fix: `personalMint` should not revert if issuance is zero;
- add `calculateIssuanceWithCheck` to know issuance without minting (while possibly updating v1 mint status);
- add testing for simple migration and invitation flows
- improve test for Circles issuance, add test for consecutive periods in personal mint

## v0.3.0

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
Chiado deployment
=================
Deployment Date: 2024-04-01 13:32:17
Version: 0.3.1-alpha
Git Commit: 1fd0982c4c86533de2845a975113bcd763df8a56
Deployer Address: 0x7619F26728Ced663E50E578EB6ff42430931564c, Intitial nonce: 81
Compiler Version: v0.8.23+commit.f704f362

Deployed Contracts:
Hub: 0x1CAc5fE351EFFa130223aC0f84EB6B7Efc7a66AD
Migration: 0x421ae522F756412808Ff62F74C20e5ebDA8C4208
NameRegistry: 0x48F6B0aa3Ca905C9DbE41717c7664639107257da
ERC20Lift: 0xBF2F902d56d7ad2F2B1d674DC8B4d8C58354e7e5
StandardTreasury: 0xD3529a99A7881DF7D11829135759AD0e4A8Ab587
BaseGroupMintPolicy: 0x6604C8eBDD57F3771e4D0Cb3A174AfaEAf38C463
MastercopyDemurrageERC20: 0x55241b3B4705f4624b282C6bFb162132a8B93B5C
MastercopyInflationaryERC20: 0x3F89b0154e1252cDcf7b86152EA10a21aDF07bFd
MastercopyStandardVault: 0xe2f033e8912dE80A363e3eFE9D840F346229bCCC
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{"contractName":"Hub","deployedAddress":"0x1CAc5fE351EFFa130223aC0f84EB6B7Efc7a66AD","sourcePath":"src/hub/Hub.sol:Hub","constructor-args":"0xdbF22D4e8962Db3b2F1d9Ff55be728A887e47710 0x48F6B0aa3Ca905C9DbE41717c7664639107257da 0x421ae522F756412808Ff62F74C20e5ebDA8C4208 0xBF2F902d56d7ad2F2B1d674DC8B4d8C58354e7e5 0xD3529a99A7881DF7D11829135759AD0e4A8Ab587 1675209600 31540000 https://fallback.aboutcircles.com/v1/circles/{id}.json","argumentsFile":"constructorArgs_Hub.txt"}
{"contractName":"Migration","deployedAddress":"0x421ae522F756412808Ff62F74C20e5ebDA8C4208","sourcePath":"src/migration/Migration.sol:Migration","constructor-args":"0xdbF22D4e8962Db3b2F1d9Ff55be728A887e47710 0x1CAc5fE351EFFa130223aC0f84EB6B7Efc7a66AD","argumentsFile":"constructorArgs_Migration.txt"}
{"contractName":"NameRegistry","deployedAddress":"0x48F6B0aa3Ca905C9DbE41717c7664639107257da","sourcePath":"src/names/NameRegistry.sol:NameRegistry","constructor-args":"0x1CAc5fE351EFFa130223aC0f84EB6B7Efc7a66AD","argumentsFile":"constructorArgs_NameRegistry.txt"}
{"contractName":"ERC20Lift","deployedAddress":"0xBF2F902d56d7ad2F2B1d674DC8B4d8C58354e7e5","sourcePath":"src/lift/ERC20Lift.sol:ERC20Lift","constructor-args":"0x1CAc5fE351EFFa130223aC0f84EB6B7Efc7a66AD 0x48F6B0aa3Ca905C9DbE41717c7664639107257da 0x55241b3B4705f4624b282C6bFb162132a8B93B5C 0x3F89b0154e1252cDcf7b86152EA10a21aDF07bFd","argumentsFile":"constructorArgs_ERC20Lift.txt"}
{"contractName":"StandardTreasury","deployedAddress":"0xD3529a99A7881DF7D11829135759AD0e4A8Ab587","sourcePath":"src/treasury/StandardTreasury.sol:StandardTreasury","constructor-args":"0x1CAc5fE351EFFa130223aC0f84EB6B7Efc7a66AD 0xe2f033e8912dE80A363e3eFE9D840F346229bCCC","argumentsFile":"constructorArgs_StandardTreasury.txt"}
{"contractName":"BaseGroupMintPolicy","deployedAddress":"0x6604C8eBDD57F3771e4D0Cb3A174AfaEAf38C463","sourcePath":"src/groups/BaseMintPolicy.sol:MintPolicy","constructor-args":"","argumentsFile":"constructorArgs_BaseGroupMintPolicy.txt"}
{"contractName":"MastercopyDemurrageERC20","deployedAddress":"0x55241b3B4705f4624b282C6bFb162132a8B93B5C","sourcePath":"src/lift/DemurrageCircles.sol:DemurrageCircles","constructor-args":"","argumentsFile":"constructorArgs_MastercopyDemurrageERC20.txt"}
{"contractName":"MastercopyInflationaryERC20","deployedAddress":"0x3F89b0154e1252cDcf7b86152EA10a21aDF07bFd","sourcePath":"src/lift/InflationaryCircles.sol:InflationaryCircles","constructor-args":"","argumentsFile":"constructorArgs_MastercopyInflationaryERC20.txt"}
{"contractName":"MastercopyStandardVault","deployedAddress":"0xe2f033e8912dE80A363e3eFE9D840F346229bCCC","sourcePath":"src/treasury/StandardVault.sol:StandardVault","constructor-args":"","argumentsFile":"constructorArgs_MastercopyStandardVault.txt"}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@

Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
0x1CAc5fE351EFFa130223aC0f84EB6B7Efc7a66AD 0x48F6B0aa3Ca905C9DbE41717c7664639107257da 0x55241b3B4705f4624b282C6bFb162132a8B93B5C 0x3F89b0154e1252cDcf7b86152EA10a21aDF07bFd
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
0xdbF22D4e8962Db3b2F1d9Ff55be728A887e47710 0x48F6B0aa3Ca905C9DbE41717c7664639107257da 0x421ae522F756412808Ff62F74C20e5ebDA8C4208 0xBF2F902d56d7ad2F2B1d674DC8B4d8C58354e7e5 0xD3529a99A7881DF7D11829135759AD0e4A8Ab587 1675209600 31540000 https://fallback.aboutcircles.com/v1/circles/{id}.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@

Original file line number Diff line number Diff line change
@@ -0,0 +1 @@

Original file line number Diff line number Diff line change
@@ -0,0 +1 @@

Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
0xdbF22D4e8962Db3b2F1d9Ff55be728A887e47710 0x1CAc5fE351EFFa130223aC0f84EB6B7Efc7a66AD
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
0x1CAc5fE351EFFa130223aC0f84EB6B7Efc7a66AD
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
0x1CAc5fE351EFFa130223aC0f84EB6B7Efc7a66AD 0xe2f033e8912dE80A363e3eFE9D840F346229bCCC
4 changes: 2 additions & 2 deletions script/deployments/chiadoDeploy.sh
Original file line number Diff line number Diff line change
Expand Up @@ -119,11 +119,11 @@ echo "MastercopyDemurrageERC20: ${MASTERCOPY_DEMURRAGE_ERC20_ADDRESS_07}"
echo "MastercopyInflationaryERC20: ${MASTERCOPY_INFLATIONARY_ERC20_ADDRESS_08}"
echo "MastercopyStandardVault: ${MASTERCOPY_STANDARD_VAULT_09}"

Deploy the contracts
# Deploy the contracts

export deployment_details_file="${OUT_DIR}/chiado-artefacts-${identifier}.txt"
echo "Deployment details will be stored in $deployment_details_file"
§

echo ""
echo "Starting deployment..."
echo "======================"
Expand Down

This file was deleted.

236 changes: 236 additions & 0 deletions script/deployments/gnosisChainDeploy.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,236 @@
#!/bin/bash

# Exit immediately if a command exits with a non-zero status,
# specifically useful for the deploy_and_store_details function
set -e

# Function to deploy contract and store deployment details
deploy_and_store_details() {
local contract_name=$1
local precalculated_address=$2
local source_path=$3
local nonce_to_use=$4
local deployment_output
local deployed_address

echo "" >&2
echo "Deploying ${contract_name}..." >&2

# Formulate the command
forge_command="forge create \
--rpc-url ${RPC_URL} \
--private-key ${PRIVATE_KEY} \
--optimizer-runs 200 \
--chain-id 100 \
--priority-gas-price 2200000000 \
--nonce ${nonce_to_use} \
${source_path} \
${@:5}"

# Print the command for debugging
echo "Executing command: $forge_command" >&2

# if DRY_RUN is not true, execute the command
if [[ "$DRY_RUN" == "true" ]]; then
echo "Dry run mode enabled. Skipping deployment steps." >&2
else
# Execute the command
deployment_output=$(eval "${forge_command}")

deployed_address=$(echo "$deployment_output" | grep "Deployed to:" | awk '{print $3}')
echo "${contract_name} deployed at ${deployed_address}" >&2

# Verify that the deployed address matches the precalculated address
if [ "$deployed_address" = "$precalculated_address" ]; then
echo "Verification Successful: Deployed address matches the precalculated address for ${contract_name}." >&2
else
echo "Verification Failed: Deployed address does not match the precalculated address for ${contract_name}." >&2
echo "Precalculated Address: $precalculated_address" >&2
echo "Deployed Address: $deployed_address" >&2
# exit the script if the addresses don't match
exit 1
fi

# sleep for 20 seconds to allow the api to not rush, and display sleep countdown
for i in {20..1}; do
echo -ne "Sleeping for $i seconds... \r" >&2
sleep 1
done
fi

# Define the filename for constructor arguments based on the contract name
arguments_file="constructorArgs_${contract_name}.txt"
arguments_path="${OUT_DIR}/${arguments_file}"
# Save constructor arguments to the file, skip "--constructor-args"
echo "${@:6}" > "${arguments_path}"

# Store deployment details in a file
echo "{\"contractName\":\"${contract_name}\",\"deployedAddress\":\"${deployed_address}\",\"sourcePath\":\"$3\",\"constructor-args\":\"${@:6}\",\"argumentsFile\":\"${arguments_file}\"}" >> "${deployment_details_file}"

# return the deployed address
echo "$deployed_address"
}

# Function to generate a compact and short identifier
generate_identifier() {
# Fetch the current Git commit hash and take the first 7 characters
local git_commit_short=$(git rev-parse HEAD | cut -c1-7)

# Get the current date and time in a compact format (YYMMDD-HMS)
local deployment_date=$1

# Fetch version from package.json
local version=$(node -p "require('./package.json').version")

# Define the summary file name with version, short git commit, and compact date
echo "${version}-${git_commit_short}-${deployment_date}"
}

# Set the environment variables, also for use in node script
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )"
source "$DIR/../../.env"

# declare Gnosis Chain constants
V1_HUB_ADDRESS='0x29b9a7fBb8995b2423a71cC17cf9810798F6C543'
# gnosis chain v1 deployment time is 1602786330 unix time,
# but we want to offset this to midnight to start day zero
# on midnight 15 October 2020
INFLATION_DAY_ZERO=1602720000
# put a long bootstrap time for testing bootstrap to one year
BOOTSTRAP_ONE_YEAR=31540000
# fallback URI
URI='https://fallback.aboutcircles.com/v1/circles/{id}.json'

# re-export the variables for use here and in the general calculation JS script
export PRIVATE_KEY=$PRIVATE_KEY_GNOSIS
export RPC_URL=$RPC_URL_GNOSIS
VERIFIER_URL=$BLOCKSCOUT_URL_GNOSIS
VERIFIER_API_KEY=$BLOCKSCOUT_API_KEY
VERIFIER=$BLOCKSCOUT_VERIFIER

# Get the current date and time in a compact format (YYMMDD-HMS) outside the functions
deployment_date=$(date "+%y%m%d-%H%M%S")
deployment_date_long=$(date "+%Y-%m-%d %H:%M:%S")
identifier=$(generate_identifier $deployment_date)

# Run the Node.js script to predict contract addresses
# Assuming predictAddresses.js is in the current directory
read DEPLOYER_ADDRESS NONCE_USED HUB_ADDRESS_01 MIGRATION_ADDRESS_02 NAMEREGISTRY_ADDRESS_03 \
ERC20LIFT_ADDRESS_04 STANDARD_TREASURY_ADDRESS_05 BASE_GROUPMINTPOLICY_ADDRESS_06 \
MASTERCOPY_DEMURRAGE_ERC20_ADDRESS_07 MASTERCOPY_INFLATIONARY_ERC20_ADDRESS_08 \
MASTERCOPY_STANDARD_VAULT_09 \
<<< $(node predictDeploymentAddresses.js)

# Check if DRY_RUN is set to "true" and adjust the directory name accordingly
if [[ "$DRY_RUN" == "true" ]]; then
OUT_DIR="$DIR/DRYRUN-gnosischain-${identifier}-DRY_RUN"
else
OUT_DIR="$DIR/gnosischain-$identifier"
fi
# Create a directory for the deployment and go there after calling node script
mkdir -p "$OUT_DIR"

# Use DEPLOYER_ADDRESS and NONCE_USED as needed
echo "Deployer Address: $DEPLOYER_ADDRESS, Nonce Used: $NONCE_USED"

# Log the predicted deployment addresses
echo "Predicted deployment addresses:"
echo "==============================="
echo "Hub: ${HUB_ADDRESS_01}"
echo "Migration: ${MIGRATION_ADDRESS_02}"
echo "NameRegistry: ${NAMEREGISTRY_ADDRESS_03}"
echo "ERC20Lift: ${ERC20LIFT_ADDRESS_04}"
echo "StandardTreasury: ${STANDARD_TREASURY_ADDRESS_05}"
echo "BaseGroupMintPolicy: ${BASE_GROUPMINTPOLICY_ADDRESS_06}"
echo "MastercopyDemurrageERC20: ${MASTERCOPY_DEMURRAGE_ERC20_ADDRESS_07}"
echo "MastercopyInflationaryERC20: ${MASTERCOPY_INFLATIONARY_ERC20_ADDRESS_08}"
echo "MastercopyStandardVault: ${MASTERCOPY_STANDARD_VAULT_09}"

# Deploy the contracts

export deployment_details_file="${OUT_DIR}/gnosischain-artefacts-${identifier}.txt"
echo "Deployment details will be stored in $deployment_details_file"

echo ""
echo "Starting deployment..."
echo "======================"

HUB=$(deploy_and_store_details "Hub" $HUB_ADDRESS_01 \
src/hub/Hub.sol:Hub $((NONCE_USED)) \
--constructor-args $V1_HUB_ADDRESS \
$NAMEREGISTRY_ADDRESS_03 $MIGRATION_ADDRESS_02 $ERC20LIFT_ADDRESS_04 \
$STANDARD_TREASURY_ADDRESS_05 $INFLATION_DAY_ZERO \
$BOOTSTRAP_ONE_YEAR $URI)

NONCE_USED=$((NONCE_USED + 1))

MIGRATION=$(deploy_and_store_details "Migration" $MIGRATION_ADDRESS_02 \
src/migration/Migration.sol:Migration $((NONCE_USED)) \
--constructor-args $V1_HUB_ADDRESS $HUB_ADDRESS_01)

NONCE_USED=$((NONCE_USED + 1))

NAME_REGISTRY=$(deploy_and_store_details "NameRegistry" $NAMEREGISTRY_ADDRESS_03 \
src/names/NameRegistry.sol:NameRegistry $((NONCE_USED)) \
--constructor-args $HUB_ADDRESS_01)

NONCE_USED=$((NONCE_USED + 1))

ERC20LIFT=$(deploy_and_store_details "ERC20Lift" $ERC20LIFT_ADDRESS_04 \
src/lift/ERC20Lift.sol:ERC20Lift $((NONCE_USED)) \
--constructor-args $HUB_ADDRESS_01 \
$NAMEREGISTRY_ADDRESS_03 $MASTERCOPY_DEMURRAGE_ERC20_ADDRESS_07 \
$MASTERCOPY_INFLATIONARY_ERC20_ADDRESS_08)

NONCE_USED=$((NONCE_USED + 1))

STANDARD_TREASURY=$(deploy_and_store_details "StandardTreasury" $STANDARD_TREASURY_ADDRESS_05 \
src/treasury/StandardTreasury.sol:StandardTreasury $((NONCE_USED)) \
--constructor-args $HUB_ADDRESS_01 $MASTERCOPY_STANDARD_VAULT_09)

NONCE_USED=$((NONCE_USED + 1))

BASE_MINTPOLICY=$(deploy_and_store_details "BaseGroupMintPolicy" $BASE_GROUPMINTPOLICY_ADDRESS_06 \
src/groups/BaseMintPolicy.sol:MintPolicy $((NONCE_USED)))

NONCE_USED=$((NONCE_USED + 1))

MC_ERC20_DEMURRAGE=$(deploy_and_store_details "MastercopyDemurrageERC20" $MASTERCOPY_DEMURRAGE_ERC20_ADDRESS_07 \
src/lift/DemurrageCircles.sol:DemurrageCircles $((NONCE_USED)))

NONCE_USED=$((NONCE_USED + 1))

MC_ERC20_INFLATION=$(deploy_and_store_details "MastercopyInflationaryERC20" $MASTERCOPY_INFLATIONARY_ERC20_ADDRESS_08 \
src/lift/InflationaryCircles.sol:InflationaryCircles $((NONCE_USED)))

NONCE_USED=$((NONCE_USED + 1))

MC_STANDARD_VAULT=$(deploy_and_store_details "MastercopyStandardVault" $MASTERCOPY_STANDARD_VAULT_09 \
src/treasury/StandardVault.sol:StandardVault $((NONCE_USED)))

# log to file

# Use the function to generate the file name
summary_file="${OUT_DIR}/gnosischain-${identifier}.log"

# Now you can use $summary_file for logging
{
echo "Gnosis Chain deployment"
echo "================="
echo "Deployment Date: $deployment_date_long"
echo "Version: $(node -p "require('./package.json').version")"
echo "Git Commit: $(git rev-parse HEAD)"
echo "Deployer Address: $DEPLOYER_ADDRESS, Initial nonce: $NONCE_USED"
echo "Compiler Version: v0.8.23+commit.f704f362" # todo: figure out where to extract this from
echo ""
echo "Deployed Contracts:"
echo "Hub: ${HUB}"
echo "Migration: ${MIGRATION}"
echo "NameRegistry: ${NAME_REGISTRY}"
echo "ERC20Lift: ${ERC20LIFT}"
echo "StandardTreasury: ${STANDARD_TREASURY}"
echo "BaseGroupMintPolicy: ${BASE_MINTPOLICY}"
echo "MastercopyDemurrageERC20: ${MC_ERC20_DEMURRAGE}"
echo "MastercopyInflationaryERC20: ${MC_ERC20_INFLATION}"
echo "MastercopyStandardVault: ${MC_STANDARD_VAULT}"
} >> "$summary_file"
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@

Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
0x00315615f899F90d6Bc46EaaC911E37871d62DD8 0xa28f05bd1C054E2AA9680497e03Df2cc17f1b3d8 0x16920293865aCe1c5e97e672eaECFD3254224b6f 0x3467E9977856A422CfE7960D0a34af2FFB91B47f
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
0x29b9a7fBb8995b2423a71cC17cf9810798F6C543 0xa28f05bd1C054E2AA9680497e03Df2cc17f1b3d8 0xE22bFb93aDFa2b446226Ffb6FDa8dC641C819f23 0xE2CD16612EaF37432a8384c5dA8a66e1CAf0E68F 0x8e9b584764C467d95C23c27c0Ed0eE96A95b427d 1602720000 31540000 https://fallback.aboutcircles.com/v1/circles/{id}.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@

Original file line number Diff line number Diff line change
@@ -0,0 +1 @@

Original file line number Diff line number Diff line change
@@ -0,0 +1 @@

Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
0x29b9a7fBb8995b2423a71cC17cf9810798F6C543 0x00315615f899F90d6Bc46EaaC911E37871d62DD8
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
0x00315615f899F90d6Bc46EaaC911E37871d62DD8
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
0x00315615f899F90d6Bc46EaaC911E37871d62DD8 0xc70FAfea358d371477BbAd1c3adE0936AC4eEe24
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
Gnosis Chain deployment
=================
Deployment Date: 2024-04-01 17:51:01
Version: 0.3.1-alpha
Git Commit: 1fd0982c4c86533de2845a975113bcd763df8a56
Deployer Address: 0x7619F26728Ced663E50E578EB6ff42430931564c, Initial nonce: 8
Compiler Version: v0.8.23+commit.f704f362

Deployed Contracts:
Hub: 0x00315615f899F90d6Bc46EaaC911E37871d62DD8
Migration: 0xE22bFb93aDFa2b446226Ffb6FDa8dC641C819f23
NameRegistry: 0xa28f05bd1C054E2AA9680497e03Df2cc17f1b3d8
ERC20Lift: 0xE2CD16612EaF37432a8384c5dA8a66e1CAf0E68F
StandardTreasury: 0x8e9b584764C467d95C23c27c0Ed0eE96A95b427d
BaseGroupMintPolicy: 0x6ecbCB0166A8143aa4AC19a43Ea31f915D3D36dB
MastercopyDemurrageERC20: 0x16920293865aCe1c5e97e672eaECFD3254224b6f
MastercopyInflationaryERC20: 0x3467E9977856A422CfE7960D0a34af2FFB91B47f
MastercopyStandardVault: 0xc70FAfea358d371477BbAd1c3adE0936AC4eEe24
Loading

0 comments on commit fca18a8

Please sign in to comment.