Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 30 additions & 12 deletions thorclient/bind/contract.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import (
"github.com/ethereum/go-ethereum/common/hexutil"

"github.com/vechain/thor/v2/test"
"github.com/vechain/thor/v2/test/datagen"
"github.com/vechain/thor/v2/thor"
"github.com/vechain/thor/v2/thorclient"
"github.com/vechain/thor/v2/tx"
Expand Down Expand Up @@ -50,32 +51,49 @@ func DeployContract(client *thorclient.Client, signer Signer, abiData []byte, by
if err != nil {
return nil, err
}
clause := tx.NewClause(nil).WithData(bc)

tag, err := client.ChainTag()
if err != nil {
return nil, err
}
best, err := client.Block("best")
if err != nil {
return nil, fmt.Errorf("failed to get best block: %w", err)
}

// Estimate gas from intrinsic gas plus simulated execution gas.
gas, err := tx.IntrinsicGas(clause)
if err != nil {
return nil, fmt.Errorf("failed to calculate intrinsic gas: %w", err)
}
caller := signer.Address()
simulation, err := simulateClause(client, caller, clause)
if err != nil {
return nil, fmt.Errorf("failed to simulate deployment clause: %w", err)
}
if simulation.Reverted || simulation.VMError != "" {
return nil, fmt.Errorf("unable to deploy contract: %+v", simulation)
}
gas += simulation.GasUsed
Comment thread
libotony marked this conversation as resolved.
Resolved

trx := tx.NewBuilder(tx.TypeLegacy).
builder := tx.NewBuilder(tx.TypeLegacy)
if best.BaseFeePerGas != nil {
builder = tx.NewBuilder(tx.TypeDynamicFee).MaxFeePerGas((*big.Int)(best.BaseFeePerGas))
Comment thread
libotony marked this conversation as resolved.
Resolved
}
trx := builder.
ChainTag(tag).
Clause(tx.NewClause(nil).WithData(bc)).
Clause(clause).
Expiration(10000).
Gas(10_000_000).
BlockRef(tx.NewBlockRef(best.Number)).
Nonce(datagen.RandUint64()).
Gas(gas).
Build()
trx, err = signer.SignTransaction(trx)
if err != nil {
return nil, err
}

signerAddr := signer.Address()
clauses, err := client.InspectTxClauses(trx, &signerAddr)
if err != nil {
return nil, err
}
if len(clauses) != 1 || clauses[0].Reverted || clauses[0].VMError != "" {
return nil, fmt.Errorf("unable to deploy contract: %+v", clauses)
}

res, err := client.SendTransaction(trx)
if err != nil {
return nil, err
Expand Down
17 changes: 3 additions & 14 deletions thorclient/bind/send.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,9 @@ import (
"math/big"
"time"

"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/common/math"

"github.com/vechain/thor/v2/api"
"github.com/vechain/thor/v2/test/datagen"
"github.com/vechain/thor/v2/thor"
"github.com/vechain/thor/v2/thorclient"
"github.com/vechain/thor/v2/tx"
)

Expand Down Expand Up @@ -98,18 +94,11 @@ func (b *SendBuilder) Submit() (*tx.Transaction, error) {
return nil, fmt.Errorf("failed to calculate intrinsic gas: %w", err)
}
caller := b.signer.Address()
simulation, err := b.op.contract.client.InspectClauses(
&api.BatchCallData{
Caller: &caller,
Clauses: api.Clauses{{To: b.op.contract.addr, Data: hexutil.Encode(clause.Data()), Value: (*math.HexOrDecimal256)(clause.Value())}},
}, thorclient.Revision("best"))
simulation, err := simulateClause(b.op.contract.client, caller, clause)
if err != nil {
return nil, fmt.Errorf("failed to simulate clauses (%s): %w", b.op.String(), err)
}
if len(simulation) != 1 {
return nil, fmt.Errorf("expected 1 simulation result, got %d", len(simulation))
}
gas += simulation[0].GasUsed
gas += simulation.GasUsed
if clause.To() != nil && len(clause.Data()) > 0 {
gas += 15_000 // buffer required for OP_CALL
Comment thread
libotony marked this conversation as resolved.
Resolved
}
Expand All @@ -134,7 +123,7 @@ func (b *SendBuilder) Submit() (*tx.Transaction, error) {
}

// Build the transaction
builder := new(tx.Builder).
builder := tx.NewBuilder(txType).
Comment thread
libotony marked this conversation as resolved.
Resolved
Clause(clause).
Gas(*opts.Gas).
ChainTag(chainTag).
Expand Down
43 changes: 43 additions & 0 deletions thorclient/bind/simulate.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
// Copyright (c) 2025 The VeChainThor developers
//
// Distributed under the GNU Lesser General Public License v3.0 software license, see the accompanying
// file LICENSE or <https://www.gnu.org/licenses/lgpl-3.0.html>

package bind

import (
"fmt"

"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/common/math"

"github.com/vechain/thor/v2/api"
"github.com/vechain/thor/v2/thor"
"github.com/vechain/thor/v2/thorclient"
"github.com/vechain/thor/v2/tx"
)

// simulateClause simulates the execution of a single clause on top of the best block
// and returns the simulation result.
func simulateClause(client *thorclient.Client, caller thor.Address, clause *tx.Clause) (*api.CallResult, error) {
var to *thor.Address
if clause.To() != nil {
addr := *clause.To()
to = &addr
}
sim, err := client.InspectClauses(&api.BatchCallData{
Caller: &caller,
Clauses: api.Clauses{{
To: to,
Data: hexutil.Encode(clause.Data()),
Value: (*math.HexOrDecimal256)(clause.Value()),
}},
}, thorclient.Revision("best"))
if err != nil {
return nil, err
}
if len(sim) != 1 {
return nil, fmt.Errorf("expected 1 simulation result, got %d", len(sim))
}
return sim[0], nil
}
2 changes: 1 addition & 1 deletion thorclient/thorclient.go
Original file line number Diff line number Diff line change
Expand Up @@ -991,7 +991,7 @@ func (c *Client) Peers() ([]*api.PeerStats, error) {
// }
//
// // Use chain tag when building transaction
// tx := tx.NewBuilder(chainTag).
// tx := tx.NewBuilder(tx.TypeDynamicFee).
// ChainTag(chainTag).
// BlockRef(blockRef).
// // ... other transaction fields
Expand Down
Loading