diff --git a/.env.example b/.env.example index 5fba10d..d886542 100644 --- a/.env.example +++ b/.env.example @@ -1,16 +1,18 @@ -PACTUS_NODES=bootstrap1.pactus.org:50051,bootstrap2.pactus.org:50051,bootstrap3.pactus.org:50051,bootstrap4.pactus.org:50051,151.115.110.114:50051,188.121.116.247:50051", -PACTUS_BRIDGE_ADDRESS= +# Enviroment +ENVIROMENT=(dev | prod) -Fee= -DB_PATH= +# Pactus -TELEGRAM_BOT_TOKEN= -TELEGRAM_CHAT_ID= +# Wrapto Lock Address +PACTUS_WALLET_ADDRESS= +PACTUS_WALLET_PASSWORD= +PACTUS_WALLET_PATH= +PACTUS_RPC= +# Polygon +POLYGON_PRIVATE_KEY= POLYGON_CONTRACT_ADDRESS= POLYGON_RPC= -POLYGON_PRIVATE_KEY= -WALLET_PATH= -WALLET_ADDRESS= -WALLET_PASSWORD= \ No newline at end of file +# Database +DATABASE_PATH= diff --git a/config/config.go b/config/config.go new file mode 100644 index 0000000..eb52777 --- /dev/null +++ b/config/config.go @@ -0,0 +1,71 @@ +package config + +import ( + "os" + + "github.com/joho/godotenv" +) + +type Config struct { + Environment string + Pactus PactusConfig + Polygon PolygonConfig + Database DatabaseConfig +} + +type PactusConfig struct { + WalletPath string + WalletPass string + LockAddr string + RPCNode string +} + +type PolygonConfig struct { + PrivateKey string + ContractAddr string + RPCNode string +} + +type DatabaseConfig struct { + Path string +} + +func LoadConfig() (*Config, error) { + if err := godotenv.Load(); err != nil { + return nil, err + } + + cfg := &Config{ + Environment: os.Getenv("NETWORK"), + Pactus: PactusConfig{ + WalletPath: os.Getenv("PACTUS_WALLET_PATH"), + WalletPass: os.Getenv("PACTUS_WALLET_PASSWORD"), + LockAddr: os.Getenv("PACTUS_WALLET_ADDRESS"), + RPCNode: os.Getenv("PACTUS_RPC"), + }, + Polygon: PolygonConfig{ + PrivateKey: os.Getenv("POLYGON_PRIVATE_KEY"), + ContractAddr: os.Getenv("POLYGON_CONTRACT_ADDRESS"), + RPCNode: os.Getenv("POLYGON_RPC"), + }, + Database: DatabaseConfig{ + os.Getenv("DATABASE_PATH"), + }, + } + + if err := cfg.basicCheck(); err != nil { + return nil, err + } + + return cfg, nil +} + +func (c *Config) basicCheck() error { + if !(c.Environment == "dev") || !(c.Environment == "prod") { + return InvalidEnvironmentError{ + Environment: c.Environment, + } + } + + return nil +} diff --git a/config/erros.go b/config/erros.go new file mode 100644 index 0000000..e99f385 --- /dev/null +++ b/config/erros.go @@ -0,0 +1,11 @@ +package config + +import "fmt" + +type InvalidEnvironmentError struct { + Environment string +} + +func (e InvalidEnvironmentError) Error() string { + return fmt.Sprintf("environment can be `dev` or `prod` not: %s", e.Environment) +} diff --git a/go.mod b/go.mod index f98dcd7..e8c6636 100644 --- a/go.mod +++ b/go.mod @@ -45,6 +45,7 @@ require ( github.com/holiman/uint256 v1.2.4 // indirect github.com/jinzhu/inflection v1.0.0 // indirect github.com/jinzhu/now v1.1.5 // indirect + github.com/joho/godotenv v1.5.1 github.com/kilic/bls12-381 v0.1.0 // indirect github.com/matoous/go-nanoid v1.5.0 github.com/mattn/go-isatty v0.0.20 // indirect diff --git a/go.sum b/go.sum index 6848220..180bb85 100644 --- a/go.sum +++ b/go.sum @@ -170,6 +170,8 @@ github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ= github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= +github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0= +github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= github.com/kilic/bls12-381 v0.1.0 h1:encrdjqKMEvabVQ7qYOKu1OvhqpK4s47wDYtNiPtlp4= github.com/kilic/bls12-381 v0.1.0/go.mod h1:vDTTHJONJ6G+P2R74EhnyotQDTliQDnFEwhdmfzw1ig= github.com/klauspost/compress v1.17.2 h1:RlWWUY/Dr4fL8qk9YG7DTZ7PDgME2V4csBXA8L/ixi4= diff --git a/sides/manager/manager.go b/sides/manager/manager.go index a6bb677..455b11d 100644 --- a/sides/manager/manager.go +++ b/sides/manager/manager.go @@ -8,28 +8,28 @@ import ( ) type Mgr struct { - Ctx context.Context - Highway chan message.Message - Bypasses map[bypass.Name]chan message.Message + ctx context.Context + highway chan message.Message + bypasses map[bypass.Name]chan message.Message } func NewManager(ctx context.Context) *Mgr { return &Mgr{ - Ctx: ctx, - Highway: make(chan message.Message, 10), // TODO: cap - Bypasses: make(map[bypass.Name]chan message.Message, 10), // TODO: cap + ctx: ctx, + highway: make(chan message.Message, 10), // TODO: what should we use as size? + bypasses: make(map[bypass.Name]chan message.Message, 10), // TODO: what should we use as size? } } func (m *Mgr) Start() { for { select { - case msg := <-m.Highway: + case msg := <-m.highway: err := m.routing(msg) if err != nil { continue } - case <-m.Ctx.Done(): + case <-m.ctx.Done(): return } } @@ -38,7 +38,7 @@ func (m *Mgr) Start() { func (m *Mgr) RegisterBypass(name bypass.Name, b chan message.Message) error { _, ok := m.isRegistered(name) if !ok { - m.Bypasses[name] = b + m.bypasses[name] = b return nil } @@ -57,7 +57,7 @@ func (m *Mgr) routing(msg message.Message) error { } func (m *Mgr) isRegistered(name bypass.Name) (chan message.Message, bool) { - v, ok := m.Bypasses[name] + v, ok := m.bypasses[name] return v, ok } diff --git a/sides/pactus/bridge.go b/sides/pactus/bridge.go index 8317de1..2236990 100644 --- a/sides/pactus/bridge.go +++ b/sides/pactus/bridge.go @@ -14,7 +14,7 @@ type Bridge struct { bypass chan message.Message } -func NewBridge(w *Wallet, b chan message.Message, bn bypass.Name) Bridge { +func newBridge(w *Wallet, b chan message.Message, bn bypass.Name) Bridge { return Bridge{ wallet: w, bypass: b, diff --git a/sides/pactus/client.go b/sides/pactus/client.go index ea4276b..2069686 100644 --- a/sides/pactus/client.go +++ b/sides/pactus/client.go @@ -16,7 +16,7 @@ type Client struct { ctx context.Context } -func NewClient(c context.Context, endpoint string) (*Client, error) { +func newClient(c context.Context, endpoint string) (*Client, error) { conn, err := grpc.Dial(endpoint, grpc.WithTransportCredentials(insecure.NewCredentials())) if err != nil { diff --git a/sides/pactus/listener.go b/sides/pactus/listener.go index edffd78..e485926 100644 --- a/sides/pactus/listener.go +++ b/sides/pactus/listener.go @@ -15,18 +15,21 @@ type Listener struct { nextBlock uint32 bypass bypass.Name highway chan message.Message + lockAddr string ctx context.Context } -func NewListener(ctx context.Context, - client *Client, bp bypass.Name, highway chan message.Message, startBlock uint32, +func newListener(ctx context.Context, + client *Client, bp bypass.Name, highway chan message.Message, + startBlock uint32, lockAddr string, ) *Listener { return &Listener{ client: client, bypass: bp, highway: highway, nextBlock: startBlock, + lockAddr: lockAddr, ctx: ctx, } @@ -63,7 +66,7 @@ func (l *Listener) ProcessBlocks() error { return err // TODO: handle errors from client } - validTxs := filterValidTxs(blk.Txs) + validTxs := l.filterValidTxs(blk.Txs) for _, tx := range validTxs { dest, err := parseMemo(tx.Memo) @@ -101,13 +104,12 @@ func (l *Listener) isEligibleBlock(h uint32) (bool, error) { return h < lst, nil } -func filterValidTxs(txs []*pactus.TransactionInfo) []*pactus.TransactionInfo { +func (l *Listener) filterValidTxs(txs []*pactus.TransactionInfo) []*pactus.TransactionInfo { validTxs := make([]*pactus.TransactionInfo, 0) for _, tx := range txs { - // TODO:read LOCKED ADDRESS from config if tx.PayloadType != pactus.PayloadType_TRANSFER_PAYLOAD && - tx.GetTransfer().Receiver != "LOCKED_ADDRESS" { + tx.GetTransfer().Receiver != l.lockAddr { continue } diff --git a/sides/pactus/pactus.go b/sides/pactus/pactus.go index 2ed2db4..5b837c2 100644 --- a/sides/pactus/pactus.go +++ b/sides/pactus/pactus.go @@ -3,8 +3,10 @@ package pactus import ( "context" + "github.com/PACZone/wrapto/config" "github.com/PACZone/wrapto/types/bypass" "github.com/PACZone/wrapto/types/message" + "github.com/pactus-project/pactus/crypto" ) type Side struct { @@ -17,16 +19,25 @@ type Side struct { } func NewSide(ctx context.Context, - highway chan message.Message, startBlock uint32, w *Wallet, b chan message.Message, + highway chan message.Message, startBlock uint32, + b chan message.Message, env string, cfg config.PactusConfig, ) (*Side, error) { - client, err := NewClient(ctx, "") // TODO:read rpc url from config + if env == "dev" { + crypto.AddressHRP = "tpc" + } + + client, err := newClient(ctx, cfg.RPCNode) if err != nil { return nil, err } - listener := NewListener(ctx, client, bypass.PACTUS, highway, startBlock) + wallet, err := openWallet(cfg.WalletPath, cfg.LockAddr, cfg.RPCNode, cfg.WalletPass) + if err != nil { + return nil, err + } - bridge := NewBridge(w, b, bypass.PACTUS) + listener := newListener(ctx, client, bypass.PACTUS, highway, startBlock, cfg.LockAddr) + bridge := newBridge(wallet, b, bypass.PACTUS) return &Side{ client: client, diff --git a/sides/pactus/wallet.go b/sides/pactus/wallet.go index e26deda..d36f4ab 100644 --- a/sides/pactus/wallet.go +++ b/sides/pactus/wallet.go @@ -14,7 +14,7 @@ type Wallet struct { wallet pWallet.Wallet } -func Open(path, addr, rpcURL, pass string) (*Wallet, error) { +func openWallet(path, addr, rpcURL, pass string) (*Wallet, error) { if !doesWalletExist(path) { return nil, WalletNotExistError{ path: path, diff --git a/sides/polygon/bridge.go b/sides/polygon/bridge.go index 50588eb..cf0dc9a 100644 --- a/sides/polygon/bridge.go +++ b/sides/polygon/bridge.go @@ -14,9 +14,9 @@ type Bridge struct { bypass chan message.Message } -func NewBridge(b chan message.Message, bn bypass.Name, c *Client) Bridge { +func newBridge(bp chan message.Message, bn bypass.Name, c *Client) Bridge { return Bridge{ - bypass: b, + bypass: bp, bypassName: bn, client: c, } diff --git a/sides/polygon/client.go b/sides/polygon/client.go index 5d504d3..29ad676 100644 --- a/sides/polygon/client.go +++ b/sides/polygon/client.go @@ -25,7 +25,7 @@ type BridgeOrder struct { Fee *big.Int } -func NewClient(rpcURL, pk, cAddr string, chainID int64) (*Client, error) { +func newClient(rpcURL, pk, cAddr string, chainID int64) (*Client, error) { client, err := ethclient.Dial(rpcURL) if err != nil { return nil, err diff --git a/sides/polygon/listener.go b/sides/polygon/listener.go index ce0d68c..df6df69 100644 --- a/sides/polygon/listener.go +++ b/sides/polygon/listener.go @@ -22,7 +22,7 @@ type Listener struct { ctx context.Context } -func NewListener(ctx context.Context, +func newListener(ctx context.Context, client *Client, bp bypass.Name, highway chan message.Message, startOrder uint32, ) *Listener { return &Listener{ @@ -51,11 +51,12 @@ func (l *Listener) Start() { func (l *Listener) ProcessOrder() error { o, err := l.client.Get(*big.NewInt(int64(l.nextOrder))) if err != nil { - return nil + return err } if o.Sender == common.HexToAddress("0x0000000000000000000000000000000000000000") { <-time.After(20 * time.Second) + return nil } diff --git a/sides/polygon/polygon.go b/sides/polygon/polygon.go index 5a19856..0faff31 100644 --- a/sides/polygon/polygon.go +++ b/sides/polygon/polygon.go @@ -3,30 +3,48 @@ package polygon import ( "context" + "github.com/PACZone/wrapto/config" "github.com/PACZone/wrapto/types/bypass" "github.com/PACZone/wrapto/types/message" ) +const ( + mainChainID int64 = 137 + mumbaiChainID int64 = 80001 +) + type Side struct { client *Client listener *Listener + bridge Bridge highway chan message.Message + bypass chan message.Message ctx context.Context } -func NewSide(ctx context.Context, highway chan message.Message, startOrder uint32, b chan message.Message, rpcURL, pk, cAddr string, chainID int64) (*Side, error) { - client, err := NewClient(rpcURL, pk, cAddr, chainID) +func NewSide(ctx context.Context, highway chan message.Message, startOrder uint32, + bp chan message.Message, env string, cfg config.PolygonConfig, +) (*Side, error) { + chainID := mainChainID + if env == "dev" { + chainID = mumbaiChainID + } + + client, err := newClient(cfg.RPCNode, cfg.PrivateKey, cfg.ContractAddr, chainID) if err != nil { return nil, err } - listener := NewListener(ctx, client, bypass.POLYGON, highway, startOrder) + listener := newListener(ctx, client, bypass.POLYGON, highway, startOrder) + bridge := newBridge(bp, bypass.POLYGON, client) return &Side{ client: client, listener: listener, + bridge: bridge, highway: highway, + bypass: bp, ctx: ctx, }, nil