Skip to content
Open
74 changes: 74 additions & 0 deletions runbooks/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
# Farcaster Protocol Runbooks

[![Txtx](https://img.shields.io/badge/Operated%20with-Txtx-gree?labelColor=gray)](https://txtx.sh)

## Available Runbooks

`txtx` Runbooks are the perfect companion to Foundry when creating Solidity smart contracts.
Foundry shines in making the development process a breeze; `txtx` makes deploying and operating on your contracts secure, simple, and reproducible.

The following Runbooks are available for this project.

### Deploy L1
Deploys all L1 contracts. To execute, run:
```console
txtx run deploy-l1 -u --env devnet
```

### Deploy L2
Deploys all L2 contracts. To execute, run:
```console
txtx run deploy-l2 -u --env devnet
```

### Grant Role
Calls the grantRole function of the StorageRegistry contract. To execute, run:
```console
txtx run grant-role --env devnet
```

## Getting Started

This repository is using [txtx](https://txtx.sh) for handling its on-chain operations.

`txtx` takes its inspiration from a battle tested devops best practice named `infrastructure as code`, that have transformed cloud architectures.


### Installation

#### macOS
```console
brew tap txtx/txtx
brew install txtx
```
#### Linux
```console
sudo snap install txtx
```

### List runbooks available in this repository
```console
$ txtx ls
ID Name Description
deploy-l1 Deploy L1 Deploys all L1 contracts
deploy-l2 Deploy L2 Deploys all L2 contracts
grant-role Grant Role Calls the grantRole function of the StorageRegistry contract
```

### Scaffold a new runbook

```console
$ txtx new
```

Access tutorials and documentation at [docs.txtx.sh](https://docs.txtx.sh) to understand the syntax and discover the powerful features of txtx.

Additionally, the [Visual Studio Code extension](https://marketplace.visualstudio.com/items?itemName=txtx.txtx) will make writing runbooks easier.



### Execute an existing runbook
```console
$ txtx run <runbook-id>
```

69 changes: 69 additions & 0 deletions runbooks/deployments/deploy-l1/main.tx
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
// Txtx supports deployments to multiple blockchains, so here we load the
// "evm" addon, which allows our Runbook to use evm-specific actions.
addon "evm" {
// Variables defined in our `addon "evm"` block are use by default on all evm actions

// Pull the chain id from our txtx.yml manifest
chain_id = input.l1_chain_id
// Pull the rpc url from our txtx.yml manifest
rpc_api_url = input.l1_rpc_api_url
}

// Declare a signer named "deployer", which will be used to sign transactions.
// This signer is created using the secret key provided as an input to the runbook.
signer "deployer" "evm::secret_key" {
// Pull the secret key from our txtx.yml manifest
secret_key = input.deployer_secret_key
// Instead of a secret key, you can also use a mnemonic to create a signer
// mnemonic = inputs.deployer_mnemonic
}

// Instead of copy/pasting keys/menomnics, you can also use the supervisor UI to sign all
// transactions in a browser wallet. To do this, use the web_wallet instead of secret_key:
// signer "deployer" "evm::web_wallet" {
// expected_address = input.deployer_address
// }


// Declare an action named "deploy_fname_resolver" that will deploy the FNAME resolver contract
// using the Create2 opcode. By default, the foundry create2 factory will be used, but you can
// specify a different factory contract if needed. See the docs for more info:
// https://docs.txtx.sh/addons/evm/actions#deploy-contract-create2
action "deploy_fname_resolver" "evm::deploy_contract_create2" {
description = "Deploy the FNAME resolver contract using the Immutable Create2 Factory"
// Using this function, txtx can automatically pull all of the needed artifacts to deploy this contract
contract = evm::get_contract_from_foundry_project("FnameResolver")
// The constructor args for the deployment. For the FNAME resolver, we need
// the server URL, the signer address, and the owner address.
constructor_args = [
// The server URL, pulled from the `txtx.yml` manifest
input.fname_resolver_server_url,
// The signer address, pulled from the `txtx.yml` manifest.
// Wrap in the `evm::address` function to properly encode the string as an address.
evm::address(input.fname_resolver_signer_address),
// The owner address, pulled from the `txtx.yml` manifest
// Wrap in the `evm::address` function to properly encode the string as an address,
evm::address(input.fname_resolver_owner_address)
]
// Pull the salt from the `txtx.yml` manifest
salt = input.fname_resolver_create2_salt

// Specify the alternative create2 factory address to use the Immutable Create2 Factory
create2_factory_address = input.immutable_create2_factory_address
// Specify the function to call on the create2 factory contract
create2_factory_function_name = "safeCreate2"
// Specify the ABI of the create2 factory contract
create2_factory_abi = variable.immutable_factory_abi

// The signer to use for this action
signer = signer.deployer
// Uncomment this to include an assertion that the deployed address matches the expected address.
// If there isn't a match, the deployment will not take place, and Runbook execution will not progress,
// preventing subsequent actions from running.
// expected_contract_address = inputs.FNAME_RESOLVER_ADDRESS
}

output "fname_resolver_address" {
description = "FNAME Resolver contract address"
value = action.deploy_fname_resolver.contract_address
}
2 changes: 2 additions & 0 deletions runbooks/deployments/deploy-l1/network.devnet.tx
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
// By naming a file `<filename>.devnet.tx`, this file will only be included in the runbook when the environment is set to `devnet`:
// `txtx run deploy-l1 --env devnet`
2 changes: 2 additions & 0 deletions runbooks/deployments/deploy-l1/network.mainnet.tx
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
// By naming a file `<filename>.mainnet.tx`, this file will only be included in the runbook when the environment is set to `mainnet`:
// `txtx run deploy-l1 --env mainnet`
6 changes: 6 additions & 0 deletions runbooks/deployments/deploy-l1/variables.tx
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
// The variable keyword is used to define a variable that can be used in other parts of the runbook.
// In this case, the variable immutable_factory_abi is defined with the value of the ABI of the Immutable Create2 Factory contract.
variable "immutable_factory_abi" {
description = "ABI of the Immutable Create2 Factory"
value = "[{\"constant\":true,\"inputs\":[{\"name\":\"deploymentAddress\",\"type\":\"address\"}],\"name\":\"hasBeenDeployed\",\"outputs\":[{\"name\":\"\",\"type\":\"bool\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"salt\",\"type\":\"bytes32\"},{\"name\":\"initializationCode\",\"type\":\"bytes\"}],\"name\":\"safeCreate2\",\"outputs\":[{\"name\":\"deploymentAddress\",\"type\":\"address\"}],\"payable\":true,\"stateMutability\":\"payable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"salt\",\"type\":\"bytes32\"},{\"name\":\"initCode\",\"type\":\"bytes\"}],\"name\":\"findCreate2Address\",\"outputs\":[{\"name\":\"deploymentAddress\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"salt\",\"type\":\"bytes32\"},{\"name\":\"initCodeHash\",\"type\":\"bytes32\"}],\"name\":\"findCreate2AddressViaHash\",\"outputs\":[{\"name\":\"deploymentAddress\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"}]"
}
217 changes: 217 additions & 0 deletions runbooks/deployments/deploy-l2/main.tx
Original file line number Diff line number Diff line change
@@ -0,0 +1,217 @@
addon "evm" {
chain_id = input.l2_chain_id
rpc_api_url = input.l2_rpc_api_url
create2_factory_address = input.immutable_create2_factory_address
create2_factory_function_name = "safeCreate2"
create2_factory_abi = "[{\"constant\":true,\"inputs\":[{\"name\":\"deploymentAddress\",\"type\":\"address\"}],\"name\":\"hasBeenDeployed\",\"outputs\":[{\"name\":\"\",\"type\":\"bool\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"salt\",\"type\":\"bytes32\"},{\"name\":\"initializationCode\",\"type\":\"bytes\"}],\"name\":\"safeCreate2\",\"outputs\":[{\"name\":\"deploymentAddress\",\"type\":\"address\"}],\"payable\":true,\"stateMutability\":\"payable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"salt\",\"type\":\"bytes32\"},{\"name\":\"initCode\",\"type\":\"bytes\"}],\"name\":\"findCreate2Address\",\"outputs\":[{\"name\":\"deploymentAddress\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"salt\",\"type\":\"bytes32\"},{\"name\":\"initCodeHash\",\"type\":\"bytes32\"}],\"name\":\"findCreate2AddressViaHash\",\"outputs\":[{\"name\":\"deploymentAddress\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"}]"
}

signer "deployer" "evm::secret_key" {
secret_key = input.deployer_secret_key
}

action "deploy_storage_registry" "evm::deploy_contract_create2" {
description = "Deploy the Storage Registry contract using the Immutable Create2 Factory"
contract = evm::get_contract_from_foundry_project("StorageRegistry")
constructor_args = [
evm::address(input.storage_rent_price_feed_address),
evm::address(input.storage_rent_uptime_feed_address),
variable.initial_usd_unit_price,
variable.initial_max_units,
evm::address(input.storage_rent_vault_address),
evm::address(input.deployer),
evm::address(input.storage_rent_admin_address),
evm::address(input.storage_rent_operator_address),
evm::address(input.storage_rent_treasurer_address)
]
salt = input.storage_rent_create2_salt
signer = signer.deployer
}

action "deploy_id_registry" "evm::deploy_contract_create2" {
description = "Deploy the IdRegistry contract using the Immutable Create2 Factory"
contract = evm::get_contract_from_foundry_project("IdRegistry")
constructor_args = [
evm::address(input.migrator_address),
evm::address(input.deployer)
]
salt = input.id_registry_create2_salt
signer = signer.deployer
}

action "deploy_id_gateway" "evm::deploy_contract_create2" {
description = "Deploy the IdGateway contract using the Immutable Create2 Factory"
contract = evm::get_contract_from_foundry_project("IdGateway")
constructor_args = [
action.deploy_id_registry.contract_address,
action.deploy_storage_registry.contract_address,
evm::address(input.deployer)
]
salt = input.id_gateway_create2_salt
signer = signer.deployer
}

action "deploy_key_registry" "evm::deploy_contract_create2" {
description = "Deploy the KeyRegistry contract using the Immutable Create2 Factory"
contract = evm::get_contract_from_foundry_project("KeyRegistry")
constructor_args = [
action.deploy_id_registry.contract_address,
evm::address(input.migrator_address),
evm::address(input.deployer),
variable.key_registry_max_keys_per_fid
]
salt = input.key_registry_create2_salt
signer = signer.deployer
}

action "deploy_key_gateway" "evm::deploy_contract_create2" {
description = "Deploy the KeyGateway contract using the Immutable Create2 Factory"
contract = evm::get_contract_from_foundry_project("KeyGateway")
constructor_args = [
action.deploy_key_registry.contract_address,
// this value was in the deployment script, but is not in the constructor
// action.deploy_storage_registry.contract_address,
evm::address(input.key_registry_owner_address)
]
salt = input.key_gateway_create2_salt
signer = signer.deployer
}

action "deploy_signed_key_request_validator" "evm::deploy_contract_create2" {
description = "Deploy the SignedKeyRequestValidator contract using the Immutable Create2 Factory"
contract = evm::get_contract_from_foundry_project("SignedKeyRequestValidator")
constructor_args = [
action.deploy_id_registry.contract_address,
evm::address(input.metadata_validator_owner_address)
]
salt = input.signed_key_request_validator_create2_salt
signer = signer.deployer
}

action "deploy_bundler" "evm::deploy_contract_create2" {
description = "Deploy the Bundler contract using the Immutable Create2 Factory"
contract = evm::get_contract_from_foundry_project("Bundler")
constructor_args = [
action.deploy_id_gateway.contract_address,
action.deploy_key_gateway.contract_address,
]
salt = input.bundler_create2_salt
signer = signer.deployer
}

action "deploy_recovery_proxy" "evm::deploy_contract_create2" {
description = "Deploy the RecoveryProxy contract using the Immutable Create2 Factory"
contract = evm::get_contract_from_foundry_project("RecoveryProxy")
constructor_args = [
action.deploy_id_registry.contract_address,
evm::address(input.recovery_proxy_owner_address)
]
salt = input.recovery_proxy_create2_salt
signer = signer.deployer
}

// Post-deployment setup
action "set_id_gateway" "evm::call_contract" {
description = "Set the IdGateway contract address in the IdRegistry contract"
contract_address = action.deploy_id_registry.contract_address
contract_abi = action.deploy_id_registry.abi
function_name = "setIdGateway"
function_args = [
action.deploy_id_gateway.contract_address
]
signer = signer.deployer
}

action "transfer_id_registry_ownership" "evm::call_contract" {
description = "Transfer ownership of the IdRegistry contract to configured initial Id Registry Owner"
contract_address = action.deploy_id_registry.contract_address
contract_abi = action.deploy_id_registry.abi
function_name = "transferOwnership"
function_args = [
evm::address(input.id_registry_owner_address)
]
signer = signer.deployer
}

action "transfer_id_gateway_ownership" "evm::call_contract" {
description = "Transfer ownership of the IdGateway contract to configured initial Id Registry Owner"
contract_address = action.deploy_id_gateway.contract_address
contract_abi = action.deploy_id_gateway.abi
function_name = "transferOwnership"
function_args = [
evm::address(input.id_registry_owner_address)
]
signer = signer.deployer
}

action "key_registry_set_validator" "evm::call_contract" {
description = "Set the Validator for the KeyRegistry contract"
contract_address = action.deploy_key_registry.contract_address
contract_abi = action.deploy_key_registry.abi
function_name = "setValidator"
function_args = [
evm::uint32(1),
evm::uint8(1),
action.deploy_signed_key_request_validator.contract_address
]
signer = signer.deployer
}

action "set_key_registry_key_gateway" "evm::call_contract" {
description = "Set the KeyGateway contract address in the KeyRegistry contract"
contract_address = action.deploy_key_registry.contract_address
contract_abi = action.deploy_key_registry.abi
function_name = "setKeyGateway"
function_args = [
action.deploy_key_gateway.contract_address
]
signer = signer.deployer
}

action "transfer_key_registry_ownership" "evm::call_contract" {
description = "Transfer ownership of the KeyRegistry contract to configured initial Key Registry Owner"
contract_address = action.deploy_key_registry.contract_address
contract_abi = action.deploy_key_registry.abi
function_name = "transferOwnership"
function_args = [
evm::address(input.key_registry_owner_address)
]
signer = signer.deployer
}

action "grant_operator_role" "evm::call_contract" {
description = "Grant the OPERATOR_ROLE to the Bundler contract"
contract_address = action.deploy_storage_registry.contract_address
contract_abi = action.deploy_storage_registry.abi
function_name = "grantRole"
function_args = [
evm::bytes32(std::keccak256("OPERATOR_ROLE")),
action.deploy_bundler.contract_address
]
signer = signer.deployer
}

action "grant_admin_role" "evm::call_contract" {
description = "Grant the ADMIN_ROLE to the Bundler contract"
contract_address = action.deploy_storage_registry.contract_address
contract_abi = action.deploy_storage_registry.abi
function_name = "grantRole"
function_args = [
evm::bytes32("0x0000000000000000000000000000000000000000000000000000000000000000"),
evm::address(input.storage_rent_role_admin_address)
]
signer = signer.deployer
}

// I couldn't get this one transaction to succeed, it keeps reverting. Will need to investigate further.
// action "renounce_role" "evm::call_contract" {
// description = "Renounce the OPERATOR_ROLE from the deployer"
// contract_address = action.deploy_storage_registry.contract_address
// contract_abi = action.deploy_storage_registry.abi
// function_name = "renounceRole"
// function_args = [
// evm::bytes32("0x0000000000000000000000000000000000000000000000000000000000000000"),
// evm::address(input.deployer)
// ]
// signer = signer.deployer
// }
Loading