2020-11-12 14:18:30 +00:00
|
|
|
package ethclient
|
2020-08-03 20:01:38 +00:00
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
2021-04-14 21:04:21 +00:00
|
|
|
"crypto/ecdsa"
|
|
|
|
"fmt"
|
2020-08-03 20:01:38 +00:00
|
|
|
"math/big"
|
|
|
|
|
2021-04-14 21:04:21 +00:00
|
|
|
hdwallet "github.com/miguelmota/go-ethereum-hdwallet"
|
|
|
|
|
|
|
|
"github.com/Secured-Finance/dione/config"
|
|
|
|
|
2021-03-05 18:40:17 +00:00
|
|
|
"github.com/Secured-Finance/dione/contracts/dioneDispute"
|
2021-03-05 19:29:09 +00:00
|
|
|
"github.com/Secured-Finance/dione/contracts/dioneOracle"
|
2020-11-15 05:59:46 +00:00
|
|
|
"github.com/Secured-Finance/dione/contracts/dioneStaking"
|
2020-11-04 17:46:35 +00:00
|
|
|
stakingContract "github.com/Secured-Finance/dione/contracts/dioneStaking"
|
2020-08-06 18:48:57 +00:00
|
|
|
"github.com/ethereum/go-ethereum/accounts/abi/bind"
|
2020-08-03 20:01:38 +00:00
|
|
|
"github.com/ethereum/go-ethereum/common"
|
2020-08-04 18:19:42 +00:00
|
|
|
"github.com/ethereum/go-ethereum/crypto"
|
2020-08-03 20:01:38 +00:00
|
|
|
"github.com/ethereum/go-ethereum/ethclient"
|
2020-10-20 18:18:36 +00:00
|
|
|
"github.com/ethereum/go-ethereum/event"
|
2020-08-03 20:01:38 +00:00
|
|
|
)
|
|
|
|
|
2020-10-30 05:23:08 +00:00
|
|
|
// TODO: change artifacts for other contracts
|
2020-08-06 18:48:57 +00:00
|
|
|
type EthereumClient struct {
|
2021-03-05 18:40:17 +00:00
|
|
|
client *ethclient.Client
|
|
|
|
ethAddress *common.Address
|
|
|
|
authTransactor *bind.TransactOpts
|
|
|
|
dioneStaking *stakingContract.DioneStakingSession
|
|
|
|
disputeContract *dioneDispute.DioneDisputeSession
|
2021-03-05 19:29:09 +00:00
|
|
|
dioneOracle *dioneOracle.DioneOracleSession
|
2020-08-03 20:01:38 +00:00
|
|
|
}
|
|
|
|
|
2020-08-06 21:47:58 +00:00
|
|
|
type OracleEvent struct {
|
|
|
|
RequestType string
|
|
|
|
CallbackAddress common.Address
|
|
|
|
CallbackMethodID [4]byte
|
|
|
|
RequestID *big.Int
|
|
|
|
}
|
|
|
|
|
2020-08-06 18:48:57 +00:00
|
|
|
type Ethereum interface {
|
2020-10-20 18:18:36 +00:00
|
|
|
Initialize(ctx context.Context, url, connectionType, privateKey, oracleEmitterContractAddress, aggregatorContractAddress string) error
|
2020-08-04 18:19:42 +00:00
|
|
|
Balance(context.Context, string) (*big.Int, error)
|
2020-10-20 18:18:36 +00:00
|
|
|
SubmitRequestAnswer(reqID *big.Int, data string, callbackAddress common.Address, callbackMethodID [4]byte) error
|
2021-03-05 18:40:17 +00:00
|
|
|
BeginDispute(miner common.Address, requestID *big.Int) error
|
2021-03-05 19:29:09 +00:00
|
|
|
VoteDispute(dhash string, voteStatus bool) error
|
|
|
|
FinishDispute(dhash string) error
|
|
|
|
SubscribeOnNewDisputes(ctx context.Context) (chan *dioneDispute.DioneDisputeNewDispute, event.Subscription, error)
|
2020-08-03 20:01:38 +00:00
|
|
|
}
|
|
|
|
|
2020-08-06 18:48:57 +00:00
|
|
|
func NewEthereumClient() *EthereumClient {
|
2020-10-21 20:36:05 +00:00
|
|
|
ethereumClient := &EthereumClient{}
|
2020-08-06 18:48:57 +00:00
|
|
|
|
|
|
|
return ethereumClient
|
|
|
|
}
|
|
|
|
|
2021-04-14 21:04:21 +00:00
|
|
|
func (c *EthereumClient) Initialize(cfg *config.EthereumConfig) error {
|
|
|
|
client, err := ethclient.Dial(cfg.GatewayAddress)
|
2020-08-03 20:01:38 +00:00
|
|
|
if err != nil {
|
2020-10-20 18:18:36 +00:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
c.client = client
|
2021-04-14 21:04:21 +00:00
|
|
|
|
|
|
|
key, err := c.getPrivateKey(cfg)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
authTransactor, err := bind.NewKeyedTransactorWithChainID(key, big.NewInt(int64(cfg.ChainID)))
|
2020-10-20 18:18:36 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
c.authTransactor = authTransactor
|
2020-11-14 00:32:50 +00:00
|
|
|
c.ethAddress = &c.authTransactor.From
|
2020-10-20 18:18:36 +00:00
|
|
|
|
2021-04-14 21:04:21 +00:00
|
|
|
stakingContract, err := dioneStaking.NewDioneStaking(common.HexToAddress(cfg.DioneStakingContractAddress), client)
|
2020-10-20 18:18:36 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2021-04-14 21:04:21 +00:00
|
|
|
oracleContract, err := dioneOracle.NewDioneOracle(common.HexToAddress(cfg.DioneOracleContractAddress), client)
|
2020-11-15 05:59:46 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2021-04-14 21:04:21 +00:00
|
|
|
disputeContract, err := dioneDispute.NewDioneDispute(common.HexToAddress(cfg.DisputeContractAddress), client)
|
2021-03-05 18:40:17 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2021-03-05 19:29:09 +00:00
|
|
|
c.dioneStaking = &dioneStaking.DioneStakingSession{
|
|
|
|
Contract: stakingContract,
|
2020-10-20 18:18:36 +00:00
|
|
|
CallOpts: bind.CallOpts{
|
|
|
|
Pending: true,
|
|
|
|
From: authTransactor.From,
|
|
|
|
Context: context.Background(),
|
|
|
|
},
|
|
|
|
TransactOpts: bind.TransactOpts{
|
|
|
|
From: authTransactor.From,
|
|
|
|
Signer: authTransactor.Signer,
|
2021-03-05 19:29:09 +00:00
|
|
|
GasLimit: 0, // 0 automatically estimates gas limit
|
|
|
|
GasPrice: nil, // nil automatically suggests gas price
|
2020-10-20 18:18:36 +00:00
|
|
|
Context: context.Background(),
|
|
|
|
},
|
|
|
|
}
|
2021-03-05 19:29:09 +00:00
|
|
|
c.disputeContract = &dioneDispute.DioneDisputeSession{
|
|
|
|
Contract: disputeContract,
|
2020-11-15 05:59:46 +00:00
|
|
|
CallOpts: bind.CallOpts{
|
|
|
|
Pending: true,
|
|
|
|
From: authTransactor.From,
|
|
|
|
Context: context.Background(),
|
|
|
|
},
|
|
|
|
TransactOpts: bind.TransactOpts{
|
|
|
|
From: authTransactor.From,
|
|
|
|
Signer: authTransactor.Signer,
|
2021-03-05 19:29:09 +00:00
|
|
|
GasLimit: 0, // 0 automatically estimates gas limit
|
|
|
|
GasPrice: nil, // nil automatically suggests gas price
|
2020-11-15 05:59:46 +00:00
|
|
|
Context: context.Background(),
|
|
|
|
},
|
|
|
|
}
|
2021-03-05 19:29:09 +00:00
|
|
|
c.dioneOracle = &dioneOracle.DioneOracleSession{
|
|
|
|
Contract: oracleContract,
|
2021-03-05 18:40:17 +00:00
|
|
|
CallOpts: bind.CallOpts{
|
|
|
|
Pending: true,
|
|
|
|
From: authTransactor.From,
|
|
|
|
Context: context.Background(),
|
|
|
|
},
|
|
|
|
TransactOpts: bind.TransactOpts{
|
|
|
|
From: authTransactor.From,
|
|
|
|
Signer: authTransactor.Signer,
|
|
|
|
GasLimit: 0, // 0 automatically estimates gas limit
|
|
|
|
GasPrice: nil, // nil automatically suggests gas price
|
|
|
|
Context: context.Background(),
|
|
|
|
},
|
|
|
|
}
|
2020-10-20 18:18:36 +00:00
|
|
|
return nil
|
2020-08-03 20:01:38 +00:00
|
|
|
}
|
|
|
|
|
2021-04-14 21:04:21 +00:00
|
|
|
func (c *EthereumClient) getPrivateKey(cfg *config.EthereumConfig) (*ecdsa.PrivateKey, error) {
|
|
|
|
if cfg.PrivateKey != "" {
|
|
|
|
key, err := crypto.HexToECDSA(cfg.PrivateKey)
|
|
|
|
return key, err
|
|
|
|
}
|
|
|
|
|
|
|
|
if cfg.MnemonicPhrase != "" {
|
|
|
|
wallet, err := hdwallet.NewFromMnemonic(cfg.MnemonicPhrase)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
path := hdwallet.DefaultBaseDerivationPath
|
|
|
|
|
|
|
|
if cfg.HDDerivationPath != "" {
|
|
|
|
parsedPath, err := hdwallet.ParseDerivationPath(cfg.HDDerivationPath)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
path = parsedPath
|
|
|
|
}
|
|
|
|
|
|
|
|
account, err := wallet.Derive(path, true)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
key, err := wallet.PrivateKey(account)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
return key, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil, fmt.Errorf("private key or mnemonic phrase isn't specified")
|
|
|
|
}
|
|
|
|
|
2020-11-14 00:32:50 +00:00
|
|
|
func (c *EthereumClient) GetEthAddress() *common.Address {
|
|
|
|
return c.ethAddress
|
|
|
|
}
|
|
|
|
|
2021-03-05 19:29:09 +00:00
|
|
|
func (c *EthereumClient) SubscribeOnOracleEvents(ctx context.Context) (chan *dioneOracle.DioneOracleNewOracleRequest, event.Subscription, error) {
|
|
|
|
resChan := make(chan *dioneOracle.DioneOracleNewOracleRequest)
|
|
|
|
requestsFilter := c.dioneOracle.Contract.DioneOracleFilterer
|
2020-10-20 18:18:36 +00:00
|
|
|
subscription, err := requestsFilter.WatchNewOracleRequest(&bind.WatchOpts{
|
|
|
|
Start: nil, //last block
|
2020-11-15 05:59:46 +00:00
|
|
|
Context: ctx,
|
2020-11-14 10:00:19 +00:00
|
|
|
}, resChan)
|
2020-08-03 20:01:38 +00:00
|
|
|
if err != nil {
|
2020-11-14 10:00:19 +00:00
|
|
|
return nil, nil, err
|
2020-08-03 20:01:38 +00:00
|
|
|
}
|
2020-11-14 10:00:19 +00:00
|
|
|
return resChan, subscription, err
|
2020-08-03 20:01:38 +00:00
|
|
|
}
|
|
|
|
|
2021-04-15 21:01:27 +00:00
|
|
|
func (c *EthereumClient) SubmitRequestAnswer(reqID *big.Int, callbackAddress common.Address, callbackMethodID [4]byte, requestParams string, requestDeadline *big.Int, data []byte) error {
|
|
|
|
_, err := c.dioneOracle.SubmitOracleRequest(requestParams, callbackAddress, callbackMethodID, reqID, requestDeadline, data)
|
2020-08-03 20:01:38 +00:00
|
|
|
if err != nil {
|
2020-10-20 18:18:36 +00:00
|
|
|
return err
|
2020-08-03 20:01:38 +00:00
|
|
|
}
|
|
|
|
|
2020-10-20 18:18:36 +00:00
|
|
|
return nil
|
2020-08-06 18:48:57 +00:00
|
|
|
}
|
2021-03-05 18:40:17 +00:00
|
|
|
|
|
|
|
func (c *EthereumClient) BeginDispute(miner common.Address, requestID *big.Int) error {
|
|
|
|
_, err := c.disputeContract.BeginDispute(miner, requestID)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2021-03-15 20:39:52 +00:00
|
|
|
func (c *EthereumClient) VoteDispute(dhash [32]byte, voteStatus bool) error {
|
|
|
|
_, err := c.disputeContract.Vote(dhash, voteStatus)
|
2021-03-05 18:40:17 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2021-03-15 20:39:52 +00:00
|
|
|
func (c *EthereumClient) FinishDispute(dhash [32]byte) error {
|
|
|
|
_, err := c.disputeContract.FinishDispute(dhash)
|
2021-03-05 18:40:17 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *EthereumClient) SubscribeOnNewDisputes(ctx context.Context) (chan *dioneDispute.DioneDisputeNewDispute, event.Subscription, error) {
|
|
|
|
resChan := make(chan *dioneDispute.DioneDisputeNewDispute)
|
|
|
|
requestsFilter := c.disputeContract.Contract.DioneDisputeFilterer
|
|
|
|
subscription, err := requestsFilter.WatchNewDispute(&bind.WatchOpts{
|
|
|
|
Start: nil, //last block
|
|
|
|
Context: ctx,
|
|
|
|
}, resChan, nil, nil)
|
|
|
|
if err != nil {
|
|
|
|
return nil, nil, err
|
|
|
|
}
|
|
|
|
return resChan, subscription, err
|
|
|
|
}
|
2021-03-05 19:29:09 +00:00
|
|
|
|
|
|
|
func (c *EthereumClient) SubscribeOnNewSubmittions(ctx context.Context) (chan *dioneOracle.DioneOracleSubmittedOracleRequest, event.Subscription, error) {
|
|
|
|
resChan := make(chan *dioneOracle.DioneOracleSubmittedOracleRequest)
|
|
|
|
requestsFilter := c.dioneOracle.Contract.DioneOracleFilterer
|
|
|
|
subscription, err := requestsFilter.WatchSubmittedOracleRequest(&bind.WatchOpts{
|
2021-03-15 20:39:52 +00:00
|
|
|
Start: nil, // last block
|
2021-03-05 19:29:09 +00:00
|
|
|
Context: ctx,
|
|
|
|
}, resChan)
|
|
|
|
if err != nil {
|
|
|
|
return nil, nil, err
|
|
|
|
}
|
|
|
|
return resChan, subscription, err
|
|
|
|
}
|