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

implement alias key support #15

Merged
merged 11 commits into from
Jul 12, 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
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -23,3 +23,5 @@ metadata.json

# Ignores yaml configuration files in the config directory
config/*.yaml

contracts/script/output/
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,7 @@ Coming soon
| OperatorStateRetriever | [`0xb7bb920538e038DFFEfcB55caBf713652ED2031F`](https://holesky.etherscan.io/address/0xb7bb920538e038DFFEfcB55caBf713652ED2031F) |
| PauserRegistry | [`0x3A8ea6e4202CdDe4a9e0cCE19c4Dc1739ba2cF0b`](https://holesky.etherscan.io/address/0x3A8ea6e4202CdDe4a9e0cCE19c4Dc1739ba2cF0b) |
| StakeRegistry | [`0x7BacD5dd5A7C3acf8bf1a3c88fB0D00B68EE626A`](https://holesky.etherscan.io/address/0x7BacD5dd5A7C3acf8bf1a3c88fB0D00B68EE626A) |
| ApConfig | [`0xb8abbb082ecaae8d1cd68378cf3b060f6f0e07eb`](https://holesky.etherscan.io/address/0xb8abbb082ecaae8d1cd68378cf3b060f6f0e07eb) |



Expand All @@ -172,3 +173,4 @@ Coming soon
| PauserRegistry | [`0xeec585186c37c517030ba371deac5c17e728c135`](https://etherscan.io/address/0xeec585186c37c517030ba371deac5c17e728c135) |
| StakeRegistry | [`0x363b3604fE8c2323a98c00906115c8b87a512a12`](https://etherscan.io/address/0x363b3604fE8c2323a98c00906115c8b87a512a12) |
| TaskManager | [`0x940f62f75cbbbd723d37c9171dc681dfba653b49`](https://etherscan.io/address/0x940f62f75cbbbd723d37c9171dc681dfba653b49) |
| ApConfig | [`0x9c02dfc92eea988902a98919bf4f035e4aaefced`](https://etherscan.io/address/0x9c02dfc92eea988902a98919bf4f035e4aaefced) |
39 changes: 39 additions & 0 deletions cmd/createAliasKey.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
/*
Copyright © 2024 Ava Protocol
*/
package cmd

import (
"github.com/spf13/cobra"

"github.com/AvaProtocol/ap-avs/operator"
)

var (
aliasKeyOption = operator.CreateAliasKeyOption{}
)

// createAliasKeyCmd represents the createAliasKey command
var createAliasKeyCmd = &cobra.Command{
Use: "create-alias-key",
Short: "Create an ECDSA private key only for AP AVS operation",
Long: `Generate an ECDSA private key to use for AP AVS operation.

Instead of using the operator's ECDSA private key to interact with
Ava Protocol AVS, you can generate an alias key and use this key to
interact with Ava Protocol operator. You will still need the EigenLayer
Operator ECDSA key to register or deregister from the AVS. But once
you registered, you don't need that operator key anymore`,
Run: func(cmd *cobra.Command, args []string) {
operator.CreateOrImportAliasKey(aliasKeyOption)
},
}

func init() {
rootCmd.AddCommand(createAliasKeyCmd)

createAliasKeyCmd.Flags().StringVarP(&(aliasKeyOption.PrivateKey), "ecdsa-private-key", "k", "", "a private key start with 0x to import as alias key")

createAliasKeyCmd.Flags().StringVarP(&(aliasKeyOption.Filename), "name", "n", "alias-ecdsa.key.json", "absolute or relative file path to save your ECDSA key to")
createAliasKeyCmd.MarkPersistentFlagRequired("name")
}
30 changes: 30 additions & 0 deletions cmd/declareAlias.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/*
Copyright © 2024 Ava Protocol
*/
package cmd

import (
"github.com/spf13/cobra"

"github.com/AvaProtocol/ap-avs/operator"
)

// declareAliasCmd represents the declareAlias command
var declareAliasCmd = &cobra.Command{
Use: "declare-alias",
Short: "Declare an alias ecdsa key file for the operator address",
Long: `Declare an alias ecdsa key file for the operator address

After creating an alias key, they key can be declare as
an alias for the operator address`,
Run: func(cmd *cobra.Command, args []string) {
operator.DeclareAlias(config, aliasKeyOption.Filename)
},
}

func init() {
rootCmd.AddCommand(declareAliasCmd)

declareAliasCmd.Flags().StringVarP(&(aliasKeyOption.Filename), "name", "n", "alias-ecdsa.key.json", "absolute or relative file path to alias ECDSA key to declare alias")
declareAliasCmd.MarkPersistentFlagRequired("name")
}
29 changes: 29 additions & 0 deletions cmd/removeAlias.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/*
Copyright © 2024 NAME HERE <EMAIL ADDRESS>
*/
package cmd

import (
"github.com/spf13/cobra"

"github.com/AvaProtocol/ap-avs/operator"
)

// removeAliasCmd represents the removeAlias command
var removeAliasCmd = &cobra.Command{
Use: "remove-alias",
Short: "Unbind alias address from your operator",
Long: `Unbind alias key from your operator address

After removal, you will either need to setup another alias key, or to use your operator ECDSA key.

When removing alias, you can run it with alias key
`,
Run: func(cmd *cobra.Command, args []string) {
operator.RemoveAlias(config)
},
}

func init() {
rootCmd.AddCommand(removeAliasCmd)
}
14 changes: 14 additions & 0 deletions contracts/deploy-ap-config.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
#!/usr/bin/env bash

set -xe

forge script \
script/DeployAPConfig.s.sol:DeployAPConfig \
--rpc-url $RPC_URL \
--private-key $PRIVATE_KEY \
--etherscan-api-key $ETHSCAN_API_KEY \
--broadcast --verify \
--slow \
-vvvv


58 changes: 58 additions & 0 deletions contracts/script/DeployAPConfig.s.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.12;

import "forge-std/Script.sol";

import "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol";
import "@openzeppelin/contracts/proxy/transparent/ProxyAdmin.sol";

import {APConfig} from "../src/core/APConfig.sol";

// To deployment and swap the implementation set 2 envs:
// CREATE_PROXY=false
// AP_PROXY_ADDRESS=0x123
// PROXY_ADMIN_ADDRESS=0x456
// When seeing the two env, the script will upgrade the underlying contract
//
// Example:
// AP_PROXY_ADDRESS=0xb8abbb082ecaae8d1cd68378cf3b060f6f0e07eb \
// SWAP_IMPL=true bash deploy-ap-config.sh
contract DeployAPConfig is Script {
function run() external {
address oakAVSProxyAdmin = vm.envAddress("PROXY_ADMIN_ADDRESS");
bool swapImpl = vm.envBool("SWAP_IMPL");

vm.startBroadcast();

string memory output = "APConfig deployment output";

// 1. Deploy the implementation
APConfig apConfig = new APConfig();
vm.serializeAddress(output, "apConfigImpl", address(apConfig));

if (swapImpl) {
ProxyAdmin oakProxyAdmin =
ProxyAdmin(oakAVSProxyAdmin);

// 3. Here we want
address apProxyAddress = vm.envAddress("AP_PROXY_ADDRESS");
oakProxyAdmin.upgrade(
TransparentUpgradeableProxy(payable(apProxyAddress)),
address(apConfig)
);
} else {
// 2. Deploy the proxy contract
TransparentUpgradeableProxy proxy = new TransparentUpgradeableProxy(
address(apConfig),
address(oakAVSProxyAdmin),
""
);
vm.serializeAddress(output, "apConfigProxy", address(proxy));
}

string memory registryJson = vm.serializeString(output, "object", output);
vm.writeJson(registryJson, "./script/output/ap_config.json");

vm.stopBroadcast();
}
}
39 changes: 39 additions & 0 deletions contracts/src/core/APConfig.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
pragma solidity ^0.8.12;

import "../interfaces/IAPConfig.sol";

contract APConfig is IAPConfig {
// Mapping from operator address to alias address
mapping(address => address) private operatorToAlias;
mapping(address => address) private aliasToOperator;

// Function to declare an alias for the operator
function declareAlias(address _alias) external override {
require(_alias != address(0), "Alias address cannot be the zero address");
require(_alias != msg.sender, "Alias address cannot be the same with operator address");

operatorToAlias[msg.sender] = _alias;
aliasToOperator[_alias] = msg.sender;

emit AliasDeclared(msg.sender, _alias);
}

// Function to undeclare an alias for the operator
function undeclare() external override {
require(aliasToOperator[msg.sender] != address(0), "No alias declared for this operator");

delete operatorToAlias[aliasToOperator[msg.sender]];
delete aliasToOperator[msg.sender];

emit AliasUndeclared(msg.sender);
}

// Function to get the alias of an operator
function getAlias(address _operator) external view override returns (address) {
return operatorToAlias[_operator];
}

function getOperatorForAlias(address _alias) external view override returns (address) {
return aliasToOperator[_alias];
}
}
20 changes: 20 additions & 0 deletions contracts/src/interfaces/IAPConfig.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.9;

interface IAPConfig {
// Event emitted when an alias is declared
event AliasDeclared(address indexed operator, address indexed aliasAddress);

// Event emitted when an alias is undeclared
event AliasUndeclared(address indexed operator);

// Function to declare an alias for the operator
function declareAlias(address _alias) external;

// Function to undeclare an alias for the operator
function undeclare() external;

// Function to get the alias of an operator
function getAlias(address _operator) external view returns (address);
function getOperatorForAlias(address _alias) external view returns (address);
}
1 change: 1 addition & 0 deletions core/chainio/abis/apconfig.abi
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
[{"type":"function","name":"declareAlias","inputs":[{"name":"_alias","type":"address","internalType":"address"}],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"getAlias","inputs":[{"name":"_operator","type":"address","internalType":"address"}],"outputs":[{"name":"","type":"address","internalType":"address"}],"stateMutability":"view"},{"type":"function","name":"getOperatorForAlias","inputs":[{"name":"_alias","type":"address","internalType":"address"}],"outputs":[{"name":"","type":"address","internalType":"address"}],"stateMutability":"view"},{"type":"function","name":"undeclare","inputs":[],"outputs":[],"stateMutability":"nonpayable"},{"type":"event","name":"AliasDeclared","inputs":[{"name":"operator","type":"address","indexed":true,"internalType":"address"},{"name":"aliasAddress","type":"address","indexed":true,"internalType":"address"}],"anonymous":false},{"type":"event","name":"AliasUndeclared","inputs":[{"name":"operator","type":"address","indexed":true,"internalType":"address"}],"anonymous":false}]
2 changes: 2 additions & 0 deletions core/chainio/apconfig/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
genabi:
abigen --abi=../abis/apconfig.abi --pkg=apconfig --type=APConfig --out=binding.go
15 changes: 15 additions & 0 deletions core/chainio/apconfig/apconfig.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package apconfig

import (
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/ethclient"
)

func GetContract(ethRpcURL string, address common.Address) (*APConfig, error) {
ethRpcClient, err := ethclient.Dial(ethRpcURL)
if err != nil {
return nil, err
}

return NewAPConfig(address, ethRpcClient)
}
Loading