Skip to content
Merged
62 changes: 58 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,16 +27,16 @@ curl -fsSL https://raw.githubusercontent.com/Layr-Labs/devkit-cli/main/install-d
Download the binary for your platform:
```bash
# macOS (Apple Silicon)
mkdir -p $HOME/bin && curl -sL https://s3.amazonaws.com/eigenlayer-devkit-releases/v0.0.10/devkit-darwin-arm64-v0.0.10.tar.gz | tar xz -C "$HOME/bin"
mkdir -p $HOME/bin && curl -sL https://s3.amazonaws.com/eigenlayer-devkit-releases/v0.1.0-preview.2.rc/devkit-darwin-arm64-v0.1.0-preview.2.rc.tar.gz | tar xz -C "$HOME/bin"

# macOS (Intel)
mkdir -p $HOME/bin && curl -sL https://s3.amazonaws.com/eigenlayer-devkit-releases/v0.0.10/devkit-darwin-amd64-v0.0.10.tar.gz | tar xz -C "$HOME/bin"
mkdir -p $HOME/bin && curl -sL https://s3.amazonaws.com/eigenlayer-devkit-releases/v0.1.0-preview.2.rc/devkit-darwin-amd64-v0.1.0-preview.2.rc.tar.gz | tar xz -C "$HOME/bin"

# Linux (x86_64 / AMD64)
mkdir -p $HOME/bin && curl -sL https://s3.amazonaws.com/eigenlayer-devkit-releases/v0.0.10/devkit-linux-amd64-v0.0.10.tar.gz | tar xz -C "$HOME/bin"
mkdir -p $HOME/bin && curl -sL https://s3.amazonaws.com/eigenlayer-devkit-releases/v0.1.0-preview.2.rc/devkit-linux-amd64-v0.1.0-preview.2.rc.tar.gz | tar xz -C "$HOME/bin"

# Linux (ARM64 / aarch64)
mkdir -p $HOME/bin && curl -sL https://s3.amazonaws.com/eigenlayer-devkit-releases/v0.0.10/devkit-linux-arm64-v0.0.10.tar.gz | tar xz -C "$HOME/bin"
mkdir -p $HOME/bin && curl -sL https://s3.amazonaws.com/eigenlayer-devkit-releases/v0.1.0-preview.2.rc/devkit-linux-arm64-v0.1.0-preview.2.rc.tar.gz | tar xz -C "$HOME/bin"
```

Add to your PATH:
Expand Down Expand Up @@ -521,6 +521,60 @@ devkit avs build --verbose
```

---

## Deploying to Testnet (v0.1.0+)

As of **v0.1.0**, DevKit supports deploying AVS contracts to public testnets. This is the next step after local development and testing.

### Create a Testnet Context

You must create a separate context for your testnet deployment:

```bash
devkit avs context create --context testnet
```

Set it as the active context:

```bash
devkit avs config --set project.context="testnet"
```

Edit the testnet configuration to set RPC endpoints, keys, and other environment details:

```bash
devkit avs context --edit --context testnet
```

> **Tip:**
> Use reliable archive RPC endpoints for both L1 and L2 chains. Configure private keys for deployment wallets in the testnet context file or via `.env` for security.

---

### Deploy AVS Contracts to Testnet

Once the `testnet` context is configured and active, you can deploy to each chain:

- **Deploy L1 contracts**:
```bash
devkit avs deploy contracts l1
```

- **Deploy L2 contracts**:
```bash
devkit avs deploy contracts l2
```

> Both commands will use the RPC URLs and keys from your active context.

---

### Next Steps After Deployment
- Verify contract addresses in your testnet context file.
- Register operators and run your AVS offchain services pointing to the testnet.
- Optionally, publish a release for operators using `devkit avs release publish`.


## Upgrade Process


Expand Down
2 changes: 1 addition & 1 deletion VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
v0.0.10
v0.1.0-preview.2.rc
8 changes: 0 additions & 8 deletions config/contexts/migrations/v0.0.8-v0.0.9.go
Original file line number Diff line number Diff line change
Expand Up @@ -100,14 +100,6 @@ func Migration_0_0_8_to_0_0_9(user, old, new *yaml.Node) (*yaml.Node, error) {
return &yaml.Node{Kind: yaml.ScalarNode, Value: "0xaCB5DE6aa94a1908E6FA577C2ade65065333B450"}
},
},
// Add skip-setup flag to avs config
{
Path: []string{"context", "avs", "skip_setup"},
Condition: migration.Always{},
Transform: func(_ *yaml.Node) *yaml.Node {
return &yaml.Node{Kind: yaml.ScalarNode, Value: "false"}
},
},
},
}

Expand Down
123 changes: 123 additions & 0 deletions config/contexts/migrations/v0.0.9-v0.1.0.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
package contextMigrations

import (
"fmt"

"github.com/Layr-Labs/devkit-cli/pkg/migration"

"gopkg.in/yaml.v3"
)

func Migration_0_0_9_to_0_1_0(user, old, new *yaml.Node) (*yaml.Node, error) {
engine := migration.PatchEngine{
Old: old,
New: new,
User: user,
Rules: []migration.PatchRule{
// Move Operators keystore to map
{
Path: []string{"context", "operators"},
Condition: migration.Always{},
Transform: func(_ *yaml.Node) *yaml.Node {
avsNode := migration.ResolveNode(user, []string{"context", "avs", "address"})
avsAddr := ""
if avsNode != nil {
avsAddr = avsNode.Value
}

ops := migration.ResolveNode(user, []string{"context", "operators"})
if ops == nil || ops.Kind != yaml.SequenceNode {
return ops
}
out := migration.CloneNode(ops)

// Fixed operatorSet IDs
opsetIDs := []int{0, 1}

for _, op := range out.Content {
if op.Kind != yaml.MappingNode {
continue
}

ecdsaPath := ""
if n := migration.ResolveNode(op, []string{"ecdsa_keystore_path"}); n != nil {
ecdsaPath = n.Value
}
ecdsaPass := ""
if n := migration.ResolveNode(op, []string{"ecdsa_keystore_password"}); n != nil {
ecdsaPass = n.Value
}
blsPath := ""
if n := migration.ResolveNode(op, []string{"bls_keystore_path"}); n != nil {
blsPath = n.Value
}
blsPass := ""
if n := migration.ResolveNode(op, []string{"bls_keystore_password"}); n != nil {
blsPass = n.Value
}

// build keystores
keystoresSeq := &yaml.Node{Kind: yaml.SequenceNode, Tag: "!!seq"}

for _, setID := range opsetIDs {
ksMap := &yaml.Node{Kind: yaml.MappingNode, Tag: "!!map"}

ksMap.Content = append(ksMap.Content,
&yaml.Node{Kind: yaml.ScalarNode, Tag: "!!str", Value: "avs"},
&yaml.Node{Kind: yaml.ScalarNode, Tag: "!!str", Value: avsAddr},

&yaml.Node{Kind: yaml.ScalarNode, Tag: "!!str", Value: "operatorSet"},
&yaml.Node{Kind: yaml.ScalarNode, Tag: "!!int", Value: fmt.Sprintf("%d", setID)},

&yaml.Node{Kind: yaml.ScalarNode, Tag: "!!str", Value: "ecdsa_keystore_path"},
&yaml.Node{Kind: yaml.ScalarNode, Tag: "!!str", Value: ecdsaPath},
&yaml.Node{Kind: yaml.ScalarNode, Tag: "!!str", Value: "ecdsa_keystore_password"},
&yaml.Node{Kind: yaml.ScalarNode, Tag: "!!str", Value: ecdsaPass},

&yaml.Node{Kind: yaml.ScalarNode, Tag: "!!str", Value: "bls_keystore_path"},
&yaml.Node{Kind: yaml.ScalarNode, Tag: "!!str", Value: blsPath},
&yaml.Node{Kind: yaml.ScalarNode, Tag: "!!str", Value: "bls_keystore_password"},
&yaml.Node{Kind: yaml.ScalarNode, Tag: "!!str", Value: blsPass},
)

keystoresSeq.Content = append(keystoresSeq.Content, ksMap)
}

// drop old flat fields and any preexisting keystore/keystores
c := op.Content[:0]
for j := 0; j < len(op.Content); j += 2 {
k := op.Content[j].Value
if k == "ecdsa_keystore_path" ||
k == "ecdsa_keystore_password" ||
k == "bls_keystore_path" ||
k == "bls_keystore_password" ||
k == "keystores" {
continue
}
c = append(c, op.Content[j], op.Content[j+1])
}
op.Content = c

// write new keystores
op.Content = append(op.Content,
&yaml.Node{Kind: yaml.ScalarNode, Tag: "!!str", Value: "keystores"},
keystoresSeq,
)
}
return out
},
},
},
}

if err := engine.Apply(); err != nil {
return nil, err
}

// Upgrade the version
if v := migration.ResolveNode(user, []string{"version"}); v != nil {
v.Value = "0.1.0"
}

return user, nil
}
13 changes: 12 additions & 1 deletion config/contexts/registry.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import (
)

// Set the latest version
const LatestVersion = "0.0.9"
const LatestVersion = "0.1.0"

// Array of default contexts to create in project
var DefaultContexts = [...]string{
Expand Down Expand Up @@ -53,6 +53,9 @@ var v0_0_8_default []byte
//go:embed v0.0.9.yaml
var v0_0_9_default []byte

//go:embed v0.1.0.yaml
var v0_1_0_default []byte

// Map of context name -> content
var ContextYamls = map[string][]byte{
"0.0.1": v0_0_1_default,
Expand All @@ -64,6 +67,7 @@ var ContextYamls = map[string][]byte{
"0.0.7": v0_0_7_default,
"0.0.8": v0_0_8_default,
"0.0.9": v0_0_9_default,
"0.1.0": v0_1_0_default,
}

// Map of sequential migrations
Expand Down Expand Up @@ -124,6 +128,13 @@ var MigrationChain = []migration.MigrationStep{
OldYAML: v0_0_8_default,
NewYAML: v0_0_9_default,
},
{
From: "0.0.9",
To: "0.1.0",
Apply: contextMigrations.Migration_0_0_9_to_0_1_0,
OldYAML: v0_0_9_default,
NewYAML: v0_1_0_default,
},
}

func MigrateContexts(logger iface.Logger) (int, error) {
Expand Down
1 change: 0 additions & 1 deletion config/contexts/v0.0.9.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,6 @@ context:
bls_keystore_password: "testpass"
# AVS configuration
avs:
skip_setup: false
address: "0x70997970C51812dc3A010C7d01b50e0d17dc79C8"
avs_private_key: "0x59c6995e998f97a5a0044966f0945389dc9e86dae88c7a8412f4603b6b78690d" # Anvil Private Key 1
metadata_url: "https://my-org.com/avs/metadata.json"
Expand Down
Loading
Loading