-
Notifications
You must be signed in to change notification settings - Fork 7
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* Send Requests Section * typescript SDK + text fixes --------- Co-authored-by: Andy Tudhope <[email protected]>
- Loading branch information
1 parent
3afa360
commit a8f1958
Showing
8 changed files
with
805 additions
and
224 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,89 @@ | ||
--- | ||
title: Deploy Simple Contract | ||
description: Deploy a Precompiled Contract | ||
--- | ||
|
||
We've written a number of example smart contracts to help get you started thinking about what's possible. For this script using the golang SDK, we'll stick to deploying one of these examples to keep things simple. | ||
|
||
Inside [suave-geth](https://github.com/flashbots/suave-geth) create a new file in `suave/devenv/cmd` called `deploy.go`: | ||
|
||
```go | ||
package main | ||
|
||
import ( | ||
"crypto/ecdsa" | ||
"fmt" | ||
|
||
_ "embed" | ||
|
||
"github.com/ethereum/go-ethereum/common" | ||
"github.com/ethereum/go-ethereum/crypto" | ||
"github.com/ethereum/go-ethereum/rpc" | ||
"github.com/ethereum/go-ethereum/suave/e2e" | ||
"github.com/ethereum/go-ethereum/suave/sdk" | ||
) | ||
|
||
var ( | ||
// This is the address we used when starting the MEVM | ||
exNodeEthAddr = common.HexToAddress("b5feafbdd752ad52afb7e1bd2e40432a485bbb7f") | ||
exNodeNetAddr = "http://localhost:8545" | ||
// This account is funded in both devenv networks | ||
// address: 0xBE69d72ca5f88aCba033a063dF5DBe43a4148De0 | ||
fundedAccount = newPrivKeyFromHex( | ||
"91ab9a7e53c220e6210460b65a7a3bb2ca181412a8a7b43ff336b3df1737ce12" | ||
) | ||
) | ||
|
||
var ( | ||
mevShareArtifact = e2e.MevShareBidContract | ||
) | ||
|
||
func main() { | ||
rpcClient, _ := rpc.Dial(exNodeNetAddr) | ||
mevmClt := sdk.NewClient(rpcClient, fundedAccount.priv, exNodeEthAddr) | ||
|
||
var mevShareContract *sdk.Contract | ||
_ = mevShareContract | ||
|
||
txnResult, err := sdk.DeployContract(mevShareArtifact.Code, mevmClt) | ||
if err != nil { | ||
fmt.Errorf("Failed to deploy contract: %v", err) | ||
} | ||
receipt, err := txnResult.Wait() | ||
if err != nil { | ||
fmt.Errorf("Failed to wait for transaction result: %v", err) | ||
} | ||
if receipt.Status == 0 { | ||
fmt.Errorf("Failed to deploy contract: %v", err) | ||
} | ||
|
||
fmt.Printf("- Example contract deployed: %s\n", receipt.ContractAddress) | ||
mevShareContract = sdk.GetContract(receipt.ContractAddress, mevShareArtifact.Abi, mevmClt) | ||
} | ||
|
||
// Helpers, not unique to SUAVE | ||
|
||
type privKey struct { | ||
priv *ecdsa.PrivateKey | ||
} | ||
|
||
func newPrivKeyFromHex(hex string) *privKey { | ||
key, err := crypto.HexToECDSA(hex) | ||
if err != nil { | ||
panic(fmt.Sprintf("failed to parse private key: %v", err)) | ||
} | ||
return &privKey{priv: key} | ||
} | ||
``` | ||
|
||
If you now run: | ||
|
||
```bash | ||
go run suave/devenv/cmd/deploy.go | ||
``` | ||
|
||
You should see the address of your new example contract printed in the terminal. | ||
|
||
The important parts to note when deploying contracts are the call to [`e2e`](https://github.com/flashbots/suave-geth/blob/main/suave/e2e/contracts.go), which helps generate ABIs and bytecode for contracts, and the `sdk.DeplyContract` and `sdk.GetContract`. | ||
|
||
If you're able to generate the necessary ABIs and bytecode, you should be able to deploy any contract you like using the above pattern. |
118 changes: 118 additions & 0 deletions
118
docs/how-to/interact-with-suave/deploy-and-test-example-suapp.mdx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,118 @@ | ||
--- | ||
title: Deploy and Test Example SUAPP | ||
description: Deploy a preocmpiled SUAPP and Interact with it | ||
--- | ||
|
||
SUAVE-geth has an example version of MEV-share along with a script that will: | ||
- deploy example MEV-share | ||
- sign an submit a transaction to be back run | ||
- grab the extracted hint from onchain | ||
- sign a back run transaction and submit it | ||
|
||
## Running the Script | ||
|
||
If you followed the [previous how-to](/how-to/run-suave), you will have SUAVE running locally, either in Docker or via the binaries themselves. | ||
|
||
In either case, you can cause a series of transactions to occur by running: | ||
|
||
```bash | ||
go run suave/devenv/cmd/main.go | ||
``` | ||
|
||
This script is focused on sending transactions to a local dev enviornment, but you can repurpose it easily for remote by changing `exNodeNetAddr`. | ||
|
||
## Step-by-Step Breakdown | ||
|
||
Below we will break down what this script is doing. | ||
|
||
### Step 1: Create and Fund Test Accounts | ||
|
||
```go | ||
testAddr1 = generatePrivKey() | ||
testAddr2 = generatePrivKey() | ||
|
||
if err := fundAccount(mevmClt, testAddr1.Address(), fundBalance); err != nil { | ||
return err | ||
} | ||
fmt.Printf("- Funded test account: %s (%s)\n", testAddr1.Address().Hex(), fundBalance.String()) | ||
``` | ||
|
||
- Generate two new private keys representing test accounts. | ||
- Fund these test accounts with a specified amount of Ether to simulate transactions. | ||
|
||
### Step 2: Deploy mev-share Contract | ||
|
||
```go | ||
// Code snippet related to the step | ||
txnResult, err := sdk.DeployContract(mevShareArtifact.Code, mevmClt) | ||
``` | ||
|
||
- Deploy the `mev-share` smart contract to the blockchain using the bytecode and a client instance. | ||
- Confirm the deployment by checking the transaction receipt status. | ||
|
||
### Step 3: Send Bid | ||
|
||
```go | ||
refundPercent := 10 | ||
bundle := &types.SBundle{ | ||
Txs: types.Transactions{ethTxn1}, | ||
RevertingHashes: []common.Hash{}, | ||
RefundPercent: &refundPercent, | ||
} | ||
bundleBytes, _ := json.Marshal(bundle) | ||
|
||
targetBlock := uint64(1) | ||
allowedPeekers := []common.Address{mevShareContract.Address()} | ||
|
||
confidentialDataBytes, _ := bundleBidContract.Abi.Methods["fetchBidConfidentialBundleData"].Outputs.Pack(bundleBytes) | ||
|
||
txnResult, err := mevShareContract.SendTransaction("newBid", []interface{}{targetBlock + 1, allowedPeekers, []common.Address{}}, confidentialDataBytes) | ||
if err != nil { | ||
return err | ||
} | ||
``` | ||
|
||
- Craft a bid using the `mev-share` contract function `newBid`. | ||
- Serialize the bundle of transactions to include in the bid. | ||
- Send the bid to the blockchain and validate its inclusion. | ||
|
||
### Step 4: Send Backrun | ||
|
||
```go | ||
backRunBundle := &types.SBundle{ | ||
Txs: types.Transactions{ethTxnBackrun}, | ||
RevertingHashes: []common.Hash{}, | ||
} | ||
backRunBundleBytes, _ := json.Marshal(backRunBundle) | ||
|
||
confidentialDataMatchBytes, _ := bundleBidContract.Abi.Methods["fetchBidConfidentialBundleData"].Outputs.Pack(backRunBundleBytes) | ||
|
||
// backrun inputs | ||
targetBlock := uint64(1) | ||
allowedPeekers := []common.Address{mevShareContract.Address()} | ||
|
||
txnResult, err := mevShareContract.SendTransaction("newMatch", []interface{}{targetBlock + 1, allowedPeekers, []common.Address{}, bidId}, confidentialDataMatchBytes) | ||
if err != nil { | ||
return err | ||
} | ||
``` | ||
|
||
- Create a backrun transaction bundle that will be sent after the initial bid. | ||
- Serialize the backrun bundle and use the `mev-share` contract's `newMatch` function to submit it. | ||
- Verify the transaction receipt to ensure the backrun was successful. | ||
|
||
#### Result | ||
If all has been succesfully run you should see the following in your terminal: | ||
```bash | ||
suave-geth$ go run suave/devenv/cmd/main.go | ||
Step 0: Create and fund test accounts | ||
- Funded test account: 0x66d5a8D6B34329c0639071275b3d78D29e11EbC6 (100000000) | ||
Step 1: Deploy mev-share contract | ||
- Mev share contract deployed: 0x8f21Fdd6B4f4CacD33151777A46c122797c8BF17 | ||
Step 2: Send bid | ||
- Bid sent at txn: 0xb49debcdead2b306d6ab6282b88fdad7c8d6a33d87df34b79f56d141eae7c08a | ||
- Bid id: 30bbc65298f24e67aaf5c95bf5f0686c | ||
Step 3: Send backrun | ||
- Backrun sent at txn: 0xcf7880e61e94aaab48c60655c321716ecab6edab752586448b0412e93a969889 | ||
- Backrun bid id: db98b83d02694fc2b13c042ad22c233 | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,112 @@ | ||
--- | ||
title: Fund Local Account | ||
description: Fund Local Accounts for Local Development | ||
--- | ||
|
||
This script will go through funding a local account using the golang SDK. | ||
|
||
Inside [suave-geth](https://github.com/flashbots/suave-geth) create a new file in `suave/devenv/cmd` called `transactions.go`: | ||
|
||
```go | ||
package main | ||
|
||
import ( | ||
"context" | ||
"crypto/ecdsa" | ||
"fmt" | ||
"math/big" | ||
"os" | ||
|
||
_ "embed" | ||
|
||
"github.com/ethereum/go-ethereum/common" | ||
"github.com/ethereum/go-ethereum/core/types" | ||
"github.com/ethereum/go-ethereum/crypto" | ||
"github.com/ethereum/go-ethereum/rpc" | ||
"github.com/ethereum/go-ethereum/suave/sdk" | ||
) | ||
|
||
var ( | ||
// This is the address we used when starting the MEVM | ||
exNodeEthAddr = common.HexToAddress("b5feafbdd752ad52afb7e1bd2e40432a485bbb7f") | ||
exNodeNetAddr = "http://localhost:8545" | ||
// This account is funded in both devenv networks | ||
// address: 0xBE69d72ca5f88aCba033a063dF5DBe43a4148De0 | ||
fundedAccount = newPrivKeyFromHex( | ||
"91ab9a7e53c220e6210460b65a7a3bb2ca181412a8a7b43ff336b3df1737ce12" | ||
) | ||
) | ||
|
||
func main() { | ||
rpcClient, _ := rpc.Dial(exNodeNetAddr) | ||
// Use the SDK to create a new client by specifying the Eth Address of the MEVM | ||
mevmClt := sdk.NewClient(rpcClient, fundedAccount.priv, exNodeEthAddr) | ||
|
||
testAddr1 := generatePrivKey() | ||
|
||
fundBalance := big.NewInt(100000000) | ||
if err := fundAccount(mevmClt, testAddr1.Address(), fundBalance); err != nil { | ||
fmt.Fprintf(os.Stderr, "Error: %v\n", err) | ||
return | ||
} | ||
fmt.Printf("Funded test account: %s (%s)\n", testAddr1.Address().Hex(), fundBalance.String()) | ||
} | ||
|
||
func fundAccount(clt *sdk.Client, to common.Address, value *big.Int) error { | ||
txn := &types.LegacyTx{ | ||
Value: value, | ||
To: &to, | ||
} | ||
result, err := clt.SendTransaction(txn) | ||
if err != nil { | ||
return err | ||
} | ||
_, err = result.Wait() | ||
if err != nil { | ||
return err | ||
} | ||
// check balance | ||
balance, err := clt.RPC().BalanceAt(context.Background(), to, nil) | ||
if err != nil { | ||
return err | ||
} | ||
if balance.Cmp(value) != 0 { | ||
return fmt.Errorf("failed to fund account") | ||
} | ||
return nil | ||
} | ||
|
||
// General types and methods we need for the above to work as we want it to, | ||
// nothing SUAVE specific | ||
type privKey struct { | ||
priv *ecdsa.PrivateKey | ||
} | ||
|
||
func (p *privKey) Address() common.Address { | ||
return crypto.PubkeyToAddress(p.priv.PublicKey) | ||
} | ||
|
||
func newPrivKeyFromHex(hex string) *privKey { | ||
key, err := crypto.HexToECDSA(hex) | ||
if err != nil { | ||
panic(fmt.Sprintf("failed to parse private key: %v", err)) | ||
} | ||
return &privKey{priv: key} | ||
} | ||
|
||
func generatePrivKey() *privKey { | ||
key, err := crypto.GenerateKey() | ||
if err != nil { | ||
panic(fmt.Sprintf("failed to generate private key: %v", err)) | ||
} | ||
return &privKey{priv: key} | ||
} | ||
``` | ||
|
||
If you run the following from your terminal, you should now have one funded account: | ||
|
||
```bash | ||
go run suave/devenv/cmd/transactions.go | ||
``` | ||
|
||
The important parts to note are the `SendTransaction` method, and the way the balance of a given account is fetched via the `RPC()` method, both available in the SDK. Using this pattern, you should be able to send most of the transactions you wish to, as well as fetch information about other accounts or transactions as is necessary. |
Oops, something went wrong.