defi

package module
v0.4.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 30, 2026 License: MIT Imports: 16 Imported by: 0

README

DeFi Simplify

DeFi Simplify is a Go SDK for composing and executing EOA-native DeFi flows through EIP-7702.

The SDK builds protocol-aware FlowStep values, compiles them into an ExecutionPlan, executes the plan atomically through a delegated DefiSimplify7702Account, and validates the mined receipt against typed event expectations.

[!WARNING] The SDK and deployed account contracts are experimental and unaudited. They can submit transactions that move funds or create debt. Use isolated accounts and review every generated flow before using real assets.

What It Provides

Area Current support
Chain Base
Account execution EIP-7702 delegation to the configured DefiSimplify7702Account
Static plans Atomic inherited executeBatch execution
Dynamic plans Atomic executeBatchDynamic execution with balance checkpoints and calldata patches
Aave V3 Supply, borrow, repay, repay all, withdraw, withdraw all
ERC20 Approve, transfer, transfer from
WETH Wrap and unwrap
Strategies Aave supply/borrow, close position, and native ETH compositions
Results Mined receipt, per-step validation status, typed protocol events, and wrapped execution errors

The SDK does not expose external Multicall or direct-EOA Flow execution as alternative modes. Every normal Flow executes through the configured delegated account so downstream protocols observe the Flow account as the caller.

Execution Model

FlowStep[]
    |
    v
ExecutionPlan
    |
    +-- PlanStatic  --> DefiSimplify7702Account.executeBatch
    |
    +-- PlanDynamic --> DefiSimplify7702Account.executeBatchDynamic
    |
    v
mined receipt
    |
    v
typed event validation

The caller does not choose an execution mode. Runner.Execute builds the Flow and dispatches from ExecutionPlan.Kind().

result, err := defi.NewRunner(client, opts, config.Base).Execute(ctx, flow)

Exact-only steps produce a static plan. Runtime amount sources, checkpoints, or calldata patches produce a dynamic plan.

Delegation Setup

EIP-7702 delegation is persistent. It is not limited to one Flow, and a reverted Flow does not clear it. Applications must treat delegation setup, switching, and clearing as explicit account lifecycle operations.

Load the checked-in Base deployment and verify its runtime code once during application initialization. The Base manifest currently selects the official Defi Simplify Contracts v1.1.0 release:

deployment, err := defisimplify7702.DeploymentForChain(config.Base)
if err != nil {
	return err
}
accountDeployment, err := deployment.Contract(defisimplify7702.AccountContract)
if err != nil {
	return err
}

code, err := client.CodeAt(ctx, accountDeployment.Address, nil)
if err != nil {
	return err
}
if err := accountDeployment.VerifyRuntimeCode(code); err != nil {
	return err
}

Delegate the EOA to that implementation:

chainID, err := config.Base.ChainID()
if err != nil {
	return err
}
manager, err := eip7702.NewManager(
	client,
	opts,
	authorizationKey,
	big.NewInt(int64(chainID)),
)
if err != nil {
	return err
}

tx, err := manager.Delegate(ctx, accountDeployment.Address)
if err != nil {
	return err
}
receipt, err := bind.WaitMined(ctx, client, tx)
if err != nil {
	return err
}
if receipt.Status != types.ReceiptStatusSuccessful {
	return errors.New("delegation transaction reverted")
}

The Runner checks the pending delegation target before each submission. This protects against submitting through an unexpected implementation, but it cannot remove the lifecycle race between preflight and transaction inclusion. Applications must serialize delegation changes and Flow execution for each EOA.

Applications upgrading from the earlier Base deployment must switch each EOA's persistent delegation explicitly by submitting a new manager.Delegate(ctx, accountDeployment.Address) transaction and waiting for its successful receipt. Existing balances and DeFi positions remain owned by the EOA; switching delegated code does not move them to the implementation contract. A reverted transaction does not restore the previous delegation.

Clear the delegation explicitly when it is no longer needed:

tx, err := manager.Clear(ctx)
if err != nil {
	return err
}
receipt, err := bind.WaitMined(ctx, client, tx)

Build An Aave Flow

Resolve the current Base Aave market and reserve metadata:

market, err := aave.BaseV3Market()
if err != nil {
	return err
}
registry, err := aave.NewRegistry(client, market)
if err != nil {
	return err
}
snapshot, err := registry.Load(ctx)
if err != nil {
	return err
}
usdc, err := snapshot.Reserve(base.USDC)
if err != nil {
	return err
}
wethReserve, err := snapshot.Reserve(base.WETH)
if err != nil {
	return err
}

Compose protocol steps and execute them atomically:

supplyAmount := decimal.NewFromInt(100)
borrowAmount := decimal.RequireFromString("0.01")

flow := defi.NewFlow(opts.From, defi.WithChain(config.Base)).
	Add(erc20.Approve(
		usdc.Underlying(),
		aave.PoolSpender(market),
		amount.Exact(supplyAmount),
	)).
	Add(aave.Supply(usdc, amount.Exact(supplyAmount))).
	Add(aave.Borrow(wethReserve, amount.Exact(borrowAmount)))

result, err := defi.NewRunner(client, opts, config.Base).Execute(ctx, flow)
if err != nil {
	return err
}
fmt.Println(result.Receipt.TxHash)

Allowance operations use the protocol-neutral erc20.Approve step. aave.PoolSpender supplies the reviewed market-specific Pool address without wrapping or renaming the ERC20 operation.

For code written against the earlier v0 API, replace:

aave.ApproveSupply(reserve, amount.Exact(value))

with:

erc20.Approve(
	reserve.Underlying(),
	aave.PoolSpender(market),
	amount.Exact(value),
)

All three amounts are known before submission, so this Flow compiles to PlanStatic and executes through inherited executeBatch.

Runtime Amounts

Dynamic plans let a later call consume a token balance observed during account execution.

amount.CurrentBalance reads the delegated EOA's current token balance:

flow := defi.NewFlow(opts.From, defi.WithChain(config.Base)).
	Add(erc20.Approve(
		usdc.Underlying(),
		aave.PoolSpender(market),
		amount.CurrentBalance(usdc.Underlying().Ref()),
	))

amount.CheckpointDelta uses only the balance gained after an explicit earlier checkpoint:

checkpoint := amount.Checkpoint("before-wrap", base.WETH)

flow := defi.NewFlow(opts.From, defi.WithChain(config.Base)).
	Add(defi.CheckpointBefore(
		weth.Wrap(base.WETH, amount.Exact(decimal.RequireFromString("0.1"))),
		checkpoint,
	)).
	Add(weth.Unwrap(base.WETH, amount.CheckpointDelta(checkpoint)))

This protects pre-existing inventory from being swept by a later step. amount.Scale(source, bps) can apply a basis-point ratio to a runtime source.

Runtime dependencies must be explicit. The SDK does not infer dependencies from call order, pipe arbitrary return data between calls, or patch native value.

Results And Errors

Runner.Execute always performs semantic receipt validation after a successful transaction:

supplies := defi.EventsOf[*aave.SupplyEvent](result)
borrows := defi.EventsOf[*aave.BorrowEvent](result)

Failures before submission return a nil result. Once a transaction is mined, transaction reverts and semantic validation failures return both a result and an error so the transaction hash and partial validation state remain available.

result, err := runner.Execute(ctx, flow)
if err != nil && result != nil {
	fmt.Println("mined transaction:", result.Receipt.TxHash)
}

Use errors.Is and errors.As with exported sentinel and typed errors. Dynamic account reverts can include the failed call index through defisimplify7702.ContractError.

Strategy Builders

The strategy package contains thin compositions of public FlowSteps:

  • AaveSupplyBorrow
  • AaveClosePosition
  • AaveSupplyNativeETH
  • AaveBorrowNativeETH
  • AaveWithdrawNativeETH
  • AaveWithdrawAllNativeETH

Strategy builders return a normal *defi.Flow. They do not read chain state, sign, submit, or select execution behavior.

Development

Run unit tests:

go test -count=1 ./...

Compile integration tests:

go test -count=1 -run '^$' -tags=integration ./integration/...

Run the Base mainnet fork suite:

BASE_RPC_URL=https://mainnet.base.org make anvil-base

In another terminal:

BASE_RPC_URL=http://127.0.0.1:8545 make test-integration

Refresh imported contract artifacts from a local defi-simplify-contracts checkout:

make update-contract-artifacts

Do not hand-edit generated contract bindings or asset catalog references.

Package Layout

Package Responsibility
root defi package Flow, ExecutionPlan, Runner, validator, and neutral execution types
amount Exact and runtime amount intent
token, assets, assets/base Chain-scoped token identity and reviewed asset catalog
aave, erc20, weth Protocol-specific FlowSteps, calldata, and event semantics
strategy Reusable compositions of public FlowSteps
client/account/eip7702 Delegation authorization, state inspection, switching, and clear
client/account/defisimplify7702 Deployment manifests, ABI translation, and account execution
integration Ginkgo Base-fork behavior tests

See Adding an asset chain for catalog extension rules. Breaking v0 API changes are documented under docs/migrations.

Documentation

Index

Constants

This section is empty.

Variables

View Source
var (
	ErrInvalidDynamicCall        = errors.New("invalid dynamic call")
	ErrInvalidCheckpointGraph    = errors.New("invalid checkpoint graph")
	ErrInvalidCalldataPatch      = errors.New("invalid calldata patch")
	ErrDynamicPlaceholderNotZero = errors.New("dynamic calldata placeholder is not zero")
)
View Source
var (
	// ErrInvalidExecutionPlan is returned when validation receives no usable plan.
	ErrInvalidExecutionPlan = errors.New("invalid execution plan")
	// ErrInvalidExecutionReceipt is returned when a receipt is nil, incomplete, or unsuccessful.
	ErrInvalidExecutionReceipt = errors.New("invalid execution receipt")
	// ErrInvalidEventExpectation is returned for nil or unnamed expectations.
	ErrInvalidEventExpectation = errors.New("invalid event expectation")
	// ErrMalformedExecutionEvent is returned when a candidate log cannot be decoded.
	ErrMalformedExecutionEvent = errors.New("malformed execution event")
	// ErrExpectedEventNotFound is returned when no candidate satisfies an expectation.
	ErrExpectedEventNotFound = errors.New("expected execution event not found")
	// ErrInvalidMatchResult is returned when an expectation or constraint violates the matching contract.
	ErrInvalidMatchResult = errors.New("invalid match result")
)
View Source
var (
	ErrEmptyFlow      = errors.New("empty flow")
	ErrMissingChain   = errors.New("flow chain is required")
	ErrInvalidAccount = errors.New("flow account is zero")
)
View Source
var ErrExecutionAccountMismatch = errors.New("flow account does not match transaction signer")

ErrExecutionAccountMismatch is returned when a Flow is built for an account other than the transaction signer.

View Source
var ErrInvalidAmountConstraint = errors.New("invalid amount constraint")

ErrInvalidAmountConstraint is returned when a constraint is nil or was configured without a required bound.

View Source
var ErrPlanKindMismatch = errors.New("execution plan kind is incompatible with accessor")

Functions

func EventsOf

func EventsOf[T DecodedEvent](result *ExecutionResult) []T

EventsOf returns every validated event assignable to T in execution order.

Types

type Action

type Action = contract.Action

Action is an existing protocol action that can encode itself into a Call.

type AmountConstraint

type AmountConstraint interface {
	Describe() string
	Match(actual *big.Int, ctx MatchContext) (MatchResult, error)
}

AmountConstraint validates a decoded event amount. Implementations must return MatchSkip rather than panic when actual is nil.

func AtLeast

func AtLeast(minimum *big.Int) AmountConstraint

AtLeast requires an amount to be greater than or equal to minimum.

func AtMost

func AtMost(maximum *big.Int) AmountConstraint

AtMost requires an amount to be less than or equal to maximum.

func Exact

func Exact(expected *big.Int) AmountConstraint

Exact requires an amount to equal expected.

func Positive

func Positive() AmountConstraint

Positive requires an amount to be greater than zero.

type BalanceCheckpoint added in v0.4.0

type BalanceCheckpoint struct {
	Token common.Address
	ID    [32]byte
}

BalanceCheckpoint is the materialized contract checkpoint value.

type BalancePatch added in v0.4.0

type BalancePatch struct {
	Token        common.Address
	CheckpointID [32]byte
	Offset       uint32
	BPS          uint16
	Source       BalanceSource
}

BalancePatch is the materialized contract calldata patch value.

type BalanceSource added in v0.4.0

type BalanceSource uint8

BalanceSource mirrors the dynamic account contract's runtime balance source.

const (
	BalanceSourceCurrentBalance BalanceSource = iota
	BalanceSourceCheckpointDelta
)

type BuildEnv

type BuildEnv struct {
	Account common.Address
	Chain   config.Chain
	Conn    EthereumClient
}

BuildEnv contains shared context passed to every step during Flow.Build.

type BuiltStep

type BuiltStep struct {
	ID           StepID
	Name         string
	Calls        []PlannedCall
	Expectations []EventExpectation
}

BuiltStep contains the calls and semantic expectations produced from the same resolved Flow step data. Flow.Build owns ID assignment; step implementations must set Name and leave ID empty.

type Call

type Call = contract.Call

Call is the neutral contract call model shared by flow builders and executors.

type CalldataPatch added in v0.4.0

type CalldataPatch struct {
	Source amount.Source
	Offset uint32
}

CalldataPatch replaces one protocol-owned ABI uint256 word with a runtime amount immediately before execution.

type CheckpointDeclaration added in v0.4.0

type CheckpointDeclaration struct {
	Ref amount.CheckpointRef
}

CheckpointDeclaration attaches a named token-balance checkpoint immediately before a planned call.

type DecodedEvent

type DecodedEvent interface {
	EventMetadata() EventMetadata
}

DecodedEvent is implemented by protocol-specific event result types.

type DynamicCall added in v0.4.0

type DynamicCall struct {
	Target            common.Address
	Value             *big.Int
	Data              []byte
	CheckpointsBefore []BalanceCheckpoint
	Patches           []BalancePatch
	ExpectsCallback   bool
}

DynamicCall is the protocol-neutral wire model for executeBatchDynamic.

type EthereumClient

type EthereumClient = contract.EthereumClient

EthereumClient is the client interface needed by steps that build calls from contract state.

type EventExpectation

type EventExpectation interface {
	ExpectationName() string
	IsCandidate(log *types.Log) bool
	Decode(log *types.Log) (DecodedEvent, error)
	Match(event DecodedEvent, ctx MatchContext) (MatchResult, error)
}

EventExpectation decodes and validates one expected protocol event.

IsCandidate must only identify logs by stable source data such as emitter and topic. Decode errors and Match errors are hard failures. Ordinary decoded field mismatches must return MatchSkip with mismatch details and a nil error. Within one BuiltStep, expectations must be declared in the same order as the corresponding events are emitted on-chain; the validator scans forward and never reuses an earlier or consumed log.

type EventMetadata

type EventMetadata struct {
	Protocol string
	Name     string
	Emitter  common.Address
	LogIndex uint
}

EventMetadata identifies a decoded protocol event without depending on its protocol-specific fields.

type ExecutionError

type ExecutionError struct {
	Stage       ExecutionStage
	StepID      StepID
	Expectation string
	LogIndex    *uint
	Err         error
}

ExecutionError wraps an execution or validation failure with stage and partial-result location metadata.

func (*ExecutionError) Error

func (e *ExecutionError) Error() string

func (*ExecutionError) Unwrap

func (e *ExecutionError) Unwrap() error

Unwrap preserves sentinel and typed errors for errors.Is and errors.As.

type ExecutionPlan

type ExecutionPlan struct {
	// contains filtered or unexported fields
}

ExecutionPlan is the ordered, executor-neutral result of building a Flow. Its contents are immutable to callers and exposed through defensive-copy accessors. Account is the semantic caller identity for steps that derive owner, sender, or onBehalfOf values from BuildEnv.Account.

func (*ExecutionPlan) Account

func (p *ExecutionPlan) Account() common.Address

Account returns the protocol-visible caller identity.

func (*ExecutionPlan) Calls deprecated

func (p *ExecutionPlan) Calls() []Call

Calls returns static plan calls in step order.

Deprecated: use StaticCalls, which reports an error for dynamic plans.

func (*ExecutionPlan) DynamicCalls added in v0.4.0

func (p *ExecutionPlan) DynamicCalls() ([]DynamicCall, error)

DynamicCalls returns materialized calls only when dynamic execution is required. Static calls within a dynamic plan are represented with empty checkpoint and patch metadata.

func (*ExecutionPlan) Kind added in v0.4.0

func (p *ExecutionPlan) Kind() PlanKind

Kind returns the execution capability required by the plan.

func (*ExecutionPlan) StaticCalls added in v0.4.0

func (p *ExecutionPlan) StaticCalls() ([]Call, error)

StaticCalls returns calls only when the plan has no runtime metadata.

func (*ExecutionPlan) Steps

func (p *ExecutionPlan) Steps() []BuiltStep

Steps returns a defensive copy of the built steps.

type ExecutionResult

type ExecutionResult struct {
	Receipt *types.Receipt
	Steps   []StepResult
}

ExecutionResult preserves the mined receipt and all available step-level semantic validation results, including partial results on failure.

func ValidateExecution

func ValidateExecution(plan *ExecutionPlan, receipt *types.Receipt) (*ExecutionResult, error)

ValidateExecution validates a mined receipt against plan expectations.

Expectations are processed in step and declaration order. Each expectation scans forward from the last accepted log. Accepted logs and all earlier logs are unavailable to later expectations, which enforces on-chain emission order and consume-once semantics structurally. Because unvalidated steps cannot consume logs, a semantic plan may only place them after all validated steps.

type ExecutionStage

type ExecutionStage string

ExecutionStage identifies where execution or semantic validation failed.

const (
	ExecutionStageTransaction ExecutionStage = "transaction"
	ExecutionStageReceipt     ExecutionStage = "receipt"
	ExecutionStageDecode      ExecutionStage = "decode"
	ExecutionStageMatch       ExecutionStage = "match"
	ExecutionStageValidation  ExecutionStage = "validation"
)

type ExpectationResult

type ExpectationResult struct {
	Name           string
	Status         ValidationStatus
	SkipReason     SkipReason
	CandidateCount int
	Mismatches     []FieldMismatch
	Event          DecodedEvent
}

ExpectationResult reports matching details for one expected event.

type FieldMismatch

type FieldMismatch struct {
	Field    string
	Expected string
	Actual   string
}

FieldMismatch explains one expected field that did not match its actual decoded value.

type Flow

type Flow struct {
	// contains filtered or unexported fields
}

Flow is an ordered composition of DeFi steps.

func NewFlow

func NewFlow(account common.Address, opts ...FlowOption) *Flow

NewFlow creates an empty flow for account.

func (*Flow) Add

func (f *Flow) Add(step FlowStep) *Flow

Add appends a step and returns the flow for fluent composition.

func (*Flow) Build

func (f *Flow) Build(ctx context.Context, conn EthereumClient) (*ExecutionPlan, error)

Build compiles all Flow steps into an ordered execution plan.

type FlowOption

type FlowOption func(*Flow)

FlowOption configures a Flow.

func WithChain

func WithChain(chain config.Chain) FlowOption

WithChain configures the chain context used when building flow steps.

type FlowStep

type FlowStep interface {
	Build(ctx context.Context, env BuildEnv) (BuiltStep, error)
}

FlowStep builds one named step from shared Flow context.

func ActionStep

func ActionStep(name string, action Action) FlowStep

ActionStep adapts an existing Action into a FlowStep.

func CheckpointBefore added in v0.4.0

func CheckpointBefore(step FlowStep, checkpoints ...amount.CheckpointRef) FlowStep

CheckpointBefore declares token-balance checkpoints immediately before the wrapped step's single call. The references can later be consumed through amount.CheckpointDelta.

type MatchContext

type MatchContext struct {
	StepID StepID
}

MatchContext provides execution-plan context to expectation and constraint matching. It intentionally has no cross-step value resolution in Phase 1.

type MatchDecision

type MatchDecision uint8

MatchDecision describes whether a decoded candidate satisfies an expectation. The zero value is MatchSkip so matching fails closed.

const (
	// MatchSkip rejects the current candidate without aborting receipt scanning.
	MatchSkip MatchDecision = iota
	// MatchAccepted accepts and consumes the current candidate log.
	MatchAccepted
)

type MatchResult

type MatchResult struct {
	Decision   MatchDecision
	Mismatches []FieldMismatch
}

MatchResult is shared by event expectations and value constraints. At the constraint level MatchSkip means the value is unsatisfied; the enclosing event expectation decides whether receipt scanning continues.

func MatchAmountConstraints

func MatchAmountConstraints(field string, actual *big.Int, ctx MatchContext, constraints ...AmountConstraint) (MatchResult, error)

MatchAmountConstraints evaluates every amount constraint and aggregates all ordinary mismatches. A constraint error remains a hard failure and aborts evaluation immediately.

type PlanKind added in v0.4.0

type PlanKind uint8

PlanKind identifies the execution capability required by a built plan.

const (
	PlanStatic PlanKind = iota + 1
	PlanDynamic
)

type PlannedCall added in v0.4.0

type PlannedCall struct {
	Call              Call
	CheckpointsBefore []CheckpointDeclaration
	Patches           []CalldataPatch
	ExpectsCallback   bool
}

PlannedCall combines one neutral call with optional dynamic execution metadata. Protocol packages own all patch offsets they place here.

type Runner

type Runner struct {
	// contains filtered or unexported fields
}

Runner executes Flows through the configured DefiSimplify7702Account delegation. The built plan determines the account entrypoint.

func NewRunner

func NewRunner(conn EthereumClient, opts *bind.TransactOpts, chain config.Chain) *Runner

NewRunner creates a Flow runner for a chain and transaction signer.

func (*Runner) Execute

func (r *Runner) Execute(ctx context.Context, flow *Flow) (*ExecutionResult, error)

Execute builds and executes flow, then validates the mined receipt against expectations generated by the same Flow steps.

Failures before a receipt exists return a nil result. Once a receipt exists, transaction and semantic validation failures return both the partial result and an error so callers retain the transaction hash and decoded progress. A plan with expectations after an unvalidated step is rejected before sending.

type SkipReason

type SkipReason string

SkipReason explains why validation was not attempted.

const (
	SkipExecutionFailed       SkipReason = "execution_failed"
	SkipInvalidReceipt        SkipReason = "invalid_receipt"
	SkipPriorValidationFailed SkipReason = "prior_validation_failed"
)

type StepID

type StepID string

StepID identifies one built occurrence of a named Flow step.

type StepResult

type StepResult struct {
	ID           StepID
	Name         string
	Status       ValidationStatus
	SkipReason   SkipReason
	Expectations []ExpectationResult
}

StepResult reports semantic validation for one built step.

type ValidationStatus

type ValidationStatus string

ValidationStatus describes the semantic validation state of a step or expectation.

const (
	ValidationValidated   ValidationStatus = "validated"
	ValidationUnvalidated ValidationStatus = "unvalidated"
	ValidationFailed      ValidationStatus = "failed"
	ValidationSkipped     ValidationStatus = "skipped"
)

Directories

Path Synopsis
Package amount defines protocol-neutral transaction amount intent.
Package amount defines protocol-neutral transaction amount intent.
Package assets provides protocol-neutral, chain-scoped asset catalogs.
Package assets provides protocol-neutral, chain-scoped asset catalogs.
base
Package base provides reviewed token references for common assets on Base.
Package base provides reviewed token references for common assets on Base.
bind
client
account/defisimplify7702
Package defisimplify7702 exposes imported Defi Simplify contract deployment identities, ABIs, parity vectors, and delegated-account execution.
Package defisimplify7702 exposes imported Defi Simplify contract deployment identities, ABIs, parity vectors, and delegated-account execution.
account/eip7702
Package eip7702 manages EIP-7702 account delegation lifecycle.
Package eip7702 manages EIP-7702 account delegation lifecycle.
contract/mock
Package mock is a generated GoMock package.
Package mock is a generated GoMock package.
cmd
internal
aaveassetmanifest
Package aaveassetmanifest adapts official Aave Address Book market exports into the provider-neutral asset manifest model.
Package aaveassetmanifest adapts official Aave Address Book market exports into the provider-neutral asset manifest model.
catalogcodegen
Package catalogcodegen renders reviewed manifest entries as chain-package named references.
Package catalogcodegen renders reviewed manifest entries as chain-package named references.
catalogloader
Package catalogloader turns checked-in neutral manifests into public asset catalogs for thin chain-specific packages.
Package catalogloader turns checked-in neutral manifests into public asset catalogs for thin chain-specific packages.
Package strategy provides opinionated Flow compositions for common DeFi workflows.
Package strategy provides opinionated Flow compositions for common DeFi workflows.
Package token defines protocol-neutral ERC20 token identity and metadata.
Package token defines protocol-neutral ERC20 token identity and metadata.
Package weth provides FlowSteps and typed event validation for canonical WETH deposit and withdrawal operations.
Package weth provides FlowSteps and typed event validation for canonical WETH deposit and withdrawal operations.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL