Commit 2c5f6ed3 authored by smartcontracts's avatar smartcontracts Committed by GitHub

feat(ct): DeployDelayedWETH script (#12662)

* feat(ct): DeployDelayedWETH script

Adds a new deployment script for deploying a new DelayedWETH
proxy contract.

* fix tests

* lint

* delete letter o

* move testdata

---------
Co-authored-by: default avatarMatthew Slipper <me@matthewslipper.com>
parent 1f335f15
...@@ -7,6 +7,10 @@ import ( ...@@ -7,6 +7,10 @@ import (
"math/big" "math/big"
"strings" "strings"
"github.com/ethereum-optimism/optimism/op-deployer/pkg/deployer/artifacts"
"github.com/ethereum-optimism/optimism/op-deployer/pkg/env"
"github.com/ethereum-optimism/optimism/op-chain-ops/foundry" "github.com/ethereum-optimism/optimism/op-chain-ops/foundry"
"github.com/ethereum-optimism/optimism/op-deployer/pkg/deployer/broadcaster" "github.com/ethereum-optimism/optimism/op-deployer/pkg/deployer/broadcaster"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
...@@ -146,7 +150,7 @@ func Apply(ctx context.Context, cfg ApplyConfig) error { ...@@ -146,7 +150,7 @@ func Apply(ctx context.Context, cfg ApplyConfig) error {
cfg.Logger.Info("artifacts download progress", "current", curr, "total", total) cfg.Logger.Info("artifacts download progress", "current", curr, "total", total)
} }
l1ArtifactsFS, cleanupL1, err := pipeline.DownloadArtifacts(ctx, intent.L1ContractsLocator, progressor) l1ArtifactsFS, cleanupL1, err := artifacts.Download(ctx, intent.L1ContractsLocator, progressor)
if err != nil { if err != nil {
return fmt.Errorf("failed to download L1 artifacts: %w", err) return fmt.Errorf("failed to download L1 artifacts: %w", err)
} }
...@@ -156,7 +160,7 @@ func Apply(ctx context.Context, cfg ApplyConfig) error { ...@@ -156,7 +160,7 @@ func Apply(ctx context.Context, cfg ApplyConfig) error {
} }
}() }()
l2ArtifactsFS, cleanupL2, err := pipeline.DownloadArtifacts(ctx, intent.L2ContractsLocator, progressor) l2ArtifactsFS, cleanupL2, err := artifacts.Download(ctx, intent.L2ContractsLocator, progressor)
if err != nil { if err != nil {
return fmt.Errorf("failed to download L2 artifacts: %w", err) return fmt.Errorf("failed to download L2 artifacts: %w", err)
} }
...@@ -171,7 +175,7 @@ func Apply(ctx context.Context, cfg ApplyConfig) error { ...@@ -171,7 +175,7 @@ func Apply(ctx context.Context, cfg ApplyConfig) error {
L2: l2ArtifactsFS, L2: l2ArtifactsFS,
} }
l1Host, err := pipeline.DefaultScriptHost(bcaster, cfg.Logger, deployer, bundle.L1, startingNonce) l1Host, err := env.DefaultScriptHost(bcaster, cfg.Logger, deployer, bundle.L1, startingNonce)
if err != nil { if err != nil {
return fmt.Errorf("failed to create L1 script host: %w", err) return fmt.Errorf("failed to create L1 script host: %w", err)
} }
......
package pipeline package artifacts
import ( import (
"archive/tar" "archive/tar"
...@@ -19,8 +19,6 @@ import ( ...@@ -19,8 +19,6 @@ import (
"github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/log"
"github.com/ethereum-optimism/optimism/op-deployer/pkg/deployer/opcm"
"github.com/ethereum-optimism/optimism/op-chain-ops/foundry" "github.com/ethereum-optimism/optimism/op-chain-ops/foundry"
) )
...@@ -40,7 +38,7 @@ func LogProgressor(lgr log.Logger) DownloadProgressor { ...@@ -40,7 +38,7 @@ func LogProgressor(lgr log.Logger) DownloadProgressor {
} }
} }
func DownloadArtifacts(ctx context.Context, loc *opcm.ArtifactsLocator, progress DownloadProgressor) (foundry.StatDirFs, CleanupFunc, error) { func Download(ctx context.Context, loc *Locator, progress DownloadProgressor) (foundry.StatDirFs, CleanupFunc, error) {
var u *url.URL var u *url.URL
var err error var err error
if loc.IsTag() { if loc.IsTag() {
......
package pipeline package artifacts
import ( import (
"context" "context"
...@@ -9,8 +9,6 @@ import ( ...@@ -9,8 +9,6 @@ import (
"os" "os"
"testing" "testing"
"github.com/ethereum-optimism/optimism/op-deployer/pkg/deployer/opcm"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
) )
...@@ -29,11 +27,11 @@ func TestDownloadArtifacts(t *testing.T) { ...@@ -29,11 +27,11 @@ func TestDownloadArtifacts(t *testing.T) {
ctx := context.Background() ctx := context.Background()
artifactsURL, err := url.Parse(ts.URL) artifactsURL, err := url.Parse(ts.URL)
require.NoError(t, err) require.NoError(t, err)
loc := &opcm.ArtifactsLocator{ loc := &Locator{
URL: artifactsURL, URL: artifactsURL,
} }
fs, cleanup, err := DownloadArtifacts(ctx, loc, nil) fs, cleanup, err := Download(ctx, loc, nil)
require.NoError(t, err) require.NoError(t, err)
require.NotNil(t, fs) require.NotNil(t, fs)
defer func() { defer func() {
......
package opcm package artifacts
import ( import (
"fmt" "fmt"
...@@ -8,7 +8,7 @@ import ( ...@@ -8,7 +8,7 @@ import (
"github.com/ethereum-optimism/optimism/op-deployer/pkg/deployer/standard" "github.com/ethereum-optimism/optimism/op-deployer/pkg/deployer/standard"
) )
type schemeUnmarshaler func(string) (*ArtifactsLocator, error) type schemeUnmarshaler func(string) (*Locator, error)
var schemeUnmarshalerDispatch = map[string]schemeUnmarshaler{ var schemeUnmarshalerDispatch = map[string]schemeUnmarshaler{
"tag": unmarshalTag, "tag": unmarshalTag,
...@@ -16,20 +16,20 @@ var schemeUnmarshalerDispatch = map[string]schemeUnmarshaler{ ...@@ -16,20 +16,20 @@ var schemeUnmarshalerDispatch = map[string]schemeUnmarshaler{
"https": unmarshalURL, "https": unmarshalURL,
} }
var DefaultL1ContractsLocator = &ArtifactsLocator{ var DefaultL1ContractsLocator = &Locator{
Tag: standard.DefaultL1ContractsTag, Tag: standard.DefaultL1ContractsTag,
} }
var DefaultL2ContractsLocator = &ArtifactsLocator{ var DefaultL2ContractsLocator = &Locator{
Tag: standard.DefaultL2ContractsTag, Tag: standard.DefaultL2ContractsTag,
} }
type ArtifactsLocator struct { type Locator struct {
URL *url.URL URL *url.URL
Tag string Tag string
} }
func (a *ArtifactsLocator) UnmarshalText(text []byte) error { func (a *Locator) UnmarshalText(text []byte) error {
str := string(text) str := string(text)
for scheme, unmarshaler := range schemeUnmarshalerDispatch { for scheme, unmarshaler := range schemeUnmarshalerDispatch {
...@@ -49,7 +49,7 @@ func (a *ArtifactsLocator) UnmarshalText(text []byte) error { ...@@ -49,7 +49,7 @@ func (a *ArtifactsLocator) UnmarshalText(text []byte) error {
return fmt.Errorf("unsupported scheme") return fmt.Errorf("unsupported scheme")
} }
func (a *ArtifactsLocator) MarshalText() ([]byte, error) { func (a *Locator) MarshalText() ([]byte, error) {
if a.URL != nil { if a.URL != nil {
return []byte(a.URL.String()), nil return []byte(a.URL.String()), nil
} }
...@@ -61,11 +61,11 @@ func (a *ArtifactsLocator) MarshalText() ([]byte, error) { ...@@ -61,11 +61,11 @@ func (a *ArtifactsLocator) MarshalText() ([]byte, error) {
return nil, fmt.Errorf("no URL, path or tag set") return nil, fmt.Errorf("no URL, path or tag set")
} }
func (a *ArtifactsLocator) IsTag() bool { func (a *Locator) IsTag() bool {
return a.Tag != "" return a.Tag != ""
} }
func unmarshalTag(tag string) (*ArtifactsLocator, error) { func unmarshalTag(tag string) (*Locator, error) {
tag = strings.TrimPrefix(tag, "tag://") tag = strings.TrimPrefix(tag, "tag://")
if !strings.HasPrefix(tag, "op-contracts/") { if !strings.HasPrefix(tag, "op-contracts/") {
return nil, fmt.Errorf("invalid tag: %s", tag) return nil, fmt.Errorf("invalid tag: %s", tag)
...@@ -75,14 +75,14 @@ func unmarshalTag(tag string) (*ArtifactsLocator, error) { ...@@ -75,14 +75,14 @@ func unmarshalTag(tag string) (*ArtifactsLocator, error) {
return nil, err return nil, err
} }
return &ArtifactsLocator{Tag: tag}, nil return &Locator{Tag: tag}, nil
} }
func unmarshalURL(text string) (*ArtifactsLocator, error) { func unmarshalURL(text string) (*Locator, error) {
u, err := url.Parse(text) u, err := url.Parse(text)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return &ArtifactsLocator{URL: u}, nil return &Locator{URL: u}, nil
} }
package opcm package artifacts
import ( import (
"net/url" "net/url"
...@@ -7,17 +7,17 @@ import ( ...@@ -7,17 +7,17 @@ import (
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
) )
func TestArtifactsLocator_Marshaling(t *testing.T) { func TestLocator_Marshaling(t *testing.T) {
tests := []struct { tests := []struct {
name string name string
in string in string
out *ArtifactsLocator out *Locator
err bool err bool
}{ }{
{ {
name: "valid tag", name: "valid tag",
in: "tag://op-contracts/v1.6.0", in: "tag://op-contracts/v1.6.0",
out: &ArtifactsLocator{ out: &Locator{
Tag: "op-contracts/v1.6.0", Tag: "op-contracts/v1.6.0",
}, },
err: false, err: false,
...@@ -37,7 +37,7 @@ func TestArtifactsLocator_Marshaling(t *testing.T) { ...@@ -37,7 +37,7 @@ func TestArtifactsLocator_Marshaling(t *testing.T) {
{ {
name: "valid HTTPS URL", name: "valid HTTPS URL",
in: "https://example.com", in: "https://example.com",
out: &ArtifactsLocator{ out: &Locator{
URL: parseUrl(t, "https://example.com"), URL: parseUrl(t, "https://example.com"),
}, },
err: false, err: false,
...@@ -45,7 +45,7 @@ func TestArtifactsLocator_Marshaling(t *testing.T) { ...@@ -45,7 +45,7 @@ func TestArtifactsLocator_Marshaling(t *testing.T) {
{ {
name: "valid file URL", name: "valid file URL",
in: "file:///tmp/artifacts", in: "file:///tmp/artifacts",
out: &ArtifactsLocator{ out: &Locator{
URL: parseUrl(t, "file:///tmp/artifacts"), URL: parseUrl(t, "file:///tmp/artifacts"),
}, },
err: false, err: false,
...@@ -71,7 +71,7 @@ func TestArtifactsLocator_Marshaling(t *testing.T) { ...@@ -71,7 +71,7 @@ func TestArtifactsLocator_Marshaling(t *testing.T) {
} }
for _, tt := range tests { for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {
var a ArtifactsLocator var a Locator
err := a.UnmarshalText([]byte(tt.in)) err := a.UnmarshalText([]byte(tt.in))
if tt.err { if tt.err {
require.Error(t, err) require.Error(t, err)
......
package bootstrap
import (
"context"
"crypto/ecdsa"
"fmt"
"math/big"
"strings"
artifacts2 "github.com/ethereum-optimism/optimism/op-deployer/pkg/deployer/artifacts"
"github.com/ethereum-optimism/optimism/op-deployer/pkg/env"
"github.com/ethereum-optimism/optimism/op-deployer/pkg/deployer/standard"
"github.com/ethereum-optimism/optimism/op-deployer/pkg/deployer/broadcaster"
"github.com/ethereum-optimism/optimism/op-deployer/pkg/deployer"
"github.com/ethereum-optimism/optimism/op-deployer/pkg/deployer/opcm"
opcrypto "github.com/ethereum-optimism/optimism/op-service/crypto"
"github.com/ethereum-optimism/optimism/op-service/ctxinterrupt"
"github.com/ethereum-optimism/optimism/op-service/ioutil"
"github.com/ethereum-optimism/optimism/op-service/jsonutil"
oplog "github.com/ethereum-optimism/optimism/op-service/log"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/ethclient"
"github.com/ethereum/go-ethereum/log"
"github.com/urfave/cli/v2"
)
type DelayedWETHConfig struct {
L1RPCUrl string
PrivateKey string
Logger log.Logger
ArtifactsLocator *artifacts2.Locator
privateKeyECDSA *ecdsa.PrivateKey
}
func (c *DelayedWETHConfig) Check() error {
if c.L1RPCUrl == "" {
return fmt.Errorf("l1RPCUrl must be specified")
}
if c.PrivateKey == "" {
return fmt.Errorf("private key must be specified")
}
privECDSA, err := crypto.HexToECDSA(strings.TrimPrefix(c.PrivateKey, "0x"))
if err != nil {
return fmt.Errorf("failed to parse private key: %w", err)
}
c.privateKeyECDSA = privECDSA
if c.Logger == nil {
return fmt.Errorf("logger must be specified")
}
if c.ArtifactsLocator == nil {
return fmt.Errorf("artifacts locator must be specified")
}
return nil
}
func DelayedWETHCLI(cliCtx *cli.Context) error {
logCfg := oplog.ReadCLIConfig(cliCtx)
l := oplog.NewLogger(oplog.AppOut(cliCtx), logCfg)
oplog.SetGlobalLogHandler(l.Handler())
l1RPCUrl := cliCtx.String(deployer.L1RPCURLFlagName)
privateKey := cliCtx.String(deployer.PrivateKeyFlagName)
artifactsURLStr := cliCtx.String(ArtifactsLocatorFlagName)
artifactsLocator := new(artifacts2.Locator)
if err := artifactsLocator.UnmarshalText([]byte(artifactsURLStr)); err != nil {
return fmt.Errorf("failed to parse artifacts URL: %w", err)
}
ctx := ctxinterrupt.WithCancelOnInterrupt(cliCtx.Context)
return DelayedWETH(ctx, DelayedWETHConfig{
L1RPCUrl: l1RPCUrl,
PrivateKey: privateKey,
Logger: l,
ArtifactsLocator: artifactsLocator,
})
}
func DelayedWETH(ctx context.Context, cfg DelayedWETHConfig) error {
if err := cfg.Check(); err != nil {
return fmt.Errorf("invalid config for DelayedWETH: %w", err)
}
lgr := cfg.Logger
progressor := func(curr, total int64) {
lgr.Info("artifacts download progress", "current", curr, "total", total)
}
artifactsFS, cleanup, err := artifacts2.Download(ctx, cfg.ArtifactsLocator, progressor)
if err != nil {
return fmt.Errorf("failed to download artifacts: %w", err)
}
defer func() {
if err := cleanup(); err != nil {
lgr.Warn("failed to clean up artifacts", "err", err)
}
}()
l1Client, err := ethclient.Dial(cfg.L1RPCUrl)
if err != nil {
return fmt.Errorf("failed to connect to L1 RPC: %w", err)
}
chainID, err := l1Client.ChainID(ctx)
if err != nil {
return fmt.Errorf("failed to get chain ID: %w", err)
}
chainIDU64 := chainID.Uint64()
superCfg, err := standard.SuperchainFor(chainIDU64)
if err != nil {
return fmt.Errorf("error getting superchain config: %w", err)
}
standardVersionsTOML, err := standard.L1VersionsDataFor(chainIDU64)
if err != nil {
return fmt.Errorf("error getting standard versions TOML: %w", err)
}
proxyAdmin, err := standard.ManagerOwnerAddrFor(chainIDU64)
if err != nil {
return fmt.Errorf("error getting superchain proxy admin: %w", err)
}
delayedWethOwner, err := standard.SystemOwnerAddrFor(chainIDU64)
if err != nil {
return fmt.Errorf("error getting superchain system owner: %w", err)
}
signer := opcrypto.SignerFnFromBind(opcrypto.PrivateKeySignerFn(cfg.privateKeyECDSA, chainID))
chainDeployer := crypto.PubkeyToAddress(cfg.privateKeyECDSA.PublicKey)
bcaster, err := broadcaster.NewKeyedBroadcaster(broadcaster.KeyedBroadcasterOpts{
Logger: lgr,
ChainID: chainID,
Client: l1Client,
Signer: signer,
From: chainDeployer,
})
if err != nil {
return fmt.Errorf("failed to create broadcaster: %w", err)
}
nonce, err := l1Client.NonceAt(ctx, chainDeployer, nil)
if err != nil {
return fmt.Errorf("failed to get starting nonce: %w", err)
}
host, err := env.DefaultScriptHost(
bcaster,
lgr,
chainDeployer,
artifactsFS,
nonce,
)
if err != nil {
return fmt.Errorf("failed to create script host: %w", err)
}
var release string
if cfg.ArtifactsLocator.IsTag() {
release = cfg.ArtifactsLocator.Tag
} else {
release = "dev"
}
lgr.Info("deploying DelayedWETH", "release", release)
superchainConfigAddr := common.Address(*superCfg.Config.SuperchainConfigAddr)
dwo, err := opcm.DeployDelayedWETH(
host,
opcm.DeployDelayedWETHInput{
Release: release,
StandardVersionsToml: standardVersionsTOML,
ProxyAdmin: proxyAdmin,
SuperchainConfigProxy: superchainConfigAddr,
DelayedWethOwner: delayedWethOwner,
DelayedWethDelay: big.NewInt(604800),
},
)
if err != nil {
return fmt.Errorf("error deploying implementations: %w", err)
}
if _, err := bcaster.Broadcast(ctx); err != nil {
return fmt.Errorf("failed to broadcast: %w", err)
}
lgr.Info("deployed DelayedWETH")
if err := jsonutil.WriteJSON(dwo, ioutil.ToStdOut()); err != nil {
return fmt.Errorf("failed to write output: %w", err)
}
return nil
}
...@@ -73,6 +73,12 @@ var OPCMFlags = []cli.Flag{ ...@@ -73,6 +73,12 @@ var OPCMFlags = []cli.Flag{
MIPSVersionFlag, MIPSVersionFlag,
} }
var DelayedWETHFlags = []cli.Flag{
deployer.L1RPCURLFlag,
deployer.PrivateKeyFlag,
ArtifactsLocatorFlag,
}
var Commands = []*cli.Command{ var Commands = []*cli.Command{
{ {
Name: "opcm", Name: "opcm",
...@@ -80,4 +86,10 @@ var Commands = []*cli.Command{ ...@@ -80,4 +86,10 @@ var Commands = []*cli.Command{
Flags: cliapp.ProtectFlags(OPCMFlags), Flags: cliapp.ProtectFlags(OPCMFlags),
Action: OPCMCLI, Action: OPCMCLI,
}, },
{
Name: "delayedweth",
Usage: "Bootstrap an instance of DelayedWETH.",
Flags: cliapp.ProtectFlags(DelayedWETHFlags),
Action: DelayedWETHCLI,
},
} }
...@@ -8,6 +8,10 @@ import ( ...@@ -8,6 +8,10 @@ import (
"math/big" "math/big"
"strings" "strings"
artifacts2 "github.com/ethereum-optimism/optimism/op-deployer/pkg/deployer/artifacts"
"github.com/ethereum-optimism/optimism/op-deployer/pkg/env"
"github.com/ethereum-optimism/optimism/op-deployer/pkg/deployer/standard" "github.com/ethereum-optimism/optimism/op-deployer/pkg/deployer/standard"
"github.com/ethereum-optimism/optimism/op-deployer/pkg/deployer/broadcaster" "github.com/ethereum-optimism/optimism/op-deployer/pkg/deployer/broadcaster"
...@@ -35,7 +39,7 @@ type OPCMConfig struct { ...@@ -35,7 +39,7 @@ type OPCMConfig struct {
L1RPCUrl string L1RPCUrl string
PrivateKey string PrivateKey string
Logger log.Logger Logger log.Logger
ArtifactsLocator *opcm.ArtifactsLocator ArtifactsLocator *artifacts2.Locator
privateKeyECDSA *ecdsa.PrivateKey privateKeyECDSA *ecdsa.PrivateKey
} }
...@@ -98,7 +102,7 @@ func OPCMCLI(cliCtx *cli.Context) error { ...@@ -98,7 +102,7 @@ func OPCMCLI(cliCtx *cli.Context) error {
l1RPCUrl := cliCtx.String(deployer.L1RPCURLFlagName) l1RPCUrl := cliCtx.String(deployer.L1RPCURLFlagName)
privateKey := cliCtx.String(deployer.PrivateKeyFlagName) privateKey := cliCtx.String(deployer.PrivateKeyFlagName)
artifactsURLStr := cliCtx.String(ArtifactsLocatorFlagName) artifactsURLStr := cliCtx.String(ArtifactsLocatorFlagName)
artifactsLocator := new(opcm.ArtifactsLocator) artifactsLocator := new(artifacts2.Locator)
if err := artifactsLocator.UnmarshalText([]byte(artifactsURLStr)); err != nil { if err := artifactsLocator.UnmarshalText([]byte(artifactsURLStr)); err != nil {
return fmt.Errorf("failed to parse artifacts URL: %w", err) return fmt.Errorf("failed to parse artifacts URL: %w", err)
} }
...@@ -131,7 +135,7 @@ func OPCM(ctx context.Context, cfg OPCMConfig) error { ...@@ -131,7 +135,7 @@ func OPCM(ctx context.Context, cfg OPCMConfig) error {
lgr.Info("artifacts download progress", "current", curr, "total", total) lgr.Info("artifacts download progress", "current", curr, "total", total)
} }
artifactsFS, cleanup, err := pipeline.DownloadArtifacts(ctx, cfg.ArtifactsLocator, progressor) artifactsFS, cleanup, err := artifacts2.Download(ctx, cfg.ArtifactsLocator, progressor)
if err != nil { if err != nil {
return fmt.Errorf("failed to download artifacts: %w", err) return fmt.Errorf("failed to download artifacts: %w", err)
} }
...@@ -184,7 +188,7 @@ func OPCM(ctx context.Context, cfg OPCMConfig) error { ...@@ -184,7 +188,7 @@ func OPCM(ctx context.Context, cfg OPCMConfig) error {
return fmt.Errorf("failed to get starting nonce: %w", err) return fmt.Errorf("failed to get starting nonce: %w", err)
} }
host, err := pipeline.DefaultScriptHost( host, err := env.DefaultScriptHost(
bcaster, bcaster,
lgr, lgr,
chainDeployer, chainDeployer,
......
...@@ -7,7 +7,7 @@ import ( ...@@ -7,7 +7,7 @@ import (
"path" "path"
"strings" "strings"
"github.com/ethereum-optimism/optimism/op-deployer/pkg/deployer/opcm" "github.com/ethereum-optimism/optimism/op-deployer/pkg/deployer/artifacts"
"github.com/ethereum-optimism/optimism/op-deployer/pkg/deployer/state" "github.com/ethereum-optimism/optimism/op-deployer/pkg/deployer/state"
...@@ -90,8 +90,8 @@ func Init(cfg InitConfig) error { ...@@ -90,8 +90,8 @@ func Init(cfg InitConfig) error {
DeploymentStrategy: cfg.DeploymentStrategy, DeploymentStrategy: cfg.DeploymentStrategy,
L1ChainID: cfg.L1ChainID, L1ChainID: cfg.L1ChainID,
FundDevAccounts: true, FundDevAccounts: true,
L1ContractsLocator: opcm.DefaultL1ContractsLocator, L1ContractsLocator: artifacts.DefaultL1ContractsLocator,
L2ContractsLocator: opcm.DefaultL2ContractsLocator, L2ContractsLocator: artifacts.DefaultL2ContractsLocator,
} }
l1ChainIDBig := intent.L1ChainIDBig() l1ChainIDBig := intent.L1ChainIDBig()
......
...@@ -8,6 +8,10 @@ import ( ...@@ -8,6 +8,10 @@ import (
"regexp" "regexp"
"time" "time"
"github.com/ethereum-optimism/optimism/op-deployer/pkg/deployer/artifacts"
"github.com/ethereum-optimism/optimism/op-deployer/pkg/env"
"github.com/ethereum-optimism/optimism/op-chain-ops/script" "github.com/ethereum-optimism/optimism/op-chain-ops/script"
"github.com/ethereum-optimism/optimism/op-deployer/pkg/deployer/broadcaster" "github.com/ethereum-optimism/optimism/op-deployer/pkg/deployer/broadcaster"
...@@ -53,7 +57,7 @@ func L2SemversCLI(cliCtx *cli.Context) error { ...@@ -53,7 +57,7 @@ func L2SemversCLI(cliCtx *cli.Context) error {
return fmt.Errorf("chain state does not have allocs") return fmt.Errorf("chain state does not have allocs")
} }
artifactsFS, cleanup, err := pipeline.DownloadArtifacts(ctx, intent.L2ContractsLocator, pipeline.LogProgressor(l)) artifactsFS, cleanup, err := artifacts.Download(ctx, intent.L2ContractsLocator, artifacts.LogProgressor(l))
if err != nil { if err != nil {
return fmt.Errorf("failed to download L2 artifacts: %w", err) return fmt.Errorf("failed to download L2 artifacts: %w", err)
} }
...@@ -63,7 +67,7 @@ func L2SemversCLI(cliCtx *cli.Context) error { ...@@ -63,7 +67,7 @@ func L2SemversCLI(cliCtx *cli.Context) error {
} }
}() }()
host, err := pipeline.DefaultScriptHost( host, err := env.DefaultScriptHost(
broadcaster.NoopBroadcaster(), broadcaster.NoopBroadcaster(),
l, l,
common.Address{19: 0x01}, common.Address{19: 0x01},
......
...@@ -7,14 +7,16 @@ import ( ...@@ -7,14 +7,16 @@ import (
"fmt" "fmt"
"log/slog" "log/slog"
"math/big" "math/big"
"net/url"
"os" "os"
"path"
"runtime"
"testing" "testing"
"time" "time"
"github.com/ethereum-optimism/optimism/op-deployer/pkg/deployer/artifacts"
"github.com/ethereum-optimism/optimism/op-chain-ops/script" "github.com/ethereum-optimism/optimism/op-chain-ops/script"
"github.com/ethereum-optimism/optimism/op-deployer/pkg/deployer/testutil"
"github.com/ethereum-optimism/optimism/op-deployer/pkg/env"
"github.com/ethereum-optimism/optimism/op-deployer/pkg/deployer/broadcaster" "github.com/ethereum-optimism/optimism/op-deployer/pkg/deployer/broadcaster"
"github.com/ethereum-optimism/optimism/op-deployer/pkg/deployer/standard" "github.com/ethereum-optimism/optimism/op-deployer/pkg/deployer/standard"
"github.com/ethereum-optimism/optimism/op-service/testutils/anvil" "github.com/ethereum-optimism/optimism/op-service/testutils/anvil"
...@@ -22,7 +24,6 @@ import ( ...@@ -22,7 +24,6 @@ import (
"github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/log"
"github.com/ethereum-optimism/optimism/op-deployer/pkg/deployer" "github.com/ethereum-optimism/optimism/op-deployer/pkg/deployer"
"github.com/ethereum-optimism/optimism/op-deployer/pkg/deployer/opcm"
"github.com/ethereum-optimism/optimism/op-deployer/pkg/deployer/pipeline" "github.com/ethereum-optimism/optimism/op-deployer/pkg/deployer/pipeline"
"github.com/ethereum-optimism/optimism/op-deployer/pkg/deployer/state" "github.com/ethereum-optimism/optimism/op-deployer/pkg/deployer/state"
...@@ -109,7 +110,7 @@ func TestEndToEndApply(t *testing.T) { ...@@ -109,7 +110,7 @@ func TestEndToEndApply(t *testing.T) {
deployerAddr, err := dk.Address(depKey) deployerAddr, err := dk.Address(depKey)
require.NoError(t, err) require.NoError(t, err)
loc := localArtifactsLocator(t) loc, _ := testutil.LocalArtifacts(t)
bcaster, err := broadcaster.NewKeyedBroadcaster(broadcaster.KeyedBroadcasterOpts{ bcaster, err := broadcaster.NewKeyedBroadcaster(broadcaster.KeyedBroadcasterOpts{
Logger: log.NewLogger(log.DiscardHandler()), Logger: log.NewLogger(log.DiscardHandler()),
...@@ -120,7 +121,7 @@ func TestEndToEndApply(t *testing.T) { ...@@ -120,7 +121,7 @@ func TestEndToEndApply(t *testing.T) {
}) })
require.NoError(t, err) require.NoError(t, err)
env, bundle, _ := createEnv(t, ctx, lgr, l1Client, bcaster, deployerAddr) env, bundle, _ := createEnv(t, lgr, l1Client, bcaster, deployerAddr)
intent, st := newIntent(t, l1ChainID, dk, l2ChainID1, loc, loc) intent, st := newIntent(t, l1ChainID, dk, l2ChainID1, loc, loc)
cg := ethClientCodeGetter(ctx, l1Client) cg := ethClientCodeGetter(ctx, l1Client)
...@@ -140,7 +141,7 @@ func TestEndToEndApply(t *testing.T) { ...@@ -140,7 +141,7 @@ func TestEndToEndApply(t *testing.T) {
t.Run("subsequent chain", func(t *testing.T) { t.Run("subsequent chain", func(t *testing.T) {
// create a new environment with wiped state to ensure we can continue using the // create a new environment with wiped state to ensure we can continue using the
// state from the previous deployment // state from the previous deployment
env, bundle, _ = createEnv(t, ctx, lgr, l1Client, bcaster, deployerAddr) env, bundle, _ = createEnv(t, lgr, l1Client, bcaster, deployerAddr)
intent.Chains = append(intent.Chains, newChainIntent(t, dk, l1ChainID, l2ChainID2)) intent.Chains = append(intent.Chains, newChainIntent(t, dk, l1ChainID, l2ChainID2))
require.NoError(t, deployer.ApplyPipeline( require.NoError(t, deployer.ApplyPipeline(
...@@ -202,15 +203,15 @@ func TestApplyExistingOPCM(t *testing.T) { ...@@ -202,15 +203,15 @@ func TestApplyExistingOPCM(t *testing.T) {
}) })
require.NoError(t, err) require.NoError(t, err)
env, bundle, _ := createEnv(t, ctx, lgr, l1Client, bcaster, deployerAddr) env, bundle, _ := createEnv(t, lgr, l1Client, bcaster, deployerAddr)
intent, st := newIntent( intent, st := newIntent(
t, t,
l1ChainID, l1ChainID,
dk, dk,
l2ChainID, l2ChainID,
opcm.DefaultL1ContractsLocator, artifacts.DefaultL1ContractsLocator,
opcm.DefaultL2ContractsLocator, artifacts.DefaultL2ContractsLocator,
) )
require.NoError(t, deployer.ApplyPipeline( require.NoError(t, deployer.ApplyPipeline(
...@@ -421,7 +422,7 @@ func TestInvalidL2Genesis(t *testing.T) { ...@@ -421,7 +422,7 @@ func TestInvalidL2Genesis(t *testing.T) {
deployerAddr, err := dk.Address(depKey) deployerAddr, err := dk.Address(depKey)
require.NoError(t, err) require.NoError(t, err)
loc := localArtifactsLocator(t) loc, _ := testutil.LocalArtifacts(t)
// these tests were generated by grepping all usages of the deploy // these tests were generated by grepping all usages of the deploy
// config in L2Genesis.s.sol. // config in L2Genesis.s.sol.
...@@ -468,7 +469,7 @@ func TestInvalidL2Genesis(t *testing.T) { ...@@ -468,7 +469,7 @@ func TestInvalidL2Genesis(t *testing.T) {
} }
for _, tt := range tests { for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {
env, bundle, _ := createEnv(t, ctx, lgr, nil, broadcaster.NoopBroadcaster(), deployerAddr) env, bundle, _ := createEnv(t, lgr, nil, broadcaster.NoopBroadcaster(), deployerAddr)
intent, st := newIntent(t, l1ChainID, dk, l2ChainID1, loc, loc) intent, st := newIntent(t, l1ChainID, dk, l2ChainID1, loc, loc)
intent.Chains = append(intent.Chains, newChainIntent(t, dk, l1ChainID, l2ChainID1)) intent.Chains = append(intent.Chains, newChainIntent(t, dk, l1ChainID, l2ChainID1))
intent.DeploymentStrategy = state.DeploymentStrategyGenesis intent.DeploymentStrategy = state.DeploymentStrategyGenesis
...@@ -490,9 +491,6 @@ func TestInvalidL2Genesis(t *testing.T) { ...@@ -490,9 +491,6 @@ func TestInvalidL2Genesis(t *testing.T) {
func setupGenesisChain(t *testing.T) (*pipeline.Env, pipeline.ArtifactsBundle, *state.Intent, *state.State) { func setupGenesisChain(t *testing.T) (*pipeline.Env, pipeline.ArtifactsBundle, *state.Intent, *state.State) {
lgr := testlog.Logger(t, slog.LevelDebug) lgr := testlog.Logger(t, slog.LevelDebug)
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
depKey := new(deployerKey) depKey := new(deployerKey)
l1ChainID := big.NewInt(77799777) l1ChainID := big.NewInt(77799777)
dk, err := devkeys.NewMnemonicDevKeys(devkeys.TestMnemonic) dk, err := devkeys.NewMnemonicDevKeys(devkeys.TestMnemonic)
...@@ -503,53 +501,25 @@ func setupGenesisChain(t *testing.T) (*pipeline.Env, pipeline.ArtifactsBundle, * ...@@ -503,53 +501,25 @@ func setupGenesisChain(t *testing.T) (*pipeline.Env, pipeline.ArtifactsBundle, *
deployerAddr, err := dk.Address(depKey) deployerAddr, err := dk.Address(depKey)
require.NoError(t, err) require.NoError(t, err)
loc := localArtifactsLocator(t) loc, _ := testutil.LocalArtifacts(t)
env, bundle, _ := createEnv(t, ctx, lgr, nil, broadcaster.NoopBroadcaster(), deployerAddr) env, bundle, _ := createEnv(t, lgr, nil, broadcaster.NoopBroadcaster(), deployerAddr)
intent, st := newIntent(t, l1ChainID, dk, l2ChainID1, loc, loc) intent, st := newIntent(t, l1ChainID, dk, l2ChainID1, loc, loc)
intent.Chains = append(intent.Chains, newChainIntent(t, dk, l1ChainID, l2ChainID1)) intent.Chains = append(intent.Chains, newChainIntent(t, dk, l1ChainID, l2ChainID1))
intent.DeploymentStrategy = state.DeploymentStrategyGenesis intent.DeploymentStrategy = state.DeploymentStrategyGenesis
return env, bundle, intent, st return env, bundle, intent, st
} }
func localArtifactsLocator(t *testing.T) *opcm.ArtifactsLocator {
_, testFilename, _, ok := runtime.Caller(0)
require.Truef(t, ok, "failed to get test filename")
monorepoDir := path.Join(path.Dir(testFilename), "..", "..", "..", "..")
artifactsDir := path.Join(monorepoDir, "packages", "contracts-bedrock", "forge-artifacts")
artifactsURL, err := url.Parse(fmt.Sprintf("file://%s", artifactsDir))
require.NoError(t, err)
loc := &opcm.ArtifactsLocator{
URL: artifactsURL,
}
return loc
}
func createEnv( func createEnv(
t *testing.T, t *testing.T,
ctx context.Context,
lgr log.Logger, lgr log.Logger,
l1Client *ethclient.Client, l1Client *ethclient.Client,
bcaster broadcaster.Broadcaster, bcaster broadcaster.Broadcaster,
deployerAddr common.Address, deployerAddr common.Address,
) (*pipeline.Env, pipeline.ArtifactsBundle, *script.Host) { ) (*pipeline.Env, pipeline.ArtifactsBundle, *script.Host) {
_, testFilename, _, ok := runtime.Caller(0) _, artifactsFS := testutil.LocalArtifacts(t)
require.Truef(t, ok, "failed to get test filename")
monorepoDir := path.Join(path.Dir(testFilename), "..", "..", "..", "..")
artifactsDir := path.Join(monorepoDir, "packages", "contracts-bedrock", "forge-artifacts")
artifactsURL, err := url.Parse(fmt.Sprintf("file://%s", artifactsDir))
require.NoError(t, err)
artifactsLocator := &opcm.ArtifactsLocator{
URL: artifactsURL,
}
artifactsFS, cleanupArtifacts, err := pipeline.DownloadArtifacts(ctx, artifactsLocator, pipeline.NoopDownloadProgressor)
require.NoError(t, err)
defer func() {
require.NoError(t, cleanupArtifacts())
}()
host, err := pipeline.DefaultScriptHost( host, err := env.DefaultScriptHost(
bcaster, bcaster,
lgr, lgr,
deployerAddr, deployerAddr,
...@@ -586,8 +556,8 @@ func newIntent( ...@@ -586,8 +556,8 @@ func newIntent(
l1ChainID *big.Int, l1ChainID *big.Int,
dk *devkeys.MnemonicDevKeys, dk *devkeys.MnemonicDevKeys,
l2ChainID *uint256.Int, l2ChainID *uint256.Int,
l1Loc *opcm.ArtifactsLocator, l1Loc *artifacts.Locator,
l2Loc *opcm.ArtifactsLocator, l2Loc *artifacts.Locator,
) (*state.Intent, *state.State) { ) (*state.Intent, *state.State) {
intent := &state.Intent{ intent := &state.Intent{
DeploymentStrategy: state.DeploymentStrategyLive, DeploymentStrategy: state.DeploymentStrategyLive,
......
package opcm
import (
"fmt"
"math/big"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum-optimism/optimism/op-chain-ops/script"
)
type DeployDelayedWETHInput struct {
Release string
StandardVersionsToml string
ProxyAdmin common.Address
SuperchainConfigProxy common.Address
DelayedWethOwner common.Address
DelayedWethDelay *big.Int
}
func (input *DeployDelayedWETHInput) InputSet() bool {
return true
}
type DeployDelayedWETHOutput struct {
DelayedWethImpl common.Address
DelayedWethProxy common.Address
}
func (output *DeployDelayedWETHOutput) CheckOutput(input common.Address) error {
return nil
}
type DeployDelayedWETHScript struct {
Run func(input, output common.Address) error
}
func DeployDelayedWETH(
host *script.Host,
input DeployDelayedWETHInput,
) (DeployDelayedWETHOutput, error) {
var output DeployDelayedWETHOutput
inputAddr := host.NewScriptAddress()
outputAddr := host.NewScriptAddress()
cleanupInput, err := script.WithPrecompileAtAddress[*DeployDelayedWETHInput](host, inputAddr, &input)
if err != nil {
return output, fmt.Errorf("failed to insert DeployDelayedWETHInput precompile: %w", err)
}
defer cleanupInput()
cleanupOutput, err := script.WithPrecompileAtAddress[*DeployDelayedWETHOutput](host, outputAddr, &output,
script.WithFieldSetter[*DeployDelayedWETHOutput])
if err != nil {
return output, fmt.Errorf("failed to insert DeployDelayedWETHOutput precompile: %w", err)
}
defer cleanupOutput()
implContract := "DeployDelayedWETH"
deployScript, cleanupDeploy, err := script.WithScript[DeployDelayedWETHScript](host, "DeployDelayedWETH.s.sol", implContract)
if err != nil {
return output, fmt.Errorf("failed to load %s script: %w", implContract, err)
}
defer cleanupDeploy()
if err := deployScript.Run(inputAddr, outputAddr); err != nil {
return output, fmt.Errorf("failed to run %s script: %w", implContract, err)
}
return output, nil
}
package opcm
import (
"math/big"
"testing"
"github.com/ethereum-optimism/optimism/op-deployer/pkg/deployer/broadcaster"
"github.com/ethereum-optimism/optimism/op-deployer/pkg/deployer/standard"
"github.com/ethereum-optimism/optimism/op-deployer/pkg/deployer/testutil"
"github.com/ethereum-optimism/optimism/op-deployer/pkg/env"
"github.com/ethereum-optimism/optimism/op-service/testlog"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/log"
"github.com/stretchr/testify/require"
)
func TestDeployDelayedWETH(t *testing.T) {
_, artifacts := testutil.LocalArtifacts(t)
host, err := env.DefaultScriptHost(
broadcaster.NoopBroadcaster(),
testlog.Logger(t, log.LevelInfo),
common.Address{'D'},
artifacts,
0,
)
require.NoError(t, err)
standardVersionsTOML, err := standard.L1VersionsDataFor(11155111)
require.NoError(t, err)
input := DeployDelayedWETHInput{
Release: "dev",
StandardVersionsToml: standardVersionsTOML,
ProxyAdmin: common.Address{'P'},
SuperchainConfigProxy: common.Address{'S'},
DelayedWethOwner: common.Address{'O'},
DelayedWethDelay: big.NewInt(100),
}
output, err := DeployDelayedWETH(host, input)
require.NoError(t, err)
require.NotEmpty(t, output.DelayedWethImpl)
require.NotEmpty(t, output.DelayedWethProxy)
}
...@@ -3,6 +3,8 @@ package pipeline ...@@ -3,6 +3,8 @@ package pipeline
import ( import (
"fmt" "fmt"
env2 "github.com/ethereum-optimism/optimism/op-deployer/pkg/env"
"github.com/ethereum-optimism/optimism/op-chain-ops/foundry" "github.com/ethereum-optimism/optimism/op-chain-ops/foundry"
"github.com/ethereum-optimism/optimism/op-deployer/pkg/deployer/broadcaster" "github.com/ethereum-optimism/optimism/op-deployer/pkg/deployer/broadcaster"
"github.com/ethereum-optimism/optimism/op-deployer/pkg/deployer/opcm" "github.com/ethereum-optimism/optimism/op-deployer/pkg/deployer/opcm"
...@@ -36,7 +38,7 @@ func GenerateL2Genesis(env *Env, intent *state.Intent, bundle ArtifactsBundle, s ...@@ -36,7 +38,7 @@ func GenerateL2Genesis(env *Env, intent *state.Intent, bundle ArtifactsBundle, s
return fmt.Errorf("failed to combine L2 init config: %w", err) return fmt.Errorf("failed to combine L2 init config: %w", err)
} }
host, err := DefaultScriptHost( host, err := env2.DefaultScriptHost(
broadcaster.NoopBroadcaster(), broadcaster.NoopBroadcaster(),
env.Logger, env.Logger,
env.Deployer, env.Deployer,
......
...@@ -6,6 +6,8 @@ import ( ...@@ -6,6 +6,8 @@ import (
"errors" "errors"
"fmt" "fmt"
"github.com/ethereum-optimism/optimism/op-deployer/pkg/deployer/artifacts"
"github.com/ethereum-optimism/optimism/op-deployer/pkg/deployer/standard" "github.com/ethereum-optimism/optimism/op-deployer/pkg/deployer/standard"
"github.com/ethereum-optimism/optimism/op-service/jsonutil" "github.com/ethereum-optimism/optimism/op-service/jsonutil"
...@@ -144,7 +146,7 @@ func conditionallySetImplementationAddresses(ctx context.Context, client *ethcli ...@@ -144,7 +146,7 @@ func conditionallySetImplementationAddresses(ctx context.Context, client *ethcli
return nil return nil
} }
func setMipsSingletonAddress(ctx context.Context, client *ethclient.Client, l1ArtifactsLocator *opcm.ArtifactsLocator, errCh chan error, opcmProxyAddress common.Address, singletonAddress *common.Address) { func setMipsSingletonAddress(ctx context.Context, client *ethclient.Client, l1ArtifactsLocator *artifacts.Locator, errCh chan error, opcmProxyAddress common.Address, singletonAddress *common.Address) {
if !l1ArtifactsLocator.IsTag() { if !l1ArtifactsLocator.IsTag() {
errCh <- errors.New("L1 contracts locator is not a tag, cannot set MIPS singleton address") errCh <- errors.New("L1 contracts locator is not a tag, cannot set MIPS singleton address")
return return
......
...@@ -156,6 +156,19 @@ func ManagerOwnerAddrFor(chainID uint64) (common.Address, error) { ...@@ -156,6 +156,19 @@ func ManagerOwnerAddrFor(chainID uint64) (common.Address, error) {
} }
} }
func SystemOwnerAddrFor(chainID uint64) (common.Address, error) {
switch chainID {
case 1:
// Set to owner of superchain proxy admin
return common.HexToAddress("0x5a0Aae59D09fccBdDb6C6CcEB07B7279367C3d2A"), nil
case 11155111:
// Set to development multisig
return common.HexToAddress("0xDEe57160aAfCF04c34C887B5962D0a69676d3C8B"), nil
default:
return common.Address{}, fmt.Errorf("unsupported chain ID: %d", chainID)
}
}
func ArtifactsURLForTag(tag string) (*url.URL, error) { func ArtifactsURLForTag(tag string) (*url.URL, error) {
switch tag { switch tag {
case "op-contracts/v1.6.0": case "op-contracts/v1.6.0":
......
...@@ -4,9 +4,9 @@ import ( ...@@ -4,9 +4,9 @@ import (
"fmt" "fmt"
"math/big" "math/big"
"github.com/ethereum-optimism/optimism/op-deployer/pkg/deployer/standard" "github.com/ethereum-optimism/optimism/op-deployer/pkg/deployer/artifacts"
"github.com/ethereum-optimism/optimism/op-deployer/pkg/deployer/opcm" "github.com/ethereum-optimism/optimism/op-deployer/pkg/deployer/standard"
"github.com/ethereum-optimism/optimism/op-service/ioutil" "github.com/ethereum-optimism/optimism/op-service/ioutil"
"github.com/ethereum-optimism/optimism/op-service/jsonutil" "github.com/ethereum-optimism/optimism/op-service/jsonutil"
...@@ -42,9 +42,9 @@ type Intent struct { ...@@ -42,9 +42,9 @@ type Intent struct {
UseInterop bool `json:"useInterop" toml:"useInterop"` UseInterop bool `json:"useInterop" toml:"useInterop"`
L1ContractsLocator *opcm.ArtifactsLocator `json:"l1ContractsLocator" toml:"l1ContractsLocator"` L1ContractsLocator *artifacts.Locator `json:"l1ContractsLocator" toml:"l1ContractsLocator"`
L2ContractsLocator *opcm.ArtifactsLocator `json:"l2ContractsLocator" toml:"l2ContractsLocator"` L2ContractsLocator *artifacts.Locator `json:"l2ContractsLocator" toml:"l2ContractsLocator"`
Chains []*ChainIntent `json:"chains" toml:"chains"` Chains []*ChainIntent `json:"chains" toml:"chains"`
...@@ -65,11 +65,11 @@ func (c *Intent) Check() error { ...@@ -65,11 +65,11 @@ func (c *Intent) Check() error {
} }
if c.L1ContractsLocator == nil { if c.L1ContractsLocator == nil {
c.L1ContractsLocator = opcm.DefaultL1ContractsLocator c.L1ContractsLocator = artifacts.DefaultL1ContractsLocator
} }
if c.L2ContractsLocator == nil { if c.L2ContractsLocator == nil {
c.L2ContractsLocator = opcm.DefaultL2ContractsLocator c.L2ContractsLocator = artifacts.DefaultL2ContractsLocator
} }
var err error var err error
......
package testutil
import (
"context"
"fmt"
"net/url"
"path"
"runtime"
"testing"
artifacts2 "github.com/ethereum-optimism/optimism/op-deployer/pkg/deployer/artifacts"
"github.com/ethereum-optimism/optimism/op-chain-ops/foundry"
op_service "github.com/ethereum-optimism/optimism/op-service"
"github.com/stretchr/testify/require"
)
func LocalArtifacts(t *testing.T) (*artifacts2.Locator, foundry.StatDirFs) {
_, testFilename, _, ok := runtime.Caller(0)
require.Truef(t, ok, "failed to get test filename")
monorepoDir, err := op_service.FindMonorepoRoot(testFilename)
require.NoError(t, err)
artifactsDir := path.Join(monorepoDir, "packages", "contracts-bedrock", "forge-artifacts")
artifactsURL, err := url.Parse(fmt.Sprintf("file://%s", artifactsDir))
require.NoError(t, err)
loc := &artifacts2.Locator{
URL: artifactsURL,
}
artifactsFS, cleanupArtifacts, err := artifacts2.Download(context.Background(), loc, artifacts2.NoopDownloadProgressor)
require.NoError(t, err)
t.Cleanup(func() {
_ = cleanupArtifacts()
})
return loc, artifactsFS
}
package pipeline package env
import ( import (
"fmt" "fmt"
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment