feat: cbridge integration

This commit is contained in:
Anthony Laibe 2022-11-22 14:49:29 +01:00 committed by Anthony Laibe
parent d43e06f4c2
commit 99ff0a18b0
15 changed files with 7113 additions and 8 deletions

File diff suppressed because one or more lines are too long

4648
contracts/celer/bridge.go Normal file

File diff suppressed because one or more lines are too long

3
contracts/celer/doc.go Normal file
View File

@ -0,0 +1,3 @@
package celer
//go:generate abigen --abi bridge.abi --pkg celer --out bridge.go

View File

@ -3,6 +3,10 @@ package bridge
import ( import (
"math/big" "math/big"
ethTypes "github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/common"
"github.com/status-im/status-go/account" "github.com/status-im/status-go/account"
"github.com/status-im/status-go/eth-node/types" "github.com/status-im/status-go/eth-node/types"
"github.com/status-im/status-go/params" "github.com/status-im/status-go/params"
@ -10,11 +14,19 @@ import (
"github.com/status-im/status-go/transactions" "github.com/status-im/status-go/transactions"
) )
func getSigner(chainID uint64, from types.Address, verifiedAccount *account.SelectedExtKey) bind.SignerFn {
return func(addr common.Address, tx *ethTypes.Transaction) (*ethTypes.Transaction, error) {
s := ethTypes.NewLondonSigner(new(big.Int).SetUint64(chainID))
return ethTypes.SignTx(tx, s, verifiedAccount.AccountKey.PrivateKey)
}
}
type TransactionBridge struct { type TransactionBridge struct {
BridgeName string BridgeName string
ChainID uint64 ChainID uint64
SimpleTx *transactions.SendTxArgs SimpleTx *transactions.SendTxArgs
HopTx *HopTxArgs HopTx *HopTxArgs
CbridgeTx *CBridgeTxArgs
} }
func (t *TransactionBridge) Value() *big.Int { func (t *TransactionBridge) Value() *big.Int {
@ -22,6 +34,8 @@ func (t *TransactionBridge) Value() *big.Int {
return t.SimpleTx.Value.ToInt() return t.SimpleTx.Value.ToInt()
} else if t.HopTx != nil { } else if t.HopTx != nil {
return t.HopTx.Amount.ToInt() return t.HopTx.Amount.ToInt()
} else if t.CbridgeTx != nil {
return t.CbridgeTx.Amount.ToInt()
} }
return big.NewInt(0) return big.NewInt(0)
@ -32,6 +46,8 @@ func (t *TransactionBridge) From() types.Address {
return t.SimpleTx.From return t.SimpleTx.From
} else if t.HopTx != nil { } else if t.HopTx != nil {
return t.HopTx.From return t.HopTx.From
} else if t.CbridgeTx != nil {
return t.CbridgeTx.From
} }
return types.HexToAddress("0x0") return types.HexToAddress("0x0")
@ -42,6 +58,8 @@ func (t *TransactionBridge) To() types.Address {
return *t.SimpleTx.To return *t.SimpleTx.To
} else if t.HopTx != nil { } else if t.HopTx != nil {
return types.Address(t.HopTx.Recipient) return types.Address(t.HopTx.Recipient)
} else if t.CbridgeTx != nil {
return types.Address(t.HopTx.Recipient)
} }
return types.HexToAddress("0x0") return types.HexToAddress("0x0")
@ -52,6 +70,8 @@ func (t *TransactionBridge) Data() types.HexBytes {
return t.SimpleTx.Data return t.SimpleTx.Data
} else if t.HopTx != nil { } else if t.HopTx != nil {
return types.HexBytes("") return types.HexBytes("")
} else if t.CbridgeTx != nil {
return types.HexBytes("")
} }
return types.HexBytes("") return types.HexBytes("")

View File

@ -0,0 +1,295 @@
package bridge
import (
"encoding/json"
"errors"
"fmt"
"io/ioutil"
"math/big"
"net/http"
"time"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
ethTypes "github.com/ethereum/go-ethereum/core/types"
"github.com/status-im/status-go/account"
"github.com/status-im/status-go/contracts/celer"
"github.com/status-im/status-go/eth-node/types"
"github.com/status-im/status-go/rpc"
"github.com/status-im/status-go/params"
"github.com/status-im/status-go/services/wallet/bridge/cbridge"
"github.com/status-im/status-go/services/wallet/token"
"github.com/status-im/status-go/transactions"
)
const baseURL = "https://cbridge-prod2.celer.app"
const testBaseURL = "https://cbridge-v2-test.celer.network"
type CBridgeTxArgs struct {
transactions.SendTxArgs
ChainID uint64 `json:"chainId"`
Symbol string `json:"symbol"`
Recipient common.Address `json:"recipient"`
Amount *hexutil.Big `json:"amount"`
}
type CBridge struct {
rpcClient *rpc.Client
tokenManager *token.Manager
prodTransferConfig *cbridge.GetTransferConfigsResponse
testTransferConfig *cbridge.GetTransferConfigsResponse
}
func NewCbridge(rpcClient *rpc.Client, tokenManager *token.Manager) *CBridge {
return &CBridge{
rpcClient: rpcClient,
tokenManager: tokenManager,
}
}
func (s *CBridge) Name() string {
return "CBridge"
}
func (s *CBridge) estimateAmt(from, to *params.Network, amountIn *big.Int, symbol string) (*cbridge.EstimateAmtResponse, error) {
client := &http.Client{
Timeout: time.Second * 5,
}
base := baseURL
if from.IsTest {
base = testBaseURL
}
url := fmt.Sprintf(
"%s/v2/estimateAmt?src_chain_id=%d&dst_chain_id=%d&token_symbol=%s&amt=%s&usr_addr=0xaa47c83316edc05cf9ff7136296b026c5de7eccd&slippage_tolerance=500",
base,
from.ChainID,
to.ChainID,
symbol,
amountIn.String(),
)
req, err := http.NewRequest(http.MethodGet, url, nil)
if err != nil {
return nil, err
}
resp, err := client.Do(req)
if err != nil {
return nil, err
}
defer func() {
if err := resp.Body.Close(); err != nil {
fmt.Println("failed to close cbridge request body", "err", err)
}
}()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
return nil, err
}
var res cbridge.EstimateAmtResponse
err = json.Unmarshal(body, &res)
if err != nil {
return nil, err
}
return &res, nil
}
func (s *CBridge) getTransferConfig(isTest bool) (*cbridge.GetTransferConfigsResponse, error) {
if !isTest && s.prodTransferConfig != nil {
return s.prodTransferConfig, nil
}
if isTest && s.testTransferConfig != nil {
return s.testTransferConfig, nil
}
client := &http.Client{
Timeout: time.Second * 5,
}
base := baseURL
if isTest {
base = testBaseURL
}
url := fmt.Sprintf("%s/v2/getTransferConfigs", base)
req, err := http.NewRequest(http.MethodGet, url, nil)
if err != nil {
return nil, err
}
resp, err := client.Do(req)
if err != nil {
return nil, err
}
defer func() {
if err := resp.Body.Close(); err != nil {
fmt.Println("failed to close cbridge request body", "err", err)
}
}()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
return nil, err
}
var res cbridge.GetTransferConfigsResponse
err = json.Unmarshal(body, &res)
if err != nil {
return nil, err
}
if isTest {
s.testTransferConfig = &res
} else {
s.prodTransferConfig = &res
}
return &res, nil
}
func (s *CBridge) Can(from, to *params.Network, token *token.Token, balance *big.Int) (bool, error) {
if from.ChainID == to.ChainID {
return false, nil
}
transferConfig, err := s.getTransferConfig(from.IsTest)
if err != nil {
return false, err
}
if transferConfig.Err != nil {
return false, errors.New(transferConfig.Err.Msg)
}
var fromAvailable *cbridge.Chain
var toAvailable *cbridge.Chain
for _, chain := range transferConfig.Chains {
if uint64(chain.GetId()) == from.ChainID {
fromAvailable = chain
}
if uint64(chain.GetId()) == to.ChainID {
toAvailable = chain
}
}
if fromAvailable == nil || toAvailable == nil {
return false, nil
}
found := false
for _, tokenInfo := range transferConfig.ChainToken[fromAvailable.GetId()].Token {
if tokenInfo.Token.Symbol == token.Symbol {
found = true
break
}
}
if !found {
return false, nil
}
found = false
for _, tokenInfo := range transferConfig.ChainToken[toAvailable.GetId()].Token {
if tokenInfo.Token.Symbol == token.Symbol {
found = true
break
}
}
if !found {
return false, nil
}
return true, nil
}
func (s *CBridge) CalculateFees(from, to *params.Network, token *token.Token, amountIn *big.Int, nativeTokenPrice, tokenPrice float64, gasPrice *big.Float) (*big.Int, *big.Int, error) {
amt, err := s.estimateAmt(from, to, amountIn, token.Symbol)
if err != nil {
return nil, nil, err
}
baseFee, _ := new(big.Int).SetString(amt.BaseFee, 10)
percFee, _ := new(big.Int).SetString(amt.PercFee, 10)
return big.NewInt(0), new(big.Int).Add(baseFee, percFee), nil
}
func (s *CBridge) EstimateGas(from, to *params.Network, token *token.Token, amountIn *big.Int) (uint64, error) {
// TODO: replace by estimate function
if token.IsNative() {
return 22000, nil // default gas limit for eth transaction
}
return 200000, nil //default gas limit for erc20 transaction
}
func (s *CBridge) Send(sendArgs *TransactionBridge, verifiedAccount *account.SelectedExtKey) (types.Hash, error) {
fromNetwork := s.rpcClient.NetworkManager.Find(sendArgs.ChainID)
if fromNetwork == nil {
return types.HexToHash(""), errors.New("network not found")
}
tk := s.tokenManager.FindToken(fromNetwork, sendArgs.CbridgeTx.Symbol)
if tk == nil {
return types.HexToHash(""), errors.New("token not found")
}
transferConfig, err := s.getTransferConfig(fromNetwork.IsTest)
if err != nil {
return types.HexToHash(""), err
}
if transferConfig.Err != nil {
return types.HexToHash(""), errors.New(transferConfig.Err.Msg)
}
addrs := ""
for _, chain := range transferConfig.Chains {
if uint64(chain.Id) == sendArgs.ChainID {
addrs = chain.ContractAddr
break
}
}
backend, err := s.rpcClient.EthClient(sendArgs.ChainID)
if err != nil {
return types.HexToHash(""), err
}
contract, err := celer.NewCeler(common.HexToAddress(addrs), backend)
if err != nil {
return types.HexToHash(""), err
}
txOpts := sendArgs.CbridgeTx.ToTransactOpts(getSigner(sendArgs.ChainID, sendArgs.CbridgeTx.From, verifiedAccount))
var tx *ethTypes.Transaction
if tk.IsNative() {
tx, err = contract.SendNative(
txOpts,
sendArgs.CbridgeTx.Recipient,
(*big.Int)(sendArgs.CbridgeTx.Amount),
sendArgs.CbridgeTx.ChainID,
uint64(time.Now().UnixMilli()),
500,
)
} else {
tx, err = contract.Send(
txOpts,
sendArgs.CbridgeTx.Recipient,
tk.Address,
(*big.Int)(sendArgs.CbridgeTx.Amount),
sendArgs.CbridgeTx.ChainID,
uint64(time.Now().UnixMilli()),
500,
)
}
if err != nil {
return types.HexToHash(""), err
}
return types.Hash(tx.Hash()), nil
}
func (s *CBridge) CalculateAmountOut(from, to *params.Network, amountIn *big.Int, symbol string) (*big.Int, error) {
amt, err := s.estimateAmt(from, to, amountIn, symbol)
if err != nil {
return nil, err
}
if amt.Err != nil {
return nil, err
}
amountOut, _ := new(big.Int).SetString(amt.EqValueTokenAmt, 10)
return amountOut, nil
}

View File

@ -0,0 +1,118 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// source: cbridge.proto
package cbridge
import (
fmt "fmt"
proto "github.com/golang/protobuf/proto"
math "math"
)
// Reference imports to suppress errors if they are not otherwise used.
var _ = proto.Marshal
var _ = fmt.Errorf
var _ = math.Inf
// This is a compile-time assertion to ensure that this generated file
// is compatible with the proto package it is being compiled against.
// A compilation error at this line likely means your copy of the
// proto package needs to be updated.
const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package
// ========== x/cbridge kv value types
// for src transfer id
// normal status flow: after sgn applied user's Send event, status is OK_TO_RELAY. then after apply Relay event
// status is SUCCESS
// can't relay flow: after apply send, status will be BAD_xxx, and there'll be no relay. so user need to InitWithdraw, status becomes
// refund_requested when sgn apply withdrawDone event, status becomes REFUND_DONE
type XferStatus int32
const (
XferStatus_UNKNOWN XferStatus = 0
// normal flow only has ok then success
XferStatus_OK_TO_RELAY XferStatus = 1
XferStatus_SUCCESS XferStatus = 2
// can't relay flow status
XferStatus_BAD_LIQUIDITY XferStatus = 3
XferStatus_BAD_SLIPPAGE XferStatus = 4
XferStatus_BAD_TOKEN XferStatus = 5
// refund, using withdraw flow
XferStatus_REFUND_REQUESTED XferStatus = 6
XferStatus_REFUND_DONE XferStatus = 7
XferStatus_BAD_XFER_DISABLED XferStatus = 8
// come, we should go to refund flow.
XferStatus_BAD_DEST_CHAIN XferStatus = 9
XferStatus_EXCEED_MAX_OUT_AMOUNT XferStatus = 10
XferStatus_XFER_DELAYED XferStatus = 11
// delayThreshold
XferStatus_BAD_ADDRESS XferStatus = 12
)
var XferStatus_name = map[int32]string{
0: "UNKNOWN",
1: "OK_TO_RELAY",
2: "SUCCESS",
3: "BAD_LIQUIDITY",
4: "BAD_SLIPPAGE",
5: "BAD_TOKEN",
6: "REFUND_REQUESTED",
7: "REFUND_DONE",
8: "BAD_XFER_DISABLED",
9: "BAD_DEST_CHAIN",
10: "EXCEED_MAX_OUT_AMOUNT",
11: "XFER_DELAYED",
12: "BAD_ADDRESS",
}
var XferStatus_value = map[string]int32{
"UNKNOWN": 0,
"OK_TO_RELAY": 1,
"SUCCESS": 2,
"BAD_LIQUIDITY": 3,
"BAD_SLIPPAGE": 4,
"BAD_TOKEN": 5,
"REFUND_REQUESTED": 6,
"REFUND_DONE": 7,
"BAD_XFER_DISABLED": 8,
"BAD_DEST_CHAIN": 9,
"EXCEED_MAX_OUT_AMOUNT": 10,
"XFER_DELAYED": 11,
"BAD_ADDRESS": 12,
}
func (x XferStatus) String() string {
return proto.EnumName(XferStatus_name, int32(x))
}
func (XferStatus) EnumDescriptor() ([]byte, []int) {
return fileDescriptor_176f0c31123a8108, []int{0}
}
func init() {
proto.RegisterEnum("cbridge.XferStatus", XferStatus_name, XferStatus_value)
}
func init() {
proto.RegisterFile("cbridge.proto", fileDescriptor_176f0c31123a8108)
}
var fileDescriptor_176f0c31123a8108 = []byte{
// 255 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x2c, 0x90, 0xcd, 0x52, 0xc3, 0x30,
0x0c, 0x84, 0x29, 0x3f, 0x0d, 0x55, 0x12, 0x50, 0x3d, 0xf4, 0xc0, 0x2b, 0x70, 0x08, 0x07, 0x9e,
0xc0, 0x89, 0x54, 0xf0, 0x24, 0xb5, 0xdb, 0xd8, 0x1e, 0x52, 0x2e, 0x1e, 0x0a, 0x85, 0xe1, 0x54,
0x26, 0x84, 0xa7, 0xe7, 0xc2, 0x18, 0x72, 0xd4, 0xa7, 0xd1, 0xee, 0x6a, 0x21, 0x7f, 0xd9, 0xf5,
0x1f, 0xaf, 0xef, 0xfb, 0xe2, 0xb3, 0x3f, 0x0c, 0x07, 0x91, 0x8c, 0xe3, 0xcd, 0xcf, 0x04, 0xa0,
0x7b, 0xdb, 0xf7, 0x76, 0x78, 0x1e, 0xbe, 0xbf, 0x44, 0x0a, 0x89, 0xd7, 0xb5, 0x36, 0x8f, 0x1a,
0x8f, 0xc4, 0x25, 0xa4, 0xa6, 0x0e, 0xce, 0x84, 0x96, 0x1b, 0xb9, 0xc5, 0x49, 0xdc, 0x5a, 0x5f,
0x55, 0x6c, 0x2d, 0x1e, 0x8b, 0x39, 0xe4, 0xa5, 0xa4, 0xd0, 0xa8, 0x8d, 0x57, 0xa4, 0xdc, 0x16,
0x4f, 0x04, 0x42, 0x16, 0x91, 0x6d, 0xd4, 0x7a, 0x2d, 0xef, 0x19, 0x4f, 0x45, 0x0e, 0xb3, 0x48,
0x9c, 0xa9, 0x59, 0xe3, 0x99, 0xb8, 0x02, 0x6c, 0x79, 0xe9, 0x35, 0x85, 0x96, 0x37, 0x9e, 0xad,
0x63, 0xc2, 0x69, 0xf4, 0x19, 0x29, 0x19, 0xcd, 0x98, 0x88, 0x05, 0xcc, 0xe3, 0x55, 0xb7, 0xe4,
0x36, 0x90, 0xb2, 0xb2, 0x6c, 0x98, 0xf0, 0x5c, 0x08, 0xb8, 0x88, 0x98, 0xd8, 0xba, 0x50, 0x3d,
0x48, 0xa5, 0x71, 0x26, 0xae, 0x61, 0xc1, 0x5d, 0xc5, 0x4c, 0x61, 0x25, 0xbb, 0x60, 0xbc, 0x0b,
0x72, 0x65, 0xbc, 0x76, 0x08, 0x31, 0xcd, 0xbf, 0x42, 0x4c, 0xcf, 0x84, 0x69, 0x34, 0x8a, 0x02,
0x92, 0xa8, 0x8d, 0x3f, 0x64, 0x65, 0xf6, 0x04, 0x45, 0x71, 0x3b, 0x76, 0xb1, 0x9b, 0xfe, 0x75,
0x73, 0xf7, 0x1b, 0x00, 0x00, 0xff, 0xff, 0xf0, 0x04, 0xef, 0xc8, 0x2c, 0x01, 0x00, 0x00,
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,176 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// source: query.proto
package cbridge
import (
fmt "fmt"
proto "github.com/golang/protobuf/proto"
math "math"
)
// Reference imports to suppress errors if they are not otherwise used.
var _ = proto.Marshal
var _ = fmt.Errorf
var _ = math.Inf
// This is a compile-time assertion to ensure that this generated file
// is compatible with the proto package it is being compiled against.
// A compilation error at this line likely means your copy of the
// proto package needs to be updated.
const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package
type TransferHistoryStatus int32
const (
TransferHistoryStatus_TRANSFER_UNKNOWN TransferHistoryStatus = 0
TransferHistoryStatus_TRANSFER_SUBMITTING TransferHistoryStatus = 1
TransferHistoryStatus_TRANSFER_FAILED TransferHistoryStatus = 2
TransferHistoryStatus_TRANSFER_WAITING_FOR_SGN_CONFIRMATION TransferHistoryStatus = 3
TransferHistoryStatus_TRANSFER_WAITING_FOR_FUND_RELEASE TransferHistoryStatus = 4
TransferHistoryStatus_TRANSFER_COMPLETED TransferHistoryStatus = 5
TransferHistoryStatus_TRANSFER_TO_BE_REFUNDED TransferHistoryStatus = 6
TransferHistoryStatus_TRANSFER_REQUESTING_REFUND TransferHistoryStatus = 7
TransferHistoryStatus_TRANSFER_REFUND_TO_BE_CONFIRMED TransferHistoryStatus = 8
TransferHistoryStatus_TRANSFER_CONFIRMING_YOUR_REFUND TransferHistoryStatus = 9
TransferHistoryStatus_TRANSFER_REFUNDED TransferHistoryStatus = 10
TransferHistoryStatus_TRANSFER_DELAYED TransferHistoryStatus = 11
)
var TransferHistoryStatus_name = map[int32]string{
0: "TRANSFER_UNKNOWN",
1: "TRANSFER_SUBMITTING",
2: "TRANSFER_FAILED",
3: "TRANSFER_WAITING_FOR_SGN_CONFIRMATION",
4: "TRANSFER_WAITING_FOR_FUND_RELEASE",
5: "TRANSFER_COMPLETED",
6: "TRANSFER_TO_BE_REFUNDED",
7: "TRANSFER_REQUESTING_REFUND",
8: "TRANSFER_REFUND_TO_BE_CONFIRMED",
9: "TRANSFER_CONFIRMING_YOUR_REFUND",
10: "TRANSFER_REFUNDED",
11: "TRANSFER_DELAYED",
}
var TransferHistoryStatus_value = map[string]int32{
"TRANSFER_UNKNOWN": 0,
"TRANSFER_SUBMITTING": 1,
"TRANSFER_FAILED": 2,
"TRANSFER_WAITING_FOR_SGN_CONFIRMATION": 3,
"TRANSFER_WAITING_FOR_FUND_RELEASE": 4,
"TRANSFER_COMPLETED": 5,
"TRANSFER_TO_BE_REFUNDED": 6,
"TRANSFER_REQUESTING_REFUND": 7,
"TRANSFER_REFUND_TO_BE_CONFIRMED": 8,
"TRANSFER_CONFIRMING_YOUR_REFUND": 9,
"TRANSFER_REFUNDED": 10,
"TRANSFER_DELAYED": 11,
}
func (x TransferHistoryStatus) String() string {
return proto.EnumName(TransferHistoryStatus_name, int32(x))
}
func (TransferHistoryStatus) EnumDescriptor() ([]byte, []int) {
return fileDescriptor_5c6ac9b241082464, []int{0}
}
type Token struct {
Symbol string `protobuf:"bytes,1,opt,name=symbol,proto3" json:"symbol,omitempty"`
Address string `protobuf:"bytes,2,opt,name=address,proto3" json:"address,omitempty"`
Decimal int32 `protobuf:"varint,3,opt,name=decimal,proto3" json:"decimal,omitempty"`
XferDisabled bool `protobuf:"varint,4,opt,name=xfer_disabled,json=xferDisabled,proto3" json:"xfer_disabled,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *Token) Reset() { *m = Token{} }
func (m *Token) String() string { return proto.CompactTextString(m) }
func (*Token) ProtoMessage() {}
func (*Token) Descriptor() ([]byte, []int) {
return fileDescriptor_5c6ac9b241082464, []int{0}
}
func (m *Token) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_Token.Unmarshal(m, b)
}
func (m *Token) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_Token.Marshal(b, m, deterministic)
}
func (m *Token) XXX_Merge(src proto.Message) {
xxx_messageInfo_Token.Merge(m, src)
}
func (m *Token) XXX_Size() int {
return xxx_messageInfo_Token.Size(m)
}
func (m *Token) XXX_DiscardUnknown() {
xxx_messageInfo_Token.DiscardUnknown(m)
}
var xxx_messageInfo_Token proto.InternalMessageInfo
func (m *Token) GetSymbol() string {
if m != nil {
return m.Symbol
}
return ""
}
func (m *Token) GetAddress() string {
if m != nil {
return m.Address
}
return ""
}
func (m *Token) GetDecimal() int32 {
if m != nil {
return m.Decimal
}
return 0
}
func (m *Token) GetXferDisabled() bool {
if m != nil {
return m.XferDisabled
}
return false
}
func init() {
proto.RegisterEnum("cbridge.TransferHistoryStatus", TransferHistoryStatus_name, TransferHistoryStatus_value)
proto.RegisterType((*Token)(nil), "cbridge.Token")
}
func init() {
proto.RegisterFile("query.proto", fileDescriptor_5c6ac9b241082464)
}
var fileDescriptor_5c6ac9b241082464 = []byte{
// 373 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x6c, 0x92, 0x51, 0x6f, 0xd3, 0x30,
0x14, 0x85, 0x49, 0xb7, 0xb6, 0xdb, 0xdd, 0x10, 0xc6, 0x63, 0x5b, 0x04, 0x12, 0x14, 0xa6, 0x49,
0x85, 0x87, 0xf2, 0xc0, 0x2f, 0x48, 0xe7, 0x9b, 0x11, 0x91, 0x3a, 0xe0, 0x38, 0x9a, 0xca, 0x8b,
0x95, 0x34, 0x2e, 0x8a, 0x68, 0x1b, 0x70, 0x52, 0xa9, 0xfd, 0xe9, 0xbc, 0xa1, 0xa4, 0x69, 0x44,
0xd1, 0x1e, 0xcf, 0x77, 0xce, 0x3d, 0xb6, 0xae, 0x2e, 0x9c, 0xfd, 0x5e, 0x6b, 0xb3, 0x1d, 0xfd,
0x32, 0x79, 0x99, 0xd3, 0xfe, 0x2c, 0x31, 0x59, 0xfa, 0x43, 0xbf, 0xdb, 0x40, 0x57, 0xe6, 0x3f,
0xf5, 0x8a, 0x5e, 0x41, 0xaf, 0xd8, 0x2e, 0x93, 0x7c, 0x61, 0x5b, 0x03, 0x6b, 0x78, 0x2a, 0x1a,
0x45, 0x6d, 0xe8, 0xc7, 0x69, 0x6a, 0x74, 0x51, 0xd8, 0x9d, 0xda, 0xd8, 0xcb, 0xca, 0x49, 0xf5,
0x2c, 0x5b, 0xc6, 0x0b, 0xfb, 0x68, 0x60, 0x0d, 0xbb, 0x62, 0x2f, 0xe9, 0x0d, 0x3c, 0xdd, 0xcc,
0xb5, 0x51, 0x69, 0x56, 0xc4, 0xc9, 0x42, 0xa7, 0xf6, 0xf1, 0xc0, 0x1a, 0x9e, 0x88, 0xf3, 0x0a,
0xb2, 0x86, 0x7d, 0xf8, 0xd3, 0x81, 0x4b, 0x69, 0xe2, 0x55, 0x31, 0xd7, 0xe6, 0x73, 0x56, 0x94,
0xb9, 0xd9, 0x86, 0x65, 0x5c, 0xae, 0x0b, 0xfa, 0x02, 0x88, 0x14, 0x0e, 0x0f, 0x5d, 0x14, 0x2a,
0xe2, 0x5f, 0x78, 0xf0, 0xc0, 0xc9, 0x13, 0x7a, 0x0d, 0x17, 0x2d, 0x0d, 0xa3, 0xf1, 0xc4, 0x93,
0xd2, 0xe3, 0xf7, 0xc4, 0xa2, 0x17, 0xf0, 0xac, 0x35, 0x5c, 0xc7, 0xf3, 0x91, 0x91, 0x0e, 0x7d,
0x0f, 0xb7, 0x2d, 0x7c, 0x70, 0xbc, 0x2a, 0xaa, 0xdc, 0x40, 0xa8, 0xf0, 0x9e, 0xab, 0xbb, 0x80,
0xbb, 0x9e, 0x98, 0x38, 0xd2, 0x0b, 0x38, 0x39, 0xa2, 0xb7, 0xf0, 0xf6, 0xd1, 0xa8, 0x1b, 0x71,
0xa6, 0x04, 0xfa, 0xe8, 0x84, 0x48, 0x8e, 0xe9, 0x15, 0xd0, 0x36, 0x76, 0x17, 0x4c, 0xbe, 0xfa,
0x28, 0x91, 0x91, 0x2e, 0x7d, 0x05, 0xd7, 0x2d, 0x97, 0x81, 0x1a, 0xa3, 0x12, 0x58, 0x8d, 0x22,
0x23, 0x3d, 0xfa, 0x1a, 0x5e, 0xb6, 0xa6, 0xc0, 0x6f, 0x11, 0x86, 0x75, 0xfd, 0x2e, 0x41, 0xfa,
0xf4, 0x06, 0xde, 0xfc, 0xe3, 0xd7, 0x2f, 0xee, 0x3a, 0x9a, 0x3f, 0x22, 0x23, 0x27, 0x07, 0xa1,
0x86, 0x57, 0x25, 0xd3, 0x20, 0xda, 0x0f, 0x91, 0x53, 0x7a, 0x09, 0xcf, 0xff, 0x6b, 0x42, 0x46,
0xe0, 0x60, 0x97, 0x0c, 0x7d, 0x67, 0x8a, 0x8c, 0x9c, 0x8d, 0xcf, 0xbf, 0xc3, 0x68, 0xf4, 0xb1,
0xb9, 0x81, 0xa4, 0x57, 0xdf, 0xc4, 0xa7, 0xbf, 0x01, 0x00, 0x00, 0xff, 0xff, 0x66, 0xef, 0xfe,
0x5f, 0x22, 0x02, 0x00, 0x00,
}

View File

@ -9,7 +9,6 @@ import (
"github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/common/hexutil"
ethTypes "github.com/ethereum/go-ethereum/core/types"
"github.com/status-im/status-go/account" "github.com/status-im/status-go/account"
"github.com/status-im/status-go/contracts" "github.com/status-im/status-go/contracts"
"github.com/status-im/status-go/eth-node/types" "github.com/status-im/status-go/eth-node/types"
@ -177,13 +176,6 @@ func (h *HopBridge) Send(sendArgs *TransactionBridge, verifiedAccount *account.S
return h.swapAndSend(sendArgs.ChainID, sendArgs.HopTx, verifiedAccount) return h.swapAndSend(sendArgs.ChainID, sendArgs.HopTx, verifiedAccount)
} }
func getSigner(chainID uint64, from types.Address, verifiedAccount *account.SelectedExtKey) bind.SignerFn {
return func(addr common.Address, tx *ethTypes.Transaction) (*ethTypes.Transaction, error) {
s := ethTypes.NewLondonSigner(new(big.Int).SetUint64(chainID))
return ethTypes.SignTx(tx, s, verifiedAccount.AccountKey.PrivateKey)
}
}
func (h *HopBridge) sendToL2(chainID uint64, sendArgs *HopTxArgs, verifiedAccount *account.SelectedExtKey) (hash types.Hash, err error) { func (h *HopBridge) sendToL2(chainID uint64, sendArgs *HopTxArgs, verifiedAccount *account.SelectedExtKey) (hash types.Hash, err error) {
bridge, err := h.contractMaker.NewHopL1Bridge(chainID, sendArgs.Symbol) bridge, err := h.contractMaker.NewHopL1Bridge(chainID, sendArgs.Symbol)
if err != nil { if err != nil {

View File

@ -0,0 +1,34 @@
syntax = "proto3";
package cbridge;
option go_package = "../cbridge";
// ========== x/cbridge kv value types
// for src transfer id
// normal status flow: after sgn applied user's Send event, status is OK_TO_RELAY. then after apply Relay event
// status is SUCCESS
// can't relay flow: after apply send, status will be BAD_xxx, and there'll be no relay. so user need to InitWithdraw, status becomes
// refund_requested when sgn apply withdrawDone event, status becomes REFUND_DONE
enum XferStatus {
UNKNOWN = 0; // use as default for unknown xfer
// normal flow only has ok then success
OK_TO_RELAY = 1; // x/cbridge emit relay, waiting for sgn nodes to send sig, then sgn will submit relay tx onchain
SUCCESS = 2; // applied onchain relay event
// can't relay flow status
BAD_LIQUIDITY = 3; // can't complete xfer due to low dst chain liquidity or equal value dest amount is 0
BAD_SLIPPAGE = 4; // slippage larger than user specified max
BAD_TOKEN = 5; // src or dest token are not supported
// refund, using withdraw flow
REFUND_REQUESTED = 6; // user/gateway called InitWithdraw, XferRefundKey has withdraw seq num
REFUND_DONE = 7; // applied onchain WithdrawDown event
BAD_XFER_DISABLED = 8; // asset is in config, but it is xfer_disabled, so this asset should not be used for transfer. If any transfer
// come, we should go to refund flow.
BAD_DEST_CHAIN = 9; // dest chain is same to src chain, relayer will ignore it.
EXCEED_MAX_OUT_AMOUNT = 10; // amount larger than max out allowance
XFER_DELAYED = 11; // relayer has successfully called onchain relay() but the onchain contract decides that the amt is greater than its
// delayThreshold
BAD_ADDRESS = 12;
}

View File

@ -0,0 +1,175 @@
syntax = "proto3";
package cbridge;
import "query.proto";
import "cbridge.proto";
option go_package = "../cbridge";
message Chain {
uint32 id = 1;
string name = 2;
string icon = 3;
uint32 block_delay = 4;
string gas_token_symbol = 5;
string explore_url = 6;
reserved 7; // rpc_url removed
string contract_addr = 8; // bridge contract addr
string drop_gas_amt = 9; // how much gas will be dropped on dst chain when transfer(dst chain gas token)
double suggested_base_fee = 10; // only for backend
}
message ChainTokenInfo {
repeated TokenInfo token = 1;
}
message TokenInfo {
Token token = 1;
string name = 2;
string icon = 3;
}
message TransferInfo {
Chain chain = 1;
Token token = 2;
string amount = 3;
}
message GetTransferStatusRequest {
string transfer_id = 1;
}
message GetTransferStatusResponse {
ErrMsg err = 1;
TransferHistoryStatus status = 2;
bytes wd_onchain = 3; // for refund only
repeated bytes sorted_sigs = 4; // for refund only
repeated bytes signers = 5; // for refund only
repeated bytes powers = 6; // for refund only
XferStatus refund_reason = 7; // used only for to_be_refund TransferStatus. BAD_LIQUIDITY, BAD_SLIPPAGE and BAD_TOKEN are used here
uint32 block_delay = 8; // waiting
string src_block_tx_link = 9;
string dst_block_tx_link = 10;
}
message GetTransferConfigsRequest {}
message GetTransferConfigsResponse {
ErrMsg err = 1;
repeated Chain chains = 2;
map<uint32, ChainTokenInfo> chain_token = 3; // map<chain_id, ChainTokenInfo>
string farming_reward_contract_addr = 4;
}
message GetTokenInfoRequest {
uint32 chain_id = 1;
string token_symbol = 2;
}
message GetTokenInfoResponse {
ErrMsg err = 1;
TokenInfo token_info = 2;
}
message EstimateAmtRequest {
uint32 src_chain_id = 1;
uint32 dst_chain_id = 2;
string token_symbol = 3;
string amt = 4;
string usr_addr = 5;
uint32 slippage_tolerance = 6; // user setting, for ui only, slippage * 1M, eg. 0.5% is 5000
}
message EstimateAmtResponse {
ErrMsg err = 1;
string eq_value_token_amt = 2; // on_dst_chain, to cal minimum_received_amt = eq_value_token_amt*(1-slippage_tolerance) - fee
float bridge_rate = 3;
string perc_fee = 4; // on_dst_chain, percentage fee based on amount
string base_fee = 7; // on_dest_chain, independent of amount, to cover relay onchain tx gas cost
uint32 slippage_tolerance = 5; // user setting, from request, slippage * 1M, eg. 0.5% is 5000
uint32 max_slippage = 6; // param for requesting on chain, slippage * 1M, eg. 0.5% is 5000
}
message WithdrawInfo {
uint32 chain_id = 1;
string amount = 2;
uint32 slippage_tolerance = 3; // user setting, for ui only, slippage * 1M, eg. 0.5% is 5000
}
message EstimateWithdrawAmtRequest {
repeated WithdrawInfo src_withdraws = 1;
uint32 dst_chain_id = 2;
string token_symbol = 3;
string usr_addr = 4;
}
message EstimateWithdrawAmtResponse {
ErrMsg err = 1;
map<uint32, EstimateWithdrawAmt> req_amt = 2; // map<src_chain_id, EstimateWithdrawAmt>
}
message EstimateWithdrawAmt {
string eq_value_token_amt = 1; // on_dst_chain, to cal minimum_received_amt = eq_value_token_amt*(1-slippage_tolerance) - fee
float bridge_rate = 2;
string perc_fee = 3; // on_dst_chain, percentage fee based on amount
string base_fee = 4; // on_dest_chain, independent of amount, to cover relay onchain tx gas cost
uint32 slippage_tolerance = 5; // user setting, for ui only, slippage * 1M, eg. 0.5% is 5000
uint32 max_slippage = 6; // param for requesting on chain, slippage * 1M, eg. 0.5% is 5000
}
message WithdrawLiquidityRequest {
bytes withdraw_req = 1; // serialized WithdrawReq in sgn/cbridge/v1/tx.proto
bytes sig = 2;
string estimated_received_amt = 3; // on dst chain
WithdrawMethodType method_type = 4; // record which type it is
}
message WithdrawLiquidityResponse {
ErrMsg err = 1;
uint64 seq_num = 2; // same as WithdrawLiquidityRequest.reqid
}
message TransferHistory {
string transfer_id = 1;
TransferInfo src_send_info = 2;
TransferInfo dst_received_info = 3;
uint64 ts = 4;
string src_block_tx_link = 5;
string dst_block_tx_link = 6;
TransferHistoryStatus status = 7;
XferStatus refund_reason = 8; // used only for to_be_refund TransferStatus. BAD_LIQUIDITY, BAD_SLIPPAGE and BAD_TOKEN are used here
}
message TransferHistoryRequest {
string next_page_token = 1; // for first page, it's ""
uint64 page_size = 2;
string addr = 3;
}
message TransferHistoryResponse {
ErrMsg err = 1;
repeated TransferHistory history = 2;
string next_page_token = 3;
uint64 current_size = 4;
}
enum WithdrawMethodType {
WD_METHOD_TYPE_UNDEFINED = 0;
WD_METHOD_TYPE_ONE_RM = 1; // for lp one chain liquidity remove
WD_METHOD_TYPE_ALL_IN_ONE = 2; // for lp multi-chain -> one chain liquidity remove
WD_METHOD_TYPE_STAKING_CLAIM = 3; // for staking claim lp reward, these entries will not be shown in lp history
}
message ErrMsg {
ErrCode code = 1;
string msg = 2;
}
enum ErrCode {
ERROR_CODE_UNDEFINED = 0;
ERROR_CODE_COMMON = 500;
ERROR_NO_TOKEN_ON_DST_CHAIN = 1001;
ERROR_NO_TOKEN_ON_SRC_CHAIN = 1002;
ERROR_INIT_WITHDRAW_FAILED = 1003;
}

View File

@ -0,0 +1,3 @@
package cbridge
//go:generate protoc --go_out=. ./cbridge.proto ./gateway.proto ./query.proto

View File

@ -0,0 +1,27 @@
syntax = "proto3";
package cbridge;
option go_package = "../cbridge";
message Token {
string symbol = 1; // upper case symbol
string address = 2;
int32 decimal = 3;
bool xfer_disabled = 4; // if set to true, won't relay if this asset is src or dest
}
enum TransferHistoryStatus {
TRANSFER_UNKNOWN = 0;
TRANSFER_SUBMITTING = 1; // user: after calling mark transfer api
TRANSFER_FAILED = 2; // user: check if tx reverted when shown status is TRANSFER_SUBMITTING
TRANSFER_WAITING_FOR_SGN_CONFIRMATION = 3; // relayer: on send tx success event
TRANSFER_WAITING_FOR_FUND_RELEASE = 4; // relayer: mark send tx
TRANSFER_COMPLETED = 5; // relayer: on relay tx success event
TRANSFER_TO_BE_REFUNDED = 6; // x: transfer rejected by sgn and waiting for withdraw api called
TRANSFER_REQUESTING_REFUND = 7; // user: withdraw api has been called and withdraw is processing by sgn
TRANSFER_REFUND_TO_BE_CONFIRMED = 8; // x: withdraw is approved by sgn
TRANSFER_CONFIRMING_YOUR_REFUND = 9; // user: mark refund has been submitted on chain
TRANSFER_REFUNDED = 10; // relayer: on refund(withdraw liquidity actually) tx event
TRANSFER_DELAYED = 11; // relayer has successfully called onchain relay() but the onchain contract decides that the amt is greater than
// its delayThreshold
}

View File

@ -335,8 +335,10 @@ func NewRouter(s *Service) *Router {
bridges := make(map[string]bridge.Bridge) bridges := make(map[string]bridge.Bridge)
simple := bridge.NewSimpleBridge(s.transactor) simple := bridge.NewSimpleBridge(s.transactor)
hop := bridge.NewHopBridge(s.rpcClient) hop := bridge.NewHopBridge(s.rpcClient)
cbridge := bridge.NewCbridge(s.rpcClient, s.tokenManager)
bridges[simple.Name()] = simple bridges[simple.Name()] = simple
bridges[hop.Name()] = hop bridges[hop.Name()] = hop
bridges[cbridge.Name()] = cbridge
return &Router{s, bridges} return &Router{s, bridges}
} }

View File

@ -1496,6 +1496,14 @@ var tokenStore = map[uint64]map[common.Address]*Token{
Decimals: 0, Decimals: 0,
ChainID: 5, ChainID: 5,
}, },
common.HexToAddress("0xf4B2cbc3bA04c478F0dC824f4806aC39982Dce73"): &Token{
Address: common.HexToAddress("0xf4B2cbc3bA04c478F0dC824f4806aC39982Dce73"),
Name: "Tether USD",
Symbol: "USDT",
Color: "#f8f8f8",
Decimals: 6,
ChainID: 5,
},
}, },
10: { 10: {
common.HexToAddress("0x7f5c764cbc14f9669b88837ca1490cca17c31607"): &Token{ common.HexToAddress("0x7f5c764cbc14f9669b88837ca1490cca17c31607"): &Token{
@ -1634,5 +1642,13 @@ var tokenStore = map[uint64]map[common.Address]*Token{
ChainID: 421613, ChainID: 421613,
PegSymbol: "USD", PegSymbol: "USD",
}, },
common.HexToAddress("0x265B25e22bcd7f10a5bD6E6410F10537Cc7567e8"): &Token{
Address: common.HexToAddress("0x265B25e22bcd7f10a5bD6E6410F10537Cc7567e8"),
Name: "Tether USD",
Symbol: "USDT",
Color: "#f8f8f8",
Decimals: 6,
ChainID: 421613,
},
}, },
} }