-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
add initial web3 packet with minimal/test implementation
Signed-off-by: p4u <[email protected]>
- Loading branch information
Showing
11 changed files
with
1,373 additions
and
2 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
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
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
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,126 @@ | ||
package main | ||
|
||
import ( | ||
"context" | ||
"flag" | ||
"math/big" | ||
"time" | ||
|
||
"github.com/ethereum/go-ethereum/common" | ||
"github.com/vocdoni/vocdoni-z-sandbox/crypto/ecc/curves" | ||
"github.com/vocdoni/vocdoni-z-sandbox/crypto/elgamal" | ||
"github.com/vocdoni/vocdoni-z-sandbox/log" | ||
"github.com/vocdoni/vocdoni-z-sandbox/types" | ||
"github.com/vocdoni/vocdoni-z-sandbox/util" | ||
"github.com/vocdoni/vocdoni-z-sandbox/web3" | ||
) | ||
|
||
var rpcs = []string{ | ||
"wss://sepolia.drpc.org", | ||
"https://sepolia.gateway.tenderly.co", | ||
"https://rpc.ankr.com/eth_sepolia", | ||
"https://eth-sepolia.public.blastapi.io", | ||
"https://1rpc.io/sepolia", | ||
} | ||
|
||
func main() { | ||
privKey := flag.String("privkey", "", "private key to use for the Ethereum account") | ||
flag.Parse() | ||
log.Init("debug", "stdout", nil) | ||
contracts, err := web3.NewContracts(&web3.Addresses{ | ||
OrganizationRegistry: common.HexToAddress("0x3d0b39c0239329955b9F0E8791dF9Aa84133c861"), | ||
ProcessRegistry: common.HexToAddress("0xd512481d0Fa6d975f9B186a9f6e59ea8E12D2C2b"), | ||
}, rpcs[0]) | ||
if err != nil { | ||
log.Fatal(err) | ||
} | ||
log.Infow("contracts initialized", "chainId", contracts.ChainID) | ||
|
||
for i := 1; i < len(rpcs); i++ { | ||
if err := contracts.AddWeb3Endpoint(rpcs[i]); err != nil { | ||
log.Warnw("failed to add endpoint", "rpc", rpcs[i], "err", err) | ||
} | ||
} | ||
|
||
if err := contracts.SetAccountPrivateKey(*privKey); err != nil { | ||
log.Fatal(err) | ||
} | ||
|
||
ctx := context.Background() | ||
newProcChan, err := contracts.MonitorProcessCreationByPolling(ctx, time.Second*5) | ||
if err != nil { | ||
log.Fatal(err) | ||
} | ||
go func() { | ||
log.Info("monitoring new processes") | ||
for { | ||
select { | ||
case <-ctx.Done(): | ||
return | ||
case proc := <-newProcChan: | ||
log.Infow("new process created", "process", proc.String()) | ||
} | ||
} | ||
}() | ||
|
||
time.Sleep(20 * time.Second) | ||
|
||
orgInfo, err := contracts.Organization(contracts.AccountAddress()) | ||
if err != nil { | ||
log.Fatal(err) | ||
} | ||
if orgInfo.MetadataURI == "" { | ||
log.Infof("organization not found, creating it") | ||
txHash, err := contracts.CreateOrganization(&types.OrganizationInfo{ | ||
Name: "Vocdoni", | ||
MetadataURI: "https://vocdoni.io", | ||
}) | ||
if err != nil { | ||
log.Fatal(err) | ||
} | ||
log.Infow("organization created", "txHash", txHash.Hex()) | ||
} else { | ||
log.Infow("organization info", "orgInfo", orgInfo) | ||
} | ||
|
||
curve := curves.New(curves.CurveTypeBN254) | ||
pubKey, _, err := elgamal.GenerateKey(curve) | ||
if err != nil { | ||
log.Fatal(err) | ||
} | ||
x, y := pubKey.Point() | ||
|
||
pid, txHash, err := contracts.CreateProcess(&types.Process{ | ||
Status: 0, | ||
OrganizationId: contracts.AccountAddress(), | ||
EncryptionKey: &types.EncryptionKey{ | ||
X: x, | ||
Y: y, | ||
}, | ||
StateRoot: util.RandomBytes(32), | ||
StartTime: time.Now().Add(5 * time.Minute), | ||
Duration: time.Hour, | ||
MetadataURI: "https://example.com/metadata", | ||
BallotMode: &types.BallotMode{ | ||
MaxCount: 2, | ||
MaxValue: *new(types.BigInt).SetUint64(100), | ||
MinValue: *new(types.BigInt).SetUint64(0), | ||
MaxTotalCost: *new(types.BigInt).SetUint64(0), | ||
MinTotalCost: *new(types.BigInt).SetUint64(0), | ||
ForceUniqueness: false, | ||
CostFromWeight: false, | ||
}, | ||
Census: &types.Census{ | ||
CensusRoot: util.RandomBytes(32), | ||
MaxVotes: new(big.Int).SetUint64(100), | ||
CensusURI: "https://example.com/census", | ||
CensusOrigin: 0, | ||
}, | ||
}) | ||
if err != nil { | ||
log.Fatal(err) | ||
} | ||
log.Infow("process created", "pid", pid.String(), "txHash", txHash.Hex()) | ||
|
||
select {} | ||
} |
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,120 @@ | ||
package web3 | ||
|
||
import ( | ||
"context" | ||
"crypto/ecdsa" | ||
"fmt" | ||
"math/big" | ||
"time" | ||
|
||
"github.com/ethereum/go-ethereum/accounts/abi/bind" | ||
"github.com/ethereum/go-ethereum/common" | ||
"github.com/ethereum/go-ethereum/crypto" | ||
bindings "github.com/vocdoni/contracts-z/golang-types" | ||
"github.com/vocdoni/vocdoni-z-sandbox/log" | ||
"github.com/vocdoni/vocdoni-z-sandbox/web3/rpc" | ||
) | ||
|
||
// Addresses contains the addresses of the contracts deployed in the network. | ||
type Addresses struct { | ||
OrganizationRegistry common.Address | ||
ProcessRegistry common.Address | ||
ResultsRegistry common.Address | ||
} | ||
|
||
// Contracts contains the bindings to the deployed contracts. | ||
type Contracts struct { | ||
ChainID uint64 | ||
organizations *bindings.OrganizationRegistry | ||
processes *bindings.ProcessRegistry | ||
web3pool *rpc.Web3Pool | ||
cli *rpc.Client | ||
privKey *ecdsa.PrivateKey | ||
address common.Address | ||
|
||
knownProcesses map[string]struct{} | ||
lastWatchBlock uint64 | ||
} | ||
|
||
// NewContracts creates a new Contracts instance with the given web3 endpoint. | ||
func NewContracts(addresses *Addresses, web3rpc string) (*Contracts, error) { | ||
w3pool := rpc.NewWeb3Pool() | ||
chainID, err := w3pool.AddEndpoint(web3rpc) | ||
if err != nil { | ||
return nil, fmt.Errorf("failed to add web3 endpoint: %w", err) | ||
} | ||
cli, err := w3pool.Client(chainID) | ||
if err != nil { | ||
return nil, fmt.Errorf("failed to get client: %w", err) | ||
} | ||
organizations, err := bindings.NewOrganizationRegistry(addresses.OrganizationRegistry, cli) | ||
if err != nil { | ||
return nil, fmt.Errorf("failed to bind organization registry: %w", err) | ||
} | ||
process, err := bindings.NewProcessRegistry(addresses.ProcessRegistry, cli) | ||
if err != nil { | ||
return nil, fmt.Errorf("failed to bind process registry: %w", err) | ||
} | ||
return &Contracts{ | ||
organizations: organizations, | ||
processes: process, | ||
ChainID: chainID, | ||
web3pool: w3pool, | ||
cli: cli, | ||
knownProcesses: make(map[string]struct{}), | ||
}, nil | ||
} | ||
|
||
// AddWeb3Endpoint adds a new web3 endpoint to the pool. | ||
func (c *Contracts) AddWeb3Endpoint(web3rpc string) error { | ||
_, err := c.web3pool.AddEndpoint(web3rpc) | ||
return err | ||
} | ||
|
||
// SetAccountPrivateKey sets the private key to be used for signing transactions. | ||
func (c *Contracts) SetAccountPrivateKey(hexPrivKey string) error { | ||
var err error | ||
c.privKey, err = crypto.HexToECDSA(hexPrivKey) | ||
if err != nil { | ||
return fmt.Errorf("failed to parse private key: %w", err) | ||
} | ||
c.address = crypto.PubkeyToAddress(c.privKey.PublicKey) | ||
return nil | ||
} | ||
|
||
// AccountAddress returns the address of the account used to sign transactions. | ||
func (c *Contracts) AccountAddress() common.Address { | ||
return c.address | ||
} | ||
|
||
// authTransactOpts helper method creates the transact options with the private | ||
// key configured in the CommunityHub. It sets the nonce, gas price, and gas | ||
// limit. If something goes wrong creating the signer, getting the nonce, or | ||
// getting the gas price, it returns an error. | ||
func (c *Contracts) authTransactOpts() (*bind.TransactOpts, error) { | ||
if c.privKey == nil { | ||
return nil, fmt.Errorf("no private key set") | ||
} | ||
bChainID := new(big.Int).SetUint64(c.ChainID) | ||
auth, err := bind.NewKeyedTransactorWithChainID(c.privKey, bChainID) | ||
if err != nil { | ||
return nil, fmt.Errorf("failed to create transactor: %w", err) | ||
} | ||
// create the context with a timeout | ||
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) | ||
defer cancel() | ||
// set the nonce | ||
log.Debugw("getting nonce", "address", c.address.Hex()) | ||
nonce, err := c.cli.PendingNonceAt(ctx, c.address) | ||
if err != nil { | ||
return nil, fmt.Errorf("failed to get nonce: %w", err) | ||
} | ||
auth.Nonce = new(big.Int).SetUint64(nonce) | ||
// set the gas tip cap | ||
if auth.GasTipCap, err = c.cli.SuggestGasTipCap(ctx); err != nil { | ||
return nil, fmt.Errorf("failed to get gas tip cap: %w", err) | ||
} | ||
// set the gas limit | ||
auth.GasLimit = 10000000 | ||
return auth, nil | ||
} |
Oops, something went wrong.