Commit ca9ae003 authored by mergify[bot]'s avatar mergify[bot] Committed by GitHub

Merge branch 'develop' into willc/atst-seperate-react

parents 3f4a4354 c10214b0
---
'@eth-optimism/atst': minor
---
Remove broken allowFailures as option
---
'@eth-optimism/atst': patch
---
Fixed bug with atst not defaulting to currently connected chain
...@@ -87,7 +87,7 @@ func (s *channelManager) Clear() { ...@@ -87,7 +87,7 @@ func (s *channelManager) Clear() {
func (s *channelManager) TxFailed(id txID) { func (s *channelManager) TxFailed(id txID) {
if data, ok := s.pendingTransactions[id]; ok { if data, ok := s.pendingTransactions[id]; ok {
s.log.Trace("marked transaction as failed", "id", id) s.log.Trace("marked transaction as failed", "id", id)
s.pendingChannel.PushFrame(id, data) s.pendingChannel.PushFrame(id, data[1:]) // strip the version byte
delete(s.pendingTransactions, id) delete(s.pendingTransactions, id)
} else { } else {
s.log.Warn("unknown transaction marked as failed", "id", id) s.log.Warn("unknown transaction marked as failed", "id", id)
......
...@@ -77,7 +77,7 @@ func TestBatchInLastPossibleBlocks(gt *testing.T) { ...@@ -77,7 +77,7 @@ func TestBatchInLastPossibleBlocks(gt *testing.T) {
} }
// 8 L1 blocks with 17 L2 blocks is the unsafe state. // 8 L1 blocks with 17 L2 blocks is the unsafe state.
// Because wew consistently batch submitted we are one epoch behind the unsafe head with the safe head // Because we consistently batch submitted we are one epoch behind the unsafe head with the safe head
verifyChainStateOnSequencer(8, 17, 8, 15, 7) verifyChainStateOnSequencer(8, 17, 8, 15, 7)
// Create the batch for L2 blocks 16 & 17 // Create the batch for L2 blocks 16 & 17
......
...@@ -464,7 +464,7 @@ func (cfg SystemConfig) Start() (*System, error) { ...@@ -464,7 +464,7 @@ func (cfg SystemConfig) Start() (*System, error) {
c.P2P = p c.P2P = p
if c.Driver.SequencerEnabled { if c.Driver.SequencerEnabled {
c.P2PSigner = &p2p.PreparedSigner{Signer: p2p.NewLegacyLocalSigner(cfg.Secrets.SequencerP2P)} c.P2PSigner = &p2p.PreparedSigner{Signer: p2p.NewLocalSigner(cfg.Secrets.SequencerP2P)}
} }
} }
......
...@@ -19,6 +19,7 @@ import ( ...@@ -19,6 +19,7 @@ import (
"time" "time"
"github.com/ethereum-optimism/optimism/op-node/eth" "github.com/ethereum-optimism/optimism/op-node/eth"
ophttp "github.com/ethereum-optimism/optimism/op-node/http"
"github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/log"
) )
...@@ -161,7 +162,8 @@ func runServer() { ...@@ -161,7 +162,8 @@ func runServer() {
mux.HandleFunc("/logs", makeGzipHandler(logsHandler)) mux.HandleFunc("/logs", makeGzipHandler(logsHandler))
log.Info("running webserver...") log.Info("running webserver...")
if err := http.Serve(l, mux); err != nil && !errors.Is(err, http.ErrServerClosed) { httpServer := ophttp.NewHttpServer(mux)
if err := httpServer.Serve(l); err != nil && !errors.Is(err, http.ErrServerClosed) {
log.Crit("http server failed", "message", err) log.Crit("http server failed", "message", err)
} }
} }
......
package http
import (
"net/http"
"github.com/ethereum/go-ethereum/rpc"
)
// Use default timeouts from Geth as battle tested default values
var timeouts = rpc.DefaultHTTPTimeouts
func NewHttpServer(handler http.Handler) *http.Server {
return &http.Server{
Handler: handler,
ReadTimeout: timeouts.ReadTimeout,
ReadHeaderTimeout: timeouts.ReadHeaderTimeout,
WriteTimeout: timeouts.WriteTimeout,
IdleTimeout: timeouts.IdleTimeout,
}
}
...@@ -7,10 +7,10 @@ import ( ...@@ -7,10 +7,10 @@ import (
"errors" "errors"
"fmt" "fmt"
"net" "net"
"net/http"
"strconv" "strconv"
"time" "time"
ophttp "github.com/ethereum-optimism/optimism/op-node/http"
"github.com/ethereum-optimism/optimism/op-service/metrics" "github.com/ethereum-optimism/optimism/op-service/metrics"
pb "github.com/libp2p/go-libp2p-pubsub/pb" pb "github.com/libp2p/go-libp2p-pubsub/pb"
...@@ -528,12 +528,10 @@ func (m *Metrics) RecordSequencerSealingTime(duration time.Duration) { ...@@ -528,12 +528,10 @@ func (m *Metrics) RecordSequencerSealingTime(duration time.Duration) {
// The server will be closed when the passed-in context is cancelled. // The server will be closed when the passed-in context is cancelled.
func (m *Metrics) Serve(ctx context.Context, hostname string, port int) error { func (m *Metrics) Serve(ctx context.Context, hostname string, port int) error {
addr := net.JoinHostPort(hostname, strconv.Itoa(port)) addr := net.JoinHostPort(hostname, strconv.Itoa(port))
server := &http.Server{ server := ophttp.NewHttpServer(promhttp.InstrumentMetricHandler(
Addr: addr,
Handler: promhttp.InstrumentMetricHandler(
m.registry, promhttp.HandlerFor(m.registry, promhttp.HandlerOpts{}), m.registry, promhttp.HandlerFor(m.registry, promhttp.HandlerOpts{}),
), ))
} server.Addr = addr
go func() { go func() {
<-ctx.Done() <-ctx.Done()
server.Close() server.Close()
......
...@@ -7,6 +7,7 @@ import ( ...@@ -7,6 +7,7 @@ import (
"net/http" "net/http"
"strconv" "strconv"
ophttp "github.com/ethereum-optimism/optimism/op-node/http"
"github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/node" "github.com/ethereum/go-ethereum/node"
"github.com/ethereum/go-ethereum/rpc" "github.com/ethereum/go-ethereum/rpc"
...@@ -87,7 +88,7 @@ func (s *rpcServer) Start() error { ...@@ -87,7 +88,7 @@ func (s *rpcServer) Start() error {
} }
s.listenAddr = listener.Addr() s.listenAddr = listener.Addr()
s.httpServer = &http.Server{Handler: mux} s.httpServer = ophttp.NewHttpServer(mux)
go func() { go func() {
if err := s.httpServer.Serve(listener); err != nil && !errors.Is(err, http.ErrServerClosed) { // todo improve error handling if err := s.httpServer.Serve(listener); err != nil && !errors.Is(err, http.ErrServerClosed) { // todo improve error handling
s.log.Error("http server failed", "err", err) s.log.Error("http server failed", "err", err)
......
...@@ -24,7 +24,7 @@ func LoadSignerSetup(ctx *cli.Context) (p2p.SignerSetup, error) { ...@@ -24,7 +24,7 @@ func LoadSignerSetup(ctx *cli.Context) (p2p.SignerSetup, error) {
return nil, fmt.Errorf("failed to read batch submitter key: %w", err) return nil, fmt.Errorf("failed to read batch submitter key: %w", err)
} }
return &p2p.PreparedSigner{Signer: p2p.NewLegacyLocalSigner(priv)}, nil return &p2p.PreparedSigner{Signer: p2p.NewLocalSigner(priv)}, nil
} }
// TODO: create remote signer // TODO: create remote signer
......
...@@ -49,7 +49,7 @@ func TestVerifyBlockSignature(t *testing.T) { ...@@ -49,7 +49,7 @@ func TestVerifyBlockSignature(t *testing.T) {
}{ }{
{ {
name: "Legacy", name: "Legacy",
newSigner: NewLegacyLocalSigner, newSigner: newLegacyLocalSigner,
}, },
{ {
name: "Updated", name: "Updated",
...@@ -102,3 +102,7 @@ func TestVerifyBlockSignature(t *testing.T) { ...@@ -102,3 +102,7 @@ func TestVerifyBlockSignature(t *testing.T) {
}) })
} }
} }
func newLegacyLocalSigner(priv *ecdsa.PrivateKey) *LocalSigner {
return &LocalSigner{priv: priv, hasher: LegacySigningHash}
}
...@@ -315,7 +315,7 @@ func TestDiscovery(t *testing.T) { ...@@ -315,7 +315,7 @@ func TestDiscovery(t *testing.T) {
// B and C don't know each other yet, but both have A as a bootnode. // B and C don't know each other yet, but both have A as a bootnode.
// It should only be a matter of time for them to connect, if they discover each other via A. // It should only be a matter of time for them to connect, if they discover each other via A.
timeout := time.After(time.Second * 10) timeout := time.After(time.Second * 60)
var peersOfB []peer.ID var peersOfB []peer.ID
// B should be connected to the bootnode (A) it used (it's a valid optimism node to connect to here) // B should be connected to the bootnode (A) it used (it's a valid optimism node to connect to here)
// C should also be connected, although this one might take more time to discover // C should also be connected, although this one might take more time to discover
......
...@@ -64,10 +64,6 @@ type LocalSigner struct { ...@@ -64,10 +64,6 @@ type LocalSigner struct {
hasher func(domain [32]byte, chainID *big.Int, payloadBytes []byte) (common.Hash, error) hasher func(domain [32]byte, chainID *big.Int, payloadBytes []byte) (common.Hash, error)
} }
func NewLegacyLocalSigner(priv *ecdsa.PrivateKey) *LocalSigner {
return &LocalSigner{priv: priv, hasher: LegacySigningHash}
}
func NewLocalSigner(priv *ecdsa.PrivateKey) *LocalSigner { func NewLocalSigner(priv *ecdsa.PrivateKey) *LocalSigner {
return &LocalSigner{priv: priv, hasher: SigningHash} return &LocalSigner{priv: priv, hasher: SigningHash}
} }
......
package crypto package crypto
import ( import (
"bytes"
"context" "context"
"crypto/ecdsa" "crypto/ecdsa"
"errors" "errors"
...@@ -56,10 +57,10 @@ func SignerFactoryFromConfig(l log.Logger, privateKey, mnemonic, hdPath string, ...@@ -56,10 +57,10 @@ func SignerFactoryFromConfig(l log.Logger, privateKey, mnemonic, hdPath string,
fromAddress = common.HexToAddress(signerConfig.Address) fromAddress = common.HexToAddress(signerConfig.Address)
signer = func(chainID *big.Int) SignerFn { signer = func(chainID *big.Int) SignerFn {
return func(ctx context.Context, address common.Address, tx *types.Transaction) (*types.Transaction, error) { return func(ctx context.Context, address common.Address, tx *types.Transaction) (*types.Transaction, error) {
if address.String() != signerConfig.Address { if !bytes.Equal(address[:], fromAddress[:]) {
return nil, fmt.Errorf("attempting to sign for %s, expected %s: ", address, signerConfig.Address) return nil, fmt.Errorf("attempting to sign for %s, expected %s: ", address, signerConfig.Address)
} }
return signerClient.SignTransaction(ctx, chainID, tx) return signerClient.SignTransaction(ctx, chainID, address, tx)
} }
} }
} else { } else {
......
...@@ -122,6 +122,11 @@ func (m *SimpleTxManager) IncreaseGasPrice(ctx context.Context, tx *types.Transa ...@@ -122,6 +122,11 @@ func (m *SimpleTxManager) IncreaseGasPrice(ctx context.Context, tx *types.Transa
gasTipCap = tip gasTipCap = tip
} }
// Return the same transaction if we don't update any fields.
// We do this because ethereum signatures are not deterministic and therefore the transaction hash will change
// when we re-sign the tx. We don't want to do that because we want to see ErrAlreadyKnown instead of ErrReplacementUnderpriced
var reusedTip, reusedFeeCap bool
// new = old * (100 + priceBump) / 100 // new = old * (100 + priceBump) / 100
// Enforce a min priceBump on the tip. Do this before the feeCap is calculated // Enforce a min priceBump on the tip. Do this before the feeCap is calculated
thresholdTip := new(big.Int).Mul(priceBumpPercent, tx.GasTipCap()) thresholdTip := new(big.Int).Mul(priceBumpPercent, tx.GasTipCap())
...@@ -129,6 +134,7 @@ func (m *SimpleTxManager) IncreaseGasPrice(ctx context.Context, tx *types.Transa ...@@ -129,6 +134,7 @@ func (m *SimpleTxManager) IncreaseGasPrice(ctx context.Context, tx *types.Transa
if tx.GasTipCapIntCmp(gasTipCap) >= 0 { if tx.GasTipCapIntCmp(gasTipCap) >= 0 {
m.l.Debug("Reusing the previous tip", "previous", tx.GasTipCap(), "suggested", gasTipCap) m.l.Debug("Reusing the previous tip", "previous", tx.GasTipCap(), "suggested", gasTipCap)
gasTipCap = tx.GasTipCap() gasTipCap = tx.GasTipCap()
reusedTip = true
} else if thresholdTip.Cmp(gasTipCap) > 0 { } else if thresholdTip.Cmp(gasTipCap) > 0 {
m.l.Debug("Overriding the tip to enforce a price bump", "previous", tx.GasTipCap(), "suggested", gasTipCap, "new", thresholdTip) m.l.Debug("Overriding the tip to enforce a price bump", "previous", tx.GasTipCap(), "suggested", gasTipCap, "new", thresholdTip)
gasTipCap = thresholdTip gasTipCap = thresholdTip
...@@ -150,11 +156,16 @@ func (m *SimpleTxManager) IncreaseGasPrice(ctx context.Context, tx *types.Transa ...@@ -150,11 +156,16 @@ func (m *SimpleTxManager) IncreaseGasPrice(ctx context.Context, tx *types.Transa
if tx.GasFeeCapIntCmp(gasFeeCap) >= 0 { if tx.GasFeeCapIntCmp(gasFeeCap) >= 0 {
m.l.Debug("Reusing the previous fee cap", "previous", tx.GasFeeCap(), "suggested", gasFeeCap) m.l.Debug("Reusing the previous fee cap", "previous", tx.GasFeeCap(), "suggested", gasFeeCap)
gasFeeCap = tx.GasFeeCap() gasFeeCap = tx.GasFeeCap()
reusedFeeCap = true
} else if thresholdFeeCap.Cmp(gasFeeCap) > 0 { } else if thresholdFeeCap.Cmp(gasFeeCap) > 0 {
m.l.Debug("Overriding the fee cap to enforce a price bump", "previous", tx.GasFeeCap(), "suggested", gasFeeCap, "new", thresholdFeeCap) m.l.Debug("Overriding the fee cap to enforce a price bump", "previous", tx.GasFeeCap(), "suggested", gasFeeCap, "new", thresholdFeeCap)
gasFeeCap = thresholdFeeCap gasFeeCap = thresholdFeeCap
} }
if reusedTip && reusedFeeCap {
return tx, nil
}
rawTx := &types.DynamicFeeTx{ rawTx := &types.DynamicFeeTx{
ChainID: tx.ChainId(), ChainID: tx.ChainId(),
Nonce: tx.Nonce(), Nonce: tx.Nonce(),
......
...@@ -4,6 +4,7 @@ import ( ...@@ -4,6 +4,7 @@ import (
"context" "context"
"errors" "errors"
"math/big" "math/big"
"math/rand"
"sync" "sync"
"testing" "testing"
"time" "time"
...@@ -11,9 +12,12 @@ import ( ...@@ -11,9 +12,12 @@ import (
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
"github.com/ethereum-optimism/optimism/op-node/testlog" "github.com/ethereum-optimism/optimism/op-node/testlog"
"github.com/ethereum-optimism/optimism/op-node/testutils"
opcrypto "github.com/ethereum-optimism/optimism/op-service/crypto"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/log"
) )
...@@ -727,3 +731,42 @@ func TestIncreaseGasPriceUseLargeIncrease(t *testing.T) { ...@@ -727,3 +731,42 @@ func TestIncreaseGasPriceUseLargeIncrease(t *testing.T) {
require.True(t, newTx.GasFeeCap().Cmp(feeCap) == 0, "new tx fee cap must be equal L1") require.True(t, newTx.GasFeeCap().Cmp(feeCap) == 0, "new tx fee cap must be equal L1")
require.True(t, newTx.GasTipCap().Cmp(borkedBackend.gasTip) == 0, "new tx tip must be equal L1") require.True(t, newTx.GasTipCap().Cmp(borkedBackend.gasTip) == 0, "new tx tip must be equal L1")
} }
// TestIncreaseGasPriceReusesTransaction asserts that if the L1 basefee & tip remain the
// same, the transaction is returned with the same signature values. The means that the error
// when submitting the transaction to the network is ErrAlreadyKnown instead of ErrReplacementUnderpriced
func TestIncreaseGasPriceReusesTransaction(t *testing.T) {
t.Parallel()
borkedBackend := failingBackend{
gasTip: big.NewInt(10),
baseFee: big.NewInt(45),
}
pk := testutils.InsecureRandomKey(rand.New(rand.NewSource(123)))
signer := opcrypto.PrivateKeySignerFn(pk, big.NewInt(10))
mgr := &SimpleTxManager{
Config: Config{
ResubmissionTimeout: time.Second,
ReceiptQueryInterval: 50 * time.Millisecond,
NumConfirmations: 1,
SafeAbortNonceTooLowCount: 3,
Signer: func(ctx context.Context, from common.Address, tx *types.Transaction) (*types.Transaction, error) {
return signer(from, tx)
},
From: crypto.PubkeyToAddress(pk.PublicKey),
},
name: "TEST",
backend: &borkedBackend,
l: testlog.Logger(t, log.LvlCrit),
}
tx := types.NewTx(&types.DynamicFeeTx{
GasTipCap: big.NewInt(10),
GasFeeCap: big.NewInt(100),
})
ctx := context.Background()
newTx, err := mgr.IncreaseGasPrice(ctx, tx)
require.NoError(t, err)
require.Equal(t, tx.Hash(), newTx.Hash())
}
...@@ -12,6 +12,7 @@ import ( ...@@ -12,6 +12,7 @@ import (
optls "github.com/ethereum-optimism/optimism/op-service/tls" optls "github.com/ethereum-optimism/optimism/op-service/tls"
"github.com/ethereum-optimism/optimism/op-service/tls/certman" "github.com/ethereum-optimism/optimism/op-service/tls/certman"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/log"
...@@ -91,8 +92,8 @@ func (s *SignerClient) pingVersion() (string, error) { ...@@ -91,8 +92,8 @@ func (s *SignerClient) pingVersion() (string, error) {
return v, nil return v, nil
} }
func (s *SignerClient) SignTransaction(ctx context.Context, chainId *big.Int, tx *types.Transaction) (*types.Transaction, error) { func (s *SignerClient) SignTransaction(ctx context.Context, chainId *big.Int, from common.Address, tx *types.Transaction) (*types.Transaction, error) {
args := NewTransactionArgsFromTransaction(chainId, tx) args := NewTransactionArgsFromTransaction(chainId, from, tx)
var result hexutil.Bytes var result hexutil.Bytes
if err := s.client.CallContext(ctx, &result, "eth_signTransaction", args); err != nil { if err := s.client.CallContext(ctx, &result, "eth_signTransaction", args); err != nil {
......
...@@ -31,12 +31,13 @@ type TransactionArgs struct { ...@@ -31,12 +31,13 @@ type TransactionArgs struct {
} }
// NewTransactionArgsFromTransaction creates a TransactionArgs struct from an EIP-1559 transaction // NewTransactionArgsFromTransaction creates a TransactionArgs struct from an EIP-1559 transaction
func NewTransactionArgsFromTransaction(chainId *big.Int, tx *types.Transaction) *TransactionArgs { func NewTransactionArgsFromTransaction(chainId *big.Int, from common.Address, tx *types.Transaction) *TransactionArgs {
data := hexutil.Bytes(tx.Data()) data := hexutil.Bytes(tx.Data())
nonce := hexutil.Uint64(tx.Nonce()) nonce := hexutil.Uint64(tx.Nonce())
gas := hexutil.Uint64(tx.Gas()) gas := hexutil.Uint64(tx.Gas())
accesses := tx.AccessList() accesses := tx.AccessList()
args := &TransactionArgs{ args := &TransactionArgs{
From: &from,
Input: &data, Input: &data,
Nonce: &nonce, Nonce: &nonce,
Value: (*hexutil.Big)(tx.Value()), Value: (*hexutil.Big)(tx.Value()),
......
...@@ -38,7 +38,7 @@ The typescript sdk provides a clean [wagmi](https://wagmi.sh/) based interface f ...@@ -38,7 +38,7 @@ The typescript sdk provides a clean [wagmi](https://wagmi.sh/) based interface f
The cli provides a convenient cli for interacting with the attestation station contract The cli provides a convenient cli for interacting with the attestation station contract
TODO put a gif here of using it ![preview](./assets/preview.gif)
## React API ## React API
......
# Assets
## preview.gif
A gif preview of using the cli
## preview.tape
The script to record the preview.gif with [vhs](https://github.com/charmbracelet/vhs)
To execute:
1. [Download vhs](https://github.com/charmbracelet/vhs)
2. Install the local version of atst
```bash
npm uninstall @eth-optimism/atst -g && npm i . -g && atst --version
```
3. Start anvil
```bash
anvil --fork-url https://mainnet.optimism.io
```
4. Record tape vhs < assets/preview.tape
```bash
vhs < assets/preview.tape
```
5. The tape will be outputted to `assets/preview.gif`
# VHS File source
# https://github.com/charmbracelet/vhs
#
# Output:
# Output <path>.gif Create a GIF output at the given <path>
# Output <path>.mp4 Create an MP4 output at the given <path>
# Output <path>.webm Create a WebM output at the given <path>
#
# Settings:
# Set FontSize <number> Set the font size of the terminal
# Set FontFamily <string> Set the font family of the terminal
# Set Height <number> Set the height of the terminal
# Set Width <number> Set the width of the terminal
# Set LetterSpacing <float> Set the font letter spacing (tracking)
# Set LineHeight <float> Set the font line height
# Set Theme <string> Set the theme of the terminal (JSON)
# Set Padding <number> Set the padding of the terminal
# Set Framerate <number> Set the framerate of the recording
# Set PlaybackSpeed <float> Set the playback speed of the recording
#
# Sleep:
# Sleep <time> Sleep for a set amount of <time> in seconds
#
# Type:
# Type[@<time>] "<characters>" Type <characters> into the terminal with a
# <time> delay between each character
#
# Keys:
# Backspace[@<time>] [number] Press the Backspace key
# Down[@<time>] [number] Press the Down key
# Enter[@<time>] [number] Press the Enter key
# Space[@<time>] [number] Press the Space key
# Tab[@<time>] [number] Press the Tab key
# Left[@<time>] [number] Press the Left Arrow key
# Right[@<time>] [number] Press the Right Arrow key
# Up[@<time>] [number] Press the Up Arrow key
# Down[@<time>] [number] Press the Down Arrow key
# Ctrl+<key> Press the Control key + <key> (e.g. Ctrl+C)
#
# Display:
# Hide Hide the subsequent commands from the output
# Show Show the subsequent commands in the output
Output assets/preview.gif
Set FontSize 16
Set Width 1920
Set Height 1080
Type "atst write --key attitude --about 0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045 --value 'feeling very optimistic' --private-key 0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80 --rpc-url http://localhost:8545"
Enter
Sleep 2000ms
Type "atst read --key attitude --about 0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045 --creator 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266 --rpc-url http://localhost:8545"
Enter
Sleep 2000ms
Type "atst write --key impress-level --about 0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045 --value 10 --private-key 0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80 --rpc-url http://localhost:8545"
Enter
Sleep 2000ms
Type "atst read --key impress-level --about 0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045 --creator 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266 --rpc-url http://localhost:8545"
Enter
Sleep 2000ms
Type "atst --help"
Enter
Sleep 2000ms
# atst cli docs # atst cli docs
![preview](../assets/preview.gif)
## Installation ## Installation
```bash ```bash
......
...@@ -171,11 +171,6 @@ const attestation = await readAttestations({ ...@@ -171,11 +171,6 @@ const attestation = await readAttestations({
* @defaults defaults to the create2 address * @defaults defaults to the create2 address
*/ */
contractAddress, contractAddress,
/**
* Boolean: Whether to allow some of the calls to fail
* Defaults to false
*/
allowFailures,
}) })
``` ```
......
...@@ -15,13 +15,13 @@ cli ...@@ -15,13 +15,13 @@ cli
.option('--creator <string>', readOptionsValidators.creator.description!) .option('--creator <string>', readOptionsValidators.creator.description!)
.option('--about <string>', readOptionsValidators.about.description!) .option('--about <string>', readOptionsValidators.about.description!)
.option('--key <string>', readOptionsValidators.key.description!) .option('--key <string>', readOptionsValidators.key.description!)
.option('--data-type [string]', readOptionsValidators.dataType.description!, { .option('--data-type <string>', readOptionsValidators.dataType.description!, {
default: readOptionsValidators.dataType.parse(undefined), default: readOptionsValidators.dataType.parse(undefined),
}) })
.option('--rpc-url [url]', readOptionsValidators.rpcUrl.description!, { .option('--rpc-url <url>', readOptionsValidators.rpcUrl.description!, {
default: readOptionsValidators.rpcUrl.parse(undefined), default: readOptionsValidators.rpcUrl.parse(undefined),
}) })
.option('--contract [address]', readOptionsValidators.contract.description!, { .option('--contract <address>', readOptionsValidators.contract.description!, {
default: readOptionsValidators.contract.parse(undefined), default: readOptionsValidators.contract.parse(undefined),
}) })
.example( .example(
...@@ -52,17 +52,17 @@ cli ...@@ -52,17 +52,17 @@ cli
'--private-key <string>', '--private-key <string>',
writeOptionsValidators.privateKey.description! writeOptionsValidators.privateKey.description!
) )
.option('--data-type [string]', readOptionsValidators.dataType.description!, { .option('--data-type <string>', readOptionsValidators.dataType.description!, {
default: writeOptionsValidators.dataType.parse(undefined), default: writeOptionsValidators.dataType.parse(undefined),
}) })
.option('--about <string>', writeOptionsValidators.about.description!) .option('--about <string>', writeOptionsValidators.about.description!)
.option('--key <string>', writeOptionsValidators.key.description!) .option('--key <string>', writeOptionsValidators.key.description!)
.option('--value <string>', writeOptionsValidators.value.description!) .option('--value <string>', writeOptionsValidators.value.description!)
.option('--rpc-url [url]', writeOptionsValidators.rpcUrl.description!, { .option('--rpc-url <url>', writeOptionsValidators.rpcUrl.description!, {
default: writeOptionsValidators.rpcUrl.parse(undefined), default: writeOptionsValidators.rpcUrl.parse(undefined),
}) })
.option( .option(
'--contract [address]', '--contract <address>',
writeOptionsValidators.contract.description!, writeOptionsValidators.contract.description!,
{ {
default: writeOptionsValidators.contract.parse(undefined), default: writeOptionsValidators.contract.parse(undefined),
......
...@@ -10,7 +10,7 @@ export const prepareWriteAttestation = async ( ...@@ -10,7 +10,7 @@ export const prepareWriteAttestation = async (
about: Address, about: Address,
key: string, key: string,
value: string | WagmiBytes | number | boolean, value: string | WagmiBytes | number | boolean,
chainId = 10, chainId: number | undefined = undefined,
contractAddress: Address = ATTESTATION_STATION_ADDRESS contractAddress: Address = ATTESTATION_STATION_ADDRESS
) => { ) => {
let formattedKey: WagmiBytes let formattedKey: WagmiBytes
......
...@@ -14,7 +14,7 @@ type Attestation = { ...@@ -14,7 +14,7 @@ type Attestation = {
export const prepareWriteAttestations = async ( export const prepareWriteAttestations = async (
attestations: Attestation[], attestations: Attestation[],
chainId = 10, chainId: number | undefined = undefined,
contractAddress: Address = ATTESTATION_STATION_ADDRESS contractAddress: Address = ATTESTATION_STATION_ADDRESS
) => { ) => {
const formattedAttestations = attestations.map((attestation) => { const formattedAttestations = attestations.map((attestation) => {
...@@ -27,9 +27,7 @@ export const prepareWriteAttestations = async ( ...@@ -27,9 +27,7 @@ export const prepareWriteAttestations = async (
`key is longer than 32 bytes: ${attestation.key}. Try using a shorter key or using 'encodeRawKey' to encode the key into 32 bytes first` `key is longer than 32 bytes: ${attestation.key}. Try using a shorter key or using 'encodeRawKey' to encode the key into 32 bytes first`
) )
} }
const formattedValue = createValue( const formattedValue = createValue(attestation.value) as WagmiBytes
attestation.value
) as WagmiBytes
return { return {
about: attestation.about, about: attestation.about,
key: formattedKey, key: formattedKey,
......
...@@ -19,7 +19,6 @@ import { parseAttestationBytes } from './parseAttestationBytes' ...@@ -19,7 +19,6 @@ import { parseAttestationBytes } from './parseAttestationBytes'
* creator: creatorAddress, * creator: creatorAddress,
* about: aboutAddress, * about: aboutAddress,
* key: 'my_key', * key: 'my_key',
* allowFailure: false,
* }, * },
* { * {
* creator: creatorAddress2, * creator: creatorAddress2,
...@@ -27,7 +26,6 @@ import { parseAttestationBytes } from './parseAttestationBytes' ...@@ -27,7 +26,6 @@ import { parseAttestationBytes } from './parseAttestationBytes'
* key: 'my_key', * key: 'my_key',
* dataType: 'number', * dataType: 'number',
* contractAddress: '0x1234', * contractAddress: '0x1234',
* allowFailure: false,
* }, * },
* ) * )
*/ */
...@@ -40,7 +38,6 @@ export const readAttestations = async ( ...@@ -40,7 +38,6 @@ export const readAttestations = async (
about, about,
key, key,
contractAddress = ATTESTATION_STATION_ADDRESS, contractAddress = ATTESTATION_STATION_ADDRESS,
allowFailure = false,
} = attestation } = attestation
if (key.length > 32) { if (key.length > 32) {
throw new Error( throw new Error(
...@@ -52,7 +49,6 @@ export const readAttestations = async ( ...@@ -52,7 +49,6 @@ export const readAttestations = async (
abi, abi,
functionName: 'attestations', functionName: 'attestations',
args: [creator, about, formatBytes32String(key) as WagmiBytes], args: [creator, about, formatBytes32String(key) as WagmiBytes],
allowFailure,
} as const } as const
}) })
......
...@@ -11,5 +11,5 @@ export interface AttestationReadParams { ...@@ -11,5 +11,5 @@ export interface AttestationReadParams {
key: string key: string
dataType?: DataTypeOption dataType?: DataTypeOption
contractAddress?: Address contractAddress?: Address
allowFailure?: boolean chainId?: number
} }
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