diff --git a/cmd/swapscan/main.go b/cmd/swapscan/main.go index bd83f994..166ae4f2 100644 --- a/cmd/swapscan/main.go +++ b/cmd/swapscan/main.go @@ -25,6 +25,7 @@ func initApp() { app.Commands = []*cli.Command{ scanEthCommand, scanBtcCommand, + scanLtcCommand, utils.LicenseCommand, utils.VersionCommand, } diff --git a/cmd/swapscan/scanltc.go b/cmd/swapscan/scanltc.go new file mode 100644 index 00000000..2e0b67f0 --- /dev/null +++ b/cmd/swapscan/scanltc.go @@ -0,0 +1,349 @@ +package main + +import ( + "fmt" + "sync" + "time" + + "github.com/anyswap/CrossChain-Bridge/cmd/utils" + "github.com/anyswap/CrossChain-Bridge/log" + "github.com/anyswap/CrossChain-Bridge/mongodb" + "github.com/anyswap/CrossChain-Bridge/params" + "github.com/anyswap/CrossChain-Bridge/rpc/client" + "github.com/anyswap/CrossChain-Bridge/tokens" + "github.com/anyswap/CrossChain-Bridge/tokens/btc/electrs" + "github.com/anyswap/CrossChain-Bridge/tokens/eth" + "github.com/anyswap/CrossChain-Bridge/tokens/ltc" + "github.com/anyswap/CrossChain-Bridge/tokens/tools" + "github.com/urfave/cli/v2" +) + +var ( + scanLtcCommand = &cli.Command{ + Action: scanLtc, + Name: "scanltc", + Usage: "scan swap on ltc", + ArgsUsage: " ", + Description: ` +scan swap on ltc +`, + Flags: []cli.Flag{ + testnetFlag, + mongoURLFlag, + dbNameFlag, + dbUserFlag, + dbPassFlag, + utils.GatewayFlag, + utils.SwapServerFlag, + utils.DepositAddressFlag, + utils.StartHeightFlag, + utils.EndHeightFlag, + utils.StableHeightFlag, + utils.JobsFlag, + }, + } +) + +type ltcSwapScanner struct { + useTestnet bool + gateway string + swapServer string + depositAddress string + startHeight uint64 + endHeight uint64 + stableHeight uint64 + jobCount uint64 + + rpcInterval time.Duration + rpcRetryCount int + + bridge *ltc.Bridge +} + +func scanLtc(ctx *cli.Context) error { + utils.SetLogger(ctx) + scanner := <cSwapScanner{ + rpcInterval: 1 * time.Second, + rpcRetryCount: 3, + } + scanner.useTestnet = ctx.Bool(testnetFlag.Name) + scanner.gateway = ctx.String(utils.GatewayFlag.Name) + scanner.swapServer = ctx.String(utils.SwapServerFlag.Name) + scanner.depositAddress = ctx.String(utils.DepositAddressFlag.Name) + scanner.startHeight = ctx.Uint64(utils.StartHeightFlag.Name) + scanner.endHeight = ctx.Uint64(utils.EndHeightFlag.Name) + scanner.stableHeight = ctx.Uint64(utils.StableHeightFlag.Name) + scanner.jobCount = ctx.Uint64(utils.JobsFlag.Name) + + log.Info("get argument success", + "testnet", scanner.useTestnet, + "gateway", scanner.gateway, + "swapServer", scanner.swapServer, + "depositAddress", scanner.depositAddress, + "start", scanner.startHeight, + "end", scanner.endHeight, + "stable", scanner.stableHeight, + "jobs", scanner.jobCount, + ) + + scanner.initMongodb(ctx) + scanner.initBridge() + scanner.verifyOptions() + scanner.run() + return nil +} + +func (scanner *ltcSwapScanner) verifyOptions() { + if !scanner.bridge.IsValidAddress(scanner.depositAddress) { + log.Fatalf("invalid deposit address '%v'", scanner.depositAddress) + } + if scanner.gateway == "" { + log.Fatal("must specify gateway address") + } + if scanner.swapServer == "" { + log.Fatal("must specify swap server address") + } + + oracle := params.OracleConfig{ + ServerAPIAddress: scanner.swapServer, + } + err := oracle.CheckConfig() + if err != nil { + log.Fatalf("check swap server failed. %v", err) + } + + start := scanner.startHeight + end := scanner.endHeight + jobs := scanner.jobCount + if end != 0 && start >= end { + log.Fatalf("wrong scan range [%v, %v)", start, end) + } + if jobs == 0 { + log.Fatal("zero jobs specified") + } +} + +func (scanner *ltcSwapScanner) initMongodb(ctx *cli.Context) { + dbURL := ctx.String(mongoURLFlag.Name) + dbName := ctx.String(dbNameFlag.Name) + userName := ctx.String(dbUserFlag.Name) + passwd := ctx.String(dbPassFlag.Name) + if dbName != "" { + mongodb.MongoServerInit([]string{dbURL}, dbName, userName, passwd) + } +} + +func (scanner *ltcSwapScanner) initBridge() { + scanner.bridge = ltc.NewCrossChainBridge(true) + scanner.bridge.GatewayConfig = &tokens.GatewayConfig{ + APIAddress: []string{scanner.gateway}, + } + ltcDecimals := uint8(8) + netID := "Mainnet" + if scanner.useTestnet { + netID = "TestNet3" + } + scanner.bridge.ChainConfig = &tokens.ChainConfig{ + BlockChain: "Bitcoin", + NetID: netID, + Confirmations: &scanner.stableHeight, + } + pairConfig := &tokens.TokenPairConfig{ + PairID: ltc.PairID, + SrcToken: &tokens.TokenConfig{ + ID: "LTC", + Name: "LTC", + Symbol: "LTC", + Decimals: <cDecimals, + DepositAddress: scanner.depositAddress, + }, + } + pairsConfig := make(map[string]*tokens.TokenPairConfig) + pairsConfig[ltc.PairID] = pairConfig + tokens.SetTokenPairsConfig(pairsConfig, false) + tokens.SrcBridge = scanner.bridge + tokens.DstBridge = eth.NewCrossChainBridge(false) +} + +func (scanner *ltcSwapScanner) run() { + start := scanner.startHeight + wend := scanner.endHeight + if wend == 0 { + wend = tools.LoopGetLatestBlockNumber(scanner.bridge) + } + if start == 0 { + start = wend + } + + scanner.doScanRangeJob(start, wend) + + if scanner.endHeight == 0 { + go scanner.scanPool() + scanner.scanLoop(wend) + } +} + +// nolint:dupl // in diff sub command +func (scanner *ltcSwapScanner) doScanRangeJob(start, end uint64) { + if start >= end { + return + } + jobs := scanner.jobCount + count := end - start + step := count / jobs + if step == 0 { + jobs = 1 + step = count + } + wg := new(sync.WaitGroup) + for i := uint64(0); i < jobs; i++ { + from := start + i*step + to := start + (i+1)*step + if i+1 == jobs { + to = end + } + wg.Add(1) + go scanner.scanRange(i+1, from, to, wg) + } + if scanner.endHeight != 0 { + wg.Wait() + } +} + +func (scanner *ltcSwapScanner) scanRange(job, from, to uint64, wg *sync.WaitGroup) { + defer wg.Done() + log.Info(fmt.Sprintf("[%v] start scan range", job), "from", from, "to", to) + + for h := from; h < to; h++ { + scanner.scanBlock(job, h, false) + } + + log.Info(fmt.Sprintf("[%v] scan range finish", job), "from", from, "to", to) +} + +func (scanner *ltcSwapScanner) scanPool() { + scanner.bridge.StartPoolTransactionScanJob() +} + +func (scanner *ltcSwapScanner) scanLoop(from uint64) { + stable := scanner.stableHeight + log.Info("start scan loop", "from", from, "stable", stable) + for { + latest := tools.LoopGetLatestBlockNumber(scanner.bridge) + for h := latest; h > from; h-- { + scanner.scanBlock(0, h, true) + } + if from+stable < latest { + from = latest - stable + } + time.Sleep(5 * time.Second) + } +} + +func (scanner *ltcSwapScanner) loopGetBlockHash(height uint64) string { + for { + blockHash, err := scanner.bridge.GetBlockHash(height) + if err == nil { + return blockHash + } + log.Warn("get block hash failed", "height", height, "err", err) + time.Sleep(scanner.rpcInterval) + } +} + +func (scanner *ltcSwapScanner) scanBlock(job, height uint64, cache bool) { + blockHash := scanner.loopGetBlockHash(height) + if cache && ltcCachedBlocks.isScanned(blockHash) { + return + } + block, err := scanner.bridge.GetBlock(blockHash) + if err != nil { + log.Warn("get block failed", "height", height, "hash", blockHash, "err", err) + return + } + txCount := *block.TxCount + log.Info(fmt.Sprintf("[%v] scan block %v start", job, height), "hash", blockHash, "txs", txCount) + + startIndex := uint32(0) + for startIndex < txCount { + var txs []*electrs.ElectTx + for i := 0; i < scanner.rpcRetryCount; i++ { + txs, err = scanner.bridge.GetBlockTransactions(blockHash, startIndex) + if err == nil { + break + } + log.Warn("get block txs failed", "height", height, "startIndex", startIndex, "err", err) + time.Sleep(scanner.rpcInterval) + } + for i, tx := range txs { + log.Trace(fmt.Sprintf("[%v] scan block %v process tx", job, height), "txid", *tx.Txid, "index", startIndex+uint32(i)) + scanner.processTx(tx) + } + log.Trace(fmt.Sprintf("[%v] scan block %v process txs", job, height), "startIndex", startIndex, "total", txCount) + startIndex += 25 // 25 is elctrs API defined + } + + if cache { + ltcCachedBlocks.addBlock(blockHash) + } + log.Info(fmt.Sprintf("[%v] scan block %v finish", job, height)) +} + +func (scanner *ltcSwapScanner) processTx(tx *electrs.ElectTx) { + txid := *tx.Txid + p2shBindAddrs, err := scanner.bridge.CheckSwapinTxType(tx) + if err != nil { + return + } + if len(p2shBindAddrs) > 0 { + for _, p2shBindAddr := range p2shBindAddrs { + log.Info("post p2sh swapin register", "txid", txid, "bind", p2shBindAddr) + args := map[string]interface{}{ + "txid": txid, + "bind": p2shBindAddr, + } + var result interface{} + for i := 0; i < scanner.rpcRetryCount; i++ { + err = client.RPCPost(&result, scanner.swapServer, "swap.P2shSwapin", args) + if tokens.ShouldRegisterSwapForError(err) { + break + } + if tools.IsSwapAlreadyExistRegisterError(err) { + break + } + log.Warn("post p2sh swapin register failed", "txid", txid, "bind", p2shBindAddr, "err", err) + } + } + } else { + value, memoScript, rightReceiver := scanner.bridge.GetReceivedValue(tx.Vout, scanner.depositAddress, "p2pkh") + if !rightReceiver || value == 0 { + return + } + bindAddress, bindOk := ltc.GetBindAddressFromMemoScipt(memoScript) + if !bindOk { + return + } + log.Info("post swapin register", "txid", txid, "pairid", ltc.PairID, "bind", bindAddress) + args := map[string]interface{}{ + "txid": txid, + "pairid": ltc.PairID, + } + var result interface{} + for i := 0; i < scanner.rpcRetryCount; i++ { + err = client.RPCPost(&result, scanner.swapServer, "swap.Swapin", args) + if tokens.ShouldRegisterSwapForError(err) { + break + } + if tools.IsSwapAlreadyExistRegisterError(err) { + break + } + log.Warn("post swapin register failed", "txid", txid, "bind", bindAddress, "err", err) + } + } +} + +var ltcCachedBlocks = &cachedSacnnedBlocks{ + capacity: 100, + nextIndex: 0, + hashes: make([]string, 100), +} diff --git a/dcrm/sign.go b/dcrm/sign.go index 79c24ef5..d3948b2c 100644 --- a/dcrm/sign.go +++ b/dcrm/sign.go @@ -131,6 +131,101 @@ func doSignImpl(dcrmNode *NodeInfo, signGroupIndex int64, signPubkey string, msg return keyID, rsvs, err } +// DoSignED25519One dcrm sign single msgHash with context msgContext +func DoSignED25519One(signPubkey, msgHash, msgContext string) (rpcAddr string, result []string, err error) { + return DoSignED25519(signPubkey, []string{msgHash}, []string{msgContext}) +} + +// DoSign dcrm sign msgHash with context msgContext +func DoSignED25519(signPubkey string, msgHash, msgContext []string) (keyID string, rsvs []string, err error) { + if !params.IsDcrmEnabled() { + return "", nil, errors.New("dcrm sign is disabled") + } + log.Debug("dcrm DoSign", "msgHash", msgHash, "msgContext", msgContext) + if signPubkey == "" { + return "", nil, errors.New("dcrm sign with empty public key") + } + var pingOk bool + for retry := 0; retry < retrySignCount; retry++ { + for _, dcrmNode := range allInitiatorNodes { + if err = pingDcrmNode(dcrmNode); err != nil { + continue + } + pingOk = true + signGroupsCount := int64(len(dcrmNode.signGroups)) + // randomly pick first subgroup to sign + randIndex, _ := rand.Int(rand.Reader, big.NewInt(signGroupsCount)) + startIndex := randIndex.Int64() + i := startIndex + for { + keyID, rsvs, err = doSignED25519Impl(dcrmNode, i, signPubkey, msgHash, msgContext) + if err == nil { + return keyID, rsvs, nil + } + i = (i + 1) % signGroupsCount + if i == startIndex { + break + } + } + } + } + if !pingOk { + err = errors.New("dcrm sign ping dcrm node failed") + } + return "", nil, err +} + +func doSignED25519Impl(dcrmNode *NodeInfo, signGroupIndex int64, signPubkey string, msgHash, msgContext []string) (keyID string, rsvs []string, err error) { + nonce, err := GetSignNonce(dcrmNode.dcrmUser.String(), dcrmNode.dcrmRPCAddress) + if err != nil { + return "", nil, err + } + txdata := SignData{ + TxType: "SIGN", + PubKey: signPubkey, + MsgHash: msgHash, + MsgContext: msgContext, + Keytype: "ED25519", + GroupID: dcrmNode.signGroups[signGroupIndex], + ThresHold: dcrmThreshold, + Mode: dcrmMode, + TimeStamp: common.NowMilliStr(), + } + payload, _ := json.Marshal(txdata) + rawTX, err := BuildDcrmRawTx(nonce, payload, dcrmNode.keyWrapper) + if err != nil { + return "", nil, err + } + + rpcAddr := dcrmNode.dcrmRPCAddress + keyID, err = Sign(rawTX, rpcAddr) + if err != nil { + return "", nil, err + } + + time.Sleep(retryGetSignStatusInterval) + var signStatus *SignStatus + i := 0 + for ; i < retryGetSignStatusCount; i++ { + signStatus, err = GetSignStatus(keyID, rpcAddr) + if err == nil { + rsvs = signStatus.Rsv + break + } + switch err { + case ErrGetSignStatusFailed, ErrGetSignStatusTimeout: + return "", nil, err + } + log.Warn("retry get sign status as error", "keyID", keyID, "err", err) + time.Sleep(retryGetSignStatusInterval) + } + if i == retryGetSignStatusCount || len(rsvs) == 0 { + return "", nil, errors.New("get sign status failed") + } + + return keyID, rsvs, err +} + // BuildDcrmRawTx build dcrm raw tx func BuildDcrmRawTx(nonce uint64, payload []byte, keyWrapper *keystore.Key) (string, error) { tx := types.NewTransaction( diff --git a/go.mod b/go.mod index cdcea7e0..ff488535 100644 --- a/go.mod +++ b/go.mod @@ -9,9 +9,17 @@ require ( github.com/btcsuite/btcwallet/wallet/txauthor v1.0.0 github.com/btcsuite/btcwallet/wallet/txrules v1.0.0 github.com/btcsuite/btcwallet/wallet/txsizes v1.0.0 + github.com/cosmos/cosmos-sdk v0.39.2 + github.com/dfuse-io/binary v0.0.0-20210216024852-4ae6830a495d + github.com/dfuse-io/solana-go v0.2.0 github.com/fastly/go-utils v0.0.0-20180712184237-d95a45783239 // indirect + github.com/fbsobreira/gotron-sdk v0.0.0-20210316163828-8cb47d581197 github.com/fsn-dev/fsn-go-sdk v0.0.0-20201127063150-d66d045799f9 github.com/fsnotify/fsnotify v1.4.9 + github.com/go-resty/resty/v2 v2.5.0 + github.com/golang/protobuf v1.4.2 + github.com/golang/snappy v0.0.3-0.20201103224600-674baa8c7fc3 // indirect + github.com/google/gofuzz v1.1.1-0.20200604201612-c04b05f3adfa // indirect github.com/gorilla/handlers v1.5.1 github.com/gorilla/mux v1.8.0 github.com/gorilla/rpc v1.2.0 @@ -25,12 +33,24 @@ require ( github.com/ltcsuite/ltcwallet/wallet/txauthor v1.0.0 github.com/ltcsuite/ltcwallet/wallet/txrules v1.0.0 github.com/ltcsuite/ltcwallet/wallet/txsizes v1.0.0 + github.com/nervosnetwork/ckb-sdk-go v0.3.0 github.com/pborman/uuid v1.2.1 github.com/shopspring/decimal v1.2.0 github.com/sirupsen/logrus v1.7.0 - github.com/stretchr/testify v1.6.1 + github.com/stretchr/testify v1.7.0 github.com/tebeka/strftime v0.1.5 // indirect + github.com/tendermint/go-amino v0.16.0 + github.com/tendermint/tendermint v0.33.9 + github.com/terra-project/core v0.4.2 github.com/urfave/cli/v2 v2.3.0 - golang.org/x/crypto v0.0.0-20201203163018-be400aefbc4c + github.com/ybbus/jsonrpc v2.1.2+incompatible + golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad + google.golang.org/grpc v1.31.1 gopkg.in/mgo.v2 v2.0.0-20190816093944-a6b53ec6cb22 ) + +replace github.com/gogo/protobuf v1.3.3 => github.com/regen-network/protobuf v1.3.3-alpha.regen.1 + +replace github.com/tendermint/tendermint => github.com/tendermint/tendermint v0.33.9 + +replace github.com/cosmos/cosmos-sdk => github.com/cosmos/cosmos-sdk v0.39.2 // indirect diff --git a/go.sum b/go.sum index 42458151..090af31e 100644 --- a/go.sum +++ b/go.sum @@ -1,26 +1,105 @@ +bou.ke/monkey v1.0.1/go.mod h1:FgHuK96Rv2Nlf+0u1OOVDpCMdsWyOFmeeketDHE7LIg= cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= +cloud.google.com/go v0.43.0/go.mod h1:BOSR3VbTLkk6FDC/TcffxP4NF/FFBGA5ku+jvKOP7pg= +cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= +cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= +cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= +cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= +cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= +cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= +cloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqClKRT5SZwBmk= +cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= +cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= +contrib.go.opencensus.io/exporter/stackdriver v0.12.6 h1:Y2FTyj0HgOhfjEW6D6ytZNoz1YcPDXmkKr1I478CWKs= +contrib.go.opencensus.io/exporter/stackdriver v0.12.6/go.mod h1:8x999/OcIPy5ivx/wDiV7Gx4D+VUPODf0mWRGRc5kSk= +dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= +github.com/99designs/keyring v1.1.6 h1:kVDC2uCgVwecxCk+9zoCt2uEL6dt+dfVzMvGgnVcIuM= +github.com/99designs/keyring v1.1.6/go.mod h1:16e0ds7LGQQcT59QqkTg72Hh5ShM51Byv5PEmW6uoRU= +github.com/Azure/azure-pipeline-go v0.2.1/go.mod h1:UGSo8XybXnIGZ3epmeBw7Jdz+HiUVpqIlpz/HKHylF4= +github.com/Azure/azure-pipeline-go v0.2.2/go.mod h1:4rQ/NZncSvGqNkkOsNpOU1tgoNuIlp9AfUH5G1tvCHc= +github.com/Azure/azure-storage-blob-go v0.7.0/go.mod h1:f9YQKtsG1nMisotuTPpO0tjNuEjKRYAcJU8/ydDI++4= +github.com/Azure/go-autorest/autorest v0.9.0/go.mod h1:xyHB1BMZT0cuDHU7I0+g046+BFDTQ8rEZB0s4Yfa6bI= +github.com/Azure/go-autorest/autorest/adal v0.5.0/go.mod h1:8Z9fGy2MpX0PvDjB1pEgQTmVqjGhiHBW7RJJEciWzS0= +github.com/Azure/go-autorest/autorest/adal v0.8.0/go.mod h1:Z6vX6WXXuyieHAXwMj0S6HY6e6wcHn37qQMBQlvY3lc= +github.com/Azure/go-autorest/autorest/date v0.1.0/go.mod h1:plvfp3oPSKwf2DNjlBjWF/7vwR+cUD/ELuzDCXwHUVA= +github.com/Azure/go-autorest/autorest/date v0.2.0/go.mod h1:vcORJHLJEh643/Ioh9+vPmf1Ij9AEBM5FuBIXLmIy0g= +github.com/Azure/go-autorest/autorest/mocks v0.1.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0= +github.com/Azure/go-autorest/autorest/mocks v0.2.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0= +github.com/Azure/go-autorest/autorest/mocks v0.3.0/go.mod h1:a8FDP3DYzQ4RYfVAxAN3SVSiiO77gL2j2ronKKP0syM= +github.com/Azure/go-autorest/logger v0.1.0/go.mod h1:oExouG+K6PryycPJfVSxi/koC6LSNgds39diKLz7Vrc= +github.com/Azure/go-autorest/tracing v0.5.0/go.mod h1:r/s2XiOKccPW3HrqB+W0TQzfbtp2fGCgRFtBroKn4Dk= github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= +github.com/ChainSafe/go-schnorrkel v0.0.0-20200405005733-88cbf1b4c40d h1:nalkkPQcITbvhmL4+C4cKA87NW0tfm3Kl9VXRoPywFg= +github.com/ChainSafe/go-schnorrkel v0.0.0-20200405005733-88cbf1b4c40d/go.mod h1:URdX5+vg25ts3aCh8H5IFZybJYKWhJHYMTnf+ULtoC4= +github.com/CosmWasm/go-cosmwasm v0.10.0 h1:3DBOiGtLllevLgf8PQO5+hRCKKqYEQJIw6cgaZzr1Ag= +github.com/CosmWasm/go-cosmwasm v0.10.0/go.mod h1:gAFCwllx97ejI+m9SqJQrmd2SBW7HA0fOjvWWJjM2uc= github.com/DataDog/zstd v1.3.6-0.20190409195224-796139022798/go.mod h1:1jcaCB/ufaK+sKp1NBhlGmpz41jOoPQ35bpF36t7BBo= +github.com/GeertJohan/go.incremental v1.0.0/go.mod h1:6fAjUhbVuX1KcMD3c8TEgVUqmo4seqhv0i0kdATSkM0= +github.com/GeertJohan/go.rice v1.0.0/go.mod h1:eH6gbSOAUv07dQuZVnBmoDP8mgsM1rtixis4Tib9if0= +github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0= +github.com/OneOfOne/xxhash v1.2.2 h1:KMrpdQIwFcEqXDklaen+P1axHaj9BSKzvpUUfnHldSE= +github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= +github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo= github.com/Shopify/sarama v1.23.1/go.mod h1:XLH1GYJnLVE0XCr6KdJGVJRTwY30moWNJ4sERjXX6fs= github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI= +github.com/StackExchange/wmi v0.0.0-20180116203802-5d049714c4a6 h1:fLjPD/aNc3UIOA6tDi6QXUemppXK3P9BI7mr2hd6gx8= +github.com/StackExchange/wmi v0.0.0-20180116203802-5d049714c4a6/go.mod h1:3eOhrUMpNV+6aFIbp5/iudMxNCF27Vw2OZgy4xEx0Fg= +github.com/VictoriaMetrics/fastcache v1.5.7/go.mod h1:ptDBkNMQI4RtmVo8VS/XwRY6RoTu1dAWCbrk+6WsEM8= +github.com/VividCortex/gohistogram v1.0.0 h1:6+hBz+qvs0JOrrNhhmR7lFxo5sINxBCGXrdtl/UvroE= +github.com/VividCortex/gohistogram v1.0.0/go.mod h1:Pf5mBqqDxYaXu3hDrrU+w6nw50o/4+TcAqDqk/vUH7g= +github.com/Workiva/go-datastructures v1.0.52 h1:PLSK6pwn8mYdaoaCZEMsXBpBotr4HHn9abU0yMQt0NI= +github.com/Workiva/go-datastructures v1.0.52/go.mod h1:Z+F2Rca0qCsVYDS8z7bAGm8f3UkzuWYS/oBZz5a7VVA= github.com/aead/siphash v1.0.1/go.mod h1:Nywa3cDsYNNK3gaciGTWPwHt0wlpNV15vwmswBAUSII= +github.com/afex/hystrix-go v0.0.0-20180502004556-fa1af6a1f4f5/go.mod h1:SkGFH1ia65gfNATL8TAiHDNxPzPdmEL5uirI2Uyuz6c= +github.com/akavel/rsrc v0.8.0/go.mod h1:uLoCtb9J+EyAqh+26kdrTgmzRBFPGOolLWKpdxkKq+c= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/allegro/bigcache v1.2.1-0.20190218064605-e24eb225f156/go.mod h1:Cb/ax3seSYIx7SuZdm2G2xzfwmv3TPSk2ucNfQESPXM= +github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ= +github.com/apache/thrift v0.13.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ= +github.com/araddon/dateparse v0.0.0-20200409225146-d820a6159ab1/go.mod h1:SLqhdZcd+dF3TEVL2RMoob5bBP5R1P1qkox+HtCBgGI= github.com/aristanetworks/fsnotify v1.4.2/go.mod h1:D/rtu7LpjYM8tRJphJ0hUBYpjai8SfX+aSNsWDTq/Ks= github.com/aristanetworks/glog v0.0.0-20180419172825-c15b03b3054f/go.mod h1:KASm+qXFKs/xjSoWn30NrWBBvdTTQq+UjkhjEJHfSFA= +github.com/aristanetworks/goarista v0.0.0-20170210015632-ea17b1a17847/go.mod h1:D/tb0zPVXnP7fmsLZjtdUhSsumbK/ij54UXjjVgMGxQ= github.com/aristanetworks/goarista v0.0.0-20191106175434-873d404c7f40 h1:ZdRuixFqR3mfx4FHzclG3COrRgWrYq0VhNgIoYoObcM= github.com/aristanetworks/goarista v0.0.0-20191106175434-873d404c7f40/go.mod h1:Z4RTxGAuYhPzcq8+EdRM+R8M48Ssle2TsWtwRKa+vns= github.com/aristanetworks/splunk-hec-go v0.3.3/go.mod h1:1VHO9r17b0K7WmOlLb9nTk/2YanvOEnLMUgsFrxBROc= +github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= +github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= +github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= +github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/aryann/difflib v0.0.0-20170710044230-e206f873d14a/go.mod h1:DAHtR1m6lCRdSC2Tm3DSWRPvIPr6xNKyeHdqDQSQT+A= +github.com/aws/aws-lambda-go v1.13.3/go.mod h1:4UKl9IzQMoD+QF79YdCuzCwp8VbmG4VAQwij/eHl5CU= +github.com/aws/aws-sdk-go v1.22.1/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= +github.com/aws/aws-sdk-go v1.25.48/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= +github.com/aws/aws-sdk-go v1.27.0/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= +github.com/aws/aws-sdk-go-v2 v0.18.0/go.mod h1:JWVYvqSMppoMJC0x5wdwiImzgXTI9FuZwxzkQq9wy+g= +github.com/bartekn/go-bip39 v0.0.0-20171116152956-a05967ea095d h1:1aAija9gr0Hyv4KfQcRcwlmFIrhkDmIj2dz5bkg/s/8= +github.com/bartekn/go-bip39 v0.0.0-20171116152956-a05967ea095d/go.mod h1:icNx/6QdFblhsEjZehARqbNumymUT/ydwlLojFdv7Sk= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= +github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/bgentry/speakeasy v0.1.0 h1:ByYyxL9InA1OWqxJqqp2A5pYHUrCiAL6K3J+LKSsQkY= +github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= +github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84= +github.com/blendle/zapdriver v1.3.1 h1:C3dydBOWYRiOk+B8X9IVZ5IOe+7cl+tGOexN4QqHfpE= +github.com/blendle/zapdriver v1.3.1/go.mod h1:mdXfREi6u5MArG4j9fewC+FGnXaBR+T4Ox4J2u4eHCc= +github.com/btcsuite/btcd v0.0.0-20171128150713-2e60448ffcc6/go.mod h1:Dmm/EzmjnCiweXmzRIAiUWCInVmPgjkzgv5k4tVyXiQ= +github.com/btcsuite/btcd v0.0.0-20190115013929-ed77733ec07d/go.mod h1:d3C0AkH6BRcvO8T0UEPu53cnw4IbV63x1bEjildYhO0= github.com/btcsuite/btcd v0.0.0-20190824003749-130ea5bddde3/go.mod h1:3J08xEfcugPacsc34/LKRU2yO7YmuT8yt28J8k2+rrI= github.com/btcsuite/btcd v0.20.1-beta/go.mod h1:wVuoA8VJLEcwgqHBwHmzLRazpKxTv13Px/pDuV7OomQ= github.com/btcsuite/btcd v0.21.0-beta h1:At9hIZdJW0s9E/fAz28nrz6AmcNlSVucCH796ZteX1M= github.com/btcsuite/btcd v0.21.0-beta/go.mod h1:ZSWyehm27aAuS9bvkATT+Xte3hjHZ+MRgMY/8NJ7K94= github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f h1:bAs4lUbRJpnnkd9VhRV3jjAVU7DJVjMaK+IsvSeZvFo= github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f/go.mod h1:TdznJufoqS23FtqVCzL0ZqgP5MqXbb4fg/WgDys70nA= +github.com/btcsuite/btcutil v0.0.0-20180706230648-ab6388e0c60a/go.mod h1:+5NJ2+qvTyV9exUAL/rxXi3DcLg2Ts+ymUAY5y4NvMg= github.com/btcsuite/btcutil v0.0.0-20190425235716-9e5f4b9a998d/go.mod h1:+5NJ2+qvTyV9exUAL/rxXi3DcLg2Ts+ymUAY5y4NvMg= github.com/btcsuite/btcutil v1.0.2 h1:9iZ1Terx9fMIOtq1VrwdqfsATL9MC2l8ZrUY6YZ2uts= github.com/btcsuite/btcutil v1.0.2/go.mod h1:j9HUFwoQRsZL3V4n+qG+CUnEGHOarIxfC3Le2Yhbcts= @@ -41,69 +120,279 @@ github.com/btcsuite/snappy-go v1.0.0/go.mod h1:8woku9dyThutzjeg+3xrA5iCpBRH8XEEg github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792 h1:R8vQdOQdZ9Y3SkEwmHoWBmX1DNXhXZqlTpq6s4tyJGc= github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792/go.mod h1:ghJtEyQwv5/p4Mg4C0fgbePVuGr935/5ddU9Z3TmDRY= github.com/btcsuite/winsvc v1.0.0/go.mod h1:jsenWakMcC0zFBFurPLEAyrnc/teJEM1O46fmI40EZs= +github.com/casbin/casbin/v2 v2.1.2/go.mod h1:YcPU1XXisHhLzuxH9coDNf2FbKpjGlbCg3n9yuLkIJQ= +github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM= +github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/cespare/cp v0.1.0/go.mod h1:SOGHArjBr4JWaSDEVpWpo/hNg6RoKrls6Oh40hiwW+s= +github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko= +github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= +github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY= +github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/clbanning/x2j v0.0.0-20191024224557-825249438eec/go.mod h1:jMjuTZXRI4dUb/I5gc9Hdhagfvm9+RyrPryS/auMzxE= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/cloudflare/cloudflare-go v0.10.2-0.20190916151808-a80f83b9add9/go.mod h1:1MxXX1Ux4x6mqPmjkUgTP1CdXIBXKX7T+Jk9Gxrmx+U= +github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= +github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8= +github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI= +github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= github.com/coreos/bbolt v1.3.3/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= -github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d h1:U+s90UTSYgptZMwQh2aRr3LuazLJIa+Pg3Kc1ylSYVY= +github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= +github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= +github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= +github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= +github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= +github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= +github.com/cosmos/cosmos-sdk v0.39.2 h1:nLfCJMkUuFt7ansi/YvCxwwxLFrgHCA3cYP4sJKYQdk= +github.com/cosmos/cosmos-sdk v0.39.2/go.mod h1:VNUluciWBFj2vkhpMcp8rYZL/kCw0FtNc7SseUjE1KM= +github.com/cosmos/go-bip39 v0.0.0-20180819234021-555e2067c45d h1:49RLWk1j44Xu4fjHb6JFYmeUnDORVwHNkDxaQ0ctCVU= +github.com/cosmos/go-bip39 v0.0.0-20180819234021-555e2067c45d/go.mod h1:tSxLoYXyBmiFeKpvmq4dzayMdCjCnu8uqmCysIGBT2Y= +github.com/cosmos/ledger-cosmos-go v0.11.1 h1:9JIYsGnXP613pb2vPjFeMMjBI5lEDsEaF6oYorTy6J4= +github.com/cosmos/ledger-cosmos-go v0.11.1/go.mod h1:J8//BsAGTo3OC/vDLjMRFLW6q0WAaXvHnVc7ZmE8iUY= +github.com/cosmos/ledger-go v0.9.2 h1:Nnao/dLwaVTk1Q5U9THldpUMMXU94BOTWPddSmVB6pI= +github.com/cosmos/ledger-go v0.9.2/go.mod h1:oZJ2hHAZROdlHiwTg4t7kP+GKIIkBT+o6c9QWFanOyI= github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= +github.com/cpuguy83/go-md2man/v2 v2.0.0 h1:EoUDS0afbrsXAZ9YQ9jdu/mZ2sXgT1/2yyNng4PGlyM= +github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= +github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= +github.com/daaku/go.zipexe v1.0.0/go.mod h1:z8IiR6TsVLEYKwXAoE/I+8ys/sDkgTzSL0CLnGVd57E= +github.com/danieljoos/wincred v1.0.2 h1:zf4bhty2iLuwgjgpraD2E9UbvO+fe54XXGJbOwe23fU= +github.com/danieljoos/wincred v1.0.2/go.mod h1:SnuYRW9lp1oJrZX/dXJqr0cPK5gYXqx3EJbmjhLdK9U= github.com/davecgh/go-spew v0.0.0-20171005155431-ecdeabc65495/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/deckarep/golang-set v0.0.0-20180603214616-504e848d77ea/go.mod h1:93vsz/8Wt4joVM7c2AVqh+YRMiUSc14yDtF28KmMOgQ= github.com/deckarep/golang-set v1.7.1 h1:SCQV0S6gTtp6itiFrTqI+pfmJ4LN85S1YzhDf9rTHJQ= github.com/deckarep/golang-set v1.7.1/go.mod h1:93vsz/8Wt4joVM7c2AVqh+YRMiUSc14yDtF28KmMOgQ= github.com/decred/dcrd/lru v1.0.0/go.mod h1:mxKOwFd7lFjN2GZYsiz/ecgqR6kkYAl+0pz0tEMk218= +github.com/dfuse-io/binary v0.0.0-20201123150056-096380ef3e5d/go.mod h1:GDFX6qH3BQZPWTeYaA4ZW98T94zs2skRoG3oMz/0jw0= +github.com/dfuse-io/binary v0.0.0-20210216024852-4ae6830a495d h1:EvEAQZ38olo+sALrqqCo345IeB2HH4im1deNOcjbi0s= +github.com/dfuse-io/binary v0.0.0-20210216024852-4ae6830a495d/go.mod h1:GDFX6qH3BQZPWTeYaA4ZW98T94zs2skRoG3oMz/0jw0= +github.com/dfuse-io/logging v0.0.0-20201110202154-26697de88c79 h1:+HRtcJejUYA/2rnyTMbOaZ4g7f4aVuFduTV/03dbpLY= +github.com/dfuse-io/logging v0.0.0-20201110202154-26697de88c79/go.mod h1:V+ED4kT/t/lKtH99JQmKIb0v9WL3VaYkJ36CfHlVECI= +github.com/dfuse-io/solana-go v0.2.0 h1:i7HzMR2b3nexyT0i+G7YeBDZFzzMbD+tEgHKsfmc7oo= +github.com/dfuse-io/solana-go v0.2.0/go.mod h1:JmxX8KYNWRCwg1RyADE2kersXSNqE1KLt+w5nEq353g= +github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= +github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= +github.com/dlclark/regexp2 v1.2.0/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc= +github.com/docker/docker v1.4.2-0.20180625184442-8e610b2b55bf/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/dop251/goja v0.0.0-20200219165308-d1232e640a87/go.mod h1:Mw6PkjjMXWbTj+nnj4s3QPXq1jaT0s5pC0iFD4+BOAA= +github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= +github.com/dvsekhvalnov/jose2go v0.0.0-20200901110807-248326c1351b h1:HBah4D48ypg3J7Np4N+HY/ZR76fx3HEUGxDU6Uk39oQ= +github.com/dvsekhvalnov/jose2go v0.0.0-20200901110807-248326c1351b/go.mod h1:7BvyPhdbLxMXIYTFPLsyJRFMsKmOZnQmzh6Gb+uquuM= github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs= github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU= github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I= +github.com/edsrzf/mmap-go v0.0.0-20160512033002-935e0e8a636c/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M= +github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M= +github.com/elastic/gosigar v0.8.1-0.20180330100440-37f05ff46ffa h1:XKAhUk/dtp+CV0VO6mhG2V7jA9vbcGcnYF/Ay9NjZrY= +github.com/elastic/gosigar v0.8.1-0.20180330100440-37f05ff46ffa/go.mod h1:cdorVVzy1fhmEqmtgqkoE3bYtCfSCkVyjTyCIo22xvs= +github.com/envoyproxy/go-control-plane v0.6.9/go.mod h1:SBwIajubJHhxtWwsL9s8ss4safvEdbitLhGGK48rN6g= +github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= +github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/ethereum/go-ethereum v1.9.14 h1:/rGoPYujLeajAHyDs8aZKYcLrurLdUJP9AzHk73QNr0= +github.com/ethereum/go-ethereum v1.9.14/go.mod h1:oP8FC5+TbICUyftkTWs+8JryntjIJLJvWvApK3z2AYw= +github.com/ethereum/go-ethereum v1.9.20 h1:kk/J5OIoaoz3DRrCXznz3RGi212mHHXwzXlY/ZQxcj0= +github.com/ethereum/go-ethereum v1.9.20/go.mod h1:JSSTypSMTkGZtAdAChH2wP5dZEvPGh3nUTuDpH+hNrg= +github.com/facebookgo/ensure v0.0.0-20160127193407-b4ab57deab51 h1:0JZ+dUmQeA8IIVUMzysrX4/AKuQwWhV2dYQuPZdvdSQ= +github.com/facebookgo/ensure v0.0.0-20160127193407-b4ab57deab51/go.mod h1:Yg+htXGokKKdzcwhuNDwVvN+uBxDGXJ7G/VN1d8fa64= +github.com/facebookgo/stack v0.0.0-20160209184415-751773369052 h1:JWuenKqqX8nojtoVVWjGfOF9635RETekkoH6Cc9SX0A= +github.com/facebookgo/stack v0.0.0-20160209184415-751773369052/go.mod h1:UbMTZqLaRiH3MsBH8va0n7s1pQYcu3uTb8G4tygF4Zg= +github.com/facebookgo/subset v0.0.0-20150612182917-8dac2c3c4870 h1:E2s37DuLxFhQDg5gKsWoLBOB0n+ZW8s599zru8FJ2/Y= +github.com/facebookgo/subset v0.0.0-20150612182917-8dac2c3c4870/go.mod h1:5tD+neXqOorC30/tWg0LCSkrqj/AR6gu8yY8/fpw1q0= github.com/fastly/go-utils v0.0.0-20180712184237-d95a45783239 h1:Ghm4eQYC0nEPnSJdVkTrXpu9KtoVCSo1hg7mtI7G9KU= github.com/fastly/go-utils v0.0.0-20180712184237-d95a45783239/go.mod h1:Gdwt2ce0yfBxPvZrHkprdPPTTS3N5rwmLE8T22KBXlw= +github.com/fatih/color v1.3.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/fatih/color v1.7.0 h1:DkWD4oS2D8LGGgTQ6IvwJJXSL5Vp2ffcQg58nFV38Ys= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/fatih/color v1.9.0 h1:8xPHl4/q1VyqGIPif1F+1V3Y3lSmrq01EabUW3CoW5s= +github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU= +github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M= +github.com/fbsobreira/gotron-sdk v0.0.0-20210316163828-8cb47d581197 h1:ExhXsDBcQpgdcxQyiY77JTUfQS1nbo6lOllBurALbR0= +github.com/fbsobreira/gotron-sdk v0.0.0-20210316163828-8cb47d581197/go.mod h1:k2Ei1n5T6T7YRLz9Cv8IJi7Q4kmHSLoJS7Nglsrec5k= github.com/felixge/httpsnoop v1.0.1 h1:lvB5Jl89CsZtGIWuTcDM1E/vkVs49/Ml7JJe07l8SPQ= github.com/felixge/httpsnoop v1.0.1/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= +github.com/fjl/memsize v0.0.0-20180418122429-ca190fb6ffbc/go.mod h1:VvhXpOYNQvB+uIk2RvXzuaQtkQJzzIx6lSBe1xv7hi0= +github.com/fortytw2/leaktest v1.3.0 h1:u8491cBMTQ8ft8aeV+adlcytMZylmA5nnwwkRZjI8vw= +github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g= +github.com/franela/goblin v0.0.0-20200105215937-c9ffbefa60db/go.mod h1:7dvUGVsVBjqR7JHJk0brhHOZYGmfBYOrK0ZhYMEtBr4= +github.com/franela/goreq v0.0.0-20171204163338-bcd34c9993f8/go.mod h1:ZhphrRTfi2rbfLwlschooIH4+wKKDR4Pdxhh+TRoA20= github.com/fsn-dev/fsn-go-sdk v0.0.0-20201127063150-d66d045799f9 h1:xPJfIdoA/Ux4kbKtV7L2h0Z10eHo0AeKAg/2YxYRA98= github.com/fsn-dev/fsn-go-sdk v0.0.0-20201127063150-d66d045799f9/go.mod h1:MtL34MP65N4fVCkYHlaXabn0mKKVOZZL2hRRS7L16ak= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= github.com/garyburd/redigo v1.6.0/go.mod h1:NR3MbYisc3/PwhQ00EMzDiPmrwpPxAn5GI05/YaO1SY= +github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff/go.mod h1:x7DCsMOv1taUwEWCzT4cmDeAkigA5/QCwUodaVOe8Ww= +github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/kit v0.10.0 h1:dXFJfIHVvUcpSgDOV+Ne6t7jXri8Tfv2uOLHUZ2XNuo= +github.com/go-kit/kit v0.10.0/go.mod h1:xUsJbQ/Fp4kEt7AFgCuvyX4a71u8h9jB8tj/ORgOZ7o= github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= +github.com/go-logfmt/logfmt v0.5.0 h1:TrB8swr/68K7m9CcGut2g3UOihhbcbiMAYiuTXdEih4= +github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= +github.com/go-ole/go-ole v1.2.1 h1:2lOsA72HgjxAuMlKpFiCbHTvu44PIVkZ5hqm3RSdI/E= +github.com/go-ole/go-ole v1.2.1/go.mod h1:7FAglXiTm7HKlQRDeOQ6ZNUHidzCWXuZWq/1dTyBNF8= +github.com/go-resty/resty/v2 v2.5.0 h1:GmCjQ7qW3Dzr3Lh7FvTrRJSWgYNWswDdOy+T8sgTAFI= +github.com/go-resty/resty/v2 v2.5.0/go.mod h1:B88+xCTEwvfD94NOuE6GS1wMlnoKNY8eEiNizfNwOwA= +github.com/go-sourcemap/sourcemap v2.1.2+incompatible/go.mod h1:F8jJfvm2KbVjc5NqelyYJmf/v5J0dwNLS2mL4sNA1Jg= +github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2 h1:ZpnhV/YsD2/4cESfV5+Hoeu/iUR3ruzNvZ+yQfO03a0= +github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2/go.mod h1:bBOAhwG1umN6/6ZUMtDFBMQR8jRg9O75tm9K00oMsK4= +github.com/gogo/googleapis v1.1.0/go.mod h1:gf4bu3Q80BeJ6H1S1vYPm8/ELATdvryBaNFGgqEef3s= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= +github.com/gogo/protobuf v1.3.1 h1:DqDEcV5aeaTmdFBePNpYsp3FlcVH/2ISVVM9Qf8PSls= +github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6 h1:ZgQEtGgCBiWRM39fZuwSd1LwSqqSW0hOdXCYYDX0R3I= +github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:tluoj9z5200jBnyusfRPU2LqT6J+DAorxEvtC7LHB+E= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.3.1-0.20190508161146-9fa652df1129 h1:tT8iWCYw4uOem71yYA3htfH+LNopJvcqZQshm56G5L4= +github.com/golang/mock v1.3.1-0.20190508161146-9fa652df1129/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= +github.com/golang/mock v1.3.1 h1:qGJ6qTW+x6xX/my+8YUVl4WNpX9B7+/l2tRsHGZ7f2s= +github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.0/go.mod h1:Qd/q+1AKNOZr9uGQzbzCmRO6sUih6GTPZv6a1/R87v0= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.2 h1:6nsPYzhq5kReh6QImI3k5qWzO4PEbvbIW2cwSfR/6xs= +github.com/golang/protobuf v1.3.2-0.20190517061210-b285ee9cfc6c/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= +github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= +github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= +github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= +github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= +github.com/golang/protobuf v1.4.1 h1:ZFgWrT+bLgsYPirOnRfKLYJLvssAegOj/hgyMFdJZe0= +github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= +github.com/golang/protobuf v1.4.2 h1:+Z5KGCizgyZCbGh1KZqA0fcLLkwbsjIzS4aV2v7wJX0= +github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/golang/snappy v0.0.2-0.20200707131729-196ae77b8a26/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/golang/snappy v0.0.2/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/golang/snappy v0.0.3-0.20201103224600-674baa8c7fc3 h1:ur2rms48b3Ep1dxh7aUV2FZEQ8jEVO2F6ILKx8ofkAg= +github.com/golang/snappy v0.0.3-0.20201103224600-674baa8c7fc3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/btree v1.0.0 h1:0udJVsspx3VBr5FwtLhQQtuAsVc79tTq0ocGIPAU6qo= +github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.0 h1:/QaMHBdZ26BB3SSst0Iwl10Epc+xhTquomWX0oZEB6w= +github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/gofuzz v0.0.0-20170612174753-24818f796faf/go.mod h1:HP5RmnzzSNb993RKQDq4+1A4ia9nllfqcQFTQJedwGI= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/gofuzz v1.1.1-0.20200604201612-c04b05f3adfa h1:Q75Upo5UN4JbPFURXZ8nLKYUvF85dyFRop/vQ0Rv+64= +github.com/google/gofuzz v1.1.1-0.20200604201612-c04b05f3adfa/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= +github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/uuid v1.0.0 h1:b4Gk+7WdP/d3HZH8EJsZpvV7EtDOgaZLtnaNGIu1adA= github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= +github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= +github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8= +github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg= +github.com/gorilla/handlers v1.4.2/go.mod h1:Qkdc/uu4tH4g6mTK6auzZ766c4CA0Ng8+o/OAirnOIQ= github.com/gorilla/handlers v1.5.1 h1:9lRY6j8DEeeBT10CvO9hGW0gmky0BprnvDI5vfhUHH4= github.com/gorilla/handlers v1.5.1/go.mod h1:t8XrUpc4KVXb7HGyJ4/cEnwQiaxrX/hz1Zv/4g96P1Q= +github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= +github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= +github.com/gorilla/mux v1.7.4/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI= github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= github.com/gorilla/rpc v1.2.0 h1:WvvdC2lNeT1SP32zrIce5l0ECBfbAlmrmSBsuc57wfk= github.com/gorilla/rpc v1.2.0/go.mod h1:V4h9r+4sF5HnzqbwIez0fKSpANP0zlYd3qR7p36jkTQ= -github.com/gorilla/websocket v1.4.1 h1:q7AeDBpnBk8AogcD4DSag/Ukw/KV+YhzLj2bP5HvKCM= +github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= +github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= +github.com/gorilla/websocket v1.4.1-0.20190629185528-ae1634f6a989/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc= +github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/graph-gophers/graphql-go v0.0.0-20191115155744-f33e81362277/go.mod h1:9CQHMSxwO4MprSdzoIEobiHpoLtHm77vfxsvsIN5Vuc= +github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= +github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= +github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= +github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= +github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= +github.com/gsterjov/go-libsecret v0.0.0-20161001094733-a6f4afe4910c h1:6rhixN/i8ZofjG1Y75iExal34USq5p+wiN1tpie8IrU= +github.com/gsterjov/go-libsecret v0.0.0-20161001094733-a6f4afe4910c/go.mod h1:NMPJylDgVpX0MLRlPy15sqSwOFv/U1GZ2m21JhFfek0= +github.com/gtank/merlin v0.1.1-0.20191105220539-8318aed1a79f/go.mod h1:T86dnYJhcGOh5BjZFCJWTDeTK7XW8uE+E21Cy/bIQ+s= +github.com/gtank/merlin v0.1.1 h1:eQ90iG7K9pOhtereWsmyRJ6RAwcP4tHTDBHXNg+u5is= +github.com/gtank/merlin v0.1.1/go.mod h1:T86dnYJhcGOh5BjZFCJWTDeTK7XW8uE+E21Cy/bIQ+s= +github.com/gtank/ristretto255 v0.1.2 h1:JEqUCPA1NvLq5DwYtuzigd7ss8fwbYay9fi4/5uMzcc= +github.com/gtank/ristretto255 v0.1.2/go.mod h1:Ph5OpO6c7xKUGROZfWVLiJf9icMDwUeIvY4OmlYW69o= +github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q= +github.com/hashicorp/consul/api v1.3.0/go.mod h1:MmDNSzIMUjNpY/mQ398R4bk2FnqQLoPndWW5VkKPlCE= +github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= +github.com/hashicorp/consul/sdk v0.3.0/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= +github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= +github.com/hashicorp/go-immutable-radix v1.0.0 h1:AKDB1HM5PWEA7i4nhcpwOrO2byshxBjXVn/J/3+z5/0= +github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= +github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= +github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU= +github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU= +github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4= +github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-uuid v1.0.1 h1:fv1ep09latC32wFoVwnqcnKJGnMSdBanPczbHAYm1BE= github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= +github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90= +github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.3/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= +github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc= +github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= +github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= +github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= +github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64= +github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ= +github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I= +github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc= +github.com/holiman/uint256 v1.1.1/go.mod h1:y4ga/t+u+Xwd7CpDgZESaRcWy0I7XMlTMA25ApIH5Jw= github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= +github.com/hudl/fargo v1.3.0/go.mod h1:y3CKSmjA+wD2gak7sUSXTAoopbhU08POFhmITJgmKTg= +github.com/huin/goupnp v1.0.0/go.mod h1:n9v9KO1tAxYH82qOn+UTIFQDmx5n1Zxd/ClZDMX7Bnc= +github.com/huin/goutil v0.0.0-20170803182201-1ca381bf3150/go.mod h1:PpLOETDnJ0o3iZrZfqZzyLl6l7F3c6L1oWn7OICBi6o= github.com/inconshreveable/log15 v0.0.0-20180818164646-67afb5ed74ec h1:CGkYB1Q7DSsH/ku+to+foV4agt2F2miquaLUgF6L178= github.com/inconshreveable/log15 v0.0.0-20180818164646-67afb5ed74ec/go.mod h1:cOaXtrgN4ScfRrD9Bre7U1thNq5RtJ8ZoP4iXVGRj6o= +github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM= +github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= +github.com/influxdata/influxdb v1.2.3-0.20180221223340-01288bdb0883/go.mod h1:qZna6X/4elxqT3yI9iZYdZrWWdeFOOprn86kgg4+IzY= github.com/influxdata/influxdb1-client v0.0.0-20190809212627-fc22c7df067e/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo= +github.com/influxdata/influxdb1-client v0.0.0-20191209144304-8bf82d3c094d/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo= +github.com/jackpal/go-nat-pmp v1.0.2-0.20160603034137-1fa385a6f458/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc= github.com/jcmturner/gofork v0.0.0-20190328161633-dc7c13fece03/go.mod h1:MK8+TM0La+2rjBD4jE12Kj1pCCxK7d2LK/UM3ncEo0o= github.com/jehiah/go-strftime v0.0.0-20171201141054-1d33003b3869 h1:IPJ3dvxmJ4uczJe5YQdrYB16oTJlGSC/OyZDqUk9xX4= github.com/jehiah/go-strftime v0.0.0-20171201141054-1d33003b3869/go.mod h1:cJ6Cj7dQo+O6GJNiMx+Pa94qKj+TG8ONdKHgMNIyyag= github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= +github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= +github.com/jmhodges/levigo v1.0.0 h1:q5EC36kV79HWeTBWsod3mG11EgStG3qArTKcvlksN1U= +github.com/jmhodges/levigo v1.0.0/go.mod h1:Q6Qx+uH3RAqyK4rFQroq9RL7mdkABMcfhEI+nNuzMJQ= +github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= github.com/jonboulle/clockwork v0.2.2 h1:UOGuzwb1PwsrDAObMuhUnj0p5ULPj8V/xJ7Kx9qUBdQ= github.com/jonboulle/clockwork v0.2.2/go.mod h1:Pkfl5aHPm1nk2H9h0bjmnJD/BcgbGXUBGnn1kMkgxc8= github.com/jordan-wright/email v0.0.0-20200917010138-e1c00e156980 h1:oA5cj6k91NbiK2Xzvt9nlAiJjHhtNxSn9KOKnryz7oE= @@ -111,7 +400,19 @@ github.com/jordan-wright/email v0.0.0-20200917010138-e1c00e156980/go.mod h1:1c7s github.com/jrick/logrotate v1.0.0/go.mod h1:LNinyqDIJnpAur+b8yyulnQw/wDuN1+BYKlTRt3OuAQ= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= +github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= +github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= +github.com/julienschmidt/httprouter v1.1.1-0.20170430222011-975b5c4c7c21/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/karalabe/hid v1.0.0/go.mod h1:Vr51f8rUOLYrfrWDFlV12GGQgM5AT8sVh+2fY4MPeu8= +github.com/karalabe/usb v0.0.0-20190919080040-51dc0efba356/go.mod h1:Od972xHfMJowv7NGVDiWVxk2zxnWgjLlJzE+F4F7AGU= +github.com/keybase/go-keychain v0.0.0-20190712205309-48d3d31d256d h1:Z+RDyXzjKE0i2sTjZ/b1uxiGtPhFy34Ou/Tk0qwN0kM= +github.com/keybase/go-keychain v0.0.0-20190712205309-48d3d31d256d/go.mod h1:JJNrCn9otv/2QP4D7SMJBgaleKpOf66PnW6F5WGNRIc= +github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= +github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/kkdai/bstream v0.0.0-20161212061736-f391b8402d23/go.mod h1:J+Gs4SYgM6CZQHDETBtE9HaSEkGmuNXF86RwHhHUvq4= github.com/kkdai/bstream v0.0.0-20181106074824-b3251f7901ec/go.mod h1:J+Gs4SYgM6CZQHDETBtE9HaSEkGmuNXF86RwHhHUvq4= @@ -132,7 +433,12 @@ github.com/lestrrat-go/file-rotatelogs v2.4.0+incompatible h1:Y6sqxHMyB1D2YSzWkL github.com/lestrrat-go/file-rotatelogs v2.4.0+incompatible/go.mod h1:ZQnN8lSECaebrkQytbHj4xNgtg8CR7RYXnPok8e0EHA= github.com/lestrrat-go/strftime v1.0.3 h1:qqOPU7y+TM8Y803I8fG9c/DyKG3xH/xkng6keC1015Q= github.com/lestrrat-go/strftime v1.0.3/go.mod h1:E1nN3pCbtMSu1yjSVeyuRFVm/U0xoR76fd03sz+Qz4g= +github.com/libp2p/go-buffer-pool v0.0.2 h1:QNK2iAFa8gjAe1SPz6mHSMuCcjs+X1wlHzeOSqcmlfs= +github.com/libp2p/go-buffer-pool v0.0.2/go.mod h1:MvaB6xw5vOrDl8rYZGLFdKAuk/hRoRZd1Vi32+RXyFM= github.com/lightninglabs/gozmq v0.0.0-20191113021534-d20a764486bf/go.mod h1:vxmQPeIQxPf6Jf9rM8R+B4rKBqLA2AjttNxkFBL2Plk= +github.com/lightstep/lightstep-tracer-common/golang/gogo v0.0.0-20190605223551-bc2310a04743/go.mod h1:qklhhLq1aX+mtWk9cPHPzaBjWImj5ULL6C7HFJtXQMM= +github.com/lightstep/lightstep-tracer-go v0.18.1/go.mod h1:jlF1pusYV4pidLvZ+XD0UBX0ZE6WURAspgAczcDHrL4= +github.com/logrusorgru/aurora v2.0.3+incompatible/go.mod h1:7rIyQOR62GCctdiQpZ/zOJlFyk6y+94wXzv6RNZgaR4= github.com/ltcsuite/lnd/queue v1.0.3/go.mod h1:L0MMGRrsJFPHhTInek8YgW2v7NyB6pXrAh6Bbg2D7u8= github.com/ltcsuite/lnd/ticker v1.0.1/go.mod h1:WZKpekfDVAVv7Gsrr0GAWC/U1XURfGesFg9sQYJbeL4= github.com/ltcsuite/ltcd v0.20.1-beta h1:ka9ZwUG7oUPppl+7ptuh5VDxGD7TWEJXu/IOOOz1yfY= @@ -153,155 +459,574 @@ github.com/ltcsuite/ltcwallet/wallet/txsizes v1.0.0/go.mod h1:BVSZSGrQP4MXD7Y3vV github.com/ltcsuite/ltcwallet/walletdb v1.2.0/go.mod h1:C4GeXkLjUw1zkKiUwTvqSKE0eJmFjM7FZBjjw6TglJw= github.com/ltcsuite/ltcwallet/wtxmgr v1.0.0/go.mod h1:mEc+C10DLTHG6iaDnBUlulZGADd1QMe+gZOiCNo/qcg= github.com/ltcsuite/neutrino v0.11.0/go.mod h1:22zulMl4XMtJJb/7Z8YR3oud1EqfbQ2oSYE4gMnNVfM= +github.com/lyft/protoc-gen-validate v0.0.13/go.mod h1:XbGvPuh87YZc5TdIa2/I4pLk0QoUACkjt2znoq26NVQ= +github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= +github.com/magiconair/properties v1.8.1 h1:ZC2Vc7/ZFkGmsVC9KvOjumD+G5lXy2RtTKyzRKO2BQ4= +github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= +github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +github.com/mattn/go-colorable v0.1.0/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= github.com/mattn/go-colorable v0.1.4 h1:snbPLB8fVfU9iwbbo30TPtbLRzwWu6aJS6Xh4eaaviA= github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= +github.com/mattn/go-ieproxy v0.0.0-20190610004146-91bb50d98149/go.mod h1:31jz6HNzdxOmlERGGEc4v/dMssOfmp2p5bT/okiKFFc= +github.com/mattn/go-ieproxy v0.0.0-20190702010315-6dee0af9227d/go.mod h1:31jz6HNzdxOmlERGGEc4v/dMssOfmp2p5bT/okiKFFc= +github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-isatty v0.0.5-0.20180830101745-3fb116b82035/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= -github.com/mattn/go-isatty v0.0.10 h1:qxFzApOv4WsAL965uUPIsXzAKCZxN2p9UqdhFS4ZW10= github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84= -github.com/mattn/go-runewidth v0.0.3 h1:a+kO+98RDGEfo6asOGMmpodZq4FNtnGP54yps8BzLR4= +github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE= +github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY= +github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= github.com/mattn/go-runewidth v0.0.3/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= +github.com/mattn/go-runewidth v0.0.4 h1:2BvfKmzob6Bmd4YsL0zygOqfdFnK7GR4QL06Do4/p7Y= +github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= +github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= +github.com/mimoo/StrobeGo v0.0.0-20181016162300-f8f6d4d2b643 h1:hLDRPB66XQT/8+wG9WsDpiCvZf1yKO7sz7scAjSlBa0= +github.com/mimoo/StrobeGo v0.0.0-20181016162300-f8f6d4d2b643/go.mod h1:43+3pMjjKimDBf5Kr4ZFNGbLql1zKkbImw+fZbw3geM= +github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1 h1:lYpkrQH5ajf0OXOcUbGjvZxxijuBwbbmlSxLiuofa+g= +github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1/go.mod h1:pD8RvIylQ358TN4wwqatJ8rNavkEINozVn9DtGI3dfQ= +github.com/minio/highwayhash v1.0.0 h1:iMSDhgUILCr0TNm8LWlSjF8N0ZIj2qbO8WHp6Q/J2BA= +github.com/minio/highwayhash v1.0.0/go.mod h1:xQboMTeM9nY9v/LlAOxFctujiv5+Aq2hR5dxBpaMbdc= +github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= +github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= +github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= +github.com/mitchellh/go-testing-interface v1.14.1 h1:jrgshOhYAUVNMAJiKbEu7EqAwgJJ2JqpQmpLJOu07cU= +github.com/mitchellh/go-testing-interface v1.14.1/go.mod h1:gfgS7OtZj6MA4U1UrDRp04twqAjfvlZyCfX3sDjEym8= +github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg= +github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY= +github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE= +github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/mr-tron/base58 v1.2.0 h1:T/HDJBh4ZCPbU39/+c3rRvE0uKBQlU27+QI8LJ4t64o= +github.com/mr-tron/base58 v1.2.0/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= +github.com/mtibben/percent v0.2.1 h1:5gssi8Nqo8QU/r2pynCm+hBQHpkB/uNK7BJCFogWdzs= +github.com/mtibben/percent v0.2.1/go.mod h1:KG9uO+SZkUp+VkRHsCdYQV3XSZrrSpR3O9ibNBTZrns= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/naoina/go-stringutil v0.1.0/go.mod h1:XJ2SJL9jCtBh+P9q5btrd/Ylo8XwT/h1USek5+NqSA0= +github.com/naoina/toml v0.1.2-0.20170918210437-9fafd6967416/go.mod h1:NBIhNtsFMo3G2szEBne+bO4gS192HuIYRqfvOWb4i1E= +github.com/nats-io/jwt v0.3.0/go.mod h1:fRYCDE99xlTsqUzISS1Bi75UBJ6ljOJQOAAu5VglpSg= +github.com/nats-io/jwt v0.3.2/go.mod h1:/euKqTS1ZD+zzjYrY7pseZrTtWQSjujC7xjPc8wL6eU= +github.com/nats-io/nats-server/v2 v2.1.2/go.mod h1:Afk+wRZqkMQs/p45uXdrVLuab3gwv3Z8C4HTBu8GD/k= +github.com/nats-io/nats.go v1.9.1/go.mod h1:ZjDU1L/7fJ09jvUSRVBR2e7+RnLiiIQyqyzEE/Zbp4w= +github.com/nats-io/nkeys v0.1.0/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w= +github.com/nats-io/nkeys v0.1.3/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w= +github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c= +github.com/nervosnetwork/ckb-sdk-go v0.3.0 h1:Ga929Ey9Sy2ydkvKbgaY0j4/1WwGflhaDg5g2zVAZ/s= +github.com/nervosnetwork/ckb-sdk-go v0.3.0/go.mod h1:68U+dmWvkMxhvNkaXrtyfTn7QQsmJTY9tNBbiASGtpY= +github.com/nkovacs/streamquote v0.0.0-20170412213628-49af9bddb229/go.mod h1:0aYXnNPJ8l7uZxf45rWW1a/uME32OF0rhiYGNQ2oF2E= +github.com/nxadm/tail v1.4.4 h1:DQuhQpB1tVlglWS2hLQ5OV6B5r8aGxSrPc5Qo6uTN78= +github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= +github.com/oklog/oklog v0.3.2/go.mod h1:FCV+B7mhrz4o+ueLpx+KqkyXRGMWOYEvfiXtdGtbWGs= +github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA= +github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= +github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= +github.com/olekukonko/tablewriter v0.0.1/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= +github.com/olekukonko/tablewriter v0.0.2-0.20190409134802-7e037d187b0c/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.10.1 h1:q/mM8GF/n0shIN8SaAZ0V+jnLPzen6WIVZdiwrRlMlo= github.com/onsi/ginkgo v1.10.1/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.12.1 h1:mFwc4LvZ0xpSvDZ3E+k8Yte0hLOMxXUlP+yXtJqkYfQ= +github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= github.com/onsi/gomega v1.4.1/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.7.0 h1:XPnZz8VVBHjVsy1vzJmRwIcSwiUO+JFfrv/xGiigmME= github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= +github.com/onsi/gomega v1.10.1 h1:o0+MgICZLuZ7xjH7Vx6zS/zcu93/BEp1VwkIW1mEXCE= +github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= +github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk= github.com/openconfig/gnmi v0.0.0-20190823184014-89b2bf29312c/go.mod h1:t+O9It+LKzfOAhKTT5O0ehDix+MTqbtT0T9t+7zzOvc= github.com/openconfig/reference v0.0.0-20190727015836-8dfd928c9696/go.mod h1:ym2A+zigScwkSEb/cVQB0/ZMpU3rqiH6X7WRRsxgOGw= +github.com/opentracing-contrib/go-observer v0.0.0-20170622124052-a52f23424492/go.mod h1:Ngi6UdF0k5OKD5t5wlmGhe/EDKPoUM3BXZSSfIuJbis= +github.com/opentracing/basictracer-go v1.0.0/go.mod h1:QfBfYuafItcjQuMwinw9GhYKwFXS9KnPs5lxoYwgW74= +github.com/opentracing/opentracing-go v1.0.2/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= +github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= +github.com/openzipkin-contrib/zipkin-go-opentracing v0.4.5/go.mod h1:/wsWhb9smxSfWAKL3wpBW7V8scJMt8N8gnaMCS9E/cA= +github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw= +github.com/openzipkin/zipkin-go v0.2.1/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4= +github.com/openzipkin/zipkin-go v0.2.2/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4= +github.com/otiai10/copy v1.0.2/go.mod h1:c7RpqBkwMom4bYTSkLSym4VSJz/XtncWRAj/J4PEIMY= +github.com/otiai10/curr v0.0.0-20150429015615-9b4961190c95/go.mod h1:9qAhocn7zKJG+0mI8eUu6xqkFDYS2kb2saOteoSB3cE= +github.com/otiai10/curr v0.0.0-20190513014714-f5a3d24e5776/go.mod h1:3HNVkVOU7vZeFXocWuvtcS0XSFLcf2XUSDHkq9t1jU4= +github.com/otiai10/mint v1.2.4/go.mod h1:d+b7n/0R3tdyUYYylALXpWQ/kTN+QobSq/4SRGBkR3M= +github.com/otiai10/mint v1.3.0/go.mod h1:F5AjcsTsWUqX+Na9fpHb52P8pcRX2CI6A3ctIT91xUo= +github.com/pact-foundation/pact-go v1.0.4/go.mod h1:uExwJY4kCzNPcHRj+hCR/HBbOOIwwtUjcrb0b5/5kLM= +github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= +github.com/pborman/uuid v0.0.0-20170112150404-1b00554d8222/go.mod h1:VyrYX9gd7irzKovcSS6BIIEwPRkP2Wm2m9ufcdFSJ34= github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k= github.com/pborman/uuid v1.2.1 h1:+ZZIw58t/ozdjRaXh/3awHfmWRbzYxJoAdNJxe/3pvw= github.com/pborman/uuid v1.2.1/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k= -github.com/peterh/liner v1.1.0 h1:f+aAedNJA6uk7+6rXsYBnhdo4Xux7ESLe+kcuVUF5os= +github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= +github.com/pelletier/go-toml v1.6.0 h1:aetoXYr0Tv7xRU/V4B4IZJ2QcbtMUFoNb3ORp7TzIK4= +github.com/pelletier/go-toml v1.6.0/go.mod h1:5N711Q9dKgbdkxHL+MEfF31hpT7l0S0s/t2kKREewys= +github.com/performancecopilot/speed v3.0.0+incompatible/go.mod h1:/CLtqpZ5gBg1M9iaPbIdPPGyKcA8hKdoy6hAWba7Yac= github.com/peterh/liner v1.1.0/go.mod h1:CRroGNssyjTd/qIG2FyxByd2S8JEAZXBl4qUrZf8GS0= +github.com/peterh/liner v1.1.1-0.20190123174540-a2c9a5303de7 h1:oYW+YCJ1pachXTQmzR3rNLYGGz4g/UgFcjb28p/viDM= +github.com/peterh/liner v1.1.1-0.20190123174540-a2c9a5303de7/go.mod h1:CRroGNssyjTd/qIG2FyxByd2S8JEAZXBl4qUrZf8GS0= github.com/pierrec/lz4 v0.0.0-20190327172049-315a67e90e41/go.mod h1:3/3N9NVKO0jef7pBehbT1qWhCMrIgbYNnFAZCqQ5LRc= +github.com/pierrec/lz4 v1.0.2-0.20190131084431-473cd7ce01a1/go.mod h1:3/3N9NVKO0jef7pBehbT1qWhCMrIgbYNnFAZCqQ5LRc= +github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/profile v1.2.1/go.mod h1:hJw3o1OdXxsrSjjVksARp5W95eeEaEfptyVZyv6JUPA= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs= +github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso= github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= github.com/prometheus/client_golang v1.1.0/go.mod h1:I1FGZT9+L76gKKOs5djB6ezCbFQP1xR9D75/vuwEF3g= +github.com/prometheus/client_golang v1.3.0/go.mod h1:hJaj2vgQTGQmVCsAACORcieXFeDPbaTKGT+JTgUa3og= +github.com/prometheus/client_golang v1.5.1 h1:bdHYieyGlH+6OLEk2YQha8THib30KP0/yD0YH9m6xcA= +github.com/prometheus/client_golang v1.5.1/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.1.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.2.0 h1:uq5h0d+GuxiXLJLNABMgp2qUWDPiLvgCzz2dUR+/W/M= +github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= +github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.6.0/go.mod h1:eBmuwkDJBwy6iBfxCBob6t6dR6ENT/y+J+Zk0j9GMYc= +github.com/prometheus/common v0.7.0/go.mod h1:DjGbpBbp5NYNiECxcL/VnbXCCaQpKd3tt26CguLLsqA= +github.com/prometheus/common v0.9.1 h1:KOMtN28tlbam3/7ZKEYKHhKoJZYYj3gMH4uc62x7X7U= +github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.0.3/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ= +github.com/prometheus/procfs v0.0.8 h1:+fpWZdT24pJBiqJdAwYBjPSk+5YmQzYNPYzQsdzLkt8= +github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= +github.com/prometheus/tsdb v0.6.2-0.20190402121629-4f204dcbc150/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= +github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= +github.com/rakyll/statik v0.1.6/go.mod h1:OEi9wJV/fMUAGx1eNjq75DKDsJVuEv1U0oYdX6GX8Zs= github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= +github.com/rcrowley/go-metrics v0.0.0-20200313005456-10cdbea86bc0 h1:MkV+77GLUNo5oJ0jf870itWm3D0Sjh7+Za9gazKc5LQ= +github.com/rcrowley/go-metrics v0.0.0-20200313005456-10cdbea86bc0/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= +github.com/rjeczalik/notify v0.9.1/go.mod h1:rKwnCoCGeuQnwBtTSPL9Dad03Vh2n40ePRrjvIXnJho= github.com/rjeczalik/notify v0.9.2 h1:MiTWrPj55mNDHEiIX5YUSKefw/+lCQVoAFmD6oQm5w8= github.com/rjeczalik/notify v0.9.2/go.mod h1:aErll2f0sUX9PXZnVNyeiObbmTlk5jnMoCa4QEjJeqM= github.com/robertkrimen/otto v0.0.0-20180617131154-15f95af6e78d/go.mod h1:xvqspoSXJTIpemEonrMDFq6XzwHYYgToXWj5eRX1OtY= +github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= +github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/rs/cors v0.0.0-20160617231935-a62a804a8a00/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU= github.com/rs/cors v1.7.0 h1:+88SsELBHx5r+hZ8TCkggzSstaWNbDvThkVK8H6f9ik= github.com/rs/cors v1.7.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU= +github.com/rs/xhandler v0.0.0-20160618193221-ed27b6fd6521/go.mod h1:RvLn4FgxWubrpZHtQLnOf6EwhN2hEMusxZOhcW9H3UQ= github.com/russross/blackfriday/v2 v2.0.1 h1:lPqVAte+HuHNfhJ/0LC98ESWRz8afy9tM/0RK8m9o+Q= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= +github.com/samuel/go-zookeeper v0.0.0-20190923202752-2cc03de413da/go.mod h1:gi+0XIa01GRL2eRQVjQkKGqKF3SF9vZR/HnPullcV2E= github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= +github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= +github.com/shengdoushi/base58 v1.0.0 h1:tGe4o6TmdXFJWoI31VoSWvuaKxf0Px3gqa3sUWhAxBs= +github.com/shengdoushi/base58 v1.0.0/go.mod h1:m5uIILfzcKMw6238iWAhP4l3s5+uXyF3+bJKUNhAL9I= +github.com/shirou/gopsutil v2.20.5+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA= github.com/shopspring/decimal v1.2.0 h1:abSATXmQEYyShuxI4/vyW3tV1MrKAJzCZ/0zLUXYbsQ= github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/sirupsen/logrus v1.7.0 h1:ShrD1U9pZB12TX0cVy0DtePoCH97K8EtX+mg7ZARUtM= github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= +github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM= +github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= +github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s= +github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= +github.com/snikch/goodman v0.0.0-20171125024755-10e37e294daa/go.mod h1:oJyF+mSPHbB5mVY2iO9KV3pTt/QbIkGaO8gQ2WrDbP4= +github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= +github.com/sony/gobreaker v0.4.1/go.mod h1:ZKptC7FHNvhBz7dN2LGjPVBz2sZJmc0/PkyDJOjmxWY= +github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= +github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= +github.com/spf13/afero v1.2.1 h1:qgMbHoJbPbw579P+1zVY+6n4nIFuIchaIjzZ/I/Yq8M= +github.com/spf13/afero v1.2.1/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk= +github.com/spf13/cast v1.3.0 h1:oget//CVOEoFewqQxwr0Ej5yjygnqGkvggSE/gB35Q8= +github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= +github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= +github.com/spf13/cobra v1.0.0 h1:6m/oheQuQ13N9ks4hubMG6BnvwOeaJrqSPLahSnczz8= +github.com/spf13/cobra v1.0.0/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE= +github.com/spf13/cobra v1.1.1 h1:KfztREH0tPxJJ+geloSLaAkaPkr4ki2Er5quFV1TDo4= +github.com/spf13/cobra v1.1.1/go.mod h1:WnodtKOvamDL/PwE2M4iKs8aMDBZ5Q5klgD3qfVJQMI= +github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= +github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk= +github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo= +github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= +github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE= +github.com/spf13/viper v1.6.3 h1:pDDu1OyEDTKzpJwdq4TiuLyMsUgRa/BT5cn5O62NoHs= +github.com/spf13/viper v1.6.3/go.mod h1:jUMtyi0/lB5yZH/FjyGAoH7IMNrIhlBf6pXZmbMDvzw= +github.com/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg= +github.com/spf13/viper v1.7.1 h1:pM5oEahlgWv/WnHXpgbKz7iLIxRf65tye2Ci+XFK5sk= +github.com/spf13/viper v1.7.1/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg= +github.com/status-im/keycard-go v0.0.0-20190316090335-8537d3370df4/go.mod h1:RZLeN1LMWmRsyYjvAu+I6Dm9QmlDaIIt+Y+4Kd7Tp+Q= +github.com/steakknife/bloomfilter v0.0.0-20180922174646-6819c0d2a570/go.mod h1:8OR4w3TdeIHIh1g6EMY5p0gVNOovcWC+1vpc7naMuAw= +github.com/steakknife/hamming v0.0.0-20180906055917-c99c65617cd3/go.mod h1:hpGUWaI9xL8pRQCTXQgocU38Qw1g0Us7n5PxxTwTCYU= +github.com/streadway/amqp v0.0.0-20190404075320-75d898a42a94/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= +github.com/streadway/amqp v0.0.0-20190827072141-edfb9018d271/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= +github.com/streadway/handy v0.0.0-20190108123426-d5acb3125c2a/go.mod h1:qNTQ5P5JnDBl6z3cMAg/SywNDC5ABu5ApDIw6lUbRmI= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.2.0 h1:Hbg2NidpLE8veEBkEZTL3CvlkUIVzuU9jDplZO54c48= +github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= -github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s= +github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= +github.com/syndtr/goleveldb v1.0.1-0.20190923125748-758128399b1d h1:gZZadD8H+fF+n9CmNhYL1Y0dJB+kLOmKd7FbPJLeGHs= +github.com/syndtr/goleveldb v1.0.1-0.20190923125748-758128399b1d/go.mod h1:9OrXJhf154huy1nPWmuSrkgjPUtUNhA+Zmy+6AESzuA= github.com/tebeka/strftime v0.1.5 h1:1NQKN1NiQgkqd/2moD6ySP/5CoZQsKa1d3ZhJ44Jpmg= github.com/tebeka/strftime v0.1.5/go.mod h1:29/OidkoWHdEKZqzyDLUyC+LmgDgdHo4WAFCDT7D/Ig= +github.com/tecbot/gorocksdb v0.0.0-20191217155057-f0fad39f321c h1:g+WoO5jjkqGAzHWCjJB1zZfXPIAaDpzXIEJ0eS6B5Ok= +github.com/tecbot/gorocksdb v0.0.0-20191217155057-f0fad39f321c/go.mod h1:ahpPrc7HpcfEWDQRZEmnXMzHY03mLDYMCxeDzy46i+8= github.com/templexxx/cpufeat v0.0.0-20180724012125-cef66df7f161/go.mod h1:wM7WEvslTq+iOEAMDLSzhVuOt5BRZ05WirO+b09GHQU= github.com/templexxx/xor v0.0.0-20181023030647-4e92f724b73b/go.mod h1:5XA7W9S6mni3h5uvOC75dA3m9CCCaS83lltmc0ukdi4= +github.com/tendermint/btcd v0.1.1 h1:0VcxPfflS2zZ3RiOAHkBiFUcPvbtRj5O7zHmcJWHV7s= +github.com/tendermint/btcd v0.1.1/go.mod h1:DC6/m53jtQzr/NFmMNEu0rxf18/ktVoVtMrnDD5pN+U= +github.com/tendermint/crypto v0.0.0-20191022145703-50d29ede1e15 h1:hqAk8riJvK4RMWx1aInLzndwxKalgi5rTqgfXxOxbEI= +github.com/tendermint/crypto v0.0.0-20191022145703-50d29ede1e15/go.mod h1:z4YtwM70uOnk8h0pjJYlj3zdYwi9l03By6iAIF5j/Pk= +github.com/tendermint/go-amino v0.14.1/go.mod h1:i/UKE5Uocn+argJJBb12qTZsCDBcAYMbR92AaJVmKso= +github.com/tendermint/go-amino v0.15.1 h1:D2uk35eT4iTsvJd9jWIetzthE5C0/k2QmMFkCN+4JgQ= +github.com/tendermint/go-amino v0.15.1/go.mod h1:TQU0M1i/ImAo+tYpZi73AU3V/dKeCoMC9Sphe2ZwGME= +github.com/tendermint/go-amino v0.16.0 h1:GyhmgQKvqF82e2oZeuMSp9JTN0N09emoSZlb2lyGa2E= +github.com/tendermint/go-amino v0.16.0/go.mod h1:TQU0M1i/ImAo+tYpZi73AU3V/dKeCoMC9Sphe2ZwGME= +github.com/tendermint/iavl v0.14.1 h1:jz7YOvGiPwmcqqVMcSMjxCu4WXtQYGhKdKrWTTJ5EKs= +github.com/tendermint/iavl v0.14.1/go.mod h1:QmfViflFiXzxKLQE4tAUuWQHq+RSuQFxablW5oJZ6sE= +github.com/tendermint/tendermint v0.33.9 h1:rRKIfu5qAXX5f9bwX1oUXSZz/ALFJjDuivhkbGUQxiU= +github.com/tendermint/tendermint v0.33.9/go.mod h1:0yUs9eIuuDq07nQql9BmI30FtYGcEC60Tu5JzB5IezM= +github.com/tendermint/tm-db v0.5.1 h1:H9HDq8UEA7Eeg13kdYckkgwwkQLBnJGgX4PgLJRhieY= +github.com/tendermint/tm-db v0.5.1/go.mod h1:g92zWjHpCYlEvQXvy9M168Su8V1IBEeawpXVVBaK4f4= +github.com/teris-io/shortid v0.0.0-20171029131806-771a37caa5cf h1:Z2X3Os7oRzpdJ75iPqWZc0HeJWFYNCvKsfpQwFpRNTA= +github.com/teris-io/shortid v0.0.0-20171029131806-771a37caa5cf/go.mod h1:M8agBzgqHIhgj7wEn9/0hJUZcrvt9VY+Ln+S1I5Mha0= +github.com/terra-project/core v0.4.2 h1:+7NxCtg8WV26ueTxgkP8tQJ070eJpo+dj/wyAknBr+0= +github.com/terra-project/core v0.4.2/go.mod h1:U8uN91QNHhKiCMRZtPpvQ637IJt2udDjhzIO3rUhUqE= +github.com/tidwall/gjson v1.6.3 h1:aHoiiem0dr7GHkW001T1SMTJ7X5PvyekH5WX0whWGnI= +github.com/tidwall/gjson v1.6.3/go.mod h1:BaHyNc5bjzYkPqgLq7mdVzeiRtULKULXLgZFKsxEHI0= +github.com/tidwall/match v1.0.1 h1:PnKP62LPNxHKTwvHHZZzdOAOCtsJTjo6dZLCwpKm5xc= +github.com/tidwall/match v1.0.1/go.mod h1:LujAq0jyVjBy028G1WhWfIzbpQfMO8bBZ6Tyb0+pL9E= +github.com/tidwall/pretty v1.0.2 h1:Z7S3cePv9Jwm1KwS0513MRaoUe3S01WPbLNV40pwWZU= +github.com/tidwall/pretty v1.0.2/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= github.com/tjfoc/gmsm v1.0.1/go.mod h1:XxO4hdhhrzAd+G4CjDqaOkd0hUzmtPR/d3EiBBMn/wc= +github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= +github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= +github.com/tyler-smith/go-bip39 v1.0.1-0.20181017060643-dbb3b84ba2ef/go.mod h1:sJ5fKU0s6JVwZjjcUEX2zFOnvq0ASQ2K9Zr6cf67kNs= +github.com/tyler-smith/go-bip39 v1.0.2 h1:+t3w+KwLXO6154GNJY+qUtIxLTmFjfUmpguQT1OlOT8= +github.com/tyler-smith/go-bip39 v1.0.2/go.mod h1:sJ5fKU0s6JVwZjjcUEX2zFOnvq0ASQ2K9Zr6cf67kNs= +github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= +github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= +github.com/urfave/cli v1.22.1 h1:+mkCCcOFKPnCmVYVcURKps1Xe+3zP90gSYGNfRkjoIY= +github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= github.com/urfave/cli/v2 v2.3.0 h1:qph92Y649prgesehzOrQjdWyxFOp/QVM+6imKHad91M= github.com/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/XcUArI= +github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= +github.com/valyala/fasttemplate v1.0.1/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8= +github.com/wsddn/go-ecdh v0.0.0-20161211032359-48726bab9208/go.mod h1:IotVbo4F+mw0EzQ08zFqg7pK3FebNXpaMsRy2RT+Ees= github.com/xdg/scram v0.0.0-20180814205039-7eeb5667e42c/go.mod h1:lB8K/P019DLNhemzwFU4jHLhdvlE6uDZjXFejJXr49I= github.com/xdg/stringprep v1.0.0/go.mod h1:Jhud4/sHMO4oL310DaZAKk9ZaJ08SJfe+sJh0HrGL1Y= +github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= +github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= github.com/xtaci/kcp-go v5.4.5+incompatible/go.mod h1:bN6vIwHQbfHaHtFpEssmWsN45a+AZwO7eyRCmEIbtvE= github.com/xtaci/lossyconn v0.0.0-20190602105132-8df528c0c9ae/go.mod h1:gXtu8J62kEgmN++bm9BVICuT/e8yiLI2KFobd/TRFsE= +github.com/ybbus/jsonrpc v2.1.2+incompatible h1:V4mkE9qhbDQ92/MLMIhlhMSbz8jNXdagC3xBR5NDwaQ= +github.com/ybbus/jsonrpc v2.1.2+incompatible/go.mod h1:XJrh1eMSzdIYFbM08flv0wp5G35eRniyeGut1z+LSiE= +github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/zondax/hid v0.9.0 h1:eiT3P6vNxAEVxXMw66eZUAAnU2zD33JBkfG/EnfAKl8= +github.com/zondax/hid v0.9.0/go.mod h1:l5wttcP0jwtdLjqjMMWFVEE7d1zO0jvSPA9OPZxWpEM= +go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= +go.etcd.io/bbolt v1.3.3 h1:MUGmc65QhB3pIlaQ5bB4LwqSj6GIonVJXpZiaKNyaKk= go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= +go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738/go.mod h1:dnLIgRNXwCJa5e+c6mIZCrds/GIG4ncV9HhK5PX7jPg= +go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= +go.opencensus.io v0.20.2/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= +go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= +go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= +go.opencensus.io v0.22.1/go.mod h1:Ap50jQcDJrx6rB6VgeeFPtuPIf3wMRvRfrfYDO6+BmA= +go.opencensus.io v0.22.2 h1:75k/FF0Q2YM8QYo07VPddOLBslDt1MZOdEslOHvmzAs= +go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= +go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= +go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= +go.uber.org/atomic v1.6.0 h1:Ezj3JGmsOnG1MoRWQkPBsKLe9DwWD9QeXzTRzzldNVk= +go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= +go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= +go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4= +go.uber.org/multierr v1.5.0 h1:KCa4XfM8CWFCpxXRGok+Q0SS/0XBhMDbHHGABQLvD2A= +go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU= +go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee h1:0mgffUl7nfd+FpvXMVz4IDEaUSmT1ysygQC7qYo7sG4= +go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= +go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= +go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM= +go.uber.org/zap v1.14.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM= +go.uber.org/zap v1.15.0/go.mod h1:Mb2vm2krFEG5DV0W9qcHBYFtp/Wku1cvYaqPsS/WYfc= +go.uber.org/zap v1.16.0 h1:uFRZXykJGK9lLY4HtgSw44DnIcAM+kRBP7x5m+NpAOM= +go.uber.org/zap v1.16.0/go.mod h1:MA8QOfq0BHJwdXa996Y4dYkAqRKB8/1K1QMMZVaNZjQ= golang.org/x/crypto v0.0.0-20170930174604-9419663f5a44/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190404164418-38d8ce5564a5/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE= +golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191202143827-86a70503ff7e/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20191206172530-e9b2fee46413/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200115085410-6d4e4cb37c7d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200311171314-f7b00557c8c4/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200406173513-056763e48d71/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200429183012-4b2356b1ed79/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20201203163018-be400aefbc4c h1:9HhBz5L/UjnK9XLtiZhYAdue5BVKep3PMmS2LuPDt8k= -golang.org/x/crypto v0.0.0-20201203163018-be400aefbc4c/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad h1:DN0cp81fZ3njFcrLCytUHRSUkqBjfTo4Tx9RJTWs0EY= +golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= +golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= +golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= +golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= +golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= +golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190930215403-16217165b5de h1:5hukYrvBGR8/eNkX5mdUezrA6JiaEZDtJb9Ei+1LlBs= +golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= +golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= +golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= +golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= +golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/mod v0.2.0 h1:KU7oHjnv3XNWfa5COkzUifxZmxp1TyI7ImMXqFxLwvQ= +golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/net v0.0.0-20180719180050-a680a1efc54d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181011144130-49bb7cea24b1/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181106065722-10aee1819953/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190125091013-d26f9f9a57f3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190206173232-65e2d4e15006/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= +golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190912160710-24e19bdeb0f2 h1:4dVFTC832rPn4pomLSz1vA+are2+dU19w1H8OngV7nc= +golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190912160710-24e19bdeb0f2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200425230154-ff2c4b7c35a0/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20201010224723-4f7140c49acb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201224014010-6772e930b67b h1:iFwSg7t5GZmB/Q5TjiEAsdoLDrdJRC1RiF2WhuV29Qw= +golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180926160741-c2ed4eda69e7/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190130150945-aca44879d564/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190712062909-fae7ac547cb7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190801041406-cbf593c0f2f3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190804053845-51ab0e2deafa/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190912141932-bc967efca4b8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191026070338-33540a1f6037 h1:YyJpGZS1sBuBCzLAR1VEpK193GlqGZbnPFnPV/5Rsb4= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191220142924-d4481acd189f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201013132646-2da7054afaeb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68 h1:nxC68pudNYkKU6jWhgrqdreuFiOQWj1Fs7T3VrH4Pjw= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 h1:v+OssWQX+hTHEmOBgwxdZxK4zHq3yOs8F9J7mk0PY8E= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2 h1:z99zHgr7hKfrUcX/KsoJk5FJfjTceCKIp96+biqP4To= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20190912185636-87d9f09c5d89/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20200103221440-774c71fcf114/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200601175630-2caf76543d99 h1:deddXmhOJb/bvD/4M/j2AUMrhHeh6GkqykJSCWyTNVk= +golang.org/x/tools v0.0.0-20200601175630-2caf76543d99/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/api v0.3.1/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk= +google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= +google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= +google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= +google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20180831171423-11092d34479b/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20190201180003-4b09977fb922/go.mod h1:L3J43x8/uS+qIUoksaLKe6OS3nUKxOKuIFz1sl2/jx4= +google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190530194941-fb225487d101/go.mod h1:z3L6/3dTEVtUr6QSP8miRzeRqwQOioJ9I66odjN4I7s= +google.golang.org/genproto v0.0.0-20190716160619-c506a9f90610/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= +google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013 h1:+kGHl1aib/qcwaRi1CbqBZ1rk19r85MNUf8HaBghugY= +google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= +google.golang.org/genproto v0.0.0-20200825200019-8632dd797987 h1:PDIOdWxZ8eRizhKa1AAvY53xsvLB1cWorMjslvY3VA8= +google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/grpc v1.16.0/go.mod h1:0JHn/cJsOMiMfNA9+DeHDlAU7KAAB5GDlYFpa9MZMio= +google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= google.golang.org/grpc v1.18.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= +google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= +google.golang.org/grpc v1.20.0/go.mod h1:chYK+tFQF0nDUGJgXMSgLCQk3phJEuONr2DCgLDdAQM= +google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= +google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= +google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= +google.golang.org/grpc v1.22.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.23.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= +google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= +google.golang.org/grpc v1.28.1/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= +google.golang.org/grpc v1.30.0 h1:M5a8xTlYTxwMn5ZFkwhRabsygDY5G8TYLyQDBxJNAxE= +google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.31.1 h1:SfXqXS5hkufcdZ/mHtYCh53P2b+92WQq/DZcKLgsFRs= +google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= +google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= +google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= +google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= +google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= +google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= +google.golang.org/protobuf v1.25.0 h1:Ejskq+SyPohKW+1uil0JJMtmHCgJPJ/qWTxr8qp+R4c= +google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/bsm/ratelimit.v1 v1.0.0-20160220154919-db14e161995a/go.mod h1:KF9sEfUPAXdG8Oev9e99iLGnl2uJMjc5B+4y3O7x610= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw= +gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= +gopkg.in/gcfg.v1 v1.2.3/go.mod h1:yesOnuUOFQAhST5vPY4nbZsb/huCgGGXlipJsBn0b3o= +gopkg.in/ini.v1 v1.51.0 h1:AQvPpx3LzTDM0AjnIRlVFwFFGC+npRopjZxLJj6gdno= +gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/jcmturner/aescts.v1 v1.0.1/go.mod h1:nsR8qBOg+OucoIW+WMhB3GspUQXq9XorLnQb9XtvcOo= gopkg.in/jcmturner/dnsutils.v1 v1.0.1/go.mod h1:m3v+5svpVOhtFAP/wSz+yzh4Mc0Fg7eRhxkJMWSIz9Q= gopkg.in/jcmturner/goidentity.v3 v3.0.0/go.mod h1:oG2kH0IvSYNIu80dVAyu/yoefjq1mNfM5bm88whjWx4= @@ -311,17 +1036,35 @@ gopkg.in/mgo.v2 v2.0.0-20190816093944-a6b53ec6cb22 h1:VpOs+IwYnYBaFnrNAeB8UUWtL3 gopkg.in/mgo.v2 v2.0.0-20190816093944-a6b53ec6cb22/go.mod h1:yeKp02qBN3iKW1OzL3MGk2IdtZzaj7SFntXj72NppTA= gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce h1:+JknDZhAj8YMt7GC73Ei8pv4MzjDUNPHgQWJdtMAaDU= gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce/go.mod h1:5AcXVHNjg+BDxry382+8OKon8SEWiKktQR07RKPsv1c= +gopkg.in/olebedev/go-duktape.v3 v3.0.0-20200316214253-d7b0ff38cac9/go.mod h1:uAJfkITjFhyEEuUfm7bsmCZRbW5WRq8s9EY8HZ6hCns= +gopkg.in/olebedev/go-duktape.v3 v3.0.0-20200619000410-60c24ae608a6/go.mod h1:uAJfkITjFhyEEuUfm7bsmCZRbW5WRq8s9EY8HZ6hCns= gopkg.in/redis.v4 v4.2.4/go.mod h1:8KREHdypkCEojGKQcjMqAODMICIVwZAONWq8RowTITA= +gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= gopkg.in/sourcemap.v1 v1.0.5/go.mod h1:2RlvNNSMglmRrcvhfuzp4hQHwOtjxlbjX7UPY/GXb78= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/urfave/cli.v1 v1.20.0 h1:NdAVW6RYxDif9DhDHaAortIu956m2c0v+09AZBPTbE0= gopkg.in/urfave/cli.v1 v1.20.0/go.mod h1:vuBzUtMdQeixQj8LVd+/98pzhxNGQoyuPBlsXHOQNO0= +gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI= +gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.3 h1:fvjTMHxHEw/mxHbtzPi3JCcKXQRAnQTBRo6YCJSVHKI= gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU= +gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.1-2019.2.3 h1:3JgtbtFHMiCmsznwGVTUWbgGov+pVqnlf1dEJTNAXeM= +honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= +rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= +sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= +sourcegraph.com/sourcegraph/appdash v0.0.0-20190731080439-ebfcffb1b5c0/go.mod h1:hI742Nqp5OhwiqlzhgfbWU4mW4yO10fP+LoT9WOswdU= diff --git a/internal/swapapi/api.go b/internal/swapapi/api.go index 77e57f2f..9659b10b 100644 --- a/internal/swapapi/api.go +++ b/internal/swapapi/api.go @@ -2,6 +2,7 @@ package swapapi import ( "encoding/hex" + "fmt" "strings" "time" @@ -356,3 +357,59 @@ func GetRegisteredAddress(address string) (*RegisteredAddress, error) { address = strings.ToLower(address) return mongodb.FindRegisteredAddress(address) } + +// AddSwapAgreement add swapin agreement +func AddSwapAgreement(args map[string]interface{}) (*PostResult, error) { + agreement, err := tokens.AgreementFromArgs(args) + if err != nil { + return nil, err + } + bz, err := tokens.TokenCDC.MarshalJSON(agreement) + if err != nil { + return nil, err + } + err = mongodb.AddSwapAgreement(agreement.Type(), agreement.Key(), fmt.Sprintf("%X", bz)) + if err != nil { + return nil, err + } + return &SuccessPostResult, nil +} + +// CancelSwapAgreement cancel swapin agreement +func CancelSwapAgreement(pkey string) (*PostResult, error) { + err := mongodb.CancelSwapAgreement(pkey) + if err != nil { + return nil, err + } + return &SuccessPostResult, nil +} + +func UpdateSwapAgreement(args map[string]interface{}) (*PostResult, error) { + agreement, err := tokens.AgreementFromArgs(args) + if err != nil { + return nil, err + } + bz, err := tokens.TokenCDC.MarshalJSON(agreement) + if err != nil { + return nil, err + } + err = mongodb.UpdateSwapAgreement(agreement.Type(), agreement.Key(), fmt.Sprintf("%X", bz)) + if err != nil { + return nil, err + } + return &SuccessPostResult, nil +} + +// GetSwapAgreement get swapin agreement +func GetSwapAgreement(pkey string) (SwapAgreement, error) { + mp, err := mongodb.FindSwapAgreement(pkey) + if err != nil { + return nil, err + } + return ConvertMgoSwapAgreementToSwapAgreement(mp) +} + +// GetLatestScannedSolanaTxid api +func GetLatestScannedSolanaTxid(address string) string { + return mongodb.FindLatestSolanaTxid(address) +} diff --git a/internal/swapapi/converts.go b/internal/swapapi/converts.go index c0fbecba..973e9230 100644 --- a/internal/swapapi/converts.go +++ b/internal/swapapi/converts.go @@ -1,6 +1,10 @@ package swapapi import ( + "encoding/hex" + "errors" + "strings" + "github.com/anyswap/CrossChain-Bridge/mongodb" "github.com/anyswap/CrossChain-Bridge/tokens" ) @@ -75,3 +79,20 @@ func ConvertMgoSwapResultsToSwapInfos(mrSlice []*mongodb.MgoSwapResult) []*SwapI } return result } + +// ConvertMgoSwapAgreementToSwapAgreement convert +func ConvertMgoSwapAgreementToSwapAgreement(mp *mongodb.MgoSwapAgreement) (tokens.SwapAgreement, error) { + bz, err := hex.DecodeString(mp.Value) + if err != nil { + return nil, err + } + var p tokens.SwapAgreement + err = tokens.TokenCDC.UnmarshalJSON(bz, &p) + if err != nil { + return nil, err + } + if strings.EqualFold(p.Type(), mp.Type) == false { + return nil, errors.New("Swapin agreement type not match") + } + return p, nil +} diff --git a/internal/swapapi/types.go b/internal/swapapi/types.go index 561b3bc4..646cb7f8 100644 --- a/internal/swapapi/types.go +++ b/internal/swapapi/types.go @@ -23,6 +23,9 @@ type LatestScanInfo = mongodb.MgoLatestScanInfo // RegisteredAddress type alias type RegisteredAddress = mongodb.MgoRegisteredAddress +// SwapAgreement type alias +type SwapAgreement = tokens.SwapAgreement + // ServerInfo server info type ServerInfo struct { Identifier string diff --git a/mongodb/api.go b/mongodb/api.go index 6b510202..87c5cbcd 100644 --- a/mongodb/api.go +++ b/mongodb/api.go @@ -1,6 +1,7 @@ package mongodb import ( + "errors" "fmt" "math/big" "strings" @@ -692,7 +693,50 @@ func FindRegisteredAddress(key string) (*MgoRegisteredAddress, error) { return &result, nil } -// ---------------------- latest swap nonces ----------------------------- +// AddSwapAgreement add swapin agreement +func AddSwapAgreement(ptype, pkey, pvalue string) error { + mp := &MgoSwapAgreement{ + Type: ptype, + Key: pkey, + Value: pvalue, + Cancelled: false, + } + err := collSwapAgreement.Insert(mp) + if err == nil { + log.Info("mongodb add swapin agreement", "key", mp.Key) + } else { + log.Debug("mongodb add swapin agreement", "key", mp.Key, "err", err) + } + return mgoError(err) +} + +// CancelSwapAgreement cancels a swapin agreement +func CancelSwapAgreement(key string) error { + err := collSwapAgreement.UpdateId(key, bson.M{"cancelled": true}) + if err != nil { + log.Debug("mongodb cancelled swapin agreement", "key", key, "err", err) + return mgoError(err) + } + log.Debug("mongodb cancelled swapin agreement", "key", key) + return nil +} + +// UpdateSwapAgreement update swapin agreement +func UpdateSwapAgreement(ptype, pkey, pvalue string) error { + mp := &MgoSwapAgreement{ + Type: ptype, + Key: pkey, + Value: pvalue, + Cancelled: false, + } + err := collSwapAgreement.UpdateId(pkey, bson.M{"$set": mp}) + if err == nil { + log.Info("mongodb update swapin agreement", "key", mp.Key) + } else { + log.Debug("mongodb update swapin agreement", "key", mp.Key, "err", err) + } + return err +} func getSwapNonceKey(address string, isSwapin bool) string { return strings.ToLower(fmt.Sprintf("%v:%v", address, isSwapin)) @@ -729,6 +773,36 @@ func UpdateLatestSwapNonce(address string, isSwapin bool, nonce uint64) (err err return mgoError(err) } +// FindSwapAgreement finds swapin agreement +func FindSwapAgreement(key string) (*MgoSwapAgreement, error) { + var result MgoSwapAgreement + err := collSwapAgreement.FindId(key).One(&result) + if err != nil { + return nil, mgoError(err) + } + if result.Cancelled { + return nil, mgoError(errors.New("Swapin agreement is cancelled")) + } + return &result, nil +} + +// FindLatestSolanaTxid finds latest solana txid +func FindLatestSolanaTxid(address string) string { + key := strings.ToLower(address) + var result MgoSolanaScannedTx + err := collSolanaScannedTx.FindId(key).One(&result) + if err != nil { + return "" + } + return result.Txid +} + +func UpdateLatestSolanaTxid(addess, txid string) error { + key := strings.ToLower(addess) + _, err := collSolanaScannedTx.UpsertId(key, MgoSolanaScannedTx{key, txid}) + return err +} + // FindLatestSwapNonce find func FindLatestSwapNonce(address string, isSwapin bool) (*MgoLatestSwapNonce, error) { var result MgoLatestSwapNonce diff --git a/mongodb/tableinit.go b/mongodb/tableinit.go index 4c1b2d5b..b2f5e41a 100644 --- a/mongodb/tableinit.go +++ b/mongodb/tableinit.go @@ -14,6 +14,8 @@ var ( collLatestScanInfo *mgo.Collection collRegisteredAddress *mgo.Collection collBlacklist *mgo.Collection + collSwapAgreement *mgo.Collection + collSolanaScannedTx *mgo.Collection collLatestSwapNonces *mgo.Collection ) @@ -32,6 +34,8 @@ func deinintCollections() { collLatestScanInfo = database.C(tbLatestScanInfo) collRegisteredAddress = database.C(tbRegisteredAddress) collBlacklist = database.C(tbBlacklist) + collSwapAgreement = database.C(tbSwapAgreement) + collSolanaScannedTx = database.C(tbSolanaScannedTx) collLatestSwapNonces = database.C(tbLatestSwapNonces) } @@ -45,6 +49,8 @@ func initCollections() { initCollection(tbLatestScanInfo, &collLatestScanInfo) initCollection(tbRegisteredAddress, &collRegisteredAddress) initCollection(tbBlacklist, &collBlacklist) + initCollection(tbSwapAgreement, &collSwapAgreement) + initCollection(tbSolanaScannedTx, &collSolanaScannedTx) initCollection(tbLatestSwapNonces, &collLatestSwapNonces, "address") initDefaultValue() diff --git a/mongodb/tables.go b/mongodb/tables.go index 9ea4148a..a950f536 100644 --- a/mongodb/tables.go +++ b/mongodb/tables.go @@ -10,6 +10,8 @@ const ( tbLatestScanInfo string = "LatestScanInfo" tbRegisteredAddress string = "RegisteredAddress" tbBlacklist string = "Blacklist" + tbSwapAgreement string = "SwapAgreement" + tbSolanaScannedTx string = "SolanaScannedTx" tbLatestSwapNonces string = "LatestSwapNonces" keyOfSrcLatestScanInfo string = "srclatest" @@ -108,6 +110,20 @@ type MgoBlackAccount struct { Timestamp int64 `bson:"timestamp"` } +// MgoSwapAgreement is hex encoded swapagreement +type MgoSwapAgreement struct { + Key string `bson:"_id"` + Type string `bson:"type"` + Value string `bson:"value"` + Cancelled bool `bson:"cancelled"` +} + +// MgoSolanaScannedTx is MgoSolanaScannedTx +type MgoSolanaScannedTx struct { + Address string `bson:"_id"` + Txid string `bson:"txid"` +} + // MgoLatestSwapNonce latest swap nonce type MgoLatestSwapNonce struct { Key string `bson:"_id"` // address + swaptype diff --git a/rpc/restapi/api.go b/rpc/restapi/api.go index f59c1de4..af6c8c7e 100644 --- a/rpc/restapi/api.go +++ b/rpc/restapi/api.go @@ -237,3 +237,53 @@ func GetRegisteredAddress(w http.ResponseWriter, r *http.Request) { res, err := swapapi.GetRegisteredAddress(address) writeResponse(w, res, err) } + +/* +// AddSwapAgreement handler +func AddSwapAgreement(w http.ResponseWriter, r *http.Request) { + vars := mux.Vars(r) + var obj = make(map[string]interface{}) + for k, v := range vars { + var x interface{} + err := json.Unmarshal([]byte(v), &x) + if err != nil { + x = v + } + obj[k] = x + } + res, err := swapapi.AddSwapAgreement(obj) + writeResponse(w, res, err) +} + +// CancelSwapAgreement handler +func CancelSwapAgreement(w http.ResponseWriter, r *http.Request) { + vars := mux.Vars(r) + pkey := vars["pkey"] + res, err := swapapi.CancelSwapAgreement(pkey) + writeResponse(w, res, err) +} + +// UpdateSwapAgreement handler +func UpdateSwapAgreement(w http.ResponseWriter, r *http.Request) { + vars := mux.Vars(r) + var obj = make(map[string]interface{}) + for k, v := range vars { + var x interface{} + err := json.Unmarshal([]byte(v), &x) + if err != nil { + x = v + } + obj[k] = x + } + res, err := swapapi.UpdateSwapAgreement(obj) + writeResponse(w, res, err) +} + +// GetSwapAgreement handler +func GetSwapAgreement(w http.ResponseWriter, r *http.Request) { + vars := mux.Vars(r) + pkey := vars["pkey"] + res, err := swapapi.GetSwapAgreement(pkey) + writeResponse(w, res, err) +} +*/ diff --git a/rpc/rpcapi/api.go b/rpc/rpcapi/api.go index 069906e4..12b1c587 100644 --- a/rpc/rpcapi/api.go +++ b/rpc/rpcapi/api.go @@ -283,3 +283,48 @@ func (s *RPCAPI) GetRegisteredAddress(r *http.Request, address *string, result * } return err } + +type SwapAgreementArgs map[string](interface{}) + +// AddSwapAgreement api +func (s *RPCAPI) AddSwapAgreement(r *http.Request, args *SwapAgreementArgs, result *swapapi.PostResult) error { + res, err := swapapi.AddSwapAgreement(*args) + if err == nil && res != nil { + *result = *res + } + return err +} + +// CancelSwapAgreement api +func (s *RPCAPI) CancelSwapAgreement(r *http.Request, pkey *string, result *swapapi.PostResult) error { + res, err := swapapi.CancelSwapAgreement(*pkey) + if err == nil && res != nil { + *result = *res + } + return err +} + +// UpdateSwapAgreement api +func (s *RPCAPI) UpdateSwapAgreement(r *http.Request, args *SwapAgreementArgs, result *swapapi.PostResult) error { + res, err := swapapi.UpdateSwapAgreement(*args) + if err == nil && res != nil { + *result = *res + } + return err +} + +// GetSwapAgreement api +func (s *RPCAPI) GetSwapAgreement(r *http.Request, pkey *string, result *swapapi.SwapAgreement) error { + res, err := swapapi.GetSwapAgreement(*pkey) + if err == nil && res != nil { + *result = res + } + return err +} + +// GetLatestScanInfo api +func (s *RPCAPI) GetLatestScannedSolanaTxid(r *http.Request, address *string, result *string) error { + res := swapapi.GetLatestScannedSolanaTxid(*address) + *result = res + return nil +} diff --git a/tokens/base.go b/tokens/base.go index 0b161f7b..b55ae57d 100644 --- a/tokens/base.go +++ b/tokens/base.go @@ -23,6 +23,8 @@ var ( DstLatestBlockHeight uint64 IsDcrmDisabled bool + + IsSwapoutToStringAddress bool = false ) // CrossChainBridgeBase base bridge diff --git a/tokens/block/blocktools/main.go b/tokens/block/blocktools/main.go new file mode 100644 index 00000000..f2098c44 --- /dev/null +++ b/tokens/block/blocktools/main.go @@ -0,0 +1,134 @@ +package main + +import ( + "fmt" + "log" + "math" + "math/big" + "time" + + "github.com/anyswap/CrossChain-Bridge/common" + "github.com/btcsuite/btcd/btcec" + "github.com/btcsuite/btcd/chaincfg" + "github.com/btcsuite/btcd/wire" + "github.com/btcsuite/btcutil" +) + +func main() { + TestNewAddressPubKeyHash() +} + +func checkError(err error) { + if err != nil { + log.Fatal(err) + } +} + +func TestNewAddressPubKeyHash() { + fmt.Println("TestNewAddressPubKeyHash") + + /*wif := "PnPaj8UeZCziJx9EBTDsZfzuYDZVaGwvrtettNeTqnhH5Z3d6B41" + privWif, err := btcutil.DecodeWIF(wif) + checkError(t, err) + + pkdata := privWif.SerializePubKey()*/ + + pkData := common.FromHex("04d38309dfdfd9adf129287b68cf2e1f1124e0cbc40cc98f94e5f2d23c26712fa3b33d63280dd1448319a6a4f4111722d6b3a730ebe07652ed2b3770947b3de2e2") + cPkData, err := ToCompressedPublicKey(pkData) + checkError(err) + + addr, err := NewAddressPubKeyHash(cPkData) + checkError(err) + fmt.Printf("NewAddressPubKeyHash: %s\n", addr) + + /*realaddr := "BXcz95EZfLBREpQrMDsKFnMJSaUYNRyhHU" + + if addr.String() != realaddr { + err := fmt.Errorf("Block address error, got %s, should be: %s", addr.String(), realaddr) + checkError(err) + } + */ +} + +func NewAddressPubKeyHash(pkData []byte) (*btcutil.AddressPubKeyHash, error) { + return btcutil.NewAddressPubKeyHash(btcutil.Hash160(pkData), &MainNetParams) +} + +var bigOne = big.NewInt(1) + +var MainNetParams = chaincfg.Params{ + Name: "mainnet", + Net: wire.MainNet, + + // Chain parameters + PowLimit: new(big.Int).Sub(new(big.Int).Lsh(bigOne, 224), bigOne), + PowLimitBits: 0x00000fff, + BIP0034Height: 1, + BIP0065Height: 1, + BIP0066Height: 1, + CoinbaseMaturity: 100, + SubsidyReductionInterval: 210000, + TargetTimespan: time.Minute * 1, // 1 minute + TargetTimePerBlock: time.Minute * 1, // 1 minute + RetargetAdjustmentFactor: 4, // 25% less, 400% more + ReduceMinDifficulty: false, + MinDiffReductionTime: 0, + GenerateSupported: false, + + // Checkpoints ordered from oldest to newest. + Checkpoints: []chaincfg.Checkpoint{}, + + // Consensus rule change deployments. + // + // The miner confirmation window is defined as: + // target proof of work timespan / target proof of work spacing + RuleChangeActivationThreshold: 1368, // 95% of MinerConfirmationWindow + MinerConfirmationWindow: 1440, // + Deployments: [chaincfg.DefinedDeployments]chaincfg.ConsensusDeployment{ + chaincfg.DeploymentTestDummy: { + BitNumber: 28, + StartTime: 1199145601, // January 1, 2008 UTC + ExpireTime: 1230767999, // December 31, 2008 UTC + }, + chaincfg.DeploymentCSV: { + BitNumber: 0, + StartTime: 0, // Always vote + ExpireTime: math.MaxInt64, // No timeout + }, + chaincfg.DeploymentSegwit: { + BitNumber: 1, + StartTime: 1584295200, // March 15, 2020 + ExpireTime: 1589565600, // May 15, 2020 + }, + }, + + // Mempool parameters + RelayNonStdTxs: false, + + // Human-readable part for Bech32 encoded segwit addresses, as defined in + // BIP 173. + Bech32HRPSegwit: "block", // always block for mainnet + + // Address encoding magics + PubKeyHashAddrID: 0x1a, // starts with B + ScriptHashAddrID: 0x1c, // starts with C + PrivateKeyID: 0x9a, // starts with 6 (uncompressed) or P (compressed) + WitnessPubKeyHashAddrID: 0x06, // starts with p2 + WitnessScriptHashAddrID: 0x0A, // starts with 7Xh + + // BIP32 hierarchical deterministic extended key magics + HDPrivateKeyID: [4]byte{0x04, 0x88, 0xAD, 0xE4}, // starts with xprv + HDPublicKeyID: [4]byte{0x04, 0x88, 0xB2, 0x1E}, // starts with xpub + + // BIP44 coin type used in the hierarchical deterministic path for + // address generation. + HDCoinType: 0, +} + +func ToCompressedPublicKey(pkData []byte) ([]byte, error) { + pubKey, err := btcec.ParsePubKey(pkData, btcec.S256()) + if err != nil { + return nil, err + } + return pubKey.SerializeCompressed(), nil +} diff --git a/tokens/bridge/bridge.go b/tokens/bridge/bridge.go index 1976bb8f..0e5578ba 100644 --- a/tokens/bridge/bridge.go +++ b/tokens/bridge/bridge.go @@ -10,10 +10,14 @@ import ( "github.com/anyswap/CrossChain-Bridge/tokens" "github.com/anyswap/CrossChain-Bridge/tokens/block" "github.com/anyswap/CrossChain-Bridge/tokens/btc" + "github.com/anyswap/CrossChain-Bridge/tokens/cosmos" "github.com/anyswap/CrossChain-Bridge/tokens/etc" "github.com/anyswap/CrossChain-Bridge/tokens/eth" "github.com/anyswap/CrossChain-Bridge/tokens/fsn" "github.com/anyswap/CrossChain-Bridge/tokens/ltc" + "github.com/anyswap/CrossChain-Bridge/tokens/solana" + "github.com/anyswap/CrossChain-Bridge/tokens/terra" + "github.com/anyswap/CrossChain-Bridge/tokens/tron" ) // NewCrossChainBridge new bridge according to chain name @@ -32,6 +36,14 @@ func NewCrossChainBridge(id string, isSrc bool) tokens.CrossChainBridge { return eth.NewCrossChainBridge(isSrc) case strings.HasPrefix(blockChainIden, "FUSION"): return fsn.NewCrossChainBridge(isSrc) + case strings.HasPrefix(blockChainIden, "COSMOS"): + return cosmos.NewCrossChainBridge(isSrc) + case strings.HasPrefix(blockChainIden, "TERRA"): + return terra.NewCrossChainBridge(isSrc) + case strings.HasPrefix(blockChainIden, "SOLANA"): + return solana.NewCrossChainBridge(isSrc) + case strings.HasPrefix(blockChainIden, "TRON"): + return tron.NewCrossChainBridge(isSrc) default: log.Fatalf("Unsupported block chain %v", id) return nil @@ -57,6 +69,12 @@ func InitCrossChainBridge(isServer bool) { tokens.DstBridge = NewCrossChainBridge(dstID, false) log.Info("New bridge finished", "source", srcID, "sourceNet", srcNet, "dest", dstID, "destNet", dstNet) + BlockChain := strings.ToUpper(srcChain.BlockChain) + switch BlockChain { + case "COSMOS", "TERRA": + tokens.SrcBridge.(cosmos.CosmosBridgeInterface).BeforeConfig() + } + tokens.SrcBridge.SetChainAndGateway(srcChain, srcGateway) log.Info("Init bridge source", "source", srcID, "gateway", srcGateway) @@ -66,7 +84,6 @@ func InitCrossChainBridge(isServer bool) { tokens.IsDcrmDisabled = cfg.Dcrm.Disable tokens.LoadTokenPairsConfig(true) - BlockChain := strings.ToUpper(srcChain.BlockChain) switch BlockChain { case "BITCOIN": btc.Init(cfg.BtcExtra) @@ -74,6 +91,8 @@ func InitCrossChainBridge(isServer bool) { ltc.Init(cfg.BtcExtra) case "BLOCK": block.Init(cfg.BtcExtra) + case "COSMOS", "TERRA": + tokens.SrcBridge.(cosmos.CosmosBridgeInterface).AfterConfig() } dcrm.Init(cfg.Dcrm, isServer) diff --git a/tokens/cosmos/accountnumber.go b/tokens/cosmos/accountnumber.go new file mode 100644 index 00000000..abf2f379 --- /dev/null +++ b/tokens/cosmos/accountnumber.go @@ -0,0 +1,20 @@ +package cosmos + +// account number is associated with account on a cosmos state +var accountNumberCached map[string]uint64 + +func (b *Bridge) GetAccountNumberCached(address string) (uint64, error) { + if accountNumberCached == nil { + accountNumberCached = make(map[string]uint64) + } + if num, ok := accountNumberCached[address]; ok && num > 0 { + return num, nil + } else { + num, err := b.GetAccountNumber(address) + if err != nil { + return 0, err + } + accountNumberCached[address] = num + return num, err + } +} diff --git a/tokens/cosmos/address.go b/tokens/cosmos/address.go new file mode 100644 index 00000000..6f5789be --- /dev/null +++ b/tokens/cosmos/address.go @@ -0,0 +1,51 @@ +package cosmos + +import ( + "encoding/hex" + "strings" + + "github.com/btcsuite/btcd/btcec" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/tendermint/tendermint/crypto/secp256k1" +) + +// IsValidAddress check address +func (b *Bridge) IsValidAddress(address string) bool { + if _, err := sdk.AccAddressFromBech32(address); err != nil { + return false + } + return true +} + +func (b *Bridge) EqualAddress(address1, address2 string) bool { + acc1, err1 := sdk.AccAddressFromBech32(address1) + acc2, err2 := sdk.AccAddressFromBech32(address2) + if err1 == nil && err2 == nil { + return acc1.Equals(acc2) + } + return false +} + +// PublicKeyToAddress returns cosmos public key address +func (b *Bridge) PublicKeyToAddress(pubKeyHex string) (address string, err error) { + pubKeyHex = strings.TrimPrefix(pubKeyHex, "0x") + bb, err := hex.DecodeString(pubKeyHex) + if err != nil { + return + } + pk, err := btcec.ParsePubKey(bb, btcec.S256()) + if err != nil { + return + } + cpk := pk.SerializeCompressed() + var pub [33]byte + copy(pub[:], cpk[:33]) + pubkey := secp256k1.PubKeySecp256k1(pub) + addr := pubkey.Address() + accAddress, err := sdk.AccAddressFromHex(addr.String()) + if err != nil { + return + } + address = accAddress.String() + return +} diff --git a/tokens/cosmos/banktypes.go b/tokens/cosmos/banktypes.go new file mode 100644 index 00000000..3070be57 --- /dev/null +++ b/tokens/cosmos/banktypes.go @@ -0,0 +1,270 @@ +package cosmos + +import ( + "fmt" + + "github.com/cosmos/cosmos-sdk/codec" + sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + "github.com/cosmos/cosmos-sdk/x/params" +) + +// bank module event types +const ( + EventTypeTransfer = "transfer" + + AttributeKeyRecipient = "recipient" + AttributeKeySender = "sender" + + AttributeValueCategory = ModuleName +) + +const ( + // module name + ModuleName = "bank" + QuerierRoute = ModuleName +) +const ( + // DefaultParamspace for params keeper + DefaultParamspace = ModuleName + // DefaultSendEnabled enabled + DefaultSendEnabled = true +) + +const ( + TypeMsgSend = "send" + TypeMsgMultiSend = "multisend" +) + +// ParamStoreKeySendEnabled is store's key for SendEnabled +var ParamStoreKeySendEnabled = []byte("sendenabled") + +// ParamKeyTable type declaration for parameters +func ParamKeyTable() params.KeyTable { + return params.NewKeyTable( + params.NewParamSetPair(ParamStoreKeySendEnabled, false, validateSendEnabled), + ) +} + +func validateSendEnabled(i interface{}) error { + _, ok := i.(bool) + if !ok { + return fmt.Errorf("invalid parameter type: %T", i) + } + + return nil +} + +// Register concrete types on codec codec +func RegisterCodec(cdc *codec.Codec) { + cdc.RegisterConcrete(MsgSend{}, "cosmos-sdk/MsgSend", nil) + cdc.RegisterConcrete(MsgMultiSend{}, "cosmos-sdk/MsgMultiSend", nil) +} + +var ModuleCdc *codec.Codec + +func init() { + ModuleCdc = codec.New() + RegisterCodec(ModuleCdc) + ModuleCdc.Seal() +} + +// x/bank module sentinel errors +var ( + ErrNoInputs = sdkerrors.Register(ModuleName, 1, "no inputs to send transaction") + ErrNoOutputs = sdkerrors.Register(ModuleName, 2, "no outputs to send transaction") + ErrInputOutputMismatch = sdkerrors.Register(ModuleName, 3, "sum inputs != sum outputs") + ErrSendDisabled = sdkerrors.Register(ModuleName, 4, "send transactions are disabled") +) + +// RouterKey is they name of the bank module +const RouterKey = ModuleName + +// MsgSend - high level transaction of the coin module +type MsgSend struct { + FromAddress sdk.AccAddress `json:"from_address" yaml:"from_address"` + ToAddress sdk.AccAddress `json:"to_address" yaml:"to_address"` + Amount sdk.Coins `json:"amount" yaml:"amount"` +} + +var _ sdk.Msg = MsgSend{} + +// NewMsgSend - construct arbitrary multi-in, multi-out send msg. +func NewMsgSend(fromAddr, toAddr sdk.AccAddress, amount sdk.Coins) MsgSend { + return MsgSend{FromAddress: fromAddr, ToAddress: toAddr, Amount: amount} +} + +// Route Implements Msg. +func (msg MsgSend) Route() string { return RouterKey } + +// Type Implements Msg. +func (msg MsgSend) Type() string { return "send" } + +// ValidateBasic Implements Msg. +func (msg MsgSend) ValidateBasic() error { + if msg.FromAddress.Empty() { + return sdkerrors.Wrap(sdkerrors.ErrInvalidAddress, "missing sender address") + } + if msg.ToAddress.Empty() { + return sdkerrors.Wrap(sdkerrors.ErrInvalidAddress, "missing recipient address") + } + if !msg.Amount.IsValid() { + return sdkerrors.Wrap(sdkerrors.ErrInvalidCoins, msg.Amount.String()) + } + if !msg.Amount.IsAllPositive() { + return sdkerrors.Wrap(sdkerrors.ErrInvalidCoins, msg.Amount.String()) + } + return nil +} + +// GetSignBytes Implements Msg. +func (msg MsgSend) GetSignBytes() []byte { + return sdk.MustSortJSON(ModuleCdc.MustMarshalJSON(msg)) +} + +// GetSigners Implements Msg. +func (msg MsgSend) GetSigners() []sdk.AccAddress { + return []sdk.AccAddress{msg.FromAddress} +} + +// MsgMultiSend - high level transaction of the coin module +type MsgMultiSend struct { + Inputs []Input `json:"inputs" yaml:"inputs"` + Outputs []Output `json:"outputs" yaml:"outputs"` +} + +var _ sdk.Msg = MsgMultiSend{} + +// NewMsgMultiSend - construct arbitrary multi-in, multi-out send msg. +func NewMsgMultiSend(in []Input, out []Output) MsgMultiSend { + return MsgMultiSend{Inputs: in, Outputs: out} +} + +// Route Implements Msg +func (msg MsgMultiSend) Route() string { return RouterKey } + +// Type Implements Msg +func (msg MsgMultiSend) Type() string { return "multisend" } + +// ValidateBasic Implements Msg. +func (msg MsgMultiSend) ValidateBasic() error { + // this just makes sure all the inputs and outputs are properly formatted, + // not that they actually have the money inside + if len(msg.Inputs) == 0 { + return ErrNoInputs + } + if len(msg.Outputs) == 0 { + return ErrNoOutputs + } + + return ValidateInputsOutputs(msg.Inputs, msg.Outputs) +} + +// GetSignBytes Implements Msg. +func (msg MsgMultiSend) GetSignBytes() []byte { + return sdk.MustSortJSON(ModuleCdc.MustMarshalJSON(msg)) +} + +// GetSigners Implements Msg. +func (msg MsgMultiSend) GetSigners() []sdk.AccAddress { + addrs := make([]sdk.AccAddress, len(msg.Inputs)) + for i, in := range msg.Inputs { + addrs[i] = in.Address + } + return addrs +} + +// Input models transaction input +type Input struct { + Address sdk.AccAddress `json:"address" yaml:"address"` + Coins sdk.Coins `json:"coins" yaml:"coins"` +} + +// ValidateBasic - validate transaction input +func (in Input) ValidateBasic() error { + if len(in.Address) == 0 { + return sdkerrors.Wrap(sdkerrors.ErrInvalidAddress, "input address missing") + } + if !in.Coins.IsValid() { + return sdkerrors.Wrap(sdkerrors.ErrInvalidCoins, in.Coins.String()) + } + if !in.Coins.IsAllPositive() { + return sdkerrors.Wrap(sdkerrors.ErrInvalidCoins, in.Coins.String()) + } + return nil +} + +// NewInput - create a transaction input, used with MsgMultiSend +func NewInput(addr sdk.AccAddress, coins sdk.Coins) Input { + return Input{ + Address: addr, + Coins: coins, + } +} + +// Output models transaction outputs +type Output struct { + Address sdk.AccAddress `json:"address" yaml:"address"` + Coins sdk.Coins `json:"coins" yaml:"coins"` +} + +// ValidateBasic - validate transaction output +func (out Output) ValidateBasic() error { + if len(out.Address) == 0 { + return sdkerrors.Wrap(sdkerrors.ErrInvalidAddress, "output address missing") + } + if !out.Coins.IsValid() { + return sdkerrors.Wrap(sdkerrors.ErrInvalidCoins, out.Coins.String()) + } + if !out.Coins.IsAllPositive() { + return sdkerrors.Wrap(sdkerrors.ErrInvalidCoins, out.Coins.String()) + } + return nil +} + +// NewOutput - create a transaction output, used with MsgMultiSend +func NewOutput(addr sdk.AccAddress, coins sdk.Coins) Output { + return Output{ + Address: addr, + Coins: coins, + } +} + +// ValidateInputsOutputs validates that each respective input and output is +// valid and that the sum of inputs is equal to the sum of outputs. +func ValidateInputsOutputs(inputs []Input, outputs []Output) error { + var totalIn, totalOut sdk.Coins + + for _, in := range inputs { + if err := in.ValidateBasic(); err != nil { + return err + } + + totalIn = totalIn.Add(in.Coins...) + } + + for _, out := range outputs { + if err := out.ValidateBasic(); err != nil { + return err + } + + totalOut = totalOut.Add(out.Coins...) + } + + // make sure inputs and outputs match + if !totalIn.IsEqual(totalOut) { + return ErrInputOutputMismatch + } + + return nil +} + +// QueryBalanceParams defines the params for querying an account balance. +type QueryBalanceParams struct { + Address sdk.AccAddress +} + +// NewQueryBalanceParams creates a new instance of QueryBalanceParams. +func NewQueryBalanceParams(addr sdk.AccAddress) QueryBalanceParams { + return QueryBalanceParams{Address: addr} +} diff --git a/tokens/cosmos/bridge.go b/tokens/cosmos/bridge.go new file mode 100644 index 00000000..ad2abda4 --- /dev/null +++ b/tokens/cosmos/bridge.go @@ -0,0 +1,181 @@ +package cosmos + +import ( + "fmt" + "strings" + "time" + + "github.com/anyswap/CrossChain-Bridge/log" + "github.com/anyswap/CrossChain-Bridge/tokens" + "github.com/anyswap/CrossChain-Bridge/tokens/eth" + sdk "github.com/cosmos/cosmos-sdk/types" + authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" + cyptes "github.com/tendermint/tendermint/rpc/core/types" +) + +var ( + // ChainIDs saves supported chain ids + ChainIDs = make(map[string]bool) +) + +// CosmosBridgeInterface interface +type CosmosBridgeInterface interface { + BeforeConfig() + AfterConfig() +} + +// BeforeConfig run before loading bridge and token config +func (b *Bridge) BeforeConfig() { + cyptes.RegisterAmino(CDC) + sdk.RegisterCodec(CDC) + RegisterCodec(CDC) + CDC.RegisterConcrete(&authtypes.BaseAccount{}, "cosmos-sdk/Account", nil) + ChainIDs["cosmos-hub4"] = true + ChainIDs["stargate-final"] = true + // SupportedCoins["ATOM"] = CosmosCoin{"uatom", 9} + tokens.IsSwapoutToStringAddress = true +} + +// AfterConfig run after loading bridge and token config +func (b *Bridge) AfterConfig() { + GetFeeAmount = b.FeeGetter() + b.InitLatestBlockNumber() + b.LoadCoins() + + switch b.ChainConfig.NetID { + case "stargate-final": + if umuon, ok := b.SupportedCoins["MUON"]; ok == false || umuon.Denom != "umuon" || umuon.Decimal != 6 { + log.Fatalf("Cosmos post-stargate bridge must have MUON token config") + } + b.MainCoin = b.SupportedCoins["MUON"] + case "cosmos-hub4": + if atom, ok := b.SupportedCoins["ATOM"]; ok == false || atom.Denom != "uatom" || atom.Decimal != 9 { + log.Fatalf("Cosmos pre-stargate bridge must have Atom token config") + } + b.MainCoin = b.SupportedCoins["ATOM"] + default: + if atom, ok := b.SupportedCoins["ATOM"]; ok == false || atom.Denom != "uatom" || atom.Decimal != 9 { + if umuon, ok := b.SupportedCoins["MUON"]; ok == false || umuon.Denom != "umuon" || umuon.Decimal != 9 { + log.Fatalf("Cosmos bridge must have one of Atom or Muon token config") + } + } + b.MainCoin = b.SupportedCoins["ATOM"] + } + log.Info("Cosmos bridge init success", "coins", b.SupportedCoins) +} + +// LoadCoins read and check token pairs config +func (b *Bridge) LoadCoins() { + pairs := tokens.GetTokenPairsConfig() + for _, tokenCfg := range pairs { + name := strings.ToUpper(tokenCfg.SrcToken.ID) + unit := tokenCfg.SrcToken.Unit + decimal := *(tokenCfg.SrcToken.Decimals) + b.SupportedCoins[name] = CosmosCoin{unit, decimal} + } +} + +// GetCoin returns supported coin by name +func (b *Bridge) GetCoin(name string) (CosmosCoin, bool) { + name = strings.ToUpper(name) + coin, ok := b.SupportedCoins[name] + if !ok { + b.LoadCoins() + } + coin, ok = b.SupportedCoins[name] + return coin, ok +} + +// CosmosCoin struct +type CosmosCoin struct { + Denom string + Decimal uint8 +} + +// Bridge cosmos bridge +type Bridge struct { + *tokens.CrossChainBridgeBase + *eth.NonceSetterBase + // MainCoin is the gas coin + MainCoin CosmosCoin + // SupportedCoins save cosmos coins + SupportedCoins map[string]CosmosCoin +} + +// NewCrossChainBridge new bridge +func NewCrossChainBridge(isSrc bool) *Bridge { + return &Bridge{ + CrossChainBridgeBase: tokens.NewCrossChainBridgeBase(isSrc), + NonceSetterBase: eth.NewNonceSetterBase(), + SupportedCoins: make(map[string]CosmosCoin), + } +} + +// SetChainAndGateway set chain and gateway config +func (b *Bridge) SetChainAndGateway(chainCfg *tokens.ChainConfig, gatewayCfg *tokens.GatewayConfig) { + b.CrossChainBridgeBase.SetChainAndGateway(chainCfg, gatewayCfg) + b.InitLatestBlockNumber() + b.VerifyChainID() +} + +// VerifyChainID verify chain id +func (b *Bridge) VerifyChainID() { + chainID := strings.ToLower(b.ChainConfig.NetID) + if ChainIDs[chainID] == false { + log.Fatalf("unsupported cosmos network: %v", b.ChainConfig.NetID) + } +} + +// VerifyTokenConfig verify token config +func (b *Bridge) VerifyTokenConfig(tokenCfg *tokens.TokenConfig) error { + if !b.IsValidAddress(tokenCfg.DepositAddress) { + return fmt.Errorf("invalid deposit address: %v", tokenCfg.DepositAddress) + } + return nil +} + +// InitLatestBlockNumber init latest block number +func (b *Bridge) InitLatestBlockNumber() { + chainCfg := b.ChainConfig + gatewayCfg := b.GatewayConfig + var latest uint64 + var err error + for { + latest, err = b.GetLatestBlockNumber() + if err == nil { + tokens.SetLatestBlockHeight(latest, b.IsSrc) + log.Info("get latst block number succeed.", "number", latest, "BlockChain", chainCfg.BlockChain, "NetID", chainCfg.NetID) + break + } + log.Error("get latst block number failed.", "BlockChain", chainCfg.BlockChain, "NetID", chainCfg.NetID, "err", err) + log.Println("retry query gateway", gatewayCfg.APIAddress) + time.Sleep(3 * time.Second) + } +} + +// DefaultSwapoutGas is default cosmos tx gas +var DefaultSwapoutGas uint64 = 300000 + +// GetFeeAmount returns StdFee +var GetFeeAmount func() authtypes.StdFee + +// FeeGetter returns a cosmos fee getter +func (b *Bridge) FeeGetter() func() authtypes.StdFee { + switch b.ChainConfig.NetID { + case "stargate-final": + return func() authtypes.StdFee { + feeAmount := []sdk.Coin{sdk.NewCoin("umuon", sdk.NewInt(3000))} + return authtypes.NewStdFee(DefaultSwapoutGas, feeAmount) + } + case "cosmos-hub4": + return func() authtypes.StdFee { + feeAmount := []sdk.Coin{sdk.NewCoin("uatom", sdk.NewInt(3000))} + return authtypes.NewStdFee(DefaultSwapoutGas, feeAmount) + } + default: + return func() authtypes.StdFee { + feeAmount := []sdk.Coin{sdk.NewCoin("uatom", sdk.NewInt(3000))} + return authtypes.NewStdFee(DefaultSwapoutGas, feeAmount) + } + } +} diff --git a/tokens/cosmos/buildtx.go b/tokens/cosmos/buildtx.go new file mode 100644 index 00000000..f17df3ad --- /dev/null +++ b/tokens/cosmos/buildtx.go @@ -0,0 +1,111 @@ +package cosmos + +import ( + "errors" + "fmt" + "strings" + + "github.com/anyswap/CrossChain-Bridge/params" + "github.com/anyswap/CrossChain-Bridge/tokens" + sdk "github.com/cosmos/cosmos-sdk/types" +) + +// BuildRawTransaction build raw tx +func (b *Bridge) BuildRawTransaction(args *tokens.BuildTxArgs) (rawTx interface{}, err error) { + var ( + pairID = args.PairID + tokenCfg = b.GetTokenConfig(pairID) + from = args.From + to = args.Bind + amount = args.Value + memo = args.Memo + ) + args.Identifier = params.GetIdentifier() + tokenCfg = b.GetTokenConfig(pairID) + if tokenCfg == nil { + return nil, fmt.Errorf("swap pair '%v' is not configed", pairID) + } + + switch args.SwapType { + case tokens.SwapinType: + return nil, tokens.ErrSwapTypeNotSupported + case tokens.SwapoutType: + from = tokenCfg.DcrmAddress // from + amount = tokens.CalcSwappedValue(pairID, args.OriginValue, false) // amount + memo = tokens.UnlockMemoPrefix + args.SwapID + } + + if from == "" { + return nil, errors.New("no sender specified") + } + + fromAcc, err := sdk.AccAddressFromBech32(from) + if err != nil { + // Never happens + return nil, errors.New("From address error") + } + toAcc, err := sdk.AccAddressFromBech32(to) + if err != nil { + return nil, errors.New("To address does not refer to a cosmos account") + } + sendcoin := sdk.NewCoin(b.MainCoin.Denom, sdk.NewIntFromBigInt(amount)) + sendmsg := NewMsgSend(fromAcc, toAcc, sdk.Coins{sendcoin}) + + fee := GetFeeAmount() + + accountNumber, err := b.GetAccountNumberCached(from) + if err != nil { + return nil, err + } + + seq, err := b.getSequence(args.PairID, from, args.SwapType) + if err != nil { + return nil, err + } + + rawTx = StdSignContent{ + ChainID: b.ChainConfig.NetID, + AccountNumber: accountNumber, + Sequence: *seq, + Fee: fee, + Msgs: []sdk.Msg{sendmsg}, + Memo: memo, + } + return +} + +func (b *Bridge) getSequence(pairID, from string, swapType tokens.SwapType) (*uint64, error) { + var seq uint64 + seq, err := b.GetPoolNonce(from, "pending") + if err != nil { + return nil, err + } + if swapType != tokens.NoSwapType { + tokenCfg := b.GetTokenConfig(pairID) + if tokenCfg != nil && from == tokenCfg.DcrmAddress { + seq = b.AdjustNonce(pairID, seq) + } + } + return &seq, nil +} + +// AdjustNonce adjust account nonce (eth like chain) +func (b *Bridge) AdjustNonce(pairID string, value uint64) (nonce uint64) { + tokenCfg := b.GetTokenConfig(pairID) + account := strings.ToLower(tokenCfg.DcrmAddress) + nonce = value + if b.IsSrcEndpoint() { + if b.SwapoutNonce[account] > value { + nonce = b.SwapoutNonce[account] + } else { + b.SwapoutNonce[account] = value + } + } else { + if b.SwapinNonce[account] > value { + nonce = b.SwapinNonce[account] + } else { + b.SwapinNonce[account] = value + } + } + return nonce +} diff --git a/tokens/cosmos/cosmos-config-example.toml b/tokens/cosmos/cosmos-config-example.toml new file mode 100644 index 00000000..e2bee9dd --- /dev/null +++ b/tokens/cosmos/cosmos-config-example.toml @@ -0,0 +1,108 @@ +# a short string to identify the bridge +Identifier = "COSMOS2ETH" + +# administrators who can do admin work like maintain blacklist etc. +Admins = [ + "0x3dfaef310a1044fd7d96750b42b44cf3775c00bf", + "0x46cbe22b687d4b72c8913e4784dfe5b20fdc2b0e" +] + +# modgodb database connection config (server only) +[MongoDB] +DBURL = "localhost:27017" +DBName = "databasename" +UserName = "username" +Password = "password" + +# bridge API service (server only) +[APIServer] +# listen port +Port = 11556 +# CORS config +AllowedOrigins = [] + +# oracle config (oracle only) +[Oracle] +# post swap register RPC requests to this server +ServerAPIAddress = "http://127.0.0.1:11556/rpc" + +# source chain config +[SrcChain] +BlockChain = "COSMOS" +NetID = "cosmos-hub4" +# tx should be in chain with at least so many confirmations to be valid on source chain +Confirmations = 0 # suggest >= 6 for Mainnet +# only tx with block height >= this initial height should be considered valid on source chain +InitialHeight = 0 +# whether enable scan blocks and register swaps +EnableScan = true + +# source blockchain gateway config +[SrcGateway] +APIAddress = [""] + +# dest chain config +[DestChain] +BlockChain = "ETHEREUM" +NetID = "Rinkeby" +# tx should be in chain with at least so many confirmations to be valid on source chain +Confirmations = 0 # suggest >= 30 for Mainnet +# only tx with block height >= this initial height should be considered valid on source chain +InitialHeight = 0 +# whether enable scan blocks and register swaps +EnableScan = false + +# dest blockchain gateway config +[DestGateway] +APIAddress = ["http://5.189.139.168:8018"] + +# DCRM config +[Dcrm] +# disable flag +Disable = false + +# dcrm group ID +GroupID = "74245ef03937fa75b979bdaa6a5952a93f53e021e0832fca4c2ad8952572c9b70f49e291de7e024b0f7fc54ec5875210db2ac775dba44448b3972b75af074d17" + +# dcrm threshold (NeededOracles=2,TotalOracles=3 represent '2/3' threshold) +NeededOracles = 2 +TotalOracles = 3 + +# dcrm mode (0:managed 1:private) +Mode = 0 + +# initiators of dcrm sign +Initiators = [ + "0x00c37841378920E2BA5151a5d1E074Cf367586c4", + "0x897a9980808a2cae0d09ff693f02a4f80abb2233" +] + +# DCRM other initiators nodes config (server only) +[[Dcrm.OtherNodes]] +# dcrm sub groups for signing +SignGroups = [ + "38a93f457c793ac3ee242b2c050a403774738e6558cfaa620fe5577bb15a28f63c39adcc0778497e5009a9ee776a0778ffcad4e95827e69efa21b893b8a78793", + "bb1dfe1ec046cc3a3b88408ae03976aabffe459b40e5def09e76f5d4c7a917133241da9da7fc05e3e172fab54ce3129a9a492d52a5a09494d0b9c1e608f661bf" +] + +# dcrm user keystore and password file (suggest using absolute path) +KeystoreFile = "/home/xxx/accounts/keystore2" +PasswordFile = "/home/xxx/accounts/password2" + +# dcrm backend node (gdcrm node RPC address) +RPCAddress = "http://127.0.0.1:2922" + +# DCRM default node config +[Dcrm.DefaultNode] +# dcrm sub groups for signing (server only) +SignGroups = [ + "38a93f457c793ac3ee242b2c050a403774738e6558cfaa620fe5577bb15a28f63c39adcc0778497e5009a9ee776a0778ffcad4e95827e69efa21b893b8a78793", + "bb1dfe1ec046cc3a3b88408ae03976aabffe459b40e5def09e76f5d4c7a917133241da9da7fc05e3e172fab54ce3129a9a492d52a5a09494d0b9c1e608f661bf" +] + +# dcrm user keystore and password file (suggest using absolute path) +KeystoreFile = "/home/xxx/accounts/keystore1" +PasswordFile = "/home/xxx/accounts/password1" + +# dcrm backend node (gdcrm node RPC address) +RPCAddress = "http://127.0.0.1:2921" diff --git a/tokens/cosmos/cosmosdev/genAddress/genAddress.go b/tokens/cosmos/cosmosdev/genAddress/genAddress.go new file mode 100644 index 00000000..0cd05108 --- /dev/null +++ b/tokens/cosmos/cosmosdev/genAddress/genAddress.go @@ -0,0 +1,37 @@ +package main + +import ( + "fmt" + + "github.com/anyswap/CrossChain-Bridge/tokens/cosmos" + "github.com/anyswap/CrossChain-Bridge/tokens/terra" +) + +func main() { + pubkey := "045c8648793e4867af465691685000ae841dccab0b011283139d2eae454b569d5789f01632e13a75a5aad8480140e895dd671cae3639f935750bea7ae4b5a2512e" + + cosmosAddr := cosmosAddress(pubkey) + fmt.Printf("cosmos address: %v\n", cosmosAddr) + + terraAddr := terraAddress(pubkey) + fmt.Printf("terra address: %v\n", terraAddr) +} + +func cosmosAddress(pubkey string) string { + b := cosmos.NewCrossChainBridge(true) + address, err := b.PublicKeyToAddress(pubkey) + if err != nil { + panic(err) + } + return address +} + +func terraAddress(pubkey string) string { + b := terra.NewCrossChainBridge(true) + terra.InitSDK() + address, err := b.PublicKeyToAddress(pubkey) + if err != nil { + panic(err) + } + return address +} diff --git a/tokens/cosmos/cosmosdev/signtx/main.go b/tokens/cosmos/cosmosdev/signtx/main.go new file mode 100644 index 00000000..21a801c7 --- /dev/null +++ b/tokens/cosmos/cosmosdev/signtx/main.go @@ -0,0 +1,344 @@ +package main + +import ( + "encoding/hex" + "encoding/json" + "fmt" + "io/ioutil" + "log" + "net/http" + "strings" + + "github.com/anyswap/CrossChain-Bridge/tools/crypto" + "github.com/btcsuite/btcd/btcec" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/auth/ante" + "github.com/cosmos/cosmos-sdk/x/auth/client/rest" + authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" + "github.com/cosmos/cosmos-sdk/x/bank" + amino "github.com/tendermint/go-amino" + "github.com/tendermint/tendermint/crypto/secp256k1" + "github.com/tendermint/tendermint/crypto/tmhash" + ctypes "github.com/tendermint/tendermint/rpc/core/types" + ttypes "github.com/tendermint/tendermint/types" + core "github.com/terra-project/core/types" + terraauth "github.com/terra-project/core/x/auth" + terrabank "github.com/terra-project/core/x/bank" +) + +var CDC = amino.NewCodec() + +func init() { + config := sdk.GetConfig() + config.SetCoinType(core.CoinType) + config.SetFullFundraiserPath(core.FullFundraiserPath) + config.SetBech32PrefixForAccount(core.Bech32PrefixAccAddr, core.Bech32PrefixAccPub) + config.SetBech32PrefixForValidator(core.Bech32PrefixValAddr, core.Bech32PrefixValPub) + config.SetBech32PrefixForConsensusNode(core.Bech32PrefixConsAddr, core.Bech32PrefixConsPub) + config.Seal() + + sdk.RegisterCodec(CDC) + ctypes.RegisterAmino(CDC) + + //stargate-final + //bank.RegisterCodec(CDC) + //authtypes.RegisterCodec(CDC) + + // tequila-0004 + terrabank.RegisterCodec(CDC) + terraauth.RegisterCodec(CDC) +} + +var ChainID = "tequila-0004" + +//var ChainID = "stargate-final" + +func genKeyX() { + priv := secp256k1.GenPrivKey() + privkeyHex := hex.EncodeToString(priv.Bytes()) + pub := priv.PubKey().Bytes() + pubkeyHex := hex.EncodeToString(pub) + fmt.Printf("Private key: %v\nPublic key: %v\n", privkeyHex, pubkeyHex) + pubkeyAddress := priv.PubKey().Address() + fmt.Printf("Public key address: %v\n", pubkeyAddress) + address, _ := sdk.AccAddressFromHex(pubkeyAddress.String()) + fmt.Printf("Address: %v\n", address.String()) +} + +func main() { + //genKey() + //sendTx() + broadcastTx() +} + +func genKey() { + priv, _ := crypto.GenerateKey() + privkeyHex := hex.EncodeToString(crypto.FromECDSA(priv)) + pub := priv.PublicKey + pubkeyHex := hex.EncodeToString(crypto.FromECDSAPub(&pub)) + fmt.Printf("Private key: %v\nPublic key: %v\n", privkeyHex, pubkeyHex) + address, err := PublicKeyToAddress(pubkeyHex) + if err != nil { + log.Fatal(err) + } + fmt.Printf("Address: %v\n", address) + + var privBytes [32]byte + privBytes1, _ := hex.DecodeString(privkeyHex) + copy(privBytes[:], privBytes1[:33]) + priv1 := secp256k1.PrivKeySecp256k1(privBytes) + pub1 := priv1.PubKey() + pubkeyAddress := pub1.Address() + address1, _ := sdk.AccAddressFromHex(pubkeyAddress.String()) + fmt.Printf("Address1: %v\n", address1.String()) +} + +/* +62625de7ed1d9ecaebb0dc8fe1425cfe994bb79c699c019d6b8c40f9e1ad8907 +046693b7612ccd92f0ec57e62aa51c72d7a978c4871c482cbf2a896575bf67ac3041b8b0ee98f5c1433115c99bdba8548939d1a7eb232ec6df00af1d8d749ec23d +terra1qj05rkrpphd55dawh7qxxmd2c72g57j2r0nlp3 +tequila-0004: 29325 + +1a05233ffa885bf369b5ff1ec829114975243fc7dbdbaabdee0cb9e4185dd678 +04bfd55e4900a1de682907642843d16fd189ccac0656fcebacd22b3e10eecc6a374344c33799bca2831ac0cef6c739558ce879bb99ef2864a533e1e50e4d9dad6b +cosmos1s88t76ev084c6d35fahkslqseep5szgeggr3q0 +stargate-final: 25361 +*/ + +func sendTx() { + pubkeyHex := "046693b7612ccd92f0ec57e62aa51c72d7a978c4871c482cbf2a896575bf67ac3041b8b0ee98f5c1433115c99bdba8548939d1a7eb232ec6df00af1d8d749ec23d" // tequila-0004 + //pubkeyHex := "04bfd55e4900a1de682907642843d16fd189ccac0656fcebacd22b3e10eecc6a374344c33799bca2831ac0cef6c739558ce879bb99ef2864a533e1e50e4d9dad6b" // stargate-final + addr, err := PublicKeyToAddress(pubkeyHex) + if err != nil { + log.Fatal(err) + } + fmt.Printf("address:\n%v\n", addr) + // terra1wr965945fxexk68mxne5en56pr6la006p7764e + // cosmos1s88t76ev084c6d35fahkslqseep5szgeggr3q0 + address, _ := sdk.AccAddressFromBech32(addr) + + address2 := address + + accountNumber := uint64(29325) // tequila-0004 + //accountNumber := uint64(25361) // stargate-final + sequence := uint64(0) + + msgs := []sdk.Msg{ + bank.MsgSend{ + FromAddress: address, + ToAddress: address2, + Amount: sdk.Coins{sdk.NewCoin("uluna", sdk.NewInt(100000))}, + //Amount: sdk.Coins{sdk.NewCoin("umuon", sdk.NewInt(10))}, + }, + } + memo := "" + + feeAmount := []sdk.Coin{sdk.NewCoin("uluna", sdk.NewInt(50000))} + //feeAmount := sdk.Coins{sdk.Coin{"umuon", sdk.NewInt(50000)}} + gas := uint64(300000) + fee := authtypes.NewStdFee(gas, feeAmount) + + signBytes := StdSignBytes(ChainID, accountNumber, sequence, fee, msgs, memo) + signString := fmt.Sprintf("%s", signBytes) + signString = strings.Replace(signString, "cosmos-sdk", "bank", 1) + fmt.Printf("\nSign string:\n%v\n", signString) + signBytes = []byte(signString) + signHash := fmt.Sprintf("%X", tmhash.Sum(signBytes)) + fmt.Printf("\nSign bytes hash:\n%s\n", signHash) + + var privBytes [32]byte + privBytes1, _ := hex.DecodeString("62625de7ed1d9ecaebb0dc8fe1425cfe994bb79c699c019d6b8c40f9e1ad8907") // tequila-0004 + //privBytes1, _ := hex.DecodeString("1a05233ffa885bf369b5ff1ec829114975243fc7dbdbaabdee0cb9e4185dd678") // stargate-final + copy(privBytes[:], privBytes1[:33]) + priv := secp256k1.PrivKeySecp256k1(privBytes) + signature, err := priv.Sign(signBytes) + + stdsig := authtypes.StdSignature{ + PubKey: priv.PubKey(), + Signature: signature, + } + signatures := []authtypes.StdSignature{stdsig} + stdtx := authtypes.StdTx{ + Msgs: msgs, + Fee: fee, + Signatures: signatures, + Memo: memo, + } + fmt.Printf("\nStd tx:\n%+v\n", stdtx) + + txBytes, err := CDC.MarshalBinaryLengthPrefixed(stdtx) + if err != nil { + log.Fatal(err) + } + fmt.Printf("\ntxBytes:\n%X\n", txBytes) + txhash := ttypes.Tx(txBytes).Hash() + fmt.Printf("\nTxhash:\n%X\n", txhash) + + // build post data + bz, err := CDC.MarshalJSON(stdtx) + if err != nil { + log.Fatal(err) + } + // Take "value" from the json struct + tempStr := make(map[string]interface{}) + err = json.Unmarshal(bz, &tempStr) + if err != nil { + log.Fatal(err) + } + value, ok := tempStr["value"].(map[string]interface{}) + if !ok { + log.Fatal(err) + } + // repass account number and sequence + signatures2, ok := value["signatures"].([]interface{}) + if !ok || len(signatures) < 1 { + log.Fatal(err) + } + signatures2[0].(map[string]interface{})["account_number"] = fmt.Sprintf("%v", accountNumber) + signatures2[0].(map[string]interface{})["sequence"] = fmt.Sprintf("%v", sequence) + value["signatures"] = signatures2 + bz2, err := json.Marshal(value) + if err != nil { + log.Fatal(err) + } + data := fmt.Sprintf(`{"tx":%v,"mode":"block"}`, string(bz2)) + fmt.Printf("\ndata:\n%+v\n", data) + + // broadcast + // https://github.com/cosmos/cosmos-sdk/blob/v0.39.2/x/auth/client/rest/broadcast.go + fmt.Printf("\n====================\n") + client := &http.Client{} + req, err := http.NewRequest("POST", "https://tequila-lcd.terra.dev/txs", strings.NewReader(data)) // tequila-0004 + //req, err := http.NewRequest("POST", "http://34.71.170.158:1317/txs", strings.NewReader(data)) // stargate-final + if err != nil { + log.Fatal(err) + } + req.Header.Set("accept", "application/json") + req.Header.Set("Content-Type", "application/json") + resp, err := client.Do(req) + if err != nil { + log.Fatal(err) + } + bodyText, err := ioutil.ReadAll(resp.Body) + if err != nil { + log.Fatal(err) + } + fmt.Printf("\nres:\n%v\n", string(bodyText)) + + // simulate handle broadcast + fmt.Printf("\n====================\n") + r, err := http.NewRequest("POST", "", strings.NewReader(data)) + if err != nil { + log.Fatal(err) + } + var req1 rest.BroadcastReq + body, err := ioutil.ReadAll(r.Body) + err = CDC.UnmarshalJSON(body, &req1) + if err != nil { + log.Fatal(err) + } + fmt.Printf("\nreq1.Tx:\n%+v\n", req1.Tx) + txBytes2, err := CDC.MarshalBinaryLengthPrefixed(req1.Tx) + if err != nil { + log.Fatal(err) + } + txhash2 := ttypes.Tx(txBytes2).Hash() + fmt.Printf("\nTxhash2:\n%X\n", txhash2) + + // verify tx + // https://github.com/cosmos/cosmos-sdk/blob/v0.39.2/x/auth/ante/sigverify.go + fmt.Printf("\n====================\n") + sigTx := ante.SigVerifiableTx(req1.Tx) + fmt.Printf("\nSigTx:\n%+v\n", sigTx) + + pubkeys := sigTx.GetPubKeys() + signers := sigTx.GetSigners() + sigs := sigTx.GetSignatures() + fmt.Printf("\npubkeys:\n%+v\nsigners:\n%+v\nsigs:\n%+v\n", pubkeys, signers, sigs) + + fmt.Printf("\nsignBytes:\n%X\n", signBytes) + valid1 := pubkeys[0].VerifyBytes(signBytes, sigs[0]) + fmt.Printf("\nvalid1:\n%v\n", valid1) + + signBytes2 := authtypes.StdSignBytes( + ChainID, accountNumber, sequence, req1.Tx.Fee, req1.Tx.Msgs, req1.Tx.Memo, + ) + fmt.Printf("\nsignBytes2:\n%X\n", signBytes2) + valid2 := pubkeys[0].VerifyBytes(signBytes2, sigs[0]) + fmt.Printf("\nvalid2:\n%v\n", valid2) +} + +func PublicKeyToAddress(pubKeyHex string) (address string, err error) { + pubKeyHex = strings.TrimPrefix(pubKeyHex, "0x") + bb, err := hex.DecodeString(pubKeyHex) + if err != nil { + return + } + pk, err := btcec.ParsePubKey(bb, btcec.S256()) + if err != nil { + return + } + cpk := pk.SerializeCompressed() + var pub [33]byte + copy(pub[:], cpk[:33]) + pubkey := secp256k1.PubKeySecp256k1(pub) + addr := pubkey.Address() + accAddress, err := sdk.AccAddressFromHex(addr.String()) + if err != nil { + return + } + address = accAddress.String() + return +} + +func StdSignBytes(chainID string, accnum uint64, sequence uint64, fee authtypes.StdFee, msgs []sdk.Msg, memo string) []byte { + msgsBytes := make([]json.RawMessage, 0, len(msgs)) + for _, msg := range msgs { + msgsBytes = append(msgsBytes, json.RawMessage(msg.GetSignBytes())) + } + bz, err := CDC.MarshalJSON(authtypes.StdSignDoc{ + AccountNumber: accnum, + ChainID: chainID, + Fee: json.RawMessage(fee.Bytes()), + Memo: memo, + Msgs: msgsBytes, + Sequence: sequence, + }) + if err != nil { + panic(err) + } + return sdk.MustSortJSON(bz) +} + +func broadcastTx() { + data := `{"tx":{"fee":{"amount":[{"amount":"50000","denom":"uluna"}],"gas":"300000"},"memo":"SWAPTX:0xcd86d1ed7c8665ff7a5d84c002c60a48d20c7404f546aa0942c70f74c21f67e3","msg":[{"type":"bank/MsgSend","value":{"amount":[{"amount":"190000","denom":"uluna"}],"from_address":"terra10rf55rx37vrtc4ws7l8v950whvwq9znmk7d9ka","to_address":"terra1sn0erxvhpvnk0m2u0aluht95eqq5zj3ykmxk73"}}],"signatures":[{"account_number":"28986","pub_key":{"type":"tendermint/PubKeySecp256k1","value":"AtODCd/f2a3xKSh7aM8uHxEk4MvEDMmPlOXy0jwmcS+j"},"sequence":"0","signature":"Cbfb7onnqX+tLFcCPuKqBGpyHTfgebCAHl48guvOj2Ui3J31BF59XGZXKqUTejAYJLMWFFIyYFZ9kfCF1qXamQ=="}]},"mode":"block"}` + client := &http.Client{} + req, err := http.NewRequest("POST", "https://tequila-lcd.terra.dev/txs", strings.NewReader(data)) // tequila-0004 + //req, err := http.NewRequest("POST", "http://34.71.170.158:1317/txs", strings.NewReader(data)) // stargate-final + if err != nil { + log.Fatal(err) + } + req.Header.Set("accept", "application/json") + req.Header.Set("Content-Type", "application/json") + resp, err := client.Do(req) + if err != nil { + log.Fatal(err) + } + bodyText, err := ioutil.ReadAll(resp.Body) + if err != nil { + log.Fatal(err) + } + fmt.Printf("\nres:\n%v\n", string(bodyText)) + //bodyText = []byte(`{"height":"2934360","txhash":"57E767BF5BEDF7A5AB9CF6894813F4D0445CD737950C7B626CD85434EBDF28E5","raw_log":"[{\"msg_index\":0,\"log\":\"\",\"events\":[{\"type\":\"message\",\"attributes\":[{\"key\":\"action\",\"value\":\"send\"},{\"key\":\"sender\",\"value\":\"terra10rf55rx37vrtc4ws7l8v950whvwq9znmk7d9ka\"},{\"key\":\"module\",\"value\":\"bank\"}]},{\"type\":\"transfer\",\"attributes\":[{\"key\":\"recipient\",\"value\":\"terra1sn0erxvhpvnk0m2u0aluht95eqq5zj3ykmxk73\"},{\"key\":\"sender\",\"value\":\"terra10rf55rx37vrtc4ws7l8v950whvwq9znmk7d9ka\"},{\"key\":\"amount\",\"value\":\"190000uluna\"}]}]}]","logs":[{"msg_index":0,"log":"","events":[{"type":"message","attributes":[{"key":"action","value":"send"},{"key":"sender","value":"terra10rf55rx37vrtc4ws7l8v950whvwq9znmk7d9ka"},{"key":"module","value":"bank"}]},{"type":"transfer","attributes":[{"key":"recipient","value":"terra1sn0erxvhpvnk0m2u0aluht95eqq5zj3ykmxk73"},{"key":"sender","value":"terra10rf55rx37vrtc4ws7l8v950whvwq9znmk7d9ka"},{"key":"amount","value":"190000uluna"}]}]}],"gas_wanted":"300000","gas_used":"70494"}`) + var res map[string]interface{} + err = json.Unmarshal([]byte(bodyText), &res) + if err != nil { + log.Fatal(err) + } + height, ok1 := res["height"].(string) + txhash, ok2 := res["txhash"].(string) + if !ok1 || !ok2 || height == "0" { + log.Fatal(fmt.Errorf("Send tx failed, response: %s", bodyText)) + } + fmt.Printf("txhash:\n%v\n", txhash) +} diff --git a/tokens/cosmos/processtx.go b/tokens/cosmos/processtx.go new file mode 100644 index 00000000..38713a93 --- /dev/null +++ b/tokens/cosmos/processtx.go @@ -0,0 +1,25 @@ +package cosmos + +import ( + "strings" + + "github.com/anyswap/CrossChain-Bridge/log" + "github.com/anyswap/CrossChain-Bridge/tokens/tools" + sdk "github.com/cosmos/cosmos-sdk/types" +) + +func (b *Bridge) processTransaction(tx sdk.TxResponse) { + if b.IsSrc { + b.processSwapin(tx) + } else { + return + } +} + +func (b *Bridge) processSwapin(tx sdk.TxResponse) { + log.Info("cosmos processSwapin", "tx", tx) + swapInfos, errs := b.verifySwapinTx(tx, true) + txid := strings.ToLower(tx.TxHash) + log.Debug("cosmos processSwapin", "txid", txid, "swapinfos", swapInfos, "errs", errs) + tools.RegisterSwapin(txid, swapInfos, errs) +} diff --git a/tokens/cosmos/restclient.go b/tokens/cosmos/restclient.go new file mode 100644 index 00000000..55699ae2 --- /dev/null +++ b/tokens/cosmos/restclient.go @@ -0,0 +1,607 @@ +package cosmos + +import ( + "encoding/json" + "fmt" + "io/ioutil" + "math/big" + "net/http" + "net/url" + "strings" + "time" + + "github.com/go-resty/resty/v2" + + sdk "github.com/cosmos/cosmos-sdk/types" + authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" + amino "github.com/tendermint/go-amino" + ctypes "github.com/tendermint/tendermint/rpc/core/types" + + "github.com/anyswap/CrossChain-Bridge/log" + "github.com/anyswap/CrossChain-Bridge/tokens" +) + +/* +Rest api doc +https://cosmos.network/rpc/v0.39.2 +https://lcd.terra.dev/swagger-ui/#/ +*/ + +var CDC = amino.NewCodec() + +// TimeFormat is cosmos time format +const TimeFormat = time.RFC3339Nano + +// GetBalance gets main token balance +// call rest api"/bank/balances/" +func (b *Bridge) GetBalance(account string) (balance *big.Int, err error) { + endpoints := b.GatewayConfig.APIAddress + for _, endpoint := range endpoints { + endpointURL, err := url.Parse(endpoint) + if err != nil { + continue + } + endpoint = endpointURL.String() + client := resty.New() + resp, err := client.R().Get(fmt.Sprintf("%vbank/balances/%v", endpoint, account)) + if err != nil || resp.StatusCode() != 200 { + log.Warn("cosmos rest request error", "resp", string(resp.Body()), "request error", err, "func", "GetBalance") + continue + } + var balances sdk.Coins + err = CDC.UnmarshalJSON(resp.Body(), &balances) + if err != nil { + log.Warn("cosmos rest request error", "unmarshal error", err, "func", "GetBalance", "resp", string(resp.Body())) + continue + } + for _, bal := range balances { + if bal.Denom != b.MainCoin.Denom { + continue + } + balance = bal.Amount.BigInt() + } + if balance == nil { + balance = big.NewInt(0) + } + return balance, nil + } + return +} + +// GetTokenBalance gets balance for given token +// call rest api"/bank/balances/" +func (b *Bridge) GetTokenBalance(tokenType, tokenName, accountAddress string) (balance *big.Int, err error) { + coin, ok := b.GetCoin(tokenName) + if !ok { + return nil, fmt.Errorf("Unsupported coin: %v", tokenName) + } + endpoints := b.GatewayConfig.APIAddress + for _, endpoint := range endpoints { + endpointURL, err := url.Parse(endpoint) + if err != nil { + continue + } + endpoint = endpointURL.String() + client := resty.New() + resp, err := client.R().Get(fmt.Sprintf("%vbank/balances/%v", endpoint, accountAddress)) + if err != nil || resp.StatusCode() != 200 { + log.Warn("cosmos rest request error", "resp", string(resp.Body()), "error", err, "func", "GetTokenBalance") + continue + } + var balances sdk.Coins + err = CDC.UnmarshalJSON(resp.Body(), &balances) + if err != nil { + log.Warn("cosmos rest request error", "unmarshal error", err, "func", "GetTokenBalance", "resp", string(resp.Body())) + continue + } + for _, bal := range balances { + if bal.Denom != coin.Denom { + continue + } + balance = bal.Amount.BigInt() + } + if balance == nil { + balance = big.NewInt(0) + } + return balance, nil + } + return +} + +// GetTokenSupply not supported +func (b *Bridge) GetTokenSupply(tokenType, tokenAddress string) (*big.Int, error) { + return nil, fmt.Errorf("Cosmos bridges does not support this method") +} + +// GetTransaction gets tx by hash, returns sdk.Tx +// call rest api "/txs/{txhash}" +func (b *Bridge) GetTransaction(txHash string) (tx interface{}, err error) { + endpoints := b.GatewayConfig.APIAddress + for _, endpoint := range endpoints { + endpointURL, err := url.Parse(endpoint) + if err != nil { + continue + } + endpoint = endpointURL.String() + client := resty.New() + + resp, err := client.R().Get(fmt.Sprintf("%vtxs/%v", endpoint, txHash)) + if err != nil || resp.StatusCode() != 200 { + log.Warn("cosmos rest request error", "resp", string(resp.Body()), "request error", err, "func", "GetTransaction") + continue + } + var txResult sdk.TxResponse + err = CDC.UnmarshalJSON(resp.Body(), &txResult) + if err != nil { + log.Warn("cosmos rest request error", "unmarshal error", err, "func", "GetTransaction", "resp", string(resp.Body())) + return nil, err + } + if txResult.Code != 0 { + return nil, fmt.Errorf("tx status error: %+v", txResult) + } + tx = txResult.Tx + err = tx.(sdk.Tx).ValidateBasic() + if err != nil { + return nil, err + } else { + return tx, err + } + } + return +} + +// GetTransactionStatus returns tx status +// call rest api "/txs/{txhash}" +func (b *Bridge) GetTransactionStatus(txHash string) (status *tokens.TxStatus) { + status = &tokens.TxStatus{ + // Receipt + //Confirmations + //BlockHeight: uint64(txRes.Height), + //BlockHash + //BlockTime + } + endpoints := b.GatewayConfig.APIAddress + for _, endpoint := range endpoints { + endpointURL, err := url.Parse(endpoint) + if err != nil { + continue + } + endpoint = endpointURL.String() + client := resty.New() + + resp, err := client.R().Get(fmt.Sprintf("%vtxs/%v", endpoint, txHash)) + if err != nil || resp.StatusCode() != 200 { + log.Warn("cosmos rest request error", "resp", string(resp.Body()), "request error", err, "func", "GetTransactionStatus") + continue + } + + var txResult sdk.TxResponse + err = CDC.UnmarshalJSON(resp.Body(), &txResult) + if err != nil { + log.Warn("cosmos rest request error", "unmarshal error", err, "func", "GetTransactionStatus", "resp", string(resp.Body())) + return + } + tx := txResult.Tx + err = tx.ValidateBasic() + if err != nil { + return + } + if txResult.Code != 0 { + status.Confirmations = 0 + } else { + status.Confirmations = 1 + } + status.BlockHeight = uint64(txResult.Height) + t, err := time.Parse(TimeFormat, txResult.Timestamp) + if err == nil { + status.BlockTime = uint64(t.Unix()) + } + + if txResult.Code == 0 && status.BlockHeight > 0 { + status.PrioriFinalized = true // asserts that tx has finalized, no need to check everything again + } + + return + } + return +} + +// GetLatestBlockNumber returns current block height +// call rest api "/blocks/latest" +func (b *Bridge) GetLatestBlockNumber() (height uint64, err error) { + endpoints := b.GatewayConfig.APIAddress + for _, endpoint := range endpoints { + endpointURL, err := url.Parse(endpoint) + if err != nil { + continue + } + endpoint = endpointURL.String() + client := resty.New() + + resp, err := client.R().Get(fmt.Sprintf("%vblocks/latest", endpoint)) + if err != nil || resp.StatusCode() != 200 { + log.Warn("cosmos rest request error", "resp", string(resp.Body()), "request error", err, "func", "GetLatestBlockNumber") + continue + } + var blockRes ctypes.ResultBlock + err = CDC.UnmarshalJSON(resp.Body(), &blockRes) + if err != nil { + log.Warn("cosmos rest request error", "unmarshal error", err, "func", "GetLatestBlockNumber", "resp", string(resp.Body())) + continue + } + height = uint64(blockRes.Block.Header.Height) + return height, nil + } + return +} + +// GetLatestBlockNumberOf returns current block height of given node +// call rest api "/blocks/latest" +func (b *Bridge) GetLatestBlockNumberOf(apiAddress string) (uint64, error) { + endpointURL, err := url.Parse(apiAddress) + if err != nil { + return 0, err + } + endpoint := endpointURL.String() + client := resty.New() + + resp, err := client.R().Get(fmt.Sprintf("%vblocks/latest", endpoint)) + if err != nil || resp.StatusCode() != 200 { + log.Warn("cosmos rest request error", "resp", string(resp.Body()), "request error", err, "func", "GetLatestBlockNumberOf") + return 0, err + } + var blockRes ctypes.ResultBlock + err = CDC.UnmarshalJSON(resp.Body(), &blockRes) + if err != nil { + log.Warn("cosmos rest request error", "unmarshal error", err, "func", "GetLatestBlockNumberOf", "resp", string(resp.Body())) + return 0, err + } + height := uint64(blockRes.Block.Header.Height) + return height, nil +} + +// GetAccountNumber gets account number, a series number of account on a cosmos state +// call rest api "/auth/accounts/" +func (b *Bridge) GetAccountNumber(address string) (uint64, error) { + endpoints := b.GatewayConfig.APIAddress + for _, endpoint := range endpoints { + endpointURL, err := url.Parse(endpoint) + if err != nil { + continue + } + endpoint = endpointURL.String() + client := resty.New() + + resp, err := client.R().Get(fmt.Sprintf("%vauth/accounts/%v", endpoint, address)) + if err != nil || resp.StatusCode() != 200 { + log.Warn("cosmos rest request error", "resp", string(resp.Body()), "request error", err, "func", "GetAccountNumber") + continue + } + tempStruct := make(map[string]interface{}) + err = json.Unmarshal(resp.Body(), &tempStruct) + if err != nil { + log.Warn("Marshal resp error", "err", err) + continue + } + result, ok := tempStruct["result"] + if !ok { + log.Warn("Get result error") + continue + } + bz, err := json.Marshal(result) + if err != nil { + log.Warn("Marshal result error", "err", err) + continue + } + var accountRes authtypes.BaseAccount + err = CDC.UnmarshalJSON(bz, &accountRes) + if err != nil { + log.Warn("cosmos rest request error", "unmarshal error", err, "func", "GetAccountNumber") + continue + } + accountNumber := accountRes.AccountNumber + return accountNumber, nil + } + return 0, nil +} + +// GetPoolNonce gets account sequence +// call rest api "/auth/accounts/" +func (b *Bridge) GetPoolNonce(address, height string) (uint64, error) { + endpoints := b.GatewayConfig.APIAddress + for _, endpoint := range endpoints { + endpointURL, err := url.Parse(endpoint) + if err != nil { + continue + } + endpoint = endpointURL.String() + client := resty.New() + + resp, err := client.R().Get(fmt.Sprintf("%vauth/accounts/%v", endpoint, address)) + if err != nil || resp.StatusCode() != 200 { + log.Warn("cosmos rest request error", "resp", string(resp.Body()), "request error", err, "func", "GetPoolNonce") + continue + } + tempStruct := make(map[string]interface{}) + err = json.Unmarshal(resp.Body(), &tempStruct) + if err != nil { + log.Warn("Marshal resp error", "err", err) + continue + } + result, ok := tempStruct["result"] + if !ok { + log.Warn("Get result error") + continue + } + bz, err := json.Marshal(result) + if err != nil { + log.Warn("Marshal result error", "err", err) + continue + } + var accountRes authtypes.BaseAccount + err = CDC.UnmarshalJSON(bz, &accountRes) + if err != nil { + log.Warn("cosmos rest request error", "unmarshal error", err, "func", "GetPoolNonce") + continue + } + seq := accountRes.Sequence + return seq, nil + } + return 0, nil +} + +// SearchTxsHash searches tx in range of blocks +// call rest api "/txs?..." +func (b *Bridge) SearchTxsHash(start, end *big.Int) ([]string, error) { + txs := make([]string, 0) + var limit = 100 + var page = 1 + var pageTotal = 1 + endpoints := b.GatewayConfig.APIAddress + + // search send + for page <= pageTotal { + log.Debug("Search send msgs", "start", start, "end", end, "limit", limit, "page", page, "pageTotal", pageTotal) + for _, endpoint := range endpoints { + endpointURL, err := url.Parse(endpoint) + if err != nil { + continue + } + endpoint = endpointURL.String() + client := resty.New() + params := fmt.Sprintf("?message.action=send&page=%v&limit=%v&tx.minheight=%v&tx.maxheight=%v", page, limit, start, end) + resp, err := client.R().Get(fmt.Sprintf("%vtxs%v", endpoint, params)) + if err != nil || resp.StatusCode() != 200 { + log.Warn("cosmos rest request error", "resp", string(resp.Body()), "request error", err, "func", "SearchTxsHash") + continue + } + var res sdk.SearchTxsResult + err = CDC.UnmarshalJSON(resp.Body(), &res) + if err != nil { + log.Warn("Search txs unmarshal error", "start", start, "end", end, "page", page, "func", "SearchTxsHash") + continue + } + pageTotal = res.PageTotal + log.Debug("Txs containing Send msgs", "length", len(res.Txs)) + for _, tx := range res.Txs { + if tx.Code != 0 { + log.Debug("discard failed tx") + continue + } + txs = append(txs, tx.TxHash) + } + break + } + page = page + 1 + } + + // search multisend + page = 1 + pageTotal = 1 + for page <= pageTotal { + log.Debug("Search multisend msgs", "start", start, "end", end, "limit", limit, "page", page, "pageTotal", pageTotal) + for _, endpoint := range endpoints { + endpointURL, err := url.Parse(endpoint) + if err != nil { + continue + } + endpoint = endpointURL.String() + client := resty.New() + params := fmt.Sprintf("?message.action=multisend&page=%v&limit=%v&tx.minheight=%v&tx.maxheight=%v", page, limit, start, end) + resp, err := client.R().Get(fmt.Sprintf("%vtxs%v", endpoint, params)) + if err != nil || resp.StatusCode() != 200 { + log.Warn("cosmos rest request error", "resp", string(resp.Body()), "request error", err, "func", "SearchTxsHash") + continue + } + var res sdk.SearchTxsResult + err = CDC.UnmarshalJSON(resp.Body(), &res) + if err != nil { + log.Warn("Search txs unmarshal error", "start", start, "end", end, "page", page, "func", "SearchTxsHash") + continue + } + pageTotal = res.PageTotal + log.Debug("Txs containing MultiSend msgs", "length", len(res.Txs)) + for _, tx := range res.Txs { + if tx.Code != 0 { + log.Debug("discard failed tx") + continue + } + txs = append(txs, tx.TxHash) + } + break + } + page = page + 1 + } + log.Debug("Search txs finish") + return txs, nil +} + +// SearchTxs searches tx in range of blocks +// call rest api "/txs?..." +func (b *Bridge) SearchTxs(start, end *big.Int) ([]sdk.TxResponse, error) { + txs := make([]sdk.TxResponse, 0) + var limit = 100 + + // search send + var page = 1 + var pageTotal = 1 + endpoints := b.GatewayConfig.APIAddress + for page <= pageTotal { + log.Debug("Search send msgs", "start", start, "end", end, "limit", limit, "page", page, "pageTotal", pageTotal) + for _, endpoint := range endpoints { + endpointURL, err := url.Parse(endpoint) + if err != nil { + continue + } + endpoint = endpointURL.String() + client := resty.New() + params := fmt.Sprintf("?message.action=send&page=%v&limit=%v&tx.minheight=%v&tx.maxheight=%v", page, limit, start, end) + resp, err := client.R().Get(fmt.Sprintf("%vtxs%v", endpoint, params)) + if err != nil || resp.StatusCode() != 200 { + log.Warn("cosmos rest request error", "resp", string(resp.Body()), "request error", err, "func", "SearchTxs") + continue + } + var res sdk.SearchTxsResult + err = CDC.UnmarshalJSON(resp.Body(), &res) + if err != nil { + log.Warn("Search txs unmarshal error", "start", start, "end", end, "page", page, "func", "SearchTxs") + continue + } + pageTotal = res.PageTotal + log.Debug("Txs containing Send msgs", "length", len(res.Txs)) + for _, txresp := range res.Txs { + if txresp.Code != 0 { + log.Debug("discard failed tx") + continue + } + txs = append(txs, txresp) + } + break + } + page = page + 1 + } + + // search multisend + page = 1 + pageTotal = 1 + for page <= pageTotal { + log.Debug("Search multisend msgs", "start", start, "end", end, "limit", limit, "page", page, "pageTotal", pageTotal) + for _, endpoint := range endpoints { + endpointURL, err := url.Parse(endpoint) + if err != nil { + continue + } + endpoint = endpointURL.String() + client := resty.New() + params := fmt.Sprintf("?message.action=multisend&page=%v&limit=%v&tx.minheight=%v&tx.maxheight=%v", page, limit, start, end) + resp, err := client.R().Get(fmt.Sprintf("%v/txs%v", endpoint, params)) + if err != nil || resp.StatusCode() != 200 { + log.Warn("cosmos rest request error", "resp", string(resp.Body()), "request error", err, "func", "SearchTxs") + continue + } + var res sdk.SearchTxsResult + err = CDC.UnmarshalJSON(resp.Body(), &res) + if err != nil { + log.Warn("Search txs unmarshal error", "start", start, "end", end, "page", page, "func", "SearchTxs") + continue + } + pageTotal = res.PageTotal + log.Debug("Txs containing MultiSend msgs", "length", len(res.Txs)) + for _, txresp := range res.Txs { + if txresp.Code != 0 { + log.Debug("discard failed tx") + continue + } + txs = append(txs, txresp) + } + break + } + page = page + 1 + } + return txs, nil +} + +// BroadcastTx broadcast tx +// post "txs" to rest api +// mode: block +func (b *Bridge) BroadcastTx(tx HashableStdTx) (string, error) { + txhash := "" + stdtx := tx.ToStdTx() + + bz, err := CDC.MarshalJSON(stdtx) + if err != nil { + return txhash, err + } + // Take "value" from the json struct + tempStr := make(map[string]interface{}) + err = json.Unmarshal(bz, &tempStr) + if err != nil { + return txhash, err + } + value, ok := tempStr["value"].(map[string]interface{}) + if !ok { + return txhash, fmt.Errorf("tx value error") + } + // repass account number and sequence + signatures, ok := value["signatures"].([]interface{}) + if !ok || len(signatures) < 1 { + return txhash, fmt.Errorf("tx value not contain signature") + } + signatures[0].(map[string]interface{})["account_number"] = fmt.Sprintf("%v", tx.AccountNumber) + signatures[0].(map[string]interface{})["sequence"] = fmt.Sprintf("%v", tx.Sequence) + value["signatures"] = signatures + bz2, err := json.Marshal(value) + if err != nil { + return txhash, err + } + data := fmt.Sprintf(`{"tx":%v,"mode":"block"}`, string(bz2)) + + log.Info("Broadcast tx", "data", data) + + endpoints := b.GatewayConfig.APIAddress + for _, endpoint := range endpoints { + endpointURL, err := url.Parse(endpoint) + if err != nil { + continue + } + endpoint = endpointURL.String() + + client := &http.Client{} + + req, err := http.NewRequest("POST", endpoint+"txs", strings.NewReader(data)) + if err != nil { + continue + } + req.Header.Set("accept", "application/json") + req.Header.Set("Content-Type", "application/json") + resp, err := client.Do(req) + if err != nil { + resp.Body.Close() + continue + } + bodyText, err := ioutil.ReadAll(resp.Body) + resp.Body.Close() + if err != nil { + continue + } + + log.Info("Broadcast tx", "resp", bodyText) + + var res map[string]interface{} + err = json.Unmarshal([]byte(bodyText), &res) + if err != nil { + log.Warn("cosmos rest request error", "unmarshal error", err, "func", "BroadcastTx") + continue + } + height, ok1 := res["height"].(string) + restxhash, ok2 := res["txhash"].(string) + if !ok1 || !ok2 || height == "0" { + log.Warn("Broadcast tx failed", "response", bodyText) + continue + } + txhash = restxhash + log.Debug("Broadcast tx success", "txhash", restxhash, "height", height) + return txhash, nil + } + return txhash, nil +} diff --git a/tokens/cosmos/scanchaintx.go b/tokens/cosmos/scanchaintx.go new file mode 100644 index 00000000..506ff4c3 --- /dev/null +++ b/tokens/cosmos/scanchaintx.go @@ -0,0 +1,184 @@ +package cosmos + +import ( + "context" + "fmt" + "math/big" + "sync" + "time" + + "github.com/anyswap/CrossChain-Bridge/log" + "github.com/anyswap/CrossChain-Bridge/tokens/tools" +) + +var ( + quickSyncFinish bool + quickSyncWorkers = uint64(4) + + maxScanHeight = uint64(100) + retryIntervalInScanJob = 3 * time.Second + restIntervalInScanJob = 3 * time.Second +) + +func (b *Bridge) getStartAndLatestHeight() (start, latest uint64) { + startHeight := tools.GetLatestScanHeight(b.IsSrc) + + chainCfg := b.GetChainConfig() + confirmations := *chainCfg.Confirmations + initialHeight := *chainCfg.InitialHeight + + latest = tools.LoopGetLatestBlockNumber(b) + + switch { + case startHeight != 0: + start = startHeight + case initialHeight != 0: + start = initialHeight + default: + if latest > confirmations { + start = latest - confirmations + } + } + if start < initialHeight { + start = initialHeight + } + if start+maxScanHeight < latest { + start = latest - maxScanHeight + } + return start, latest +} + +// StartChainTransactionScanJob scan job +func (b *Bridge) StartChainTransactionScanJob() { + chainName := b.ChainConfig.BlockChain + log.Infof("[scanchain] start %v scan chain job", chainName) + + start, latest := b.getStartAndLatestHeight() + _ = tools.UpdateLatestScanInfo(b.IsSrc, start) + log.Infof("[scanchain] start %v scan chain loop from %v latest=%v", chainName, start, latest) + + if latest > start { + go b.quickSync(context.Background(), nil, start, latest+1) + } else { + quickSyncFinish = true + } + + stable := latest + //errorSubject := fmt.Sprintf("[scanchain] get %v block failed", chainName) + scanSubject := fmt.Sprintf("[scanchain] scanned %v block", chainName) + + scannedRange := tools.NewCachedScannedBlocks(67) + var quickSyncCtx context.Context + var quickSyncCancel context.CancelFunc + for { + latest = tools.LoopGetLatestBlockNumber(b) + if stable+maxScanHeight < latest { + if quickSyncCancel != nil { + select { + case <-quickSyncCtx.Done(): + default: + log.Warn("cancel quick sync range", "stable", stable, "latest", latest) + quickSyncCancel() + } + } + quickSyncCtx, quickSyncCancel = context.WithCancel(context.Background()) + go b.quickSync(quickSyncCtx, quickSyncCancel, stable+1, latest) + stable = latest + } + + for h := stable; h < latest; { + start := h / 10 * 10 + end := start + if latest-start > 10 { + end = start + 9 + } else { + stable = end + 1 + break + } + blockRange := fmt.Sprintf("%v-%v", start, end) + log.Debug("cosmos scan loop", "range", blockRange) + if scannedRange.IsBlockScanned(blockRange) { + h = end + 1 + continue + } + txs, err := b.SearchTxs(big.NewInt(int64(start)), big.NewInt(int64(end))) + if err != nil { + log.Warn("Search txs in range error", "range", blockRange, "error", err) + continue + } + for _, tx := range txs { + b.processTransaction(tx) + } + scannedRange.CacheScannedBlock(blockRange, end) + log.Info(scanSubject, "blockRange", blockRange, "txs", len(txs)) + h = end + 1 + stable = end + 1 + } + if quickSyncFinish { + _ = tools.UpdateLatestScanInfo(b.IsSrc, stable) + } + time.Sleep(restIntervalInScanJob) + } +} + +func (b *Bridge) quickSync(ctx context.Context, cancel context.CancelFunc, start, end uint64) { + chainName := b.ChainConfig.BlockChain + log.Printf("[scanchain] begin %v syncRange job. start=%v end=%v", chainName, start, end) + count := end - start + workers := quickSyncWorkers + if count < 10 { + workers = 1 + } + step := count / workers + wg := new(sync.WaitGroup) + wg.Add(int(workers)) + for i := uint64(0); i < workers; i++ { + wstt := start + i*step + wend := start + (i+1)*step + if i+1 == workers { + wend = end + } + go b.quickSyncRange(ctx, i+1, wstt, wend, wg) + } + wg.Wait() + if cancel != nil { + cancel() + } else { + quickSyncFinish = true + } + log.Printf("[scanchain] finish %v syncRange job. start=%v end=%v", chainName, start, end) +} + +func (b *Bridge) quickSyncRange(ctx context.Context, idx, start, end uint64, wg *sync.WaitGroup) { + defer wg.Done() + chainName := b.ChainConfig.BlockChain + log.Printf("[scanchain] id=%v begin %v syncRange start=%v end=%v", idx, chainName, start, end) + + select { + case <-ctx.Done(): + break + default: + } + + for h := start; h < end; { + h2 := h + if end-h > 100 { + h2 = h + 100 + + h = h2 + 1 + } else { + h2 = end + } + txs, err := b.SearchTxs(big.NewInt(int64(h)), big.NewInt(int64(h2))) + if err != nil { + log.Warn("Search txs in range error", "range", fmt.Sprintf("%v-%v", h, h2), "error", err) + continue + } + for _, tx := range txs { + b.processTransaction(tx) + } + h = h2 + 1 + } + + log.Printf("[scanchain] id=%v finish %v syncRange start=%v end=%v", idx, chainName, start, end) +} diff --git a/tokens/cosmos/scanpooltx.go b/tokens/cosmos/scanpooltx.go new file mode 100644 index 00000000..e3c7d312 --- /dev/null +++ b/tokens/cosmos/scanpooltx.go @@ -0,0 +1,14 @@ +package cosmos + +import ( + "github.com/anyswap/CrossChain-Bridge/tokens/tools" +) + +var ( + scannedTxs = tools.NewCachedScannedTxs(3000) +) + +// StartPoolTransactionScanJob scan job +func (b *Bridge) StartPoolTransactionScanJob() { + return +} diff --git a/tokens/cosmos/sendtx.go b/tokens/cosmos/sendtx.go new file mode 100644 index 00000000..08c08375 --- /dev/null +++ b/tokens/cosmos/sendtx.go @@ -0,0 +1,21 @@ +package cosmos + +import ( + "errors" + + "github.com/anyswap/CrossChain-Bridge/log" +) + +// SendTransaction send signed tx +func (b *Bridge) SendTransaction(signedTx interface{}) (txHash string, err error) { + tx, ok := signedTx.(HashableStdTx) + if !ok { + return "", errors.New("wrong signed transaction type") + } + txHash, err = b.BroadcastTx(tx) + if err != nil { + log.Info("SendTransaction failed", "hash", txHash, "err", err) + return txHash, err + } + return txHash, nil +} diff --git a/tokens/cosmos/signtx.go b/tokens/cosmos/signtx.go new file mode 100644 index 00000000..af1430e3 --- /dev/null +++ b/tokens/cosmos/signtx.go @@ -0,0 +1,198 @@ +package cosmos + +import ( + "crypto/ecdsa" + "encoding/hex" + "encoding/json" + "errors" + "fmt" + "strings" + "time" + + "github.com/anyswap/CrossChain-Bridge/common" + "github.com/anyswap/CrossChain-Bridge/dcrm" + "github.com/anyswap/CrossChain-Bridge/log" + "github.com/anyswap/CrossChain-Bridge/tokens" + "github.com/anyswap/CrossChain-Bridge/tools/crypto" + + "github.com/btcsuite/btcd/btcec" + authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" + "github.com/tendermint/tendermint/crypto/secp256k1" +) + +const ( + retryGetSignStatusCount = 70 + retryGetSignStatusInterval = 10 * time.Second +) + +func (b *Bridge) verifyTransactionWithArgs(tx StdSignContent, args *tokens.BuildTxArgs) error { + tokenCfg := b.GetTokenConfig(args.PairID) + if len(tx.Msgs) != 1 { + return errors.New("wrong msgs length") + } + msg, ok := tx.Msgs[0].(MsgSend) + if !ok { + return errors.New("msg types error") + } + switch { + case strings.EqualFold(args.From, msg.FromAddress.String()) == false: + return fmt.Errorf("[cosmos verify transaction with args] From address not match, args.From: %v, msg.FromAddress: %v", args.From, msg.FromAddress.String()) + case strings.EqualFold(msg.FromAddress.String(), tokenCfg.DcrmAddress) == false: + return fmt.Errorf("[cosmos verify transaction with args] From address is not dcrm address, args.From: %v, dcrm address: %v", msg.FromAddress.String(), tokenCfg.DcrmAddress) + case b.IsValidAddress(args.Bind) == false: + return fmt.Errorf("[cosmos verify transaction with args] Invalid to address: %v", args.Bind) + case strings.EqualFold(args.Bind, msg.ToAddress.String()) == false: + return fmt.Errorf("[cosmos verify transaction with args] To address not match, args.To: %v, msg.ToAddress: %v", args.Bind, msg.ToAddress.String()) + default: + } + if len(msg.Amount) != 1 { + return errors.New("wrong amount length") + } + amount := msg.Amount[0] + checkPairID, err := b.getPairID(amount) + if err != nil || checkPairID != args.PairID { + return fmt.Errorf("[cosmos verify transaction with args] Token type not match, %v, %v", checkPairID, args.PairID) + } + if amount.Amount.BigInt().Cmp(args.OriginValue) >= 0 { + return fmt.Errorf("[cosmos verify transaction with args] Amount not match, %v, %v", amount.Amount.BigInt(), args.OriginValue) + } + return nil +} + +// DcrmSignTransaction dcrm sign raw tx +func (b *Bridge) DcrmSignTransaction(rawTx interface{}, args *tokens.BuildTxArgs) (signedTx interface{}, txHash string, err error) { + tx, ok := rawTx.(StdSignContent) + if !ok { + return nil, "", errors.New("wrong raw tx param") + } + err = b.verifyTransactionWithArgs(tx, args) + if err != nil { + return nil, "", err + } + msgHash := tx.Hash() + jsondata, _ := json.Marshal(args) + msgContext := string(jsondata) + rpcAddr, keyID, err := dcrm.DoSignOne(b.GetDcrmPublicKey(args.PairID), msgHash, msgContext) + if err != nil { + return nil, "", err + } + log.Info(b.ChainConfig.BlockChain+" DcrmSignTransaction start", "keyID", keyID, "msghash", msgHash, "txid", args.SwapID) + time.Sleep(retryGetSignStatusInterval) + + var rsv string + i := 0 + for ; i < retryGetSignStatusCount; i++ { + signStatus, err2 := dcrm.GetSignStatus(keyID[0], rpcAddr) + if err2 == nil { + if len(signStatus.Rsv) != 1 { + return nil, "", fmt.Errorf("get sign status require one rsv but have %v (keyID = %v)", len(signStatus.Rsv), keyID) + } + + rsv = signStatus.Rsv[0] + break + } + switch err2 { + case dcrm.ErrGetSignStatusFailed, dcrm.ErrGetSignStatusTimeout: + return nil, "", err2 + } + log.Warn("retry get sign status as error", "err", err2, "txid", args.SwapID, "keyID", keyID, "bridge", args.Identifier, "swaptype", args.SwapType.String()) + time.Sleep(retryGetSignStatusInterval) + } + if i == retryGetSignStatusCount || rsv == "" { + return nil, "", errors.New("get sign status failed") + } + + log.Trace(b.ChainConfig.BlockChain+" DcrmSignTransaction get rsv success", "keyID", keyID, "rsv", rsv) + + signature := common.FromHex(rsv) + + if len(signature) != crypto.SignatureLength { + log.Error("DcrmSignTransaction wrong length of signature") + return nil, "", errors.New("wrong signature of keyID " + keyID[0]) + } + + // pub + pubHex := b.GetDcrmPublicKey(args.PairID) + pubBytes, err := hex.DecodeString(pubHex) + if err != nil { + return nil, "", errors.New("wrong dcrm public key") + } + + pub, err := btcec.ParsePubKey(pubBytes, btcec.S256()) + if err != nil { + return nil, "", errors.New("wrong dcrm public key") + } + + cpub := pub.SerializeCompressed() + var arr [33]byte + copy(arr[:], cpub[:33]) + pubkey := secp256k1.PubKeySecp256k1(arr) + + rsvb, err := hex.DecodeString(rsv) + if err != nil { + return + } + var signatureBytes []byte + if len(rsvb) == 65 { + signatureBytes = rsvb[:64] + } + stdsig := authtypes.StdSignature{ + PubKey: pubkey, + Signature: signatureBytes, + } + signedTx = HashableStdTx{ + StdSignContent: tx, + Signatures: []authtypes.StdSignature{stdsig}, + } + + if pubkey.VerifyBytes(tx.SignBytes(), signatureBytes) == false { + log.Error("Dcrm sign verify error") + return nil, "", errors.New("wrong signature") + } + + txHash = msgHash + log.Info(b.ChainConfig.BlockChain+" DcrmSignTransaction success", "keyID", keyID, "txhash", txHash, "nonce", signedTx.(HashableStdTx).Sequence) + return signedTx, txHash, err +} + +// SignTransaction sign tx with pairID +func (b *Bridge) SignTransaction(rawTx interface{}, pairID string) (signedTx interface{}, txHash string, err error) { + privKey := b.GetTokenConfig(pairID).GetDcrmAddressPrivateKey() + return b.SignTransactionWithPrivateKey(rawTx, privKey) +} + +// SignTransactionWithPrivateKey sign tx with ECDSA private key +func (b *Bridge) SignTransactionWithPrivateKey(rawTx interface{}, privKey *ecdsa.PrivateKey) (signedTx interface{}, txHash string, err error) { + // rawTx is of type authtypes.StdSignDoc + tx, ok := rawTx.(StdSignContent) + if !ok { + return nil, "", errors.New("wrong raw tx param") + } + + signBytes := tx.SignBytes() + + var privBytes [32]byte + btcecpriv := btcec.PrivateKey(*privKey) + copy(privBytes[:], btcecpriv.Serialize()[:33]) + priv := secp256k1.PrivKeySecp256k1(privBytes) + signature, err := priv.Sign(signBytes) + if err != nil { + return nil, "", err + } + + pub := priv.PubKey() + + stdsig := authtypes.StdSignature{ + PubKey: pub, + Signature: signature, + } + + signedTx = HashableStdTx{ + StdSignContent: tx, + Signatures: []authtypes.StdSignature{stdsig}, + } + + txHash = signedTx.(HashableStdTx).Hash() + + return +} diff --git a/tokens/cosmos/tokenPairConfigs/cosmos-config-tokenpair-example.toml b/tokens/cosmos/tokenPairConfigs/cosmos-config-tokenpair-example.toml new file mode 100644 index 00000000..57dcd43e --- /dev/null +++ b/tokens/cosmos/tokenPairConfigs/cosmos-config-tokenpair-example.toml @@ -0,0 +1,68 @@ +PairID = "TERRA" + +# source token config +[SrcToken] +# ID must be ERC20 if source token is erc20 token +ID = "ATOM" +Name = "Atom coin" +Symbol = "ATOM" +Decimals = 9 +Description = "Atom coin" +# if ID is ERC20, this is the erc20 token's contract address +ContractAddress = "" +# deposit to this address to make swap +DepositAddress = "cosmos1qj05rkrpphd55dawh7qxxmd2c72g57j29tflr3" +# withdraw from this address +DcrmAddress = "cosmos1qj05rkrpphd55dawh7qxxmd2c72g57j29tflr3" +# dcrm address public key +DcrmPubkey = "045c8648793e4867af465691685000ae841dccab0b011283139d2eae454b569d5789f01632e13a75a5aad8480140e895dd671cae3639f935750bea7ae4b5a2512e" +# maximum deposit value +MaximumSwap = 1000.0 +# minimum deposit value +MinimumSwap = 0.00001 +# calced deposit fee = deposit value * this rate (when in [min, max] deposit fee range) +SwapFeeRate = 0.001 +# maximum deposit fee, if calced deposit fee is larger than this fee, then use this value as deposit fee +MaximumSwapFee = 0.01 +# minimum deposit fee, if calced deposit fee is smaller than this fee, then use this value as deposit fee +MinimumSwapFee = 0.00001 +# plus this percentage of gas price to make tx more easier to be mined in source chain +# corresponding to send asset on source chain (eg. BTC) for withdrawing +PlusGasPricePercentage = 15 # plus 15% gas price +# if deposit value is larger than this value then need more verify strategy +BigValueThreshold = 5.0 +# disable deposit function if this flag is true +DisableSwap = false +# Unit name +Unit = "uatom" + +# dest token config +[DestToken] +ID = "anyATOM" +Name = "ANY ATOM" +Symbol = "anyATOM" +Decimals = 9 +Description = "" +# mapping erc20 token address +ContractAddress = "" +# mapping erc20 token creator +DcrmAddress = "0xbF0A46d3700E23a98F38079cE217742c92Bb66bC" +# dcrm address public key +DcrmPubkey = "045c8648793e4867af465691685000ae841dccab0b011283139d2eae454b569d5789f01632e13a75a5aad8480140e895dd671cae3639f935750bea7ae4b5a2512e" +# maximum withdraw value +MaximumSwap = 100.0 +# minimum withdraw value +MinimumSwap = 0.00001 +# calced withdraw fee = withdraw value * this rate (when in [min, max] withdraw fee range) +SwapFeeRate = 0.001 +# maximum withdraw fee, if calced withdraw fee is larger than this fee, then use this value as withdraw fee +MaximumSwapFee = 0.01 +# minimum withdraw fee, if calced withdraw fee is smaller than this fee, then use this value as withdraw fee +MinimumSwapFee = 0.00001 +# plus this percentage of gas price to make tx more easier to be mined in dest chain +# corresponding to send mapping token on dest chain (eg. mBTC) for depositing +PlusGasPricePercentage = 1 # plus 1% gas price +# if withdraw value is larger than this value then need more verify strategy +BigValueThreshold = 50.0 +# disable withdraw function if this flag is true +DisableSwap = false diff --git a/tokens/cosmos/types.go b/tokens/cosmos/types.go new file mode 100644 index 00000000..22d83bc1 --- /dev/null +++ b/tokens/cosmos/types.go @@ -0,0 +1,75 @@ +package cosmos + +import ( + "encoding/json" + "fmt" + + sdk "github.com/cosmos/cosmos-sdk/types" + authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" + "github.com/tendermint/tendermint/crypto/tmhash" +) + +// StdSignContent saves all tx components required to build SignBytes +type StdSignContent struct { + AccountNumber uint64 + ChainID string + Fee authtypes.StdFee + Memo string + Msgs []sdk.Msg + Sequence uint64 +} + +// HashableStdTx saves all data of a signed tx +type HashableStdTx struct { + StdSignContent + Signatures []authtypes.StdSignature +} + +// SignBytes returns sign bytes +func (tx StdSignContent) SignBytes() []byte { + signBytes := StdSignBytes(tx.ChainID, tx.AccountNumber, tx.Sequence, tx.Fee, tx.Msgs, tx.Memo) + return SignBytesModifier(signBytes) // ugly but works +} + +// Hash returns tx sign bytes hash string +// not the tx hash +func (tx StdSignContent) Hash() string { + signBytes := tx.SignBytes() + txHash := fmt.Sprintf("%X", tmhash.Sum(signBytes)) + return txHash +} + +// ToStdTx converts HashableStdTx to authtypes.StdTx +func (tx HashableStdTx) ToStdTx() authtypes.StdTx { + return authtypes.StdTx{ + Msgs: tx.Msgs, + Fee: tx.Fee, + Signatures: tx.Signatures, + Memo: tx.Memo, + } +} + +// StdSignBytes returns signing bytes +func StdSignBytes(chainID string, accnum uint64, sequence uint64, fee authtypes.StdFee, msgs []sdk.Msg, memo string) []byte { + msgsBytes := make([]json.RawMessage, 0, len(msgs)) + for _, msg := range msgs { + msgsBytes = append(msgsBytes, json.RawMessage(msg.GetSignBytes())) + } + bz, err := CDC.MarshalJSON(authtypes.StdSignDoc{ + AccountNumber: accnum, + ChainID: chainID, + Fee: json.RawMessage(fee.Bytes()), + Memo: memo, + Msgs: msgsBytes, + Sequence: sequence, + }) + if err != nil { + panic(err) + } + return sdk.MustSortJSON(bz) +} + +// SignBytesModifier modifies sign bytes +var SignBytesModifier (func([]byte) []byte) = func(bz []byte) []byte { + return bz +} diff --git a/tokens/cosmos/verifytx.go b/tokens/cosmos/verifytx.go new file mode 100644 index 00000000..328cce09 --- /dev/null +++ b/tokens/cosmos/verifytx.go @@ -0,0 +1,332 @@ +package cosmos + +import ( + "errors" + "fmt" + "math/big" + "strings" + + "github.com/anyswap/CrossChain-Bridge/log" + "github.com/anyswap/CrossChain-Bridge/tokens" + "github.com/anyswap/CrossChain-Bridge/tokens/tools" + + sdk "github.com/cosmos/cosmos-sdk/types" + authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" +) + +// VerifyMsgHash verify msg hash +func (b *Bridge) VerifyMsgHash(rawTx interface{}, msgHash []string) (err error) { + tx, ok := rawTx.(StdSignContent) + if !ok { + return errors.New("raw tx type assertion error") + } + + txHash := tx.Hash() + if strings.EqualFold(txHash, msgHash[0]) == true { + return nil + } + return errors.New("msg hash not match") +} + +// VerifyTransaction impl +func (b *Bridge) VerifyTransaction(pairID, txHash string, allowUnstable bool) (*tokens.TxSwapInfo, error) { + if !b.IsSrc { + return nil, tokens.ErrBridgeDestinationNotSupported + } + swapInfos, errs := b.verifySwapinTxWithHash(pairID, txHash, allowUnstable) + // swapinfos have already aggregated + for i, swapInfo := range swapInfos { + if strings.EqualFold(swapInfo.PairID, pairID) { + return swapInfo, errs[i] + } + } + log.Warn("No such swapInfo") + return nil, nil +} + +func (b *Bridge) verifySwapinTx(txresp sdk.TxResponse, allowUnstable bool) (swapInfos []*tokens.TxSwapInfo, errs []error) { + swapInfos = make([]*tokens.TxSwapInfo, 0) + swapInfoMap := make(map[string][]*tokens.TxSwapInfo) + txid := strings.ToLower(txresp.TxHash) + cosmostx := txresp.Tx + + // get bind address from memo + bindaddress, ok := b.GetBindAddressFromMemo(cosmostx) + if !ok { + return swapInfos, []error{fmt.Errorf("Cannot get bind address")} + } + if err := b.checkSwapinBindAddress(bindaddress); err != nil { + errs = []error{err} + return swapInfos, errs + } + + // check every msg + // if type is bank/send or bank/multisend, check every coin in every output + // add to swapinfo + msgs := cosmostx.GetMsgs() + for _, msg := range msgs { + if err := msg.ValidateBasic(); err != nil { + continue + } + msgtype := msg.Type() + if msgtype == TypeMsgSend { + // MsgSend + msgsend, ok := msg.(MsgSend) + if !ok { + continue + } + + for _, coin := range msgsend.Amount { + pairID, err := b.getPairID(coin) + if err != nil { + continue + } + tokenCfg := b.GetTokenConfig(pairID) + if tokenCfg == nil { + continue + } + if b.EqualAddress(msgsend.ToAddress.String(), tokenCfg.DepositAddress) == false { + continue + } + swapInfo := &tokens.TxSwapInfo{} + swapInfo.PairID = pairID + swapInfo.To = tokenCfg.DepositAddress + swapInfo.Bind = bindaddress + swapInfo.From = bindaddress + swapInfo.Value = coin.Amount.BigInt() + if swapInfoMap[pairID] == nil { + swapInfoMap[pairID] = make([]*tokens.TxSwapInfo, 0) + } + swapInfoMap[pairID] = append(swapInfoMap[pairID], swapInfo) + } + + } else if msgtype == TypeMsgMultiSend { + // MsgMultisend + msgmultisend, ok := msg.(MsgMultiSend) + if !ok { + continue + } + for _, output := range msgmultisend.Outputs { + for _, coin := range output.Coins { + pairID, err := b.getPairID(coin) + if err != nil { + continue + } + tokenCfg := b.GetTokenConfig(pairID) + if tokenCfg == nil { + continue + } + if b.EqualAddress(output.Address.String(), tokenCfg.DepositAddress) == false { + continue + } + swapInfo := &tokens.TxSwapInfo{} + swapInfo.PairID = pairID + swapInfo.To = tokenCfg.DepositAddress + swapInfo.Bind = bindaddress + swapInfo.From = bindaddress + swapInfo.Value = coin.Amount.BigInt() + if swapInfoMap[pairID] == nil { + swapInfoMap[pairID] = make([]*tokens.TxSwapInfo, 0) + } + swapInfoMap[pairID] = append(swapInfoMap[pairID], swapInfo) + } + } + } else { + continue + } + } + + // aggregate by pairID + for k, v := range swapInfoMap { + if len(v) < 1 { + continue + } + aggSwapInfo := &tokens.TxSwapInfo{} + aggSwapInfo.PairID = k + aggSwapInfo.To = v[0].To + aggSwapInfo.Bind = v[0].Bind + aggSwapInfo.Hash = txid + aggSwapInfo.Value = big.NewInt(0) + for _, swapInfo := range v { + aggSwapInfo.Value = new(big.Int).Add(aggSwapInfo.Value, swapInfo.Value) + } + swapInfos = append(swapInfos, aggSwapInfo) + errs = append(errs, nil) + } + + return swapInfos, errs +} + +// NotSupportedCoinErr is an error +var NotSupportedCoinErr = errors.New("coin not supported") + +// getPairID returns pairID corresponding to given coin +// returns error when coin type not supported +func (b *Bridge) getPairID(coin sdk.Coin) (string, error) { + for k, v := range b.SupportedCoins { + if strings.EqualFold(v.Denom, coin.Denom) { + return strings.ToLower(k), nil + } + } + // if not exists, reload coins and find it + b.LoadCoins() + for k, v := range b.SupportedCoins { + if strings.EqualFold(v.Denom, coin.Denom) { + return strings.ToLower(k), nil + } + } + return "", NotSupportedCoinErr +} + +func (b *Bridge) verifySwapinTxWithHash(pairID, txHash string, allowUnstable bool) (swapInfos []*tokens.TxSwapInfo, errs []error) { + txid := strings.ToLower(txHash) + tx, err := b.GetTransaction(txHash) + if err != nil { + log.Debug("[verifySwapin] "+b.ChainConfig.BlockChain+" Bridge::GetTransaction fail", "tx", txHash, "err", err) + errs = []error{tokens.ErrTxNotStable} + return nil, errs + } + cosmostx, ok := tx.(sdk.Tx) + if !ok { + log.Debug("[verifySwapin] "+b.ChainConfig.BlockChain+" Bridge::Transacton is of wrong type", "tx", txHash) + return nil, []error{errors.New("Tx is of wrong type")} + } + swapInfos = make([]*tokens.TxSwapInfo, 0) + swapInfoMap := make(map[string][]*tokens.TxSwapInfo) + + // get bind address from memo + bindaddress, ok := b.GetBindAddressFromMemo(cosmostx) + if !ok { + return swapInfos, []error{fmt.Errorf("Cannot get bind address")} + } + if err := b.checkSwapinBindAddress(bindaddress); err != nil { + errs = []error{err} + return swapInfos, errs + } + + // check every msg + // if type is bank/send or bank/multisend, check every coin in every output + // add to swapinfo + msgs := cosmostx.GetMsgs() + for _, msg := range msgs { + if err := msg.ValidateBasic(); err != nil { + continue + } + msgtype := msg.Type() + if msgtype == TypeMsgSend { + // MsgSend + msgsend, ok := msg.(MsgSend) + if !ok { + continue + } + + for _, coin := range msgsend.Amount { + pairID, err := b.getPairID(coin) + if err != nil { + continue + } + tokenCfg := b.GetTokenConfig(pairID) + if tokenCfg == nil { + continue + } + if b.EqualAddress(msgsend.ToAddress.String(), tokenCfg.DepositAddress) == false { + continue + } + swapInfo := &tokens.TxSwapInfo{} + swapInfo.PairID = pairID + swapInfo.To = tokenCfg.DepositAddress + swapInfo.Bind = bindaddress + swapInfo.From = bindaddress + swapInfo.Value = coin.Amount.BigInt() + if swapInfoMap[pairID] == nil { + swapInfoMap[pairID] = make([]*tokens.TxSwapInfo, 0) + } + swapInfoMap[pairID] = append(swapInfoMap[pairID], swapInfo) + } + + } else if msgtype == TypeMsgMultiSend { + // MsgMultisend + msgmultisend, ok := msg.(MsgMultiSend) + if !ok { + continue + } + for _, output := range msgmultisend.Outputs { + for _, coin := range output.Coins { + pairID, err := b.getPairID(coin) + if err != nil { + continue + } + tokenCfg := b.GetTokenConfig(pairID) + if tokenCfg == nil { + continue + } + if b.EqualAddress(output.Address.String(), tokenCfg.DepositAddress) == false { + continue + } + swapInfo := &tokens.TxSwapInfo{} + swapInfo.PairID = pairID + swapInfo.To = tokenCfg.DepositAddress + swapInfo.Bind = bindaddress + swapInfo.From = bindaddress + swapInfo.Value = coin.Amount.BigInt() + if swapInfoMap[pairID] == nil { + swapInfoMap[pairID] = make([]*tokens.TxSwapInfo, 0) + } + swapInfoMap[pairID] = append(swapInfoMap[pairID], swapInfo) + } + } + } else { + continue + } + } + + // aggregate by pairID + for k, v := range swapInfoMap { + if len(v) < 1 { + continue + } + aggSwapInfo := &tokens.TxSwapInfo{} + aggSwapInfo.PairID = k + aggSwapInfo.Hash = txid + aggSwapInfo.To = v[0].To + aggSwapInfo.Bind = v[0].Bind + // aggSwapInfo.TxId = v[0].TxId + aggSwapInfo.Value = big.NewInt(0) + for _, swapInfo := range v { + aggSwapInfo.Value = new(big.Int).Add(aggSwapInfo.Value, swapInfo.Value) + } + swapInfos = append(swapInfos, aggSwapInfo) + errs = append(errs, nil) + } + + return swapInfos, errs +} + +// GetBindAddressFromMemo get tx memo from an sdk.Tx +func (b *Bridge) GetBindAddressFromMemo(tx sdk.Tx) (address string, ok bool) { + authtx, ok := tx.(authtypes.StdTx) + if !ok { + log.Warn("GetBindAddressFromMemo: Tx is not auth StdTx", "Tx", tx) + return "", false + } + memo := authtx.Memo + dstBridge := tokens.DstBridge + if ok = dstBridge.IsValidAddress(memo); ok { + memo = strings.ToLower(memo) + return memo, ok + } else { + log.Warn("GetBindAddressFromMemo: memo is not a valid address", "memo", memo) + return "", false + } +} + +func (b *Bridge) checkSwapinBindAddress(bindAddr string) error { + if !tokens.DstBridge.IsValidAddress(bindAddr) { + log.Warn("wrong bind address in swapin", "bind", bindAddr) + return tokens.ErrTxWithWrongMemo + } + if !tools.IsAddressRegistered(bindAddr) { + return tokens.ErrTxSenderNotRegistered + } + return nil +} diff --git a/tokens/eth/verifycontractaddress.go b/tokens/eth/verifycontractaddress.go index 762af238..b28f0c2e 100644 --- a/tokens/eth/verifycontractaddress.go +++ b/tokens/eth/verifycontractaddress.go @@ -7,6 +7,7 @@ import ( "github.com/anyswap/CrossChain-Bridge/common" "github.com/anyswap/CrossChain-Bridge/log" + "github.com/anyswap/CrossChain-Bridge/tokens" "github.com/anyswap/CrossChain-Bridge/tokens/btc" ) @@ -133,7 +134,7 @@ func (b *Bridge) VerifyMbtcContractAddress(contract string) (err error) { // InitExtCodeParts init extended code parts func InitExtCodeParts() { - InitExtCodePartsWithFlag(isMbtcSwapout()) + InitExtCodePartsWithFlag(tokens.IsSwapoutToStringAddress) } // InitExtCodePartsWithFlag init extended code parts with flag diff --git a/tokens/eth/verifyswapouttx.go b/tokens/eth/verifyswapouttx.go index 4cd7c133..55e9b347 100644 --- a/tokens/eth/verifyswapouttx.go +++ b/tokens/eth/verifyswapouttx.go @@ -321,7 +321,7 @@ func parseSwapoutToBtcTxLogs(logs []*types.RPCLog) (bind string, value *big.Int, } func parseTxInputEncodedData(encData []byte) (bind string, value *big.Int, err error) { - if isMbtcSwapout() { + if isMbtcSwapout() || tokens.IsSwapoutToStringAddress { return parseSwapoutToBtcEncodedData(encData, true) } diff --git a/tokens/solana/address.go b/tokens/solana/address.go new file mode 100644 index 00000000..7d15ff04 --- /dev/null +++ b/tokens/solana/address.go @@ -0,0 +1,40 @@ +package solana + +import ( + "encoding/hex" + "errors" + "fmt" + + "github.com/dfuse-io/solana-go" +) + +// IsValidAddress check address +func (b *Bridge) IsValidAddress(address string) bool { + _, err := solana.PublicKeyFromBase58(address) + return (err == nil) +} + +// PublicKeyToAddress returns cosmos public key address +func (b *Bridge) PublicKeyToAddress(pubKeyHex string) (address string, err error) { + bz, err := hex.DecodeString(pubKeyHex) + if err != nil { + return "", errors.New("Decode pubkey hex error") + } + pub := PublicKeyFromBytes(bz) + return fmt.Sprintf("%s", pub), nil +} + +func PublicKeyFromBytes(in []byte) (out solana.PublicKey) { + byteCount := len(in) + if byteCount == 0 { + return + } + + max := 32 + if byteCount < max { + max = byteCount + } + + copy(out[:], in[0:max]) + return +} diff --git a/tokens/solana/bridge.go b/tokens/solana/bridge.go new file mode 100644 index 00000000..6555cf30 --- /dev/null +++ b/tokens/solana/bridge.go @@ -0,0 +1,94 @@ +package solana + +import ( + "fmt" + "strings" + "time" + + "github.com/dfuse-io/solana-go" + + "github.com/anyswap/CrossChain-Bridge/log" + "github.com/anyswap/CrossChain-Bridge/tokens" +) + +var PairID = "sol" + +// Bridge solana bridge +type Bridge struct { + *tokens.CrossChainBridgeBase +} + +func (b *Bridge) RegisterCDC(isSrc bool) { + if isSrc { + tokens.TokenCDC.RegisterConcrete(&Solana2ETHSwapinAgreement{}, Solana2ETHSwapinAgreementType, nil) + } else { + tokens.TokenCDC.RegisterConcrete(Ð2SolanaSwapinAgreement{}, ETH2SolanaSwapinAgreementType, nil) + tokens.TokenCDC.RegisterConcrete(Ð2SolanaSwapoutAgreement{}, ETH2SolanaSwapoutAgreementType, nil) + } +} + +// NewCrossChainBridge new bridge +func NewCrossChainBridge(isSrc bool) *Bridge { + tokens.IsSwapoutToStringAddress = true + b := &Bridge{ + CrossChainBridgeBase: tokens.NewCrossChainBridgeBase(isSrc), + } + b.RegisterCDC(isSrc) + return b +} + +// SetChainAndGateway set chain and gateway config +func (b *Bridge) SetChainAndGateway(chainCfg *tokens.ChainConfig, gatewayCfg *tokens.GatewayConfig) { + b.CrossChainBridgeBase.SetChainAndGateway(chainCfg, gatewayCfg) + b.InitLatestBlockNumber() + b.VerifyChainID() +} + +// VerifyChainID verify chain id +func (b *Bridge) VerifyChainID() { + networkID := strings.ToLower(b.ChainConfig.NetID) + switch networkID { + case "mainnet", "testnet", "devnet": + default: + log.Fatalf("unsupported solana network: %v", b.ChainConfig.NetID) + } +} + +// InitLatestBlockNumber init latest block number +func (b *Bridge) InitLatestBlockNumber() { + chainCfg := b.ChainConfig + gatewayCfg := b.GatewayConfig + var latest uint64 + var err error + for { + latest, err = b.GetLatestBlockNumber() + if err == nil { + tokens.SetLatestBlockHeight(latest, b.IsSrc) + log.Info("get latst block number succeed.", "number", latest, "BlockChain", chainCfg.BlockChain, "NetID", chainCfg.NetID) + break + } + log.Error("get latst block number failed.", "BlockChain", chainCfg.BlockChain, "NetID", chainCfg.NetID, "err", err) + log.Println("retry query gateway", gatewayCfg.APIAddress) + time.Sleep(3 * time.Second) + } +} + +// VerifyTokenConfig verify token config +func (b *Bridge) VerifyTokenConfig(tokenCfg *tokens.TokenConfig) error { + if tokenCfg.PrivateKeyType != tokens.ED25519KeyType { + return fmt.Errorf("solana private key type must be ed25519") + } + if !b.IsValidAddress(tokenCfg.DcrmAddress) { + return fmt.Errorf("invalid dcrm address (not p2pkh): %v", tokenCfg.DcrmAddress) + } + if !b.IsValidAddress(tokenCfg.DepositAddress) { + return fmt.Errorf("invalid deposit address: %v", tokenCfg.DepositAddress) + } + if strings.EqualFold(tokenCfg.Symbol, "SOL") && *tokenCfg.Decimals != 9 { + return fmt.Errorf("invalid decimals for SOL: want 9 but have %v", *tokenCfg.Decimals) + } + if _, err := solana.PublicKeyFromBase58(tokenCfg.ContractAddress); err != nil { + return fmt.Errorf("invalid solana program id (contract address)") + } + return nil +} diff --git a/tokens/solana/buildtx.go b/tokens/solana/buildtx.go new file mode 100644 index 00000000..a4cbc6eb --- /dev/null +++ b/tokens/solana/buildtx.go @@ -0,0 +1,77 @@ +package solana + +import ( + "errors" + "fmt" + + bin "github.com/dfuse-io/binary" + "github.com/dfuse-io/solana-go" + "github.com/dfuse-io/solana-go/programs/system" + + "github.com/anyswap/CrossChain-Bridge/params" + "github.com/anyswap/CrossChain-Bridge/tokens" +) + +// BuildRawTransaction build raw tx +func (b *Bridge) BuildRawTransaction(args *tokens.BuildTxArgs) (rawTx interface{}, err error) { + var ( + pairID = args.PairID + from = args.From + to = args.Bind + amount = args.Value + ) + args.Identifier = params.GetIdentifier() + tokenCfg := b.GetTokenConfig(pairID) + if tokenCfg == nil { + return nil, fmt.Errorf("swap pair '%v' is not configed", pairID) + } + switch args.SwapType { + case tokens.SwapinType: + return nil, tokens.ErrSwapTypeNotSupported + case tokens.SwapoutType: + from = tokenCfg.DcrmAddress // from + amount = tokens.CalcSwappedValue(pairID, args.OriginValue, false) // amount + } + + if from == "" { + return nil, errors.New("no sender specified") + } + + fromPubkey, err := solana.PublicKeyFromBase58(from) + if err != nil { + return nil, errors.New("from address error") + } + toPubkey, err := solana.PublicKeyFromBase58(to) + if err != nil { + return nil, errors.New("to address error") + } + lamports := amount.Uint64() + transfer := &system.Instruction{ + BaseVariant: bin.BaseVariant{ + TypeID: 2, // 0 表示 create account,1 空缺,2 表示 transfer + Impl: &system.Transfer{ + Lamports: bin.Uint64(lamports), + Accounts: &system.TransferAccounts{ + From: &solana.AccountMeta{PublicKey: fromPubkey, IsSigner: true, IsWritable: true}, + To: &solana.AccountMeta{PublicKey: toPubkey, IsSigner: false, IsWritable: true}, + }, + }, + }, + } + rbh, err := b.GetRecentBlockhash() + if err != nil { + return nil, errors.New("get recent blockhash error") + } + blockHash, err := solana.PublicKeyFromBase58(rbh) + if err != nil { + return nil, errors.New("get recent blockhash error") + } + opt := &solana.Options{ + Payer: fromPubkey, + } + tx, err := solana.TransactionWithInstructions([]solana.TransactionInstruction{transfer}, blockHash, opt) + if err != nil { + return nil, fmt.Errorf("Solana transaction with instructions error: %v", err) + } + return tx, nil +} diff --git a/tokens/solana/processtx.go b/tokens/solana/processtx.go new file mode 100644 index 00000000..53bc3a9b --- /dev/null +++ b/tokens/solana/processtx.go @@ -0,0 +1,41 @@ +package solana + +import ( + "strings" + + "github.com/anyswap/CrossChain-Bridge/log" + "github.com/anyswap/CrossChain-Bridge/tokens/tools" +) + +func (b *Bridge) processTransactionWithTxid(txid string) { + tx, err := b.GetTransaction(txid) + if err != nil { + log.Warn("get tx failed", "txid", txid) + return + } + b.processTransaction(tx.(*GetConfirmedTransactonResult)) +} + +func (b *Bridge) processTransaction(tx *GetConfirmedTransactonResult) { + if b.IsSrc { + b.processSwapin(tx) + } else { + b.processSwapout(tx) + } +} + +func (b *Bridge) processSwapin(tx *GetConfirmedTransactonResult) { + log.Info("soalna processSwapin", "tx", tx) + swapInfos, errs := b.verifySwapinTx(tx, true) + txid := strings.ToLower(tx.Transaction.Signatures[0].String()) + log.Debug("solana processSwapin", "txid", txid, "swapinfos", swapInfos, "errs", errs) + tools.RegisterSwapin(txid, swapInfos, errs) +} + +func (b *Bridge) processSwapout(tx *GetConfirmedTransactonResult) { + log.Info("soalna processSwapout", "tx", tx) + swapInfos, errs := b.verifySwapoutTx(tx, true) + txid := strings.ToLower(tx.Transaction.Signatures[0].String()) + log.Debug("solana processSwapout", "txid", txid, "swapinfos", swapInfos, "errs", errs) + tools.RegisterSwapout(txid, swapInfos, errs) +} diff --git a/tokens/solana/rpc.go b/tokens/solana/rpc.go new file mode 100644 index 00000000..0521eeea --- /dev/null +++ b/tokens/solana/rpc.go @@ -0,0 +1,257 @@ +package solana + +import ( + "context" + "fmt" + "math/big" + "strings" + + bin "github.com/dfuse-io/binary" + "github.com/dfuse-io/solana-go" + solanarpc "github.com/dfuse-io/solana-go/rpc" + "github.com/ybbus/jsonrpc" + + "github.com/anyswap/CrossChain-Bridge/log" + "github.com/anyswap/CrossChain-Bridge/tokens" +) + +func (b *Bridge) getClients() (clis []*solanarpc.Client) { + endpoints := b.GatewayConfig.APIAddress + clis = make([]*solanarpc.Client, 0) + for _, endpoint := range endpoints { + cli := solanarpc.NewClient(endpoint) + if cli != nil { + clis = append(clis, cli) + } + } + return +} + +func (b *Bridge) getURLs() (rpcURL []string) { + return b.GatewayConfig.APIAddress +} + +type RPCError struct { + errs []error + method string +} + +func (e *RPCError) log(msg error) { + log.Warn("[Solana RPC error]", "method", e.method, "msg", msg) + if len(e.errs) < 1 { + e.errs = make([]error, 1) + } + e.errs = append(e.errs, msg) +} + +func (e *RPCError) Error() error { + return fmt.Errorf("[Solana RPC error] method: %v errors:%+v", e.method, e.errs) +} + +// GetLatestBlockNumber returns current finalized block height +func (b *Bridge) GetLatestBlockNumber() (height uint64, err error) { + ctx := context.Background() + rpcError := &RPCError{[]error{}, "GetLatestBlockNumber"} + for _, cli := range b.getClients() { + res, err := cli.GetSlot(ctx, "") + if err == nil { + return uint64(res), nil + } else { + rpcError.log(err) + } + } + return 0, rpcError.Error() +} + +// GetLatestBlockNumberOf returns current finalized block height from given node +func (b *Bridge) GetLatestBlockNumberOf(apiAddress string) (uint64, error) { + ctx := context.Background() + cli := solanarpc.NewClient(apiAddress) + rpcError := &RPCError{[]error{}, "GetLatestBlockNumberOf"} + res, err := cli.GetSlot(ctx, "") + if err != nil { + rpcError.log(err) + return 0, rpcError.Error() + } + return uint64(res), nil +} + +// GetBalance gets SOL token balance +func (b *Bridge) GetBalance(account string) (balance *big.Int, err error) { + ctx := context.Background() + rpcError := &RPCError{[]error{}, "GetBalance"} + for _, cli := range b.getClients() { + res, err := cli.GetBalance(ctx, account, "finalized") + if err == nil { + return new(big.Int).SetUint64(uint64(res.Value)), nil + } else { + rpcError.log(err) + } + } + return big.NewInt(0), rpcError.Error() +} + +// GetRecentBlockhash gets recent block hash +func (b *Bridge) GetRecentBlockhash() (string, error) { + ctx := context.Background() + rpcError := &RPCError{[]error{}, "GetBalance"} + for _, cli := range b.getClients() { + res, err := cli.GetRecentBlockhash(ctx, "finalized") + if err == nil { + return res.Value.Blockhash.String(), nil + } else { + rpcError.log(err) + } + } + return "", rpcError.Error() +} + +// GetTokenBalance gets balance for given token +func (b *Bridge) GetTokenBalance(tokenType, tokenName, accountAddress string) (balance *big.Int, err error) { + return nil, fmt.Errorf("Solana bridges does not support this method") +} + +// GetTokenSupply not supported +func (b *Bridge) GetTokenSupply(tokenType, tokenAddress string) (*big.Int, error) { + return nil, fmt.Errorf("Solana bridges does not support this method") +} + +type GetConfirmedTransactonResult struct { + Transaction *solana.Transaction `json:"transaction"` + Meta *solanarpc.TransactionMeta `json:"meta,omitempty"` + Slot bin.Uint64 `json:"slot,omitempty"` + BlockTime bin.Uint64 `json:"blockTime,omitempty"` +} + +// GetTransaction gets tx by hash, returns sdk.Tx +func (b *Bridge) GetTransaction(txHash string) (tx interface{}, err error) { + rpcError := &RPCError{[]error{}, "GetConfirmedTransaction"} + params := []interface{}{txHash, "json"} + for _, rpcURL := range b.getURLs() { + rpcClient := jsonrpc.NewClient(rpcURL) + tx := &GetConfirmedTransactonResult{} + err := rpcClient.CallFor(tx, "getConfirmedTransaction", params...) + if err == nil { + return tx, nil + } else { + rpcError.log(err) + } + } + return nil, rpcError.Error() +} + +// GetTransactionStatus returns tx status +func (b *Bridge) GetTransactionStatus(txHash string) (status *tokens.TxStatus) { + status = new(tokens.TxStatus) + params := []interface{}{txHash, "json"} + rpcError := &RPCError{[]error{}, "GetConfirmedTransaction"} + for _, rpcURL := range b.getURLs() { + rpcClient := jsonrpc.NewClient(rpcURL) + tx := &GetConfirmedTransactonResult{} + err := rpcClient.CallFor(tx, "getConfirmedTransaction", params...) + if err == nil && tx.Meta.Err == nil { + status.Receipt = tx + status.Confirmations = 1 + status.PrioriFinalized = true + status.BlockHeight = uint64(tx.Slot) + status.BlockHash = "" + status.BlockTime = uint64(tx.BlockTime) + return + } else { + status.Confirmations = 0 + rpcError.log(err) + return + } + } + return +} + +// BroadcastTx broadcast tx +func (b *Bridge) BroadcastTx(tx *solana.Transaction) (hash string, err error) { + ctx := context.Background() + rpcError := &RPCError{[]error{}, "GetBalance"} + for _, cli := range b.getClients() { + hash, err := cli.SendTransaction(ctx, tx) + if err == nil { + return hash, nil + } else { + rpcError.log(err) + } + } + return "", rpcError.Error() +} + +// GetBlockByNumber get block by number +func (b *Bridge) GetBlockByNumber(num *big.Int) (block *solanarpc.GetConfirmedBlockResult, err error) { + ctx := context.Background() + rpcError := &RPCError{[]error{}, "GetBalance"} + for _, cli := range b.getClients() { + block, err := cli.GetConfirmedBlock(ctx, num.Uint64(), "") + if err == nil { + return block, nil + } else { + rpcError.log(err) + } + } + return nil, rpcError.Error() +} + +func (b *Bridge) searchTxs(address string, before, until string, limit uint64) (txs []string, err error) { + rpcError := &RPCError{[]error{}, "SearchTxs"} + acct, err := solana.PublicKeyFromBase58(address) + if err != nil { + rpcError.log(err) + return nil, rpcError.Error() + } + + opts := &solanarpc.GetConfirmedSignaturesForAddress2Opts{ + Limit: limit, + } + if until != "" { + opts.Until = until + } + if before != "" { + opts.Before = before + } + + ctx := context.Background() + for _, cli := range b.getClients() { + res, err := cli.GetConfirmedSignaturesForAddress2(ctx, acct, opts) + if err != nil { + rpcError.log(err) + continue + } + txs = make([]string, 0) + for _, tx := range res { + txs = append(txs, tx.Signature) + } + return txs, nil + } + return nil, rpcError.Error() +} + +// SearchTxs searches txs for address +func (b *Bridge) SearchTxs(address string, start, end string) (txs []string, err error) { + before := end + util := start + limit := uint64(10) + txs = make([]string, 0) + for { + txs1, err := b.searchTxs(address, before, util, limit) + if err != nil { + return nil, err + } + txs = append(txs, txs1...) + if len(txs1) == 0 || strings.EqualFold(txs1[len(txs1)-1], util) { + break + } + before = txs[len(txs)-1] + } + if end != "" { + txs = append([]string{end}, txs...) + } + if start != "" { + txs = append(txs, start) + } + return txs, nil +} diff --git a/tokens/solana/scanchaintx.go b/tokens/solana/scanchaintx.go new file mode 100644 index 00000000..f9547690 --- /dev/null +++ b/tokens/solana/scanchaintx.go @@ -0,0 +1,223 @@ +package solana + +import ( + "context" + "fmt" + "math/big" + "sync" + "time" + + bin "github.com/dfuse-io/binary" + + "github.com/anyswap/CrossChain-Bridge/log" + "github.com/anyswap/CrossChain-Bridge/tokens" + "github.com/anyswap/CrossChain-Bridge/tokens/tools" +) + +var ( + quickSyncFinish bool + quickSyncWorkers = uint64(4) + + maxScanHeight = uint64(100) + retryIntervalInScanJob = 3 * time.Second + restIntervalInScanJob = 3 * time.Second +) + +func (b *Bridge) getStartAndLatestHeight() (start, latest uint64) { + startHeight := tools.GetLatestScanHeight(b.IsSrc) + + chainCfg := b.GetChainConfig() + confirmations := *chainCfg.Confirmations + initialHeight := *chainCfg.InitialHeight + + latest = tools.LoopGetLatestBlockNumber(b) + + switch { + case startHeight != 0: + start = startHeight + case initialHeight != 0: + start = initialHeight + default: + if latest > confirmations { + start = latest - confirmations + } + } + if start < initialHeight { + start = initialHeight + } + if start+maxScanHeight < latest { + start = latest - maxScanHeight + } + return start, latest +} + +func (b *Bridge) StartChainTransactionScanJob() { + chainName := b.ChainConfig.BlockChain + log.Infof("[scanchain] start %v scan chain job", chainName) + + // get addresses + pairIDs := tokens.GetAllPairIDs() + if len(pairIDs) == 0 { + return + } + + for _, pairID := range pairIDs { + tokenCfg := tokens.GetTokenConfig(pairID, b.IsSrc) + depositAddress := tokenCfg.DepositAddress + + // For every address, start a scanner + go func(depositAddress string) { + // get scanned tx + scanned := tools.GetLatestScannedSolanaTxid(depositAddress) + for { + txs, err := b.SearchTxs(depositAddress, scanned, "") + if err != nil { + log.Warn("Scan solana tx error", "address", depositAddress, "error", err) + continue + } + if len(txs) > 0 { + scanned = txs[0] + err := tools.UpdateLatestScannedSolanaTxid(depositAddress, scanned) + if err != nil { + log.Warn("UpdateLatestScannedSolanaTxid error", "address", depositAddress, "txid", scanned, "error", err) + } + } + for _, txid := range txs { + go b.processTransactionWithTxid(txid) + } + } + }(depositAddress) + } +} + +// StartChainTransactionScanJob2 scan job +func (b *Bridge) StartChainTransactionScanJob2() { + chainName := b.ChainConfig.BlockChain + log.Infof("[scanchain] start %v scan chain job", chainName) + + start, latest := b.getStartAndLatestHeight() + _ = tools.UpdateLatestScanInfo(b.IsSrc, start) + log.Infof("[scanchain] start %v scan chain loop from %v latest=%v", chainName, start, latest) + + if latest > start { + go b.quickSync(context.Background(), nil, start, latest+1) + } else { + quickSyncFinish = true + } + + stable := latest + errorSubject := fmt.Sprintf("[scanchain] get %v block failed", chainName) + scanSubject := fmt.Sprintf("[scanchain] scanned %v block", chainName) + + scannedBlocks := tools.NewCachedScannedBlocks(67) + var quickSyncCtx context.Context + var quickSyncCancel context.CancelFunc + + for { + latest = tools.LoopGetLatestBlockNumber(b) + if stable+maxScanHeight < latest { + if quickSyncCancel != nil { + select { + case <-quickSyncCtx.Done(): + default: + log.Warn("cancel quick sync range", "stable", stable, "latest", latest) + quickSyncCancel() + } + } + quickSyncCtx, quickSyncCancel = context.WithCancel(context.Background()) + go b.quickSync(quickSyncCtx, quickSyncCancel, stable+1, latest) + stable = latest + } + for h := stable; h <= latest; { + block, err := b.GetBlockByNumber(new(big.Int).SetUint64(h)) + if err != nil { + log.Error(errorSubject, "height", h, "err", err) + time.Sleep(retryIntervalInScanJob) + continue + } + blockHash := block.Blockhash.String() + if scannedBlocks.IsBlockScanned(blockHash) { + h++ + continue + } + for _, entry := range block.Transactions { + tx := &GetConfirmedTransactonResult{ + Transaction: entry.Transaction, + Meta: entry.Meta, + Slot: bin.Uint64(h), + BlockTime: block.BlockTime, + } + b.processTransaction(tx) + } + scannedBlocks.CacheScannedBlock(blockHash, h) + log.Info(scanSubject, "blockHash", blockHash, "height", h, "txs", len(block.Transactions)) + h++ + } + stable = latest + if quickSyncFinish { + _ = tools.UpdateLatestScanInfo(b.IsSrc, stable) + } + time.Sleep(restIntervalInScanJob) + } +} + +func (b *Bridge) quickSync(ctx context.Context, cancel context.CancelFunc, start, end uint64) { + chainName := b.ChainConfig.BlockChain + log.Printf("[scanchain] begin %v syncRange job. start=%v end=%v", chainName, start, end) + count := end - start + workers := quickSyncWorkers + if count < 10 { + workers = 1 + } + step := count / workers + wg := new(sync.WaitGroup) + wg.Add(int(workers)) + for i := uint64(0); i < workers; i++ { + wstt := start + i*step + wend := start + (i+1)*step + if i+1 == workers { + wend = end + } + go b.quickSyncRange(ctx, i+1, wstt, wend, wg) + } + wg.Wait() + if cancel != nil { + cancel() + } else { + quickSyncFinish = true + } + log.Printf("[scanchain] finish %v syncRange job. start=%v end=%v", chainName, start, end) +} + +func (b *Bridge) quickSyncRange(ctx context.Context, idx, start, end uint64, wg *sync.WaitGroup) { + defer wg.Done() + chainName := b.ChainConfig.BlockChain + log.Printf("[scanchain] id=%v begin %v syncRange start=%v end=%v", idx, chainName, start, end) + + for h := start; h < end; { + select { + case <-ctx.Done(): + break + default: + } + block, err := b.GetBlockByNumber(new(big.Int).SetUint64(h)) + if err != nil { + log.Errorf("[scanchain] id=%v get %v block failed at height %v. err=%v", idx, chainName, h, err) + time.Sleep(retryIntervalInScanJob) + continue + } + for _, entry := range block.Transactions { + tx := &GetConfirmedTransactonResult{ + Transaction: entry.Transaction, + Meta: entry.Meta, + Slot: bin.Uint64(h), + BlockTime: block.BlockTime, + } + b.processTransaction(tx) + } + log.Tracef("[scanchain] id=%v scanned %v block, height=%v hash=%v txs=%v", idx, chainName, h, block.Blockhash.String(), len(block.Transactions)) + h++ + } + + log.Printf("[scanchain] id=%v finish %v syncRange start=%v end=%v", idx, chainName, start, end) +} diff --git a/tokens/solana/scanpooltx.go b/tokens/solana/scanpooltx.go new file mode 100644 index 00000000..4ee69f10 --- /dev/null +++ b/tokens/solana/scanpooltx.go @@ -0,0 +1,14 @@ +package solana + +import ( + "github.com/anyswap/CrossChain-Bridge/tokens/tools" +) + +var ( + scannedTxs = tools.NewCachedScannedTxs(3000) +) + +// StartPoolTransactionScanJob scan job +func (b *Bridge) StartPoolTransactionScanJob() { + return +} diff --git a/tokens/solana/sendtx.go b/tokens/solana/sendtx.go new file mode 100644 index 00000000..8e4ff25b --- /dev/null +++ b/tokens/solana/sendtx.go @@ -0,0 +1,23 @@ +package solana + +import ( + "errors" + + "github.com/dfuse-io/solana-go" + + "github.com/anyswap/CrossChain-Bridge/log" +) + +// SendTransaction send signed tx +func (b *Bridge) SendTransaction(signedTx interface{}) (txHash string, err error) { + tx, ok := signedTx.(*solana.Transaction) + if !ok { + return "", errors.New("wrong signed transaction type") + } + txHash, err = b.BroadcastTx(tx) + if err != nil { + log.Info("SendTransaction failed", "hash", txHash, "err", err) + return txHash, err + } + return txHash, nil +} diff --git a/tokens/solana/signtx.go b/tokens/solana/signtx.go new file mode 100644 index 00000000..ee9fdc28 --- /dev/null +++ b/tokens/solana/signtx.go @@ -0,0 +1,161 @@ +package solana + +import ( + "bytes" + "crypto/ed25519" + "encoding/json" + "errors" + "fmt" + "math/big" + "strings" + "time" + + bin "github.com/dfuse-io/binary" + "github.com/dfuse-io/solana-go" + "github.com/dfuse-io/solana-go/programs/system" + + "github.com/anyswap/CrossChain-Bridge/common" + "github.com/anyswap/CrossChain-Bridge/dcrm" + "github.com/anyswap/CrossChain-Bridge/log" + "github.com/anyswap/CrossChain-Bridge/tokens" +) + +const ( + retryGetSignStatusCount = 70 + retryGetSignStatusInterval = 10 * time.Second +) + +func (b *Bridge) verifyTransactionWithArgs(tx *solana.Transaction, args *tokens.BuildTxArgs) error { + tokenCfg := b.GetTokenConfig(args.PairID) + if len(tx.Message.Instructions) != 1 { + return errors.New("wrong solana instructions length") + } + ins := tx.Message.Instructions[0] + if len(ins.Accounts) < 2 { + return errors.New("wrong solana transfer account count") + } + txprogram := tx.Message.AccountKeys[ins.ProgramIDIndex] + typeID := ins.Data[0] + txfrom := tx.Message.AccountKeys[ins.Accounts[0]].String() + txto := tx.Message.AccountKeys[ins.Accounts[1]].String() + lamports := new(bin.Uint64) + decoder := bin.NewDecoder(ins.Data[4:]) + err := decoder.Decode(lamports) + if err != nil { + return errors.New("cannot decode solana transfer data") + } + txamount := new(big.Int).SetUint64(uint64(*lamports)) + switch { + case txprogram != system.PROGRAM_ID: + return errors.New("wrong solana program id") + case typeID != byte(0x2): + return errors.New("wrong solana instruction id") + case strings.EqualFold(txfrom, args.From) == false: + return errors.New("wrong solana transfer from address") + case strings.EqualFold(txfrom, tokenCfg.DcrmAddress) == false: + return errors.New("solana transfer from address is not dcrm address") + case strings.EqualFold(txto, args.Bind) == false: + return errors.New("wrong solana transfer to address") + case txamount.Cmp(args.OriginValue) >= 0: + return errors.New("solana transfer amount not match") + default: + } + return nil +} + +// DcrmSignTransaction dcrm sign raw tx +func (b *Bridge) DcrmSignTransaction(rawTx interface{}, args *tokens.BuildTxArgs) (signedTx interface{}, txHash string, err error) { + tx, ok := rawTx.(*solana.Transaction) + if !ok { + return nil, "", errors.New("wrong raw tx param") + } + err = b.verifyTransactionWithArgs(tx, args) + if err != nil { + return nil, "", err + } + + m := tx.Message + buf := new(bytes.Buffer) + err = bin.NewEncoder(buf).Encode(m) + if err != nil { + return nil, "", err + } + msgHash := buf.Bytes() + jsondata, _ := json.Marshal(args) + msgContext := string(jsondata) + rpcAddr, keyID, err := dcrm.DoSignED25519One(b.GetDcrmPublicKey(args.PairID), fmt.Sprintf("%X", msgHash), msgContext) + if err != nil { + return nil, "", err + } + log.Info(b.ChainConfig.BlockChain+" DcrmSignTransaction start", "keyID", keyID, "msghash", fmt.Sprintf("%X", msgHash), "txid", args.SwapID) + time.Sleep(retryGetSignStatusInterval) + + var rsv string + i := 0 + for ; i < retryGetSignStatusCount; i++ { + signStatus, err2 := dcrm.GetSignStatus(keyID[0], rpcAddr) + if err2 == nil { + if len(signStatus.Rsv) != 1 { + return nil, "", fmt.Errorf("get sign status require one rsv but have %v (keyID = %v)", len(signStatus.Rsv), keyID) + } + + rsv = signStatus.Rsv[0] + break + } + switch err2 { + case dcrm.ErrGetSignStatusFailed, dcrm.ErrGetSignStatusTimeout: + return nil, "", err2 + } + log.Warn("retry get sign status as error", "err", err2, "txid", args.SwapID, "keyID", keyID, "bridge", args.Identifier, "swaptype", args.SwapType.String()) + time.Sleep(retryGetSignStatusInterval) + } + if i == retryGetSignStatusCount || rsv == "" { + return nil, "", errors.New("get sign status failed") + } + + log.Trace(b.ChainConfig.BlockChain+" DcrmSignTransaction get rsv success", "keyID", keyID, "rsv", rsv) + + signature := common.FromHex(rsv) + + var solanasignature solana.Signature + copy(solanasignature[:], signature[:64]) + tx.Signatures = append(tx.Signatures, solanasignature) + signedTx = tx + + txHash = solanasignature.String() + log.Info(b.ChainConfig.BlockChain+" DcrmSignTransaction success", "keyID", keyID, "txhash", txHash) + return signedTx, txHash, err +} + +// SignTransaction sign tx with pairID +func (b *Bridge) SignTransaction(rawTx interface{}, pairID string) (signedTx interface{}, txHash string, err error) { + privKey := b.GetTokenConfig(pairID).GetDcrmAddressED25519PrivateKey() + return b.SignTransactionWithPrivateKey(rawTx, privKey) +} + +// SignTransactionWithPrivateKey sign tx with ECDSA private key +func (b *Bridge) SignTransactionWithPrivateKey(rawTx interface{}, privKey *ed25519.PrivateKey) (signedTx interface{}, txHash string, err error) { + // rawTx is of type authtypes.StdSignDoc + tx, ok := rawTx.(*solana.Transaction) + if !ok { + return nil, "", errors.New("wrong raw tx param") + } + + m := tx.Message + buf := new(bytes.Buffer) + err = bin.NewEncoder(buf).Encode(m) + if err != nil { + return nil, "", err + } + messageCnt := buf.Bytes() + + p := solana.PrivateKey(*privKey) + signature, err := p.Sign(messageCnt) + err = bin.NewEncoder(buf).Encode(m) + if err != nil { + return nil, "", err + } + tx.Signatures = append(tx.Signatures, signature) + + return tx, signature.String(), nil +} diff --git a/tokens/solana/solanaAddress/solanaAddress.go b/tokens/solana/solanaAddress/solanaAddress.go new file mode 100644 index 00000000..d6d8b5b3 --- /dev/null +++ b/tokens/solana/solanaAddress/solanaAddress.go @@ -0,0 +1,56 @@ +package main + +import ( + "encoding/hex" + "errors" + "flag" + "fmt" + "log" + + "github.com/dfuse-io/solana-go" +) + +/* +Usage: + solanaAddress -pubkey="04d38309dfdfd9adf129287b68cf2e1f1124e0cbc40cc98f94e5f2d23c26712fa3b33d63280dd1448319a6a4f4111722d6b3a730ebe07652ed2b3770947b3de2e2" + KqhC7vpe7D9Sa1UMv9VLKj6xMovgL8QHd1mjW3Aws3t +*/ + +var pubkeyhex string + +func init() { + flag.StringVar(&pubkeyhex, "pubkey", "", "pubkey hex") +} + +func main() { + flag.Parse() + address, err := PubkeyHexToAddress(pubkeyhex) + if err != nil { + log.Fatal(err) + } + fmt.Println(address) +} + +func PubkeyHexToAddress(pubkeyHex string) (string, error) { + bz, err := hex.DecodeString(pubkeyHex) + if err != nil { + return "", errors.New("Decode pubkey hex error") + } + pub := PublicKeyFromBytes(bz) + return fmt.Sprintf("%s", pub), nil +} + +func PublicKeyFromBytes(in []byte) (out solana.PublicKey) { + byteCount := len(in) + if byteCount == 0 { + return + } + + max := 32 + if byteCount < max { + max = byteCount + } + + copy(out[:], in[0:max]) + return +} diff --git a/tokens/solana/solanadev/go.mod b/tokens/solana/solanadev/go.mod new file mode 100644 index 00000000..f84c28c2 --- /dev/null +++ b/tokens/solana/solanadev/go.mod @@ -0,0 +1,8 @@ +module github.com/gaozhengxin/CrossChain-Bridge/cmd/solanaTools + +go 1.15 + +require ( + github.com/dfuse-io/binary v0.0.0-20210216024852-4ae6830a495d + github.com/dfuse-io/solana-go v0.2.0 +) diff --git a/tokens/solana/solanadev/go.sum b/tokens/solana/solanadev/go.sum new file mode 100644 index 00000000..7ce05823 --- /dev/null +++ b/tokens/solana/solanadev/go.sum @@ -0,0 +1,416 @@ +cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= +cloud.google.com/go v0.43.0/go.mod h1:BOSR3VbTLkk6FDC/TcffxP4NF/FFBGA5ku+jvKOP7pg= +cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= +cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= +cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= +cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= +cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= +cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= +cloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqClKRT5SZwBmk= +cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= +cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= +contrib.go.opencensus.io/exporter/stackdriver v0.12.6 h1:Y2FTyj0HgOhfjEW6D6ytZNoz1YcPDXmkKr1I478CWKs= +contrib.go.opencensus.io/exporter/stackdriver v0.12.6/go.mod h1:8x999/OcIPy5ivx/wDiV7Gx4D+VUPODf0mWRGRc5kSk= +dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= +github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= +github.com/GeertJohan/go.incremental v1.0.0/go.mod h1:6fAjUhbVuX1KcMD3c8TEgVUqmo4seqhv0i0kdATSkM0= +github.com/GeertJohan/go.rice v1.0.0/go.mod h1:eH6gbSOAUv07dQuZVnBmoDP8mgsM1rtixis4Tib9if0= +github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= +github.com/akavel/rsrc v0.8.0/go.mod h1:uLoCtb9J+EyAqh+26kdrTgmzRBFPGOolLWKpdxkKq+c= +github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= +github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= +github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/aws/aws-sdk-go v1.22.1/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= +github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= +github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= +github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84= +github.com/blendle/zapdriver v1.3.1 h1:C3dydBOWYRiOk+B8X9IVZ5IOe+7cl+tGOexN4QqHfpE= +github.com/blendle/zapdriver v1.3.1/go.mod h1:mdXfREi6u5MArG4j9fewC+FGnXaBR+T4Ox4J2u4eHCc= +github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= +github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= +github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= +github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= +github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= +github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= +github.com/daaku/go.zipexe v1.0.0/go.mod h1:z8IiR6TsVLEYKwXAoE/I+8ys/sDkgTzSL0CLnGVd57E= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/dfuse-io/binary v0.0.0-20201123150056-096380ef3e5d/go.mod h1:GDFX6qH3BQZPWTeYaA4ZW98T94zs2skRoG3oMz/0jw0= +github.com/dfuse-io/binary v0.0.0-20210216024852-4ae6830a495d h1:EvEAQZ38olo+sALrqqCo345IeB2HH4im1deNOcjbi0s= +github.com/dfuse-io/binary v0.0.0-20210216024852-4ae6830a495d/go.mod h1:GDFX6qH3BQZPWTeYaA4ZW98T94zs2skRoG3oMz/0jw0= +github.com/dfuse-io/logging v0.0.0-20201110202154-26697de88c79 h1:+HRtcJejUYA/2rnyTMbOaZ4g7f4aVuFduTV/03dbpLY= +github.com/dfuse-io/logging v0.0.0-20201110202154-26697de88c79/go.mod h1:V+ED4kT/t/lKtH99JQmKIb0v9WL3VaYkJ36CfHlVECI= +github.com/dfuse-io/solana-go v0.2.0 h1:i7HzMR2b3nexyT0i+G7YeBDZFzzMbD+tEgHKsfmc7oo= +github.com/dfuse-io/solana-go v0.2.0/go.mod h1:JmxX8KYNWRCwg1RyADE2kersXSNqE1KLt+w5nEq353g= +github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= +github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= +github.com/fatih/color v1.7.0 h1:DkWD4oS2D8LGGgTQ6IvwJJXSL5Vp2ffcQg58nFV38Ys= +github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= +github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= +github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6 h1:ZgQEtGgCBiWRM39fZuwSd1LwSqqSW0hOdXCYYDX0R3I= +github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= +github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= +github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= +github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= +github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= +github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= +github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= +github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= +github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= +github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= +github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +github.com/gorilla/rpc v1.2.0 h1:WvvdC2lNeT1SP32zrIce5l0ECBfbAlmrmSBsuc57wfk= +github.com/gorilla/rpc v1.2.0/go.mod h1:V4h9r+4sF5HnzqbwIez0fKSpANP0zlYd3qR7p36jkTQ= +github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc= +github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= +github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= +github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= +github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q= +github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= +github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= +github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= +github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= +github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU= +github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU= +github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4= +github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90= +github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.3/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= +github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= +github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64= +github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ= +github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I= +github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc= +github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= +github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= +github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= +github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= +github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= +github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= +github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= +github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= +github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/logrusorgru/aurora v2.0.3+incompatible/go.mod h1:7rIyQOR62GCctdiQpZ/zOJlFyk6y+94wXzv6RNZgaR4= +github.com/magiconair/properties v1.8.1 h1:ZC2Vc7/ZFkGmsVC9KvOjumD+G5lXy2RtTKyzRKO2BQ4= +github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= +github.com/mattn/go-colorable v0.0.9 h1:UVL0vNpWh04HeJXV0KLcaT7r06gOH2l4OW6ddYRUIY4= +github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +github.com/mattn/go-isatty v0.0.3 h1:ns/ykhmWi7G9O+8a448SecJU3nSMBXJfqQkl0upE1jI= +github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= +github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= +github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= +github.com/mitchellh/go-testing-interface v1.14.1 h1:jrgshOhYAUVNMAJiKbEu7EqAwgJJ2JqpQmpLJOu07cU= +github.com/mitchellh/go-testing-interface v1.14.1/go.mod h1:gfgS7OtZj6MA4U1UrDRp04twqAjfvlZyCfX3sDjEym8= +github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg= +github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY= +github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/mr-tron/base58 v1.2.0 h1:T/HDJBh4ZCPbU39/+c3rRvE0uKBQlU27+QI8LJ4t64o= +github.com/mr-tron/base58 v1.2.0/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= +github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/nkovacs/streamquote v0.0.0-20170412213628-49af9bddb229/go.mod h1:0aYXnNPJ8l7uZxf45rWW1a/uME32OF0rhiYGNQ2oF2E= +github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= +github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= +github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= +github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= +github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= +github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= +github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= +github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= +github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= +github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= +github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= +github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= +github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= +github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= +github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= +github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= +github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= +github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= +github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= +github.com/spf13/cobra v1.1.1/go.mod h1:WnodtKOvamDL/PwE2M4iKs8aMDBZ5Q5klgD3qfVJQMI= +github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= +github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg= +github.com/spf13/viper v1.7.1/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0= +github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= +github.com/teris-io/shortid v0.0.0-20171029131806-771a37caa5cf h1:Z2X3Os7oRzpdJ75iPqWZc0HeJWFYNCvKsfpQwFpRNTA= +github.com/teris-io/shortid v0.0.0-20171029131806-771a37caa5cf/go.mod h1:M8agBzgqHIhgj7wEn9/0hJUZcrvt9VY+Ln+S1I5Mha0= +github.com/tidwall/gjson v1.6.3 h1:aHoiiem0dr7GHkW001T1SMTJ7X5PvyekH5WX0whWGnI= +github.com/tidwall/gjson v1.6.3/go.mod h1:BaHyNc5bjzYkPqgLq7mdVzeiRtULKULXLgZFKsxEHI0= +github.com/tidwall/match v1.0.1 h1:PnKP62LPNxHKTwvHHZZzdOAOCtsJTjo6dZLCwpKm5xc= +github.com/tidwall/match v1.0.1/go.mod h1:LujAq0jyVjBy028G1WhWfIzbpQfMO8bBZ6Tyb0+pL9E= +github.com/tidwall/pretty v1.0.2 h1:Z7S3cePv9Jwm1KwS0513MRaoUe3S01WPbLNV40pwWZU= +github.com/tidwall/pretty v1.0.2/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= +github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= +github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= +github.com/valyala/fasttemplate v1.0.1/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8= +github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= +github.com/ybbus/jsonrpc v2.1.2+incompatible h1:V4mkE9qhbDQ92/MLMIhlhMSbz8jNXdagC3xBR5NDwaQ= +github.com/ybbus/jsonrpc v2.1.2+incompatible/go.mod h1:XJrh1eMSzdIYFbM08flv0wp5G35eRniyeGut1z+LSiE= +github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= +go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= +go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= +go.opencensus.io v0.22.1 h1:8dP3SGL7MPB94crU3bEPplMPe83FI4EouesJUeFHv50= +go.opencensus.io v0.22.1/go.mod h1:Ap50jQcDJrx6rB6VgeeFPtuPIf3wMRvRfrfYDO6+BmA= +go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= +go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= +go.uber.org/atomic v1.6.0 h1:Ezj3JGmsOnG1MoRWQkPBsKLe9DwWD9QeXzTRzzldNVk= +go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= +go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= +go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4= +go.uber.org/multierr v1.5.0 h1:KCa4XfM8CWFCpxXRGok+Q0SS/0XBhMDbHHGABQLvD2A= +go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU= +go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee h1:0mgffUl7nfd+FpvXMVz4IDEaUSmT1ysygQC7qYo7sG4= +go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= +go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= +go.uber.org/zap v1.14.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM= +go.uber.org/zap v1.16.0 h1:uFRZXykJGK9lLY4HtgSw44DnIcAM+kRBP7x5m+NpAOM= +go.uber.org/zap v1.16.0/go.mod h1:MA8QOfq0BHJwdXa996Y4dYkAqRKB8/1K1QMMZVaNZjQ= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20191206172530-e9b2fee46413/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= +golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= +golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= +golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= +golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= +golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190930215403-16217165b5de h1:5hukYrvBGR8/eNkX5mdUezrA6JiaEZDtJb9Ei+1LlBs= +golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= +golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= +golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= +golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= +golang.org/x/mod v0.2.0 h1:KU7oHjnv3XNWfa5COkzUifxZmxp1TyI7ImMXqFxLwvQ= +golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190804053845-51ab0e2deafa/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd h1:xhmwyvizuTgC2qz7ZlMluP20uW+C3Rm0FD/WLDX8884= +golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= +golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20200601175630-2caf76543d99 h1:deddXmhOJb/bvD/4M/j2AUMrhHeh6GkqykJSCWyTNVk= +golang.org/x/tools v0.0.0-20200601175630-2caf76543d99/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= +google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= +google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= +google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= +google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190716160619-c506a9f90610/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= +google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= +google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= +google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= +google.golang.org/grpc v1.22.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= +google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= +google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= +google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= +google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= +google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= +gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= +gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU= +gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.1-2019.2.3 h1:3JgtbtFHMiCmsznwGVTUWbgGov+pVqnlf1dEJTNAXeM= +honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= +rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= diff --git a/tokens/solana/solanadev/main.go b/tokens/solana/solanadev/main.go new file mode 100644 index 00000000..d288ccab --- /dev/null +++ b/tokens/solana/solanadev/main.go @@ -0,0 +1,330 @@ +/* +This file provides Solana dev tools like generate key pair, build address, sign and verify tx, call rpc etc. +*/ +package main + +import ( + "bytes" + "context" + "encoding/hex" + "errors" + "fmt" + "log" + "math/big" + + bin "github.com/dfuse-io/binary" + "github.com/dfuse-io/solana-go" + "github.com/dfuse-io/solana-go/programs/system" + "github.com/dfuse-io/solana-go/rpc" + "github.com/dfuse-io/solana-go/rpc/ws" + "github.com/mr-tron/base58" +) + +func main() { + //key_test() + //tx_test() + //GetLatestBlock() + //SubscribeAccount() + SearchTxs() +} + +func DecodeTransferData() { + val, err := base58.Decode("3Bxs45iLYCoeyGyd") + checkError(err) + fmt.Printf("val: %v\n", val) + if val[0] == byte(0x2) { + fmt.Println("It's a transfer") + } + lamports := new(bin.Uint64) + decoder := bin.NewDecoder(val[4:]) + err = decoder.Decode(lamports) + checkError(err) + fmt.Printf("lamports: %v\n", uint64(*lamports)) +} + +func checkError(err error) { + if err != nil { + log.Fatal(err) + } +} + +func key_test() { + // 1. Generate new key pair + fmt.Printf("\n\n======== 1. Generate new key pair ========\n\n") + GenerateKeyPair() + + // private Base58: 3tFWtC14qLFNCZjGZHhBjE9Ff78SUtvVrcV13QPz2nRiQV6JpycbYp7oRibUn39jYYm65nHNVA6CSv6rHvEXY3vm + // public Base58: 7R9zUfmcXPUFGEtWtjuFUjhW5WD2i4G6ZL4TFbDJSozu + // private hex: 903AF3796D5A9ADB3E2936C4ED5A7349DA29E01ED80EB8850A5570DAAFB38CE15F563A2419B55C64AFB8565CD8883E6EDC184AAAC9197180490725ECEE6F248E + // public hex: 5F563A2419B55C64AFB8565CD8883E6EDC184AAAC9197180490725ECEE6F248E + + // 2.Read private key Base58 + fmt.Printf("\n\n======== 2. Read private key base58 ========\n\n") + priv2, err := solana.PrivateKeyFromBase58("3tFWtC14qLFNCZjGZHhBjE9Ff78SUtvVrcV13QPz2nRiQV6JpycbYp7oRibUn39jYYm65nHNVA6CSv6rHvEXY3vm") + checkError(err) + pub2 := priv2.PublicKey() + fmt.Printf("Private key:\n%s\nPublic key:\n%s\n", priv2, pub2) + fmt.Printf("\nPrivate key hex:\n%X\nPublic key hex:\n%X\n", []byte(priv2), pub2[:]) + + // 3. Read public key Base58, convert to hex + fmt.Printf("\n\n======== 3. Read public key Base58, convert to hex ========\n\n") + pub3, err := solana.PublicKeyFromBase58("7R9zUfmcXPUFGEtWtjuFUjhW5WD2i4G6ZL4TFbDJSozu") + checkError(err) + fmt.Printf("Public key hex:\n%X\n", pub3[:]) + + // 4. Read public key hex, convert to Base58 + fmt.Printf("\n\n======== 4. Read public key hex, convert to Base58 ========\n\n") + pub4, err := PubkeyHexToAddress("5F563A2419B55C64AFB8565CD8883E6EDC184AAAC9197180490725ECEE6F248E") + checkError(err) + fmt.Printf("Public key Base58 (address):\n%v\n", pub4) +} + +// GenerateKeyPair returns a new ed25519 key pair +func GenerateKeyPair() { + pub, priv, err := solana.NewRandomPrivateKey() + checkError(err) + + // Base58 format + fmt.Printf("Private key:\n%s\nPublic key:\n%s\n", priv, pub) + + // Hex format + // private key has a 64 bytes including 32 bytes suffix, which is the public key + // public key has 32 bytes + fmt.Printf("\nPrivate key hex:\n%X\nPublic key hex:\n%X\n", []byte(priv), pub[:]) +} + +// PubkeyHexToAddress returns public key address, that is just the public key encoded in base58 +func PubkeyHexToAddress(pubkeyHex string) (string, error) { + bz, err := hex.DecodeString(pubkeyHex) + if err != nil { + return "", errors.New("Decode pubkey hex error") + } + pub := PublicKeyFromBytes(bz) + return fmt.Sprintf("%s", pub), nil +} + +func PublicKeyFromBytes(in []byte) (out solana.PublicKey) { + byteCount := len(in) + if byteCount == 0 { + return + } + + max := 32 + if byteCount < max { + max = byteCount + } + + copy(out[:], in[0:max]) + return +} + +func buildUnsignedTx(fromAddress, toAddress string, amount *big.Int) *solana.Transaction { + from, err := solana.PublicKeyFromBase58(fromAddress) + checkError(err) + to, err := solana.PublicKeyFromBase58(toAddress) + checkError(err) + lamports := amount.Uint64() + + transfer := &system.Instruction{ + BaseVariant: bin.BaseVariant{ + TypeID: 2, // 0 表示 create account,1 空缺,2 表示 transfer + Impl: &system.Transfer{ + Lamports: bin.Uint64(lamports), + Accounts: &system.TransferAccounts{ + From: &solana.AccountMeta{PublicKey: from, IsSigner: true, IsWritable: true}, + To: &solana.AccountMeta{PublicKey: to, IsSigner: false, IsWritable: true}, + }, + }, + }, + } + + /*ctx := context.Background() + cli := GetClient() + + resRbt, err := cli.GetRecentBlockhash(ctx, "finalized") + checkError(err) + blockHash := resRbt.Value.Blockhash*/ + blockHash, _ := solana.PublicKeyFromBase58("BZWW21AB8Qx2eQRWBcNQNQ4ZRRaQDwmNU1no6iQChTyS") + fmt.Printf("\nRecent block hash: %v\n", blockHash) + + opt := &solana.Options{ + Payer: from, + } + + tx, err := solana.TransactionWithInstructions([]solana.TransactionInstruction{transfer}, blockHash, opt) + checkError(err) + fmt.Printf("\nTransaction: %+v\n", tx) + return tx +} + +func signTx(tx *solana.Transaction, priv solana.PrivateKey) []byte { + m := tx.Message + fmt.Printf("\nMessage: %+v\n", m) + + buf := new(bytes.Buffer) + err := bin.NewEncoder(buf).Encode(m) + checkError(err) + + messageCnt := buf.Bytes() + fmt.Printf("\nMessage bytes: %+v\n", messageCnt) + signature, err := priv.Sign(messageCnt) + checkError(err) + fmt.Printf("\nSignature: %+v\n", signature) + fmt.Printf("\nSignature bytes: %+v\n", signature[:]) + return signature[:] +} + +func makeSignedTx(tx *solana.Transaction, sig []byte) *solana.Transaction { + var signature [64]byte + copy(signature[:], sig) + tx.Signatures = append(tx.Signatures, signature) + fmt.Printf("\nSigned tx: %+v\n", tx) + return tx +} + +func simulateTx(tx *solana.Transaction) { + ctx := context.Background() + cli := GetClient() + resSmt, err := cli.SimulateTransaction(ctx, tx) + checkError(err) + fmt.Printf("\nSimulate transaction result: %+v\n", resSmt) +} + +func sendTx(tx *solana.Transaction) { + ctx := context.Background() + cli := GetClient() + txid, err := cli.SendTransaction(ctx, tx) + checkError(err) + fmt.Printf("\nSend transaction success: %v\n", txid) // 2Rt9koHr14HL3MKKoq1iqSE1z8vC6a7MCsNih7R4v2XyGSVDzstDJqagicJUfwTmZFD9WHTFtuY3r6qgwd6haWrH*/ +} + +func tx_test() { + tx := buildUnsignedTx("7R9zUfmcXPUFGEtWtjuFUjhW5WD2i4G6ZL4TFbDJSozu", "2z55nksdCojo3jDW5reezbZMEvBQmdgPvMa7djMn3vR4", big.NewInt(2333)) + + priv, _ := solana.PrivateKeyFromBase58("3tFWtC14qLFNCZjGZHhBjE9Ff78SUtvVrcV13QPz2nRiQV6JpycbYp7oRibUn39jYYm65nHNVA6CSv6rHvEXY3vm") + + sig := signTx(tx, priv) + + signedTx := makeSignedTx(tx, sig) + + // 仿真 + simulateTx(signedTx) + + // 真实发送 + //sendTx(signedTx) +} + +func GetClient() *rpc.Client { + var endpoint = "https://testnet.solana.com" + cli := rpc.NewClient(endpoint) + return cli +} + +func GetLatestBlock() { + ctx := context.Background() + var endpoint = "https://testnet.solana.com" + cli := rpc.NewClient(endpoint) + res, err := cli.GetSlot(ctx, "") + checkError(err) + fmt.Printf("res: %+v\n", res) + + block, err := cli.GetConfirmedBlock(ctx, uint64(bin.Uint64(res)), "") + checkError(err) + fmt.Printf("block: %+v\n", block) +} + +func SubscribeAccount() { + ctx := context.Background() + var endpoint = "wss://testnet.solana.com" + cli, err := ws.Dial(ctx, endpoint) + checkError(err) + acct, _ := solana.PublicKeyFromBase58("7R9zUfmcXPUFGEtWtjuFUjhW5WD2i4G6ZL4TFbDJSozu") + sbscrpt, err := cli.AccountSubscribe(acct, "finalized") + checkError(err) + fmt.Printf("subscription: %+v\n", sbscrpt) + for { + res, err := sbscrpt.Recv() + checkError(err) + fmt.Printf("res: %+v\n", res) + } +} + +func SubscribeSlot() { + ctx := context.Background() + var endpoint = "wss://testnet.solana.com" + cli, err := ws.Dial(ctx, endpoint) + checkError(err) + sbscrpt, err := cli.SlotSubscribe() + checkError(err) + fmt.Printf("subscription: %+v\n", sbscrpt) + for { + res, err := sbscrpt.Recv() + checkError(err) + fmt.Printf("res: %+v\n", res) + } +} + +func searchTxs(address string, before, until string, limit uint64) (txs []string, err error) { + acct, err := solana.PublicKeyFromBase58(address) + checkError(err) + + opts := &rpc.GetConfirmedSignaturesForAddress2Opts{ + Limit: limit, + } + if until != "" { + opts.Until = until + } + if before != "" { + opts.Before = before + } + + ctx := context.Background() + var endpoint = "https://testnet.solana.com" + cli := rpc.NewClient(endpoint) + + res, err := cli.GetConfirmedSignaturesForAddress2(ctx, acct, opts) + checkError(err) + txs = make([]string, 0) + for _, tx := range res { + txs = append(txs, tx.Signature) + } + return txs, nil +} + +func searchAllTxs(address string, start, end string) (txs []string, err error) { + before := end + util := start + limit := uint64(5) + txs = make([]string, 0) + for { + txs1, err := searchTxs(address, before, util, limit) + if err != nil { + return nil, err + } + txs = append(txs, txs1...) + if len(txs1) == 0 || txs1[len(txs1)-1] == util { + break + } + before = txs[len(txs)-1] + } + if end != "" { + txs = append([]string{end}, txs...) + } + if start != "" { + txs = append(txs, start) + } + return txs, nil +} + +func SearchTxs() { + address := "2z55nksdCojo3jDW5reezbZMEvBQmdgPvMa7djMn3vR4" + start := "" + //start := "67DUqEMTzRfr9WWrd28Sbdh1tYRhF9AFjSBDbARuaMzkV5GZ46wxnehDyMMGZVXogDQKoqhxspSvGQjWzXpcFT8C" + end := "" + //end := "3tvdDrKbRA7XCzc3aKAyKVHLTGuiU71mzXPCwDMWvU4NQtJBX7PNt9iDMbUh54BM9f9gqBSxBtSJpDvbF1wcRreP" + txs, err := searchAllTxs(address, start, end) + checkError(err) + for _, txid := range txs { + fmt.Printf("tx: %+v\n", txid) + } +} diff --git a/tokens/solana/swapAgreement.go b/tokens/solana/swapAgreement.go new file mode 100644 index 00000000..8813a773 --- /dev/null +++ b/tokens/solana/swapAgreement.go @@ -0,0 +1,76 @@ +package solana + +import ( + "strings" +) + +/* + | Solana2ETH | ETH2Solana | +Swapin | Solana2ETHSwapinAgreement | ETH2SolanaSwapinAgreement | +Swapout | Read bind address from ETH tx data | ETH2SolanaSwapoutAgreement | +*/ + +const ( + Solana2ETHSwapinAgreementType = "Solana2ETHSwapinAgreement" + ETH2SolanaSwapinAgreementType = "ETH2SolanaSwapinAgreement" + ETH2SolanaSwapoutAgreementType = "ETH2SolanaSwapoutAgreement" +) + +const ( + SolanaAddressPrefix = "solana-" + ETHAddressPrefix = "eth-" +) + +type Solana2ETHSwapinAgreement struct { + SolanaDepositAddress string `json:"solanadepositaddress"` + ETHBindAddress string `json:"ethbindaddress"` +} + +func (p *Solana2ETHSwapinAgreement) Key() string { + depositAddress := strings.ToLower(p.SolanaDepositAddress) + return SolanaAddressPrefix + depositAddress +} + +func (p *Solana2ETHSwapinAgreement) Type() string { + return Solana2ETHSwapinAgreementType +} + +func (p *Solana2ETHSwapinAgreement) Value() interface{} { + return strings.ToLower(p.ETHBindAddress) +} + +type ETH2SolanaSwapinAgreement struct { + ETHDepositAddress string `json:"ethdepositaddress"` + SolanaBindAddress string `json:"solanabindaddress"` +} + +func (p *ETH2SolanaSwapinAgreement) Key() string { + depositAddress := strings.ToLower(p.ETHDepositAddress) + return ETHAddressPrefix + depositAddress +} + +func (p *ETH2SolanaSwapinAgreement) Type() string { + return ETH2SolanaSwapinAgreementType +} + +func (p *ETH2SolanaSwapinAgreement) Value() interface{} { + return strings.ToLower(p.SolanaBindAddress) +} + +type ETH2SolanaSwapoutAgreement struct { + SolanaWithdrawAddress string `json:"solanawithdrawaddress"` + ETHBindAddress string `json:"ethbindaddress"` +} + +func (p *ETH2SolanaSwapoutAgreement) Key() string { + withdrawAddress := strings.ToLower(p.SolanaWithdrawAddress) + return SolanaAddressPrefix + withdrawAddress +} + +func (p *ETH2SolanaSwapoutAgreement) Type() string { + return ETH2SolanaSwapoutAgreementType +} + +func (p *ETH2SolanaSwapoutAgreement) Value() interface{} { + return strings.ToLower(p.ETHBindAddress) +} diff --git a/tokens/solana/verifytx.go b/tokens/solana/verifytx.go new file mode 100644 index 00000000..f0ab0b95 --- /dev/null +++ b/tokens/solana/verifytx.go @@ -0,0 +1,263 @@ +package solana + +import ( + "bytes" + "errors" + "fmt" + "math/big" + "strings" + + bin "github.com/dfuse-io/binary" + "github.com/dfuse-io/solana-go" + "github.com/dfuse-io/solana-go/programs/system" + + "github.com/anyswap/CrossChain-Bridge/log" + "github.com/anyswap/CrossChain-Bridge/tokens" + "github.com/anyswap/CrossChain-Bridge/tokens/tools" +) + +func addSwapInfoConsiderError(swapInfo *tokens.TxSwapInfo, err error, swapInfos *[]*tokens.TxSwapInfo, errs *[]error) { + if !tokens.ShouldRegisterSwapForError(err) { + return + } + *swapInfos = append(*swapInfos, swapInfo) + *errs = append(*errs, err) +} + +// VerifyMsgHash verify msg hash +func (b *Bridge) VerifyMsgHash(rawTx interface{}, msgHash []string) (err error) { + tx, ok := rawTx.(*solana.Transaction) + if !ok { + return errors.New("verify msg hash tx type error") + } + + if len(msgHash) < 1 { + return errors.New("no msg hash") + } + mh := msgHash[0] + + m := tx.Message + buf := new(bytes.Buffer) + err = bin.NewEncoder(buf).Encode(m) + if err != nil { + return err + } + messageCnt := buf.Bytes() + + if strings.EqualFold(string(messageCnt), mh) == false { + return errors.New("msg hash not match") + } + return nil +} + +// VerifyTransaction impl +func (b *Bridge) VerifyTransaction(pairID, txHash string, allowUnstable bool) (*tokens.TxSwapInfo, error) { + if !b.IsSrc { + swapInfos, errs := b.verifySwapoutTxWithHash(txHash, allowUnstable) + // swapinfos have already aggregated + for i, swapInfo := range swapInfos { + if strings.EqualFold(swapInfo.PairID, pairID) { + return swapInfo, errs[i] + } + } + log.Warn("No such swapInfo") + } else { + swapInfos, errs := b.verifySwapinTxWithHash(txHash, allowUnstable) + // swapinfos have already aggregated + for i, swapInfo := range swapInfos { + if strings.EqualFold(swapInfo.PairID, pairID) { + return swapInfo, errs[i] + } + } + log.Warn("No such swapInfo") + } + return nil, nil +} + +func (b *Bridge) verifySwapinTx(tx *GetConfirmedTransactonResult, allowUnstable bool) (swapInfos []*tokens.TxSwapInfo, errs []error) { + pairIDs := tokens.GetAllPairIDs() + if len(pairIDs) == 0 { + addSwapInfoConsiderError(nil, tokens.ErrTxWithWrongReceiver, &swapInfos, &errs) + return swapInfos, errs + } + + for _, pairID := range pairIDs { + tokenCfg := tokens.GetTokenConfig(pairID, b.IsSrc) + + depositAddress := tokenCfg.DepositAddress + if tx.Meta.Err != nil { + swapInfos = append(swapInfos, &tokens.TxSwapInfo{PairID: pairID}) + errs = append(errs, fmt.Errorf("Solana tx error: %v", tx.Meta.Err)) + break + } + if len(tx.Transaction.Signatures) < 1 { + swapInfos = append(swapInfos, &tokens.TxSwapInfo{PairID: pairID}) + errs = append(errs, fmt.Errorf("Unexpected, no signature")) + break + } + for _, ins := range tx.Transaction.Message.Instructions { + if int(ins.ProgramIDIndex) >= len(tx.Transaction.Message.AccountKeys) { + swapInfos = append(swapInfos, &tokens.TxSwapInfo{PairID: pairID}) + errs = append(errs, fmt.Errorf("Unexpected, wrong program ID index")) + continue + } + if tx.Transaction.Message.AccountKeys[ins.ProgramIDIndex] != system.PROGRAM_ID { + swapInfos = append(swapInfos, &tokens.TxSwapInfo{PairID: pairID}) + errs = append(errs, fmt.Errorf("Program ID not match")) + continue + } + if len(ins.Accounts) != 2 { + swapInfos = append(swapInfos, &tokens.TxSwapInfo{PairID: pairID}) + errs = append(errs, fmt.Errorf("Tx has not enough account keys")) + continue + } + to := tx.Transaction.Message.AccountKeys[ins.Accounts[1]] + if strings.EqualFold(to.String(), depositAddress) == false { + swapInfos = append(swapInfos, &tokens.TxSwapInfo{PairID: pairID}) + errs = append(errs, fmt.Errorf("Tx recipient not match")) + continue + } + from := tx.Transaction.Message.AccountKeys[ins.Accounts[0]] + bind, ok := b.getSolana2ETHSwapinBindAddress(from.String()) + if !ok { + swapInfos = append(swapInfos, &tokens.TxSwapInfo{PairID: pairID}) + errs = append(errs, fmt.Errorf("Bind address not found or invalid")) + continue + } + if len(ins.Data) < 1 { + swapInfos = append(swapInfos, &tokens.TxSwapInfo{PairID: pairID}) + errs = append(errs, fmt.Errorf("No transfer data")) + continue + } + if ins.Data[0] != byte(0x2) { + // Transfer prefix + swapInfos = append(swapInfos, &tokens.TxSwapInfo{PairID: pairID}) + errs = append(errs, fmt.Errorf("Transfer data prefix is not 0x2: %v", ins.Data[0])) + continue + } + lamports := new(bin.Uint64) + decoder := bin.NewDecoder(ins.Data[4:]) + err := decoder.Decode(lamports) + if err != nil { + swapInfos = append(swapInfos, &tokens.TxSwapInfo{PairID: pairID}) + errs = append(errs, fmt.Errorf("Decode transfer data error: %v", err)) + continue + } + value := new(big.Int).SetUint64(uint64(*lamports)) + swapInfo := &tokens.TxSwapInfo{ + PairID: pairID, + Hash: tx.Transaction.Signatures[0].String(), + Height: uint64(tx.Slot), + Timestamp: uint64(tx.BlockTime), + From: from.String(), + TxTo: to.String(), + To: to.String(), + Bind: bind, + Value: value, + } + swapInfos = append(swapInfos, swapInfo) + errs = append(errs, nil) + } + } + return swapInfos, errs +} + +func (b *Bridge) verifySwapinTxWithHash(txid string, allowUnstable bool) (swapInfos []*tokens.TxSwapInfo, errs []error) { + tx, err := b.GetTransaction(txid) + if err != nil { + return nil, []error{err} + } + txres, ok := tx.(*GetConfirmedTransactonResult) + if !ok { + return nil, []error{errors.New("Solana transaction type error")} + } + return b.verifySwapinTx(txres, allowUnstable) +} + +func (b *Bridge) verifySwapoutTx(tx *GetConfirmedTransactonResult, allowUnstable bool) (swapInfos []*tokens.TxSwapInfo, errs []error) { + pairIDs := tokens.GetAllPairIDs() + if len(pairIDs) == 0 { + addSwapInfoConsiderError(nil, tokens.ErrTxWithWrongReceiver, &swapInfos, &errs) + return swapInfos, errs + } + + for _, pairID := range pairIDs { + tokenCfg := tokens.GetTokenConfig(pairID, b.IsSrc) + + fmt.Printf("PairID: %v\nToken cfg: %+v\n", pairID, tokenCfg) + // TODO + } + return nil, nil +} + +func (b *Bridge) verifySwapoutTxWithHash(txid string, allowUnstable bool) (swapInfos []*tokens.TxSwapInfo, errs []error) { + tx, err := b.GetTransaction(txid) + if err != nil { + return nil, []error{err} + } + txres, ok := tx.(*GetConfirmedTransactonResult) + if !ok { + return nil, []error{errors.New("Solana transaction type error")} + } + return b.verifySwapoutTx(txres, allowUnstable) +} + +func (b *Bridge) getSolana2ETHSwapinBindAddress(solanaAddress string) (ethAddress string, ok bool) { + solanaAddress = strings.ToLower(solanaAddress) + pkey := SolanaAddressPrefix + solanaAddress + agreement, err := tools.GetSwapAgreement(pkey) + if err != nil { + return "", false + } + sp, ok := agreement.(*Solana2ETHSwapinAgreement) + if !ok { + return "", false + } + ethAddress = sp.ETHBindAddress + + dstBridge := tokens.DstBridge + if dstBridge.IsValidAddress(ethAddress) { + return ethAddress, true + } + return "", false +} + +func (b *Bridge) getETH2SolanaSwapinAgreementBindAddress(ethAddress string) (solanaAddress string, ok bool) { + ethAddress = strings.ToLower(ethAddress) + pkey := ETHAddressPrefix + ethAddress + agreement, err := tools.GetSwapAgreement(pkey) + if err != nil { + return "", false + } + sp, ok := agreement.(*ETH2SolanaSwapinAgreement) + if !ok { + return "", false + } + solanaAddress = sp.SolanaBindAddress + + dstBridge := tokens.DstBridge + if dstBridge.IsValidAddress(solanaAddress) { + return solanaAddress, true + } + return "", false +} + +func (b *Bridge) getETH2SolanaSwapoutAgreementBindAddress(solanaAddress string) (ethAddress string, ok bool) { + solanaAddress = strings.ToLower(solanaAddress) + pkey := SolanaAddressPrefix + solanaAddress + agreement, err := tools.GetSwapAgreement(pkey) + if err != nil { + return "", false + } + sp, ok := agreement.(*ETH2SolanaSwapoutAgreement) + if !ok { + return "", false + } + ethAddress = sp.ETHBindAddress + + srcBridge := tokens.SrcBridge + if srcBridge.IsValidAddress(ethAddress) { + return solanaAddress, true + } + return "", false +} diff --git a/tokens/swapAgreement.go b/tokens/swapAgreement.go new file mode 100644 index 00000000..04d9037e --- /dev/null +++ b/tokens/swapAgreement.go @@ -0,0 +1,41 @@ +package tokens + +import ( + "encoding/json" + + amino "github.com/tendermint/go-amino" +) + +var TokenCDC = amino.NewCodec() + +func init() { + TokenCDC.RegisterInterface((*SwapAgreement)(nil), nil) +} + +// SwapAgreement interface +// to be implemented with definition of swap binding rule +type SwapAgreement interface { + // Type returns agreement type + // e.g. "solana-eth-bindaddress" + Type() string + // Key returns something identifies a swap binding rule + // e.g. for solana-eth, Key should be solana address + Key() string + // Value returns data required to define a binding rule + // For solana-eth, Value should return an eth binding address + Value() interface{} +} + +// AgreementFromArgs takes args from api, returns SwapAgreement +func AgreementFromArgs(args map[string](interface{})) (SwapAgreement, error) { + bz, err := json.Marshal(args) + if err != nil { + return nil, err + } + var p SwapAgreement + err = TokenCDC.UnmarshalJSON(bz, &p) + if err != nil { + return nil, err + } + return p, nil +} diff --git a/tokens/terra/bridge.go b/tokens/terra/bridge.go new file mode 100644 index 00000000..0f56f213 --- /dev/null +++ b/tokens/terra/bridge.go @@ -0,0 +1,137 @@ +package terra + +import ( + "fmt" + "strings" + "time" + + "github.com/anyswap/CrossChain-Bridge/log" + "github.com/anyswap/CrossChain-Bridge/tokens" + "github.com/anyswap/CrossChain-Bridge/tokens/cosmos" + sdk "github.com/cosmos/cosmos-sdk/types" + authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" + ctypes "github.com/tendermint/tendermint/rpc/core/types" + core "github.com/terra-project/core/types" +) + +// Bridge struct +type Bridge struct { + *cosmos.Bridge +} + +// InitSDK init cosmos sdk +func InitSDK() { + config := sdk.GetConfig() + config.SetCoinType(core.CoinType) + config.SetFullFundraiserPath(core.FullFundraiserPath) + config.SetBech32PrefixForAccount(core.Bech32PrefixAccAddr, core.Bech32PrefixAccPub) + config.SetBech32PrefixForValidator(core.Bech32PrefixValAddr, core.Bech32PrefixValPub) + config.SetBech32PrefixForConsensusNode(core.Bech32PrefixConsAddr, core.Bech32PrefixConsPub) + config.Seal() +} + +// BeforeConfig run before loading bridge and token config +func (b *Bridge) BeforeConfig() { + ctypes.RegisterAmino(cosmos.CDC) + sdk.RegisterCodec(cosmos.CDC) + cosmos.CDC.RegisterConcrete(cosmos.MsgSend{}, "bank/MsgSend", nil) + cosmos.CDC.RegisterConcrete(cosmos.MsgMultiSend{}, "bank/MsgMultiSend", nil) + cosmos.CDC.RegisterConcrete(authtypes.StdTx{}, "core/StdTx", nil) + cosmos.CDC.RegisterConcrete(&authtypes.BaseAccount{}, "core/Account", nil) + InitSDK() + cosmos.ChainIDs["columbus-4"] = true + cosmos.ChainIDs["tequila-0004"] = true + cosmos.SignBytesModifier = TerraSignBytesModifier + /*b.SupportedCoins["LUNA"] = cosmos.CosmosCoin{"uluna", 6} + b.SupportedCoins["USD"] = cosmos.CosmosCoin{"uusd", 6} + b.SupportedCoins["KRW"] = cosmos.CosmosCoin{"ukrw", 6} + b.SupportedCoins["SDR"] = cosmos.CosmosCoin{"usdr", 6} + b.SupportedCoins["CNY"] = cosmos.CosmosCoin{"ucny", 6} + b.SupportedCoins["JPY"] = cosmos.CosmosCoin{"ujpy", 6} + b.SupportedCoins["EUR"] = cosmos.CosmosCoin{"ueur", 6} + b.SupportedCoins["GBP"] = cosmos.CosmosCoin{"ugbp", 6} + b.SupportedCoins["UMNT"] = cosmos.CosmosCoin{"umnt", 6}*/ + tokens.IsSwapoutToStringAddress = true +} + +// AfterConfig run after loading bridge and token config +func (b *Bridge) AfterConfig() { + cosmos.GetFeeAmount = b.FeeGetter() + b.Bridge.InitLatestBlockNumber() + b.LoadCoins() + if luna, ok := b.SupportedCoins["LUNA"]; ok == false || luna.Denom != "uluna" || luna.Decimal != 6 { + log.Info("Terra init coins", "luna", luna, "ok", ok, "check denom", (luna.Denom != "uluna"), "check decimal", luna.Decimal != 6) + log.Fatalf("Terra bridge must have Luna token config") + } + b.MainCoin = b.SupportedCoins["LUNA"] + log.Info("Terra bridge init success", "coins", b.SupportedCoins) +} + +// NewCrossChainBridge new bridge +func NewCrossChainBridge(isSrc bool) *Bridge { + return &Bridge{ + Bridge: cosmos.NewCrossChainBridge(isSrc), + } +} + +// SetChainAndGateway set chain and gateway config +func (b *Bridge) SetChainAndGateway(chainCfg *tokens.ChainConfig, gatewayCfg *tokens.GatewayConfig) { + b.CrossChainBridgeBase.SetChainAndGateway(chainCfg, gatewayCfg) + b.InitLatestBlockNumber() + b.VerifyChainID() +} + +// VerifyChainID verify chain id +func (b *Bridge) VerifyChainID() { + chainID := strings.ToLower(b.ChainConfig.NetID) + if cosmos.ChainIDs[chainID] == false { + log.Fatalf("unsupported cosmos network: %v", b.ChainConfig.NetID) + } +} + +// VerifyTokenConfig verify token config +func (b *Bridge) VerifyTokenConfig(tokenCfg *tokens.TokenConfig) error { + if !b.IsValidAddress(tokenCfg.DepositAddress) { + return fmt.Errorf("invalid deposit address: %v", tokenCfg.DepositAddress) + } + return nil +} + +// InitLatestBlockNumber init latest block number +func (b *Bridge) InitLatestBlockNumber() { + chainCfg := b.ChainConfig + gatewayCfg := b.GatewayConfig + var latest uint64 + var err error + for { + latest, err = b.GetLatestBlockNumber() + if err == nil { + tokens.SetLatestBlockHeight(latest, b.IsSrc) + log.Info("get latst block number succeed.", "number", latest, "BlockChain", chainCfg.BlockChain, "NetID", chainCfg.NetID) + break + } + log.Error("get latst block number failed.", "BlockChain", chainCfg.BlockChain, "NetID", chainCfg.NetID, "err", err) + log.Println("retry query gateway", gatewayCfg.APIAddress) + time.Sleep(3 * time.Second) + } +} + +// DefaultSwapoutGas is terra default gas +var DefaultSwapoutGas uint64 = 300000 + +// FeeGetter returns terra fee getter +func (b *Bridge) FeeGetter() func() authtypes.StdFee { + return func() authtypes.StdFee { + // TODO + feeAmount := []sdk.Coin{sdk.NewCoin("uluna", sdk.NewInt(50000))} + return authtypes.NewStdFee(DefaultSwapoutGas, feeAmount) + } +} + +// TerraSignBytesModifier is used to build terra special sign bytes +var TerraSignBytesModifier = func(bz []byte) []byte { + signString := fmt.Sprintf("%s", bz) + signString = strings.Replace(signString, "cosmos-sdk/MsgSend", "bank/MsgSend", -1) + signString = strings.Replace(signString, "cosmos-sdk/MsgMultiSend", "bank/MsgMultiSend", -1) + return []byte(signString) +} diff --git a/tokens/terra/terra-config-example.toml b/tokens/terra/terra-config-example.toml new file mode 100644 index 00000000..05e734ef --- /dev/null +++ b/tokens/terra/terra-config-example.toml @@ -0,0 +1,108 @@ +# a short string to identify the bridge +Identifier = "TERRA2ETH" + +# administrators who can do admin work like maintain blacklist etc. +Admins = [ + "0x3dfaef310a1044fd7d96750b42b44cf3775c00bf", + "0x46cbe22b687d4b72c8913e4784dfe5b20fdc2b0e" +] + +# modgodb database connection config (server only) +[MongoDB] +DBURL = "localhost:27017" +DBName = "databasename" +UserName = "username" +Password = "password" + +# bridge API service (server only) +[APIServer] +# listen port +Port = 11556 +# CORS config +AllowedOrigins = [] + +# oracle config (oracle only) +[Oracle] +# post swap register RPC requests to this server +ServerAPIAddress = "http://127.0.0.1:11556/rpc" + +# source chain config +[SrcChain] +BlockChain = "TERRA" +NetID = "mytestnet" +# tx should be in chain with at least so many confirmations to be valid on source chain +Confirmations = 0 # suggest >= 6 for Mainnet +# only tx with block height >= this initial height should be considered valid on source chain +InitialHeight = 0 +# whether enable scan blocks and register swaps +EnableScan = true + +# source blockchain gateway config +[SrcGateway] +APIAddress = ["http://5.189.139.168:2317"] + +# dest chain config +[DestChain] +BlockChain = "ETHEREUM" +NetID = "Rinkeby" +# tx should be in chain with at least so many confirmations to be valid on source chain +Confirmations = 0 # suggest >= 30 for Mainnet +# only tx with block height >= this initial height should be considered valid on source chain +InitialHeight = 0 +# whether enable scan blocks and register swaps +EnableScan = false + +# dest blockchain gateway config +[DestGateway] +APIAddress = ["http://5.189.139.168:8018"] + +# DCRM config +[Dcrm] +# disable flag +Disable = false + +# dcrm group ID +GroupID = "74245ef03937fa75b979bdaa6a5952a93f53e021e0832fca4c2ad8952572c9b70f49e291de7e024b0f7fc54ec5875210db2ac775dba44448b3972b75af074d17" + +# dcrm threshold (NeededOracles=2,TotalOracles=3 represent '2/3' threshold) +NeededOracles = 2 +TotalOracles = 3 + +# dcrm mode (0:managed 1:private) +Mode = 0 + +# initiators of dcrm sign +Initiators = [ + "0x00c37841378920E2BA5151a5d1E074Cf367586c4", + "0x897a9980808a2cae0d09ff693f02a4f80abb2233" +] + +# DCRM other initiators nodes config (server only) +[[Dcrm.OtherNodes]] +# dcrm sub groups for signing +SignGroups = [ + "38a93f457c793ac3ee242b2c050a403774738e6558cfaa620fe5577bb15a28f63c39adcc0778497e5009a9ee776a0778ffcad4e95827e69efa21b893b8a78793", + "bb1dfe1ec046cc3a3b88408ae03976aabffe459b40e5def09e76f5d4c7a917133241da9da7fc05e3e172fab54ce3129a9a492d52a5a09494d0b9c1e608f661bf" +] + +# dcrm user keystore and password file (suggest using absolute path) +KeystoreFile = "/home/xxx/accounts/keystore2" +PasswordFile = "/home/xxx/accounts/password2" + +# dcrm backend node (gdcrm node RPC address) +RPCAddress = "http://127.0.0.1:2922" + +# DCRM default node config +[Dcrm.DefaultNode] +# dcrm sub groups for signing (server only) +SignGroups = [ + "38a93f457c793ac3ee242b2c050a403774738e6558cfaa620fe5577bb15a28f63c39adcc0778497e5009a9ee776a0778ffcad4e95827e69efa21b893b8a78793", + "bb1dfe1ec046cc3a3b88408ae03976aabffe459b40e5def09e76f5d4c7a917133241da9da7fc05e3e172fab54ce3129a9a492d52a5a09494d0b9c1e608f661bf" +] + +# dcrm user keystore and password file (suggest using absolute path) +KeystoreFile = "/home/xxx/accounts/keystore1" +PasswordFile = "/home/xxx/accounts/password1" + +# dcrm backend node (gdcrm node RPC address) +RPCAddress = "http://127.0.0.1:2921" diff --git a/tokens/terra/tokenPairConfigs/terra-config-tokenpair-example.toml b/tokens/terra/tokenPairConfigs/terra-config-tokenpair-example.toml new file mode 100644 index 00000000..e1860491 --- /dev/null +++ b/tokens/terra/tokenPairConfigs/terra-config-tokenpair-example.toml @@ -0,0 +1,68 @@ +PairID = "TERRA" + +# source token config +[SrcToken] +# ID must be ERC20 if source token is erc20 token +ID = "LUNA" +Name = "Luna coin" +Symbol = "LUNA" +Decimals = 6 +Description = "Luna coin" +# if ID is ERC20, this is the erc20 token's contract address +ContractAddress = "" +# deposit to this address to make swap +DepositAddress = "terra1qj05rkrpphd55dawh7qxxmd2c72g57j2r0nlp3" +# withdraw from this address +DcrmAddress = "terra1qj05rkrpphd55dawh7qxxmd2c72g57j2r0nlp3" +# dcrm address public key +DcrmPubkey = "045c8648793e4867af465691685000ae841dccab0b011283139d2eae454b569d5789f01632e13a75a5aad8480140e895dd671cae3639f935750bea7ae4b5a2512e" +# maximum deposit value +MaximumSwap = 1000.0 +# minimum deposit value +MinimumSwap = 0.00001 +# calced deposit fee = deposit value * this rate (when in [min, max] deposit fee range) +SwapFeeRate = 0.001 +# maximum deposit fee, if calced deposit fee is larger than this fee, then use this value as deposit fee +MaximumSwapFee = 0.01 +# minimum deposit fee, if calced deposit fee is smaller than this fee, then use this value as deposit fee +MinimumSwapFee = 0.00001 +# plus this percentage of gas price to make tx more easier to be mined in source chain +# corresponding to send asset on source chain (eg. BTC) for withdrawing +PlusGasPricePercentage = 15 # plus 15% gas price +# if deposit value is larger than this value then need more verify strategy +BigValueThreshold = 5.0 +# disable deposit function if this flag is true +DisableSwap = false +# Unit name +Unit = "uluna" + +# dest token config +[DestToken] +ID = "anyLUNA" +Name = "ANY LUNA" +Symbol = "anyLUNA" +Decimals = 6 +Description = "" +# mapping erc20 token address +ContractAddress = "" +# mapping erc20 token creator +DcrmAddress = "0xbF0A46d3700E23a98F38079cE217742c92Bb66bC" +# dcrm address public key +DcrmPubkey = "045c8648793e4867af465691685000ae841dccab0b011283139d2eae454b569d5789f01632e13a75a5aad8480140e895dd671cae3639f935750bea7ae4b5a2512e" +# maximum withdraw value +MaximumSwap = 100.0 +# minimum withdraw value +MinimumSwap = 0.00001 +# calced withdraw fee = withdraw value * this rate (when in [min, max] withdraw fee range) +SwapFeeRate = 0.001 +# maximum withdraw fee, if calced withdraw fee is larger than this fee, then use this value as withdraw fee +MaximumSwapFee = 0.01 +# minimum withdraw fee, if calced withdraw fee is smaller than this fee, then use this value as withdraw fee +MinimumSwapFee = 0.00001 +# plus this percentage of gas price to make tx more easier to be mined in dest chain +# corresponding to send mapping token on dest chain (eg. mBTC) for depositing +PlusGasPricePercentage = 1 # plus 1% gas price +# if withdraw value is larger than this value then need more verify strategy +BigValueThreshold = 50.0 +# disable withdraw function if this flag is true +DisableSwap = false diff --git a/tokens/tools/swaptools.go b/tokens/tools/swaptools.go index 635cba22..b9968f8a 100644 --- a/tokens/tools/swaptools.go +++ b/tokens/tools/swaptools.go @@ -1,7 +1,9 @@ package tools import ( + "encoding/hex" "errors" + "strings" "time" "github.com/anyswap/CrossChain-Bridge/dcrm" @@ -180,6 +182,31 @@ func GetP2shBindAddress(p2shAddress string) (bindAddress string) { return "" } +// GetLatestScannedSolanaTxid get latest scanned solana txid +func GetLatestScannedSolanaTxid(address string) string { + if mongodb.HasSession() { + return mongodb.FindLatestSolanaTxid(address) + } + var result = "" + for { + err := client.RPCPost(&result, params.ServerAPIAddress, "swap.GetLatestScannedSolanaTxid", address) + if err == nil { + txid := result + log.Info("GetLatestScannedSolanaTxid", "txid", txid) + return txid + } + time.Sleep(1 * time.Second) + } +} + +// UpdateLatestScannedSolanaTxid updates latest scanned solana txid +func UpdateLatestScannedSolanaTxid(address, txid string) error { + if dcrm.IsSwapServer() { + return mongodb.UpdateLatestSolanaTxid(address, txid) + } + return nil +} + // GetLatestScanHeight get latest scanned block height func GetLatestScanHeight(isSrc bool) uint64 { if mongodb.HasSession() { @@ -242,3 +269,29 @@ func IsAddressRegistered(address string) bool { } return false } + +// GetSwapAgreement find swapin agreement +func GetSwapAgreement(pkey string) (tokens.SwapAgreement, error) { + mp, err := mongodb.FindSwapAgreement(pkey) + if err != nil { + return nil, err + } + return ConvertMgoSwapAgreementToSwapAgreement(mp) +} + +// ConvertMgoSwapAgreementToSwapAgreement convert +func ConvertMgoSwapAgreementToSwapAgreement(mp *mongodb.MgoSwapAgreement) (tokens.SwapAgreement, error) { + bz, err := hex.DecodeString(mp.Value) + if err != nil { + return nil, err + } + var p tokens.SwapAgreement + err = tokens.TokenCDC.UnmarshalJSON(bz, &p) + if err != nil { + return nil, err + } + if strings.EqualFold(p.Type(), mp.Type) == false { + return nil, errors.New("Swapin agreement type not match") + } + return p, nil +} diff --git a/tokens/tron/address.go b/tokens/tron/address.go new file mode 100644 index 00000000..2508a1e7 --- /dev/null +++ b/tokens/tron/address.go @@ -0,0 +1,83 @@ +package tron + +import ( + "encoding/hex" + "math/big" + "strings" + + tronaddress "github.com/fbsobreira/gotron-sdk/pkg/address" + troncommon "github.com/fbsobreira/gotron-sdk/pkg/common" + + "github.com/anyswap/CrossChain-Bridge/common" + "github.com/anyswap/CrossChain-Bridge/tools/crypto" +) + +// IsValidAddress check address +func (b *Bridge) IsValidAddress(address string) bool { + if common.IsHexAddress(address) { + _, err := ethToTron(address) + return err == nil + } + _, err := tronaddress.Base58ToAddress(address) + return err == nil +} + +// PublicKeyToAddress returns cosmos public key address +func (b *Bridge) PublicKeyToAddress(pubKeyHex string) (address string, err error) { + pubKeyHex = strings.TrimPrefix(pubKeyHex, "0x") + bz, err := hex.DecodeString(pubKeyHex) + if err != nil { + return "", err + } + ecdsaPub, err := crypto.UnmarshalPubkey(bz) + if err != nil { + return "", err + } + ethAddress := crypto.PubkeyToAddress(*ecdsaPub) + address = tronaddress.Address(append([]byte{0x41}, ethAddress.Bytes()...)).String() + return +} + +func EqualAddress(addr1, addr2 string) bool { + addr1 = anyToEth(addr1) + addr2 = anyToEth(addr2) + return strings.EqualFold(addr1, addr2) +} + +func ethToTron(ethAddress string) (string, error) { + intaddr, ok := new(big.Int).SetString(ethAddress, 16) + if ok { + ethAddress = common.BigToAddress(intaddr).String() + } + bz, _ := troncommon.FromHex(ethAddress) + tronaddr := tronaddress.Address(append([]byte{0x41}, bz...)) + return tronaddr.String(), nil +} + +func tronToEth(tronAddress string) (string, error) { + addr, err := tronaddress.Base58ToAddress(tronAddress) + if err != nil || len(addr) == 0 { + return "", err + } + ethaddr := common.BytesToAddress(addr.Bytes()) + return ethaddr.String(), nil +} + +func anyToTron(address string) string { + addr, err := tronaddress.Base58ToAddress(address) + if err != nil { + address, err = ethToTron(address) + if err != nil { + return "" + } + } else { + address = addr.String() + } + return address +} + +func anyToEth(address string) string { + tronaddr := anyToTron(address) + address, _ = tronToEth(tronaddr) + return address +} diff --git a/tokens/tron/bridge.go b/tokens/tron/bridge.go new file mode 100644 index 00000000..38bb3b91 --- /dev/null +++ b/tokens/tron/bridge.go @@ -0,0 +1,93 @@ +package tron + +import ( + "fmt" + "strings" + "time" + + "github.com/anyswap/CrossChain-Bridge/log" + "github.com/anyswap/CrossChain-Bridge/tokens" +) + +type Bridge struct { + *tokens.CrossChainBridgeBase +} + +const ( + PairID = "TRX" + TRC10TokenType = "TRC10" + TRC20TokenType = "TRC20" +) + +// NewCrossChainBridge new bridge +/* + 1. tron -> eth/fusion/bsc/heco + TRX -> anyTRX (ERC20) + TRC20 tokens -> anyTokens (ERC20) + 2. eth/fusion/bsc/heco -> tron + ETH/FSN/BNB/HT -> anyETH/anyFSN/anyBNB/anyHT (TRC20) + USDT/Anyswap/BUSD/HUSD (ERC20) -> anyTokens (TRC20) + 3. btc/ltc -> tron + BTC/LTC -> anyBTC/anyLTC (TRC20) +*/ +func NewCrossChainBridge(isSrc bool) *Bridge { + tokens.IsSwapoutToStringAddress = false + InitExtCodeParts() + return &Bridge{ + CrossChainBridgeBase: tokens.NewCrossChainBridgeBase(isSrc), + } +} + +// VerifyChainID verify chain id +func (b *Bridge) VerifyChainID() { + networkID := strings.ToLower(b.ChainConfig.NetID) + switch networkID { + case "mainnet", "shasta": + default: + log.Fatalf("unsupported solana network: %v", b.ChainConfig.NetID) + } +} + +// InitLatestBlockNumber init latest block number +func (b *Bridge) InitLatestBlockNumber() { + chainCfg := b.ChainConfig + gatewayCfg := b.GatewayConfig + var latest uint64 + var err error + for { + latest, err = b.GetLatestBlockNumber() + if err == nil { + tokens.SetLatestBlockHeight(latest, b.IsSrc) + log.Info("get latst block number succeed.", "number", latest, "BlockChain", chainCfg.BlockChain, "NetID", chainCfg.NetID) + break + } + log.Error("get latst block number failed.", "BlockChain", chainCfg.BlockChain, "NetID", chainCfg.NetID, "err", err) + log.Println("retry query gateway", gatewayCfg.APIAddress) + time.Sleep(3 * time.Second) + } +} + +// VerifyTokenConfig verify token config +func (b *Bridge) VerifyTokenConfig(tokenCfg *tokens.TokenConfig) error { + if tokenCfg.ContractAddress != "" { + if !b.IsValidAddress(tokenCfg.ContractAddress) { + return fmt.Errorf("invalid contract address: %v", tokenCfg.ContractAddress) + } + switch { + case !b.IsSrc: + if err := b.VerifyMbtcContractAddress(tokenCfg.ContractAddress); err != nil { + return fmt.Errorf("wrong contract address: %v, %v", tokenCfg.ContractAddress, err) + } + case tokenCfg.IsTrc20(): + if err := b.VerifyTrc20ContractAddress(tokenCfg.ContractAddress, tokenCfg.ContractCodeHash, tokenCfg.IsProxyErc20()); err != nil { + return fmt.Errorf("wrong contract address: %v, %v", tokenCfg.ContractAddress, err) + } + default: + return fmt.Errorf("unsupported type of contract address '%v' in source chain, please assign SrcToken.ID (eg. ERC20) in config file", tokenCfg.ContractAddress) + } + log.Info("verify contract address pass", "address", tokenCfg.ContractAddress) + } else if tokenCfg.ID != "TRX" { + return fmt.Errorf("token ID is not TRX and contract address is not given") + } + return nil +} diff --git a/tokens/tron/buildtx.go b/tokens/tron/buildtx.go new file mode 100644 index 00000000..f6617343 --- /dev/null +++ b/tokens/tron/buildtx.go @@ -0,0 +1,154 @@ +package tron + +import ( + "encoding/hex" + "errors" + "fmt" + + "github.com/fbsobreira/gotron-sdk/pkg/proto/core" + proto "github.com/golang/protobuf/proto" + + "github.com/anyswap/CrossChain-Bridge/common" + "github.com/anyswap/CrossChain-Bridge/log" + "github.com/anyswap/CrossChain-Bridge/params" + "github.com/anyswap/CrossChain-Bridge/tokens" + "github.com/anyswap/CrossChain-Bridge/tokens/eth" +) + +var ( + SwapinFeeLimit int64 = 300000000 // 300 TRX + TransferTRXLimit int64 = 300000000 // 300 TRX + TransferTRC20FeeLimit int64 = 300000000 // 300 TRX + + ExtraExpiration int64 = 900000 // 15 min +) + +// BuildRawTransaction build raw tx +func (b *Bridge) BuildRawTransaction(args *tokens.BuildTxArgs) (rawTx interface{}, err error) { + args.Identifier = params.GetIdentifier() + // For server, build tx and set TronExtra with marshal tx + // For oracle nodes, TronExtra should exists in args + // unmarshal raw tx from TronExtra, + // verify tx with main args such as PairID, From, To, Amount and omit other args + // return the decoded raw tx so that it afford to pass msg hash check + if args.Extra != nil && args.Extra.TronExtra != nil { + rawtx, decodeErr := hex.DecodeString(args.Extra.TronExtra.RawTx) + if decodeErr != nil { + return nil, decodeErr + } + + var coretx core.Transaction + unmarshalErr := proto.Unmarshal(rawtx, &coretx) + if unmarshalErr != nil { + return nil, unmarshalErr + } + + verifyErr := b.verifyTransactionWithArgs(&coretx, args) + if verifyErr == nil { + return &coretx, nil + } + return nil, verifyErr + } + + var input []byte + var tokenCfg *tokens.TokenConfig + if args.Input == nil { + if args.SwapType != tokens.NoSwapType { + pairID := args.PairID + tokenCfg = b.GetTokenConfig(pairID) + if tokenCfg == nil { + return nil, tokens.ErrUnknownPairID + } + if args.From == "" { + args.From = tokenCfg.DcrmAddress // from + } + } + switch args.SwapType { + case tokens.SwapinType: + if b.IsSrc { + return nil, tokens.ErrBuildSwapTxInWrongEndpoint + } + // mint mapping asset + err = b.buildSwapinTxInput(args) + if err != nil { + return nil, err + } + rawTx, err = b.BuildSwapinTx(args.From, args.To, *args.Input) + if err == nil { + txmsg, _ := proto.Marshal(rawTx.(*core.Transaction)) + args.Extra = &tokens.AllExtras{ + TronExtra: &tokens.TronExtraArgs{ + RawTx: fmt.Sprintf("%X", txmsg), + }, + } + } + return + case tokens.SwapoutType: + if !b.IsSrc { + return nil, tokens.ErrBuildSwapTxInWrongEndpoint + } + if tokenCfg.IsTrc20() { + // TRC20 + amount := tokens.CalcSwappedValue(args.PairID, args.OriginValue, false) + args.To = tokenCfg.ContractAddress + // transfer trc20 + rawTx, err = b.BuildTRC20Transfer(args.From, args.Bind, args.To, amount) + if err == nil { + txmsg, _ := proto.Marshal(rawTx.(*core.Transaction)) + args.Extra = &tokens.AllExtras{ + TronExtra: &tokens.TronExtraArgs{ + RawTx: fmt.Sprintf("%X", txmsg), + }, + } + } + return + } else { + // TRX + args.To = args.Bind + input = []byte(tokens.UnlockMemoPrefix + args.SwapID) + amount := tokens.CalcSwappedValue(args.PairID, args.OriginValue, false) + args.Value = amount + // transfer trx + rawTx, err = b.BuildTransfer(args.From, args.To, amount, input) + if err == nil { + txmsg, _ := proto.Marshal(rawTx.(*core.Transaction)) + args.Extra = &tokens.AllExtras{ + TronExtra: &tokens.TronExtraArgs{ + RawTx: fmt.Sprintf("%X", txmsg), + }, + } + } + return + } + } + } else { + input = *args.Input + if args.SwapType != tokens.NoSwapType { + return nil, fmt.Errorf("forbid build raw swap tx with input data") + } + } + return nil, fmt.Errorf("Cannot build tron transaction") +} + +// build input for calling `Swapin(bytes32 txhash, address account, uint256 amount)` +func (b *Bridge) buildSwapinTxInput(args *tokens.BuildTxArgs) error { + pairID := args.PairID + funcHash := eth.ExtCodeParts["SwapinFuncHash"] + txHash := common.HexToHash(args.SwapID) + address := common.HexToAddress(args.Bind) + if address == (common.Address{}) || !common.IsHexAddress(args.Bind) { + log.Warn("swapin to wrong address", "address", args.Bind) + return errors.New("can not swapin to empty or invalid address") + } + amount := tokens.CalcSwappedValue(pairID, args.OriginValue, true) + + input := eth.PackDataWithFuncHash(funcHash, txHash, address, amount) + args.Input = &input // input + + token := b.GetTokenConfig(pairID) + if token == nil { + return tokens.ErrUnknownPairID + } + args.To = token.ContractAddress // to + return nil +} diff --git a/tokens/tron/processtx.go b/tokens/tron/processtx.go new file mode 100644 index 00000000..ccb8769e --- /dev/null +++ b/tokens/tron/processtx.go @@ -0,0 +1,34 @@ +package tron + +import ( + "fmt" + + "github.com/anyswap/CrossChain-Bridge/tokens/tools" + "github.com/fbsobreira/gotron-sdk/pkg/proto/api" +) + +func (b *Bridge) processTransaction(txext *api.TransactionExtention) { + if b.IsSrc { + b.processSwapin(txext) + } else { + b.processSwapout(txext) + } +} + +func (b *Bridge) processSwapin(txext *api.TransactionExtention) { + tx := &TransactionExtention{ + Transaction: txext.Transaction, + Txid: txext.GetTxid(), + } + swapInfos, errs := b.verifySwapinTx(tx, true) + tools.RegisterSwapin(fmt.Sprintf("%X", txext.GetTxid()), swapInfos, errs) +} + +func (b *Bridge) processSwapout(txext *api.TransactionExtention) { + tx := &TransactionExtention{ + Transaction: txext.Transaction, + Txid: txext.GetTxid(), + } + swapInfos, errs := b.verifySwapoutTx(tx, true) + tools.RegisterSwapout(fmt.Sprintf("%X", txext.GetTxid()), swapInfos, errs) +} diff --git a/tokens/tron/rpc.go b/tokens/tron/rpc.go new file mode 100644 index 00000000..b8442ae7 --- /dev/null +++ b/tokens/tron/rpc.go @@ -0,0 +1,498 @@ +package tron + +import ( + "context" + "errors" + "fmt" + "math/big" + "strings" + "time" + + tronaddress "github.com/fbsobreira/gotron-sdk/pkg/address" + "github.com/fbsobreira/gotron-sdk/pkg/client" + "github.com/fbsobreira/gotron-sdk/pkg/common" + "github.com/fbsobreira/gotron-sdk/pkg/proto/api" + "github.com/fbsobreira/gotron-sdk/pkg/proto/core" + "google.golang.org/grpc" + + "github.com/anyswap/CrossChain-Bridge/log" + "github.com/anyswap/CrossChain-Bridge/tokens" +) + +var GRPC_TIMEOUT = time.Second * 15 + +func (b *Bridge) getClients() []*client.GrpcClient { + endpoints := b.GatewayConfig.APIAddress + clis := make([]*client.GrpcClient, 0) + for _, endpoint := range endpoints { + cli := client.NewGrpcClientWithTimeout(endpoint, GRPC_TIMEOUT) + if cli != nil { + clis = append(clis, cli) + } + } + return clis +} + +type RPCError struct { + errs []error + method string +} + +func (e *RPCError) log(msg error) { + log.Warn("[Tron RPC error]", "method", e.method, "msg", msg) + if len(e.errs) < 1 { + e.errs = make([]error, 1) + } + e.errs = append(e.errs, msg) +} + +func (e *RPCError) Error() error { + return fmt.Errorf("[Tron RPC error] method: %v errors:%+v", e.method, e.errs) +} + +// GetLatestBlockNumber returns current finalized block height +func (b *Bridge) GetLatestBlockNumber() (height uint64, err error) { + rpcError := &RPCError{[]error{}, "GetLatestBlockNumber"} + for _, cli := range b.getClients() { + err = cli.Start(grpc.WithInsecure()) + if err != nil { + rpcError.log(err) + continue + } + res, err := cli.GetNowBlock() + if err == nil { + if res.BlockHeader.RawData.Number > 0 { + height = uint64(res.BlockHeader.RawData.Number) + cli.Stop() + break + } + } else { + rpcError.log(err) + } + cli.Stop() + } + if height > 0 { + return height, nil + } + return 0, rpcError.Error() +} + +// GetLatestBlockNumberOf returns current finalized block height from given node +func (b *Bridge) GetLatestBlockNumberOf(apiAddress string) (uint64, error) { + rpcError := &RPCError{[]error{}, "GetLatestBlockNumberOf"} + cli := client.NewGrpcClientWithTimeout(apiAddress, GRPC_TIMEOUT) + if cli == nil { + rpcError.log(errors.New("New client failed")) + return 0, rpcError.Error() + } + err := cli.Start(grpc.WithInsecure()) + if err != nil { + rpcError.log(err) + return 0, rpcError.Error() + } + res, err := cli.GetNowBlock() + if err != nil { + rpcError.log(err) + return 0, rpcError.Error() + } + return uint64(res.BlockHeader.RawData.Number), nil +} + +// GetBalance gets TRON token balance +func (b *Bridge) GetBalance(account string) (balance *big.Int, err error) { + rpcError := &RPCError{[]error{}, "GetBalance"} + for _, cli := range b.getClients() { + err = cli.Start(grpc.WithInsecure()) + if err != nil { + rpcError.log(err) + continue + } + res, err := cli.GetAccount(account) + if err == nil { + if res.Balance > 0 { + balance = big.NewInt(int64(res.Balance)) + cli.Stop() + break + } + } else { + rpcError.log(err) + } + cli.Stop() + } + if balance.Cmp(big.NewInt(0)) > 0 { + return balance, nil + } + return big.NewInt(0), rpcError.Error() +} + +func (b *Bridge) GetTokenBalance(tokenType, tokenAddress, accountAddress string) (balance *big.Int, err error) { + switch strings.ToUpper(tokenType) { + case TRC20TokenType: + return b.GetTrc20Balance(tokenAddress, accountAddress) + case TRC10TokenType: + return nil, fmt.Errorf("[%v] can not get token balance of token with type '%v'", b.ChainConfig.BlockChain, tokenType) + default: + return nil, fmt.Errorf("[%v] can not get token balance of token with type '%v'", b.ChainConfig.BlockChain, tokenType) + } +} + +// GetTrc20Balance gets balance for given ERC20 token +func (b *Bridge) GetTrc20Balance(tokenAddress, accountAddress string) (balance *big.Int, err error) { + rpcError := &RPCError{[]error{}, "GetTrc20Balance"} + for _, cli := range b.getClients() { + err = cli.Start(grpc.WithInsecure()) + if err != nil { + rpcError.log(err) + continue + } + res, err := cli.TRC20ContractBalance(accountAddress, tokenAddress) + if err == nil { + balance = res + cli.Stop() + break + } else { + rpcError.log(err) + } + cli.Stop() + } + if balance.Cmp(big.NewInt(0)) > 0 { + return balance, nil + } + return big.NewInt(0), rpcError.Error() +} + +// GetTokenSupply impl +func (b *Bridge) GetTokenSupply(tokenType, tokenAddress string) (*big.Int, error) { + switch strings.ToUpper(tokenType) { + case TRC20TokenType: + return b.GetErc20TotalSupply(tokenAddress) + case TRC10TokenType: + return nil, fmt.Errorf("[%v] can not get token supply of token with type '%v'", b.ChainConfig.BlockChain, tokenType) + default: + return nil, fmt.Errorf("[%v] can not get token supply of token with type '%v'", b.ChainConfig.BlockChain, tokenType) + } +} + +// GetTokenSupply not supported +func (b *Bridge) GetErc20TotalSupply(tokenAddress string) (totalSupply *big.Int, err error) { + totalSupplyMethodSignature := "0x18160ddd" + rpcError := &RPCError{[]error{}, "GetErc20TotalSupply"} + for _, cli := range b.getClients() { + err = cli.Start(grpc.WithInsecure()) + if err != nil { + rpcError.log(err) + continue + } + result, err := cli.TRC20Call("", tokenAddress, totalSupplyMethodSignature, true, 0) + if err == nil { + totalSupply = new(big.Int).SetBytes(result.GetConstantResult()[0]) + cli.Stop() + break + } else { + rpcError.log(err) + } + cli.Stop() + } + if totalSupply.Cmp(big.NewInt(0)) > 0 { + return totalSupply, nil + } + return big.NewInt(0), rpcError.Error() +} + +// GetTransaction gets tx by hash, returns sdk.Tx +func (b *Bridge) GetTransaction(txHash string) (tx interface{}, err error) { + rpcError := &RPCError{[]error{}, "GetTransaction"} + for _, cli := range b.getClients() { + err = cli.Start(grpc.WithInsecure()) + if err != nil { + rpcError.log(err) + continue + } + tx, err = cli.GetTransactionByID(txHash) + if err == nil { + cli.Stop() + break + } + cli.Stop() + } + if err != nil { + return nil, rpcError.Error() + } + return +} + +// GetTransactionStatus returns tx status +func (b *Bridge) GetTransactionStatus(txHash string) (status *tokens.TxStatus) { + status = &tokens.TxStatus{} + var tx *core.TransactionInfo + rpcError := &RPCError{[]error{}, "GetTransactionStatus"} + for _, cli := range b.getClients() { + err := cli.Start(grpc.WithInsecure()) + if err != nil { + rpcError.log(err) + continue + } + tx, err = cli.GetTransactionInfoByID(txHash) + if err == nil && tx != nil { + cli.Stop() + break + } + cli.Stop() + } + + if tx == nil { + if tx1, err1 := b.GetTransaction(txHash); err1 != nil { + tx2, ok1 := tx1.(core.Transaction) + if !ok1 || tx2.GetRet()[0].GetRet() != core.Transaction_Result_SUCESS { + status.CustomeCheckStable = func(confirmations uint64) int { + return 2 + } + return + } + } + return nil + } + if tx.Result != core.TransactionInfo_SUCESS { + status.CustomeCheckStable = func(confirmations uint64) int { + return 1 + } + return + } + + rsrcres := tx.GetReceipt().GetResult() + if rsrcres != core.Transaction_Result_SUCCESS && rsrcres != core.Transaction_Result_DEFAULT { + status.CustomeCheckStable = func(confirmations uint64) int { + return 1 + } + return + } + + status.Receipt = tx + status.PrioriFinalized = false + status.BlockHeight = uint64(tx.BlockNumber) + status.BlockTime = uint64(tx.BlockTimeStamp / 1000) + + if latest, err := b.GetLatestBlockNumber(); err == nil { + status.Confirmations = latest - status.BlockHeight + } + status.CustomeCheckStable = func(confirmations uint64) int { + if status.Receipt == nil { + return 1 // fail + } + if status.Confirmations >= confirmations { + return 0 // stable + } + return 2 // unstable + } + return +} + +// BuildTransfer returns an unsigned tron transfer tx +func (b *Bridge) BuildTransfer(from, to string, amount *big.Int, input []byte) (tx *core.Transaction, err error) { + from = anyToTron(from) + to = anyToTron(to) + n, _ := new(big.Int).SetString("18446740000000000000", 0) + if amount.Cmp(n) > 0 { + return nil, errors.New("Amount exceed max uint64") + } + contract := &core.TransferContract{} + contract.OwnerAddress, err = common.DecodeCheck(from) + if err != nil { + return nil, err + } + contract.ToAddress, err = common.DecodeCheck(to) + if err != nil { + return nil, err + } + contract.Amount = amount.Int64() + rpcError := &RPCError{[]error{}, "BuildTransfer"} + ctx, cancel := context.WithTimeout(context.Background(), GRPC_TIMEOUT) + defer cancel() + for _, cli := range b.getClients() { + err = cli.Start(grpc.WithInsecure()) + if err != nil { + rpcError.log(err) + continue + } + txext, err1 := cli.Client.CreateTransaction2(ctx, contract) + if txext != nil { + txext.Transaction.RawData.Expiration = txext.Transaction.RawData.Expiration + ExtraExpiration + txext.Transaction.RawData.FeeLimit = TransferTRXLimit + } + err = err1 + if err == nil { + cli.Stop() + cancel() + tx = txext.Transaction + if tx == nil { + err = fmt.Errorf("%v", txext) + rpcError.log(err) + } + break + } + rpcError.log(err) + cli.Stop() + cancel() + } + if err != nil { + return nil, rpcError.Error() + } + return tx, nil +} + +// BuildTRC20Transfer returns an unsigned trc20 transfer tx +func (b *Bridge) BuildTRC20Transfer(from, to, tokenAddress string, amount *big.Int) (tx *core.Transaction, err error) { + tokenAddress = anyToTron(tokenAddress) + from = anyToTron(from) + to = anyToTron(to) + n, _ := new(big.Int).SetString("18446740000000000000", 0) + if amount.Cmp(n) > 0 { + return nil, errors.New("Amount exceed max uint64") + } + rpcError := &RPCError{[]error{}, "BuildTRC20Transfer"} + for _, cli := range b.getClients() { + err = cli.Start(grpc.WithInsecure()) + if err != nil { + rpcError.log(err) + continue + } + txext, err1 := cli.TRC20Send(from, to, tokenAddress, amount, TransferTRC20FeeLimit) + if txext != nil { + txext.Transaction.RawData.Expiration = txext.Transaction.RawData.Expiration + ExtraExpiration + } + err = err1 + if err == nil { + tx = txext.Transaction + cli.Stop() + break + } + rpcError.log(err) + cli.Stop() + } + if err != nil { + return nil, rpcError.Error() + } + return tx, nil +} + +// BuildSwapinTx returns an unsigned mapping asset minting tx +func (b *Bridge) BuildSwapinTx(from, tokenAddress string, dataBytes []byte) (tx *core.Transaction, err error) { + tokenAddress = anyToTron(tokenAddress) + from = anyToTron(from) + + fromAddr, _ := tronaddress.Base58ToAddress(from) + tokenAddr, _ := tronaddress.Base58ToAddress(tokenAddress) + ct := &core.TriggerSmartContract{ + OwnerAddress: fromAddr.Bytes(), + ContractAddress: tokenAddr.Bytes(), + Data: dataBytes, + } + + rpcError := &RPCError{[]error{}, "BuildSwapinTx"} + + ctx, cancel := context.WithTimeout(context.Background(), GRPC_TIMEOUT) + defer cancel() + + for _, cli := range b.getClients() { + err = cli.Start(grpc.WithInsecure()) + if err != nil { + rpcError.log(err) + continue + } + txext, err1 := cli.Client.TriggerConstantContract(ctx, ct) + if txext != nil { + txext.Transaction.RawData.FeeLimit = SwapinFeeLimit + txext.Transaction.RawData.Expiration = txext.Transaction.RawData.Expiration + ExtraExpiration + } + err = err1 + if err == nil { + tx = txext.Transaction + cli.Stop() + break + } + rpcError.log(err) + cli.Stop() + } + if err != nil { + return nil, rpcError.Error() + } + return tx, nil +} + +// GetCode returns contract bytecode +func (b *Bridge) GetCode(contractAddress string) (data []byte, err error) { + contractDesc, err := tronaddress.Base58ToAddress(contractAddress) + if err != nil { + return nil, err + } + message := new(api.BytesMessage) + message.Value = contractDesc + rpcError := &RPCError{[]error{}, "GetCode"} + for _, cli := range b.getClients() { + err = cli.Start(grpc.WithInsecure()) + ctx, cancel := context.WithTimeout(context.Background(), GRPC_TIMEOUT) + if err != nil { + rpcError.log(err) + cancel() + continue + } + sm, err1 := cli.Client.GetContract(ctx, message) + err = err1 + if err == nil { + data = sm.Bytecode + cli.Stop() + cancel() + break + } + cli.Stop() + cancel() + } + if err != nil { + return nil, rpcError.Error() + } + return data, nil +} + +// GetBlockByLimitNext gets block by limit next +func (b *Bridge) GetBlockByLimitNext(start, end int64) (res *api.BlockListExtention, err error) { + rpcError := &RPCError{[]error{}, "GetBlockByLimitNext"} + for _, cli := range b.getClients() { + err = cli.Start(grpc.WithInsecure()) + if err != nil { + rpcError.log(err) + continue + } + res, err = cli.GetBlockByLimitNext(start, end) + if err == nil { + cli.Stop() + break + } + rpcError.log(err) + } + if err != nil { + return nil, rpcError.Error() + } + return res, nil +} + +// BroadcastTx broadcast tx to network +func (b *Bridge) BroadcastTx(tx *core.Transaction) (err error) { + rpcError := &RPCError{[]error{}, "BroadcastTx"} + for _, cli := range b.getClients() { + err = cli.Start(grpc.WithInsecure()) + if err != nil { + rpcError.log(err) + continue + } + res, err := cli.Broadcast(tx) + if err == nil { + cli.Stop() + if res.Code != 0 { + rpcError.log(fmt.Errorf("bad transaction: %v", string(res.GetMessage()))) + } + return nil + } + rpcError.log(err) + } + return rpcError.Error() +} diff --git a/tokens/tron/scanchaintx.go b/tokens/tron/scanchaintx.go new file mode 100644 index 00000000..8ac9bdba --- /dev/null +++ b/tokens/tron/scanchaintx.go @@ -0,0 +1,71 @@ +package tron + +import ( + "time" + + "github.com/anyswap/CrossChain-Bridge/log" + "github.com/anyswap/CrossChain-Bridge/tokens/tools" +) + +var ( + step int = 100 + longSleep = time.Second * 2 + shortSleep = time.Millisecond * 500 + + maxScanHeight = uint64(100) + retryIntervalInScanJob = 3 * time.Second + restIntervalInScanJob = 3 * time.Second +) + +// StartChainTransactionScanJob scan job +func (b *Bridge) StartChainTransactionScanJob() { + chainName := b.ChainConfig.BlockChain + log.Infof("[scanchain] start %v scan chain job", chainName) + + chainCfg := b.GetChainConfig() + var start, end int64 + start = int64(tools.GetLatestScanHeight(b.IsSrc)) + if start == 0 { + start = int64(*chainCfg.InitialHeight) + } + if start == 0 { + latest, _ := b.GetLatestBlockNumber() + start = int64(latest) + } + log.Infof("[scanchain] latest scan height is %v", start) + end = start + int64(step) + for { + res, err := b.GetBlockByLimitNext(start, end) + if err != nil { + log.Warn("Get block failed", "start", start, "end", end) + continue + } + + log.Debug("Find tron block", "num", len(res.Block)) + for _, block := range res.Block { + //log.Debugf("Check tron block %x, fount tron tx %v", block.Blockid, len(block.Transactions)) + for _, tx := range block.Transactions { + // log.Debugf("Check tron tx: %x", tx.GetTxid()) + b.processTransaction(tx) + } + } + + latest := start + int64(len(res.Block)) - 1 + err = tools.UpdateLatestScanInfo(b.IsSrc, uint64(latest)) + if err != nil { + log.Warn("[scanchain] update latest scan info", "error", err) + } + start = start + int64(len(res.Block)) + end = start + int64(step) + if len(res.Block) < step { + time.Sleep(longSleep) + } else { + time.Sleep(shortSleep) + } + } +} + +// StartPoolTransactionScanJob not implemented for tron +func (b *Bridge) StartPoolTransactionScanJob() { + return +} diff --git a/tokens/tron/sendtx.go b/tokens/tron/sendtx.go new file mode 100644 index 00000000..03738512 --- /dev/null +++ b/tokens/tron/sendtx.go @@ -0,0 +1,28 @@ +package tron + +import ( + "errors" + "fmt" + + "github.com/fbsobreira/gotron-sdk/pkg/proto/core" + + "github.com/anyswap/CrossChain-Bridge/log" +) + +// SendTransaction send signed tx +func (b *Bridge) SendTransaction(signedTx interface{}) (txHash string, err error) { + tx, ok := signedTx.(*core.Transaction) + if !ok { + fmt.Printf("signed tx is %+v\n", signedTx) + return "", errors.New("wrong signed transaction type") + } + txHash = CalcTxHash(tx) + err = b.BroadcastTx(tx) + if err != nil { + log.Info("SendTransaction failed", "hash", txHash, "err", err) + return txHash, err + } + log.Info("SendTransaction success", "hash", txHash) + //#log.Trace("SendTransaction success", "raw", tx.RawStr()) + return txHash, nil +} diff --git a/tokens/tron/signtx.go b/tokens/tron/signtx.go new file mode 100644 index 00000000..404b3ea2 --- /dev/null +++ b/tokens/tron/signtx.go @@ -0,0 +1,191 @@ +package tron + +import ( + "crypto/ecdsa" + "crypto/sha256" + "encoding/json" + "errors" + "fmt" + "math/big" + "time" + + tronaddress "github.com/fbsobreira/gotron-sdk/pkg/address" + "github.com/fbsobreira/gotron-sdk/pkg/proto/core" + proto "github.com/golang/protobuf/proto" + "github.com/golang/protobuf/ptypes" + + "github.com/anyswap/CrossChain-Bridge/common" + "github.com/anyswap/CrossChain-Bridge/dcrm" + "github.com/anyswap/CrossChain-Bridge/log" + "github.com/anyswap/CrossChain-Bridge/tokens" + "github.com/anyswap/CrossChain-Bridge/tokens/eth" + "github.com/anyswap/CrossChain-Bridge/tools/crypto" +) + +const ( + retryGetSignStatusCount = 70 + retryGetSignStatusInterval = 10 * time.Second +) + +// oracle nodes cannot build an identical Tron tx with BuildTxArgs, which they check signing message against +// instead, they accept the raw tx from BuildTxArgs.TronExtra when rebuilding tx and check everything in this function +func (b *Bridge) verifyTransactionWithArgs(tx *core.Transaction, args *tokens.BuildTxArgs) error { + tokenCfg := b.GetTokenConfig(args.PairID) + if tokenCfg == nil { + return fmt.Errorf("[sign] verify tx with unknown pairID '%v'", args.PairID) + } + isSwapin := (args.SwapType == tokens.SwapinType) + rawdata := tx.GetRawData() + contracts := rawdata.GetContract() + if l := len(contracts); l != 1 { + return fmt.Errorf("[sign] Tron tx contract number is not 1: %v", l) + } + if isSwapin { + // Swapin + var contract core.TriggerSmartContract + err := ptypes.UnmarshalAny(contracts[0].GetParameter(), &contract) + if err != nil { + return fmt.Errorf("[sign] Decode tron contract error: %v", err) + } + txFrom := tronaddress.Address(contract.OwnerAddress).String() + if EqualAddress(txFrom, args.From) == false || EqualAddress(txFrom, tokenCfg.DcrmAddress) == false { + return fmt.Errorf("[sign] Swapin tx with wrong from address") + } + txRecipient := tronaddress.Address(contract.ContractAddress).String() + if EqualAddress(txRecipient, tokenCfg.ContractAddress) == false { + return fmt.Errorf("[sign] Swapin tx recipient is not token contract address") + } + //checkInput := *args.Input + err = b.buildSwapinTxInput(args) + if err != nil { + log.Warn("[sign] Swapin tx cannot build input", "error", err) + } + input := contract.Data + _, bindAddress, value, err := eth.ParseErc20SwapinTxInput(&input, anyToEth(tokenCfg.DcrmAddress)) + if err != nil { + return fmt.Errorf("[sign] Swapin tx with wrong input data: %v", err) + } + if EqualAddress(args.Bind, bindAddress) == false { + return fmt.Errorf("[sign] Swapin tx with wrong bind address") + } + argsValue := tokens.CalcSwappedValue(args.PairID, args.OriginValue, isSwapin) + if argsValue.Cmp(value) != 0 { + return fmt.Errorf("[sign] Swapin tx with wrong value") + } + } else if tokenCfg.IsTrc20() { + // TRC20 + var contract core.TriggerSmartContract + err := ptypes.UnmarshalAny(contracts[0].GetParameter(), &contract) + if err != nil { + return fmt.Errorf("[sign] Decode tron contract error: %v", err) + } + txFrom := tronaddress.Address(contract.OwnerAddress).String() + if EqualAddress(txFrom, args.From) == false { + return fmt.Errorf("[sign] TRC20 transfer with wrong from address") + } + txRecipient := tronaddress.Address(contract.ContractAddress).String() + if EqualAddress(txRecipient, tokenCfg.ContractAddress) == false { + return fmt.Errorf("[sign] TRC20 transfer recipient is not token contract address") + } + input := contract.Data + transferto, transfervalue, err := ParseTransferTxInput(&input) + if err != nil { + return fmt.Errorf("[sign] TRC20 transfer with wrong input data: %v", err) + } + if EqualAddress(args.Bind, transferto) == false { + return fmt.Errorf("[sign] TRC20 transfer with wrong bind address") + } + argsValue := tokens.CalcSwappedValue(args.PairID, args.OriginValue, isSwapin) + if argsValue.Cmp(transfervalue) != 0 { + return fmt.Errorf("[sign] TRC20 transfer with wrong value") + } + } else { + // Not TRC20 + var contract core.TransferContract + err := ptypes.UnmarshalAny(contracts[0].GetParameter(), &contract) + if err != nil { + return fmt.Errorf("[sign] Decode tron contract error: %v", err) + } + txFrom := tronaddress.Address(contract.OwnerAddress).String() + if EqualAddress(txFrom, args.From) == false { + return fmt.Errorf("[sign] TRX transfer with wrong from address") + } + txRecipient := tronaddress.Address(contract.ToAddress).String() + if EqualAddress(txRecipient, args.Bind) == false { + return fmt.Errorf("[sign] TRX transfer with wrong recipient, has %v, want %v", txRecipient, args.Bind) + } + argsValue := tokens.CalcSwappedValue(args.PairID, args.OriginValue, isSwapin) + if argsValue.Cmp(big.NewInt(contract.Amount)) != 0 { + return fmt.Errorf("[sign] TRX transfer with wrong value") + } + } + return nil +} + +// DcrmSignTransaction dcrm sign raw tx +func (b *Bridge) DcrmSignTransaction(rawTx interface{}, args *tokens.BuildTxArgs) (signedTx interface{}, txHash string, err error) { + tx, ok := rawTx.(*core.Transaction) + if !ok { + return nil, "", errors.New("wrong raw tx param") + } + err = b.verifyTransactionWithArgs(tx, args) + if err != nil { + return nil, "", err + } + + txHash = CalcTxHash(tx) + jsondata, _ := json.Marshal(args) + msgContext := string(jsondata) + keyID, rsvs, err := dcrm.DoSignOne(b.GetDcrmPublicKey(args.PairID), txHash, msgContext) + if err != nil { + return nil, "", err + } + log.Info(b.ChainConfig.BlockChain+" DcrmSignTransaction finished", "keyID", keyID, "msghash", txHash, "txid", args.SwapID, "data", msgContext) + + if len(rsvs) != 1 { + return nil, "", fmt.Errorf("get sign status require one rsv but have %v (keyID = %v)", len(rsvs), keyID) + } + + rsv := rsvs[0] + + log.Trace(b.ChainConfig.BlockChain+" DcrmSignTransaction get rsv success", "keyID", keyID, "rsv", rsv) + + signature := common.FromHex(rsv) + + tx.Signature = append(tx.Signature, signature) + signedTx = tx + log.Info(b.ChainConfig.BlockChain+" DcrmSignTransaction success", "keyID", keyID, "txhassh", txHash) + return signedTx, txHash, err +} + +// SignTransaction sign tx with pairID +func (b *Bridge) SignTransaction(rawTx interface{}, pairID string) (signedTx interface{}, txHash string, err error) { + privKey := b.GetTokenConfig(pairID).GetDcrmAddressPrivateKey() + return b.SignTransactionWithPrivateKey(rawTx, privKey) +} + +// SignTransactionWithPrivateKey sign tx with ECDSA private key +func (b *Bridge) SignTransactionWithPrivateKey(rawTx interface{}, privKey *ecdsa.PrivateKey) (signedTx interface{}, txHash string, err error) { + // rawTx is of type authtypes.StdSignDoc + tx, ok := rawTx.(*core.Transaction) + if !ok { + return nil, "", errors.New("wrong raw tx param") + } + + rawData, err := proto.Marshal(tx.GetRawData()) + if err != nil { + return nil, "", err + } + h256h := sha256.New() + h256h.Write(rawData) + hash := h256h.Sum(nil) + txhash := fmt.Sprintf("%X", hash) + + signature, err := crypto.Sign(hash, privKey) + if err != nil { + return nil, "", err + } + tx.Signature = append(tx.Signature, signature) + signedTx = tx + return tx, txhash, nil +} diff --git a/tokens/tron/trondev/go.mod b/tokens/tron/trondev/go.mod new file mode 100644 index 00000000..d5a00aa0 --- /dev/null +++ b/tokens/tron/trondev/go.mod @@ -0,0 +1,12 @@ +module github.com/gaozhengxin/CrossChain-Bridge/tokens/tron/trondev + +go 1.15 + +replace github.com/anyswap/CrossChain-Bridge => ../../.. + +require ( + github.com/anyswap/CrossChain-Bridge v0.0.0-00010101000000-000000000000 + github.com/fbsobreira/gotron-sdk v0.0.0-20210316163828-8cb47d581197 + github.com/golang/protobuf v1.5.2 + google.golang.org/grpc v1.37.0 +) diff --git a/tokens/tron/trondev/go.sum b/tokens/tron/trondev/go.sum new file mode 100644 index 00000000..922b4b2d --- /dev/null +++ b/tokens/tron/trondev/go.sum @@ -0,0 +1,912 @@ +bou.ke/monkey v1.0.1/go.mod h1:FgHuK96Rv2Nlf+0u1OOVDpCMdsWyOFmeeketDHE7LIg= +cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= +cloud.google.com/go v0.43.0/go.mod h1:BOSR3VbTLkk6FDC/TcffxP4NF/FFBGA5ku+jvKOP7pg= +cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= +cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= +cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= +cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= +cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= +cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= +cloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqClKRT5SZwBmk= +cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= +cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= +contrib.go.opencensus.io/exporter/stackdriver v0.12.6/go.mod h1:8x999/OcIPy5ivx/wDiV7Gx4D+VUPODf0mWRGRc5kSk= +dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= +github.com/99designs/keyring v1.1.6/go.mod h1:16e0ds7LGQQcT59QqkTg72Hh5ShM51Byv5PEmW6uoRU= +github.com/Azure/azure-pipeline-go v0.2.1/go.mod h1:UGSo8XybXnIGZ3epmeBw7Jdz+HiUVpqIlpz/HKHylF4= +github.com/Azure/azure-pipeline-go v0.2.2/go.mod h1:4rQ/NZncSvGqNkkOsNpOU1tgoNuIlp9AfUH5G1tvCHc= +github.com/Azure/azure-storage-blob-go v0.7.0/go.mod h1:f9YQKtsG1nMisotuTPpO0tjNuEjKRYAcJU8/ydDI++4= +github.com/Azure/go-autorest/autorest v0.9.0/go.mod h1:xyHB1BMZT0cuDHU7I0+g046+BFDTQ8rEZB0s4Yfa6bI= +github.com/Azure/go-autorest/autorest/adal v0.5.0/go.mod h1:8Z9fGy2MpX0PvDjB1pEgQTmVqjGhiHBW7RJJEciWzS0= +github.com/Azure/go-autorest/autorest/adal v0.8.0/go.mod h1:Z6vX6WXXuyieHAXwMj0S6HY6e6wcHn37qQMBQlvY3lc= +github.com/Azure/go-autorest/autorest/date v0.1.0/go.mod h1:plvfp3oPSKwf2DNjlBjWF/7vwR+cUD/ELuzDCXwHUVA= +github.com/Azure/go-autorest/autorest/date v0.2.0/go.mod h1:vcORJHLJEh643/Ioh9+vPmf1Ij9AEBM5FuBIXLmIy0g= +github.com/Azure/go-autorest/autorest/mocks v0.1.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0= +github.com/Azure/go-autorest/autorest/mocks v0.2.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0= +github.com/Azure/go-autorest/autorest/mocks v0.3.0/go.mod h1:a8FDP3DYzQ4RYfVAxAN3SVSiiO77gL2j2ronKKP0syM= +github.com/Azure/go-autorest/logger v0.1.0/go.mod h1:oExouG+K6PryycPJfVSxi/koC6LSNgds39diKLz7Vrc= +github.com/Azure/go-autorest/tracing v0.5.0/go.mod h1:r/s2XiOKccPW3HrqB+W0TQzfbtp2fGCgRFtBroKn4Dk= +github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= +github.com/ChainSafe/go-schnorrkel v0.0.0-20200405005733-88cbf1b4c40d/go.mod h1:URdX5+vg25ts3aCh8H5IFZybJYKWhJHYMTnf+ULtoC4= +github.com/CosmWasm/go-cosmwasm v0.10.0/go.mod h1:gAFCwllx97ejI+m9SqJQrmd2SBW7HA0fOjvWWJjM2uc= +github.com/DataDog/zstd v1.3.6-0.20190409195224-796139022798/go.mod h1:1jcaCB/ufaK+sKp1NBhlGmpz41jOoPQ35bpF36t7BBo= +github.com/GeertJohan/go.incremental v1.0.0/go.mod h1:6fAjUhbVuX1KcMD3c8TEgVUqmo4seqhv0i0kdATSkM0= +github.com/GeertJohan/go.rice v1.0.0/go.mod h1:eH6gbSOAUv07dQuZVnBmoDP8mgsM1rtixis4Tib9if0= +github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0= +github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= +github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo= +github.com/Shopify/sarama v1.23.1/go.mod h1:XLH1GYJnLVE0XCr6KdJGVJRTwY30moWNJ4sERjXX6fs= +github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI= +github.com/StackExchange/wmi v0.0.0-20180116203802-5d049714c4a6/go.mod h1:3eOhrUMpNV+6aFIbp5/iudMxNCF27Vw2OZgy4xEx0Fg= +github.com/VictoriaMetrics/fastcache v1.5.7/go.mod h1:ptDBkNMQI4RtmVo8VS/XwRY6RoTu1dAWCbrk+6WsEM8= +github.com/VividCortex/gohistogram v1.0.0/go.mod h1:Pf5mBqqDxYaXu3hDrrU+w6nw50o/4+TcAqDqk/vUH7g= +github.com/Workiva/go-datastructures v1.0.52/go.mod h1:Z+F2Rca0qCsVYDS8z7bAGm8f3UkzuWYS/oBZz5a7VVA= +github.com/aead/siphash v1.0.1/go.mod h1:Nywa3cDsYNNK3gaciGTWPwHt0wlpNV15vwmswBAUSII= +github.com/afex/hystrix-go v0.0.0-20180502004556-fa1af6a1f4f5/go.mod h1:SkGFH1ia65gfNATL8TAiHDNxPzPdmEL5uirI2Uyuz6c= +github.com/akavel/rsrc v0.8.0/go.mod h1:uLoCtb9J+EyAqh+26kdrTgmzRBFPGOolLWKpdxkKq+c= +github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/allegro/bigcache v1.2.1-0.20190218064605-e24eb225f156/go.mod h1:Cb/ax3seSYIx7SuZdm2G2xzfwmv3TPSk2ucNfQESPXM= +github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ= +github.com/apache/thrift v0.13.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ= +github.com/araddon/dateparse v0.0.0-20200409225146-d820a6159ab1/go.mod h1:SLqhdZcd+dF3TEVL2RMoob5bBP5R1P1qkox+HtCBgGI= +github.com/aristanetworks/fsnotify v1.4.2/go.mod h1:D/rtu7LpjYM8tRJphJ0hUBYpjai8SfX+aSNsWDTq/Ks= +github.com/aristanetworks/glog v0.0.0-20180419172825-c15b03b3054f/go.mod h1:KASm+qXFKs/xjSoWn30NrWBBvdTTQq+UjkhjEJHfSFA= +github.com/aristanetworks/goarista v0.0.0-20170210015632-ea17b1a17847/go.mod h1:D/tb0zPVXnP7fmsLZjtdUhSsumbK/ij54UXjjVgMGxQ= +github.com/aristanetworks/goarista v0.0.0-20191106175434-873d404c7f40 h1:ZdRuixFqR3mfx4FHzclG3COrRgWrYq0VhNgIoYoObcM= +github.com/aristanetworks/goarista v0.0.0-20191106175434-873d404c7f40/go.mod h1:Z4RTxGAuYhPzcq8+EdRM+R8M48Ssle2TsWtwRKa+vns= +github.com/aristanetworks/splunk-hec-go v0.3.3/go.mod h1:1VHO9r17b0K7WmOlLb9nTk/2YanvOEnLMUgsFrxBROc= +github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= +github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= +github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= +github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/aryann/difflib v0.0.0-20170710044230-e206f873d14a/go.mod h1:DAHtR1m6lCRdSC2Tm3DSWRPvIPr6xNKyeHdqDQSQT+A= +github.com/aws/aws-lambda-go v1.13.3/go.mod h1:4UKl9IzQMoD+QF79YdCuzCwp8VbmG4VAQwij/eHl5CU= +github.com/aws/aws-sdk-go v1.22.1/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= +github.com/aws/aws-sdk-go v1.25.48/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= +github.com/aws/aws-sdk-go v1.27.0/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= +github.com/aws/aws-sdk-go-v2 v0.18.0/go.mod h1:JWVYvqSMppoMJC0x5wdwiImzgXTI9FuZwxzkQq9wy+g= +github.com/bartekn/go-bip39 v0.0.0-20171116152956-a05967ea095d/go.mod h1:icNx/6QdFblhsEjZehARqbNumymUT/ydwlLojFdv7Sk= +github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= +github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= +github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84= +github.com/blendle/zapdriver v1.3.1/go.mod h1:mdXfREi6u5MArG4j9fewC+FGnXaBR+T4Ox4J2u4eHCc= +github.com/btcsuite/btcd v0.0.0-20171128150713-2e60448ffcc6/go.mod h1:Dmm/EzmjnCiweXmzRIAiUWCInVmPgjkzgv5k4tVyXiQ= +github.com/btcsuite/btcd v0.0.0-20190115013929-ed77733ec07d/go.mod h1:d3C0AkH6BRcvO8T0UEPu53cnw4IbV63x1bEjildYhO0= +github.com/btcsuite/btcd v0.0.0-20190824003749-130ea5bddde3/go.mod h1:3J08xEfcugPacsc34/LKRU2yO7YmuT8yt28J8k2+rrI= +github.com/btcsuite/btcd v0.20.1-beta/go.mod h1:wVuoA8VJLEcwgqHBwHmzLRazpKxTv13Px/pDuV7OomQ= +github.com/btcsuite/btcd v0.21.0-beta h1:At9hIZdJW0s9E/fAz28nrz6AmcNlSVucCH796ZteX1M= +github.com/btcsuite/btcd v0.21.0-beta/go.mod h1:ZSWyehm27aAuS9bvkATT+Xte3hjHZ+MRgMY/8NJ7K94= +github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f/go.mod h1:TdznJufoqS23FtqVCzL0ZqgP5MqXbb4fg/WgDys70nA= +github.com/btcsuite/btcutil v0.0.0-20180706230648-ab6388e0c60a/go.mod h1:+5NJ2+qvTyV9exUAL/rxXi3DcLg2Ts+ymUAY5y4NvMg= +github.com/btcsuite/btcutil v0.0.0-20190425235716-9e5f4b9a998d/go.mod h1:+5NJ2+qvTyV9exUAL/rxXi3DcLg2Ts+ymUAY5y4NvMg= +github.com/btcsuite/btcutil v1.0.2/go.mod h1:j9HUFwoQRsZL3V4n+qG+CUnEGHOarIxfC3Le2Yhbcts= +github.com/btcsuite/btcwallet/wallet/txauthor v1.0.0/go.mod h1:VufDts7bd/zs3GV13f/lXc/0lXrPnvxD/NvmpG/FEKU= +github.com/btcsuite/btcwallet/wallet/txrules v1.0.0/go.mod h1:UwQE78yCerZ313EXZwEiu3jNAtfXj2n2+c8RWiE/WNA= +github.com/btcsuite/btcwallet/wallet/txsizes v1.0.0/go.mod h1:pauEU8UuMFiThe5PB3EO+gO5kx87Me5NvdQDsTuq6cs= +github.com/btcsuite/go-socks v0.0.0-20170105172521-4720035b7bfd/go.mod h1:HHNXQzUsZCxOoE+CPiyCTO6x34Zs86zZUiwtpXoGdtg= +github.com/btcsuite/goleveldb v0.0.0-20160330041536-7834afc9e8cd/go.mod h1:F+uVaaLLH7j4eDXPRvw78tMflu7Ie2bzYOH4Y8rRKBY= +github.com/btcsuite/goleveldb v1.0.0/go.mod h1:QiK9vBlgftBg6rWQIj6wFzbPfRjiykIEhBH4obrXJ/I= +github.com/btcsuite/snappy-go v0.0.0-20151229074030-0bdef8d06723/go.mod h1:8woku9dyThutzjeg+3xrA5iCpBRH8XEEg3lh6TiUghc= +github.com/btcsuite/snappy-go v1.0.0/go.mod h1:8woku9dyThutzjeg+3xrA5iCpBRH8XEEg3lh6TiUghc= +github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792/go.mod h1:ghJtEyQwv5/p4Mg4C0fgbePVuGr935/5ddU9Z3TmDRY= +github.com/btcsuite/winsvc v1.0.0/go.mod h1:jsenWakMcC0zFBFurPLEAyrnc/teJEM1O46fmI40EZs= +github.com/casbin/casbin/v2 v2.1.2/go.mod h1:YcPU1XXisHhLzuxH9coDNf2FbKpjGlbCg3n9yuLkIJQ= +github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM= +github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/cespare/cp v0.1.0/go.mod h1:SOGHArjBr4JWaSDEVpWpo/hNg6RoKrls6Oh40hiwW+s= +github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= +github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/clbanning/x2j v0.0.0-20191024224557-825249438eec/go.mod h1:jMjuTZXRI4dUb/I5gc9Hdhagfvm9+RyrPryS/auMzxE= +github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/cloudflare/cloudflare-go v0.10.2-0.20190916151808-a80f83b9add9/go.mod h1:1MxXX1Ux4x6mqPmjkUgTP1CdXIBXKX7T+Jk9Gxrmx+U= +github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= +github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= +github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8= +github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI= +github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= +github.com/coreos/bbolt v1.3.3/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= +github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= +github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= +github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= +github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= +github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= +github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= +github.com/cosmos/cosmos-sdk v0.39.2/go.mod h1:VNUluciWBFj2vkhpMcp8rYZL/kCw0FtNc7SseUjE1KM= +github.com/cosmos/go-bip39 v0.0.0-20180819234021-555e2067c45d/go.mod h1:tSxLoYXyBmiFeKpvmq4dzayMdCjCnu8uqmCysIGBT2Y= +github.com/cosmos/ledger-cosmos-go v0.11.1/go.mod h1:J8//BsAGTo3OC/vDLjMRFLW6q0WAaXvHnVc7ZmE8iUY= +github.com/cosmos/ledger-go v0.9.2/go.mod h1:oZJ2hHAZROdlHiwTg4t7kP+GKIIkBT+o6c9QWFanOyI= +github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= +github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= +github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= +github.com/daaku/go.zipexe v1.0.0/go.mod h1:z8IiR6TsVLEYKwXAoE/I+8ys/sDkgTzSL0CLnGVd57E= +github.com/danieljoos/wincred v1.0.2/go.mod h1:SnuYRW9lp1oJrZX/dXJqr0cPK5gYXqx3EJbmjhLdK9U= +github.com/davecgh/go-spew v0.0.0-20171005155431-ecdeabc65495/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/deckarep/golang-set v0.0.0-20180603214616-504e848d77ea/go.mod h1:93vsz/8Wt4joVM7c2AVqh+YRMiUSc14yDtF28KmMOgQ= +github.com/deckarep/golang-set v1.7.1 h1:SCQV0S6gTtp6itiFrTqI+pfmJ4LN85S1YzhDf9rTHJQ= +github.com/deckarep/golang-set v1.7.1/go.mod h1:93vsz/8Wt4joVM7c2AVqh+YRMiUSc14yDtF28KmMOgQ= +github.com/decred/dcrd/lru v1.0.0/go.mod h1:mxKOwFd7lFjN2GZYsiz/ecgqR6kkYAl+0pz0tEMk218= +github.com/dfuse-io/binary v0.0.0-20201123150056-096380ef3e5d/go.mod h1:GDFX6qH3BQZPWTeYaA4ZW98T94zs2skRoG3oMz/0jw0= +github.com/dfuse-io/binary v0.0.0-20210216024852-4ae6830a495d/go.mod h1:GDFX6qH3BQZPWTeYaA4ZW98T94zs2skRoG3oMz/0jw0= +github.com/dfuse-io/logging v0.0.0-20201110202154-26697de88c79/go.mod h1:V+ED4kT/t/lKtH99JQmKIb0v9WL3VaYkJ36CfHlVECI= +github.com/dfuse-io/solana-go v0.2.0/go.mod h1:JmxX8KYNWRCwg1RyADE2kersXSNqE1KLt+w5nEq353g= +github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= +github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= +github.com/dlclark/regexp2 v1.2.0/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc= +github.com/docker/docker v1.4.2-0.20180625184442-8e610b2b55bf/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/dop251/goja v0.0.0-20200219165308-d1232e640a87/go.mod h1:Mw6PkjjMXWbTj+nnj4s3QPXq1jaT0s5pC0iFD4+BOAA= +github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= +github.com/dvsekhvalnov/jose2go v0.0.0-20200901110807-248326c1351b/go.mod h1:7BvyPhdbLxMXIYTFPLsyJRFMsKmOZnQmzh6Gb+uquuM= +github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs= +github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU= +github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I= +github.com/edsrzf/mmap-go v0.0.0-20160512033002-935e0e8a636c/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M= +github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M= +github.com/envoyproxy/go-control-plane v0.6.9/go.mod h1:SBwIajubJHhxtWwsL9s8ss4safvEdbitLhGGK48rN6g= +github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= +github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= +github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/ethereum/go-ethereum v1.9.20 h1:kk/J5OIoaoz3DRrCXznz3RGi212mHHXwzXlY/ZQxcj0= +github.com/ethereum/go-ethereum v1.9.20/go.mod h1:JSSTypSMTkGZtAdAChH2wP5dZEvPGh3nUTuDpH+hNrg= +github.com/facebookgo/ensure v0.0.0-20160127193407-b4ab57deab51/go.mod h1:Yg+htXGokKKdzcwhuNDwVvN+uBxDGXJ7G/VN1d8fa64= +github.com/facebookgo/stack v0.0.0-20160209184415-751773369052/go.mod h1:UbMTZqLaRiH3MsBH8va0n7s1pQYcu3uTb8G4tygF4Zg= +github.com/facebookgo/subset v0.0.0-20150612182917-8dac2c3c4870/go.mod h1:5tD+neXqOorC30/tWg0LCSkrqj/AR6gu8yY8/fpw1q0= +github.com/fastly/go-utils v0.0.0-20180712184237-d95a45783239/go.mod h1:Gdwt2ce0yfBxPvZrHkprdPPTTS3N5rwmLE8T22KBXlw= +github.com/fatih/color v1.3.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU= +github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M= +github.com/fbsobreira/gotron-sdk v0.0.0-20210316163828-8cb47d581197 h1:ExhXsDBcQpgdcxQyiY77JTUfQS1nbo6lOllBurALbR0= +github.com/fbsobreira/gotron-sdk v0.0.0-20210316163828-8cb47d581197/go.mod h1:k2Ei1n5T6T7YRLz9Cv8IJi7Q4kmHSLoJS7Nglsrec5k= +github.com/felixge/httpsnoop v1.0.1/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= +github.com/fjl/memsize v0.0.0-20180418122429-ca190fb6ffbc/go.mod h1:VvhXpOYNQvB+uIk2RvXzuaQtkQJzzIx6lSBe1xv7hi0= +github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g= +github.com/franela/goblin v0.0.0-20200105215937-c9ffbefa60db/go.mod h1:7dvUGVsVBjqR7JHJk0brhHOZYGmfBYOrK0ZhYMEtBr4= +github.com/franela/goreq v0.0.0-20171204163338-bcd34c9993f8/go.mod h1:ZhphrRTfi2rbfLwlschooIH4+wKKDR4Pdxhh+TRoA20= +github.com/fsn-dev/fsn-go-sdk v0.0.0-20201127063150-d66d045799f9/go.mod h1:MtL34MP65N4fVCkYHlaXabn0mKKVOZZL2hRRS7L16ak= +github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= +github.com/garyburd/redigo v1.6.0/go.mod h1:NR3MbYisc3/PwhQ00EMzDiPmrwpPxAn5GI05/YaO1SY= +github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff/go.mod h1:x7DCsMOv1taUwEWCzT4cmDeAkigA5/QCwUodaVOe8Ww= +github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= +github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/kit v0.10.0/go.mod h1:xUsJbQ/Fp4kEt7AFgCuvyX4a71u8h9jB8tj/ORgOZ7o= +github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= +github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= +github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= +github.com/go-ole/go-ole v1.2.1/go.mod h1:7FAglXiTm7HKlQRDeOQ6ZNUHidzCWXuZWq/1dTyBNF8= +github.com/go-resty/resty/v2 v2.5.0/go.mod h1:B88+xCTEwvfD94NOuE6GS1wMlnoKNY8eEiNizfNwOwA= +github.com/go-sourcemap/sourcemap v2.1.2+incompatible/go.mod h1:F8jJfvm2KbVjc5NqelyYJmf/v5J0dwNLS2mL4sNA1Jg= +github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= +github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2/go.mod h1:bBOAhwG1umN6/6ZUMtDFBMQR8jRg9O75tm9K00oMsK4= +github.com/gogo/googleapis v1.1.0/go.mod h1:gf4bu3Q80BeJ6H1S1vYPm8/ELATdvryBaNFGgqEef3s= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= +github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:tluoj9z5200jBnyusfRPU2LqT6J+DAorxEvtC7LHB+E= +github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.3.1-0.20190508161146-9fa652df1129/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= +github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.0/go.mod h1:Qd/q+1AKNOZr9uGQzbzCmRO6sUih6GTPZv6a1/R87v0= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2-0.20190517061210-b285ee9cfc6c/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= +github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= +github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= +github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= +github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= +github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= +github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/golang/snappy v0.0.2-0.20200707131729-196ae77b8a26/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/golang/snappy v0.0.2/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/golang/snappy v0.0.3-0.20201103224600-674baa8c7fc3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= +github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/gofuzz v0.0.0-20170612174753-24818f796faf/go.mod h1:HP5RmnzzSNb993RKQDq4+1A4ia9nllfqcQFTQJedwGI= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/gofuzz v1.1.1-0.20200604201612-c04b05f3adfa/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= +github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= +github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.1.2 h1:EVhdT+1Kseyi1/pUmXKaFxYsDNy9RQYkMWRH68J/W7Y= +github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= +github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= +github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg= +github.com/gorilla/handlers v1.4.2/go.mod h1:Qkdc/uu4tH4g6mTK6auzZ766c4CA0Ng8+o/OAirnOIQ= +github.com/gorilla/handlers v1.5.1/go.mod h1:t8XrUpc4KVXb7HGyJ4/cEnwQiaxrX/hz1Zv/4g96P1Q= +github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= +github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= +github.com/gorilla/mux v1.7.4/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= +github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= +github.com/gorilla/rpc v1.2.0/go.mod h1:V4h9r+4sF5HnzqbwIez0fKSpANP0zlYd3qR7p36jkTQ= +github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= +github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= +github.com/gorilla/websocket v1.4.1-0.20190629185528-ae1634f6a989/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= +github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/graph-gophers/graphql-go v0.0.0-20191115155744-f33e81362277/go.mod h1:9CQHMSxwO4MprSdzoIEobiHpoLtHm77vfxsvsIN5Vuc= +github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= +github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= +github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= +github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= +github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= +github.com/gsterjov/go-libsecret v0.0.0-20161001094733-a6f4afe4910c/go.mod h1:NMPJylDgVpX0MLRlPy15sqSwOFv/U1GZ2m21JhFfek0= +github.com/gtank/merlin v0.1.1-0.20191105220539-8318aed1a79f/go.mod h1:T86dnYJhcGOh5BjZFCJWTDeTK7XW8uE+E21Cy/bIQ+s= +github.com/gtank/merlin v0.1.1/go.mod h1:T86dnYJhcGOh5BjZFCJWTDeTK7XW8uE+E21Cy/bIQ+s= +github.com/gtank/ristretto255 v0.1.2/go.mod h1:Ph5OpO6c7xKUGROZfWVLiJf9icMDwUeIvY4OmlYW69o= +github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q= +github.com/hashicorp/consul/api v1.3.0/go.mod h1:MmDNSzIMUjNpY/mQ398R4bk2FnqQLoPndWW5VkKPlCE= +github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= +github.com/hashicorp/consul/sdk v0.3.0/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= +github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= +github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= +github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= +github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU= +github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU= +github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4= +github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= +github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90= +github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.3/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= +github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= +github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= +github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64= +github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ= +github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I= +github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc= +github.com/holiman/uint256 v1.1.1/go.mod h1:y4ga/t+u+Xwd7CpDgZESaRcWy0I7XMlTMA25ApIH5Jw= +github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= +github.com/hudl/fargo v1.3.0/go.mod h1:y3CKSmjA+wD2gak7sUSXTAoopbhU08POFhmITJgmKTg= +github.com/huin/goupnp v1.0.0/go.mod h1:n9v9KO1tAxYH82qOn+UTIFQDmx5n1Zxd/ClZDMX7Bnc= +github.com/huin/goutil v0.0.0-20170803182201-1ca381bf3150/go.mod h1:PpLOETDnJ0o3iZrZfqZzyLl6l7F3c6L1oWn7OICBi6o= +github.com/inconshreveable/log15 v0.0.0-20180818164646-67afb5ed74ec/go.mod h1:cOaXtrgN4ScfRrD9Bre7U1thNq5RtJ8ZoP4iXVGRj6o= +github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= +github.com/influxdata/influxdb v1.2.3-0.20180221223340-01288bdb0883/go.mod h1:qZna6X/4elxqT3yI9iZYdZrWWdeFOOprn86kgg4+IzY= +github.com/influxdata/influxdb1-client v0.0.0-20190809212627-fc22c7df067e/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo= +github.com/influxdata/influxdb1-client v0.0.0-20191209144304-8bf82d3c094d/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo= +github.com/jackpal/go-nat-pmp v1.0.2-0.20160603034137-1fa385a6f458/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc= +github.com/jcmturner/gofork v0.0.0-20190328161633-dc7c13fece03/go.mod h1:MK8+TM0La+2rjBD4jE12Kj1pCCxK7d2LK/UM3ncEo0o= +github.com/jehiah/go-strftime v0.0.0-20171201141054-1d33003b3869/go.mod h1:cJ6Cj7dQo+O6GJNiMx+Pa94qKj+TG8ONdKHgMNIyyag= +github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= +github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= +github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= +github.com/jmhodges/levigo v1.0.0/go.mod h1:Q6Qx+uH3RAqyK4rFQroq9RL7mdkABMcfhEI+nNuzMJQ= +github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= +github.com/jonboulle/clockwork v0.2.2/go.mod h1:Pkfl5aHPm1nk2H9h0bjmnJD/BcgbGXUBGnn1kMkgxc8= +github.com/jordan-wright/email v0.0.0-20200917010138-e1c00e156980/go.mod h1:1c7szIrayyPPB/987hsnvNzLushdWf4o/79s3P08L8A= +github.com/jrick/logrotate v1.0.0/go.mod h1:LNinyqDIJnpAur+b8yyulnQw/wDuN1+BYKlTRt3OuAQ= +github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= +github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= +github.com/julienschmidt/httprouter v1.1.1-0.20170430222011-975b5c4c7c21/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/karalabe/hid v1.0.0/go.mod h1:Vr51f8rUOLYrfrWDFlV12GGQgM5AT8sVh+2fY4MPeu8= +github.com/karalabe/usb v0.0.0-20190919080040-51dc0efba356/go.mod h1:Od972xHfMJowv7NGVDiWVxk2zxnWgjLlJzE+F4F7AGU= +github.com/keybase/go-keychain v0.0.0-20190712205309-48d3d31d256d/go.mod h1:JJNrCn9otv/2QP4D7SMJBgaleKpOf66PnW6F5WGNRIc= +github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= +github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/kkdai/bstream v0.0.0-20161212061736-f391b8402d23/go.mod h1:J+Gs4SYgM6CZQHDETBtE9HaSEkGmuNXF86RwHhHUvq4= +github.com/kkdai/bstream v0.0.0-20181106074824-b3251f7901ec/go.mod h1:J+Gs4SYgM6CZQHDETBtE9HaSEkGmuNXF86RwHhHUvq4= +github.com/kkdai/bstream v1.0.0/go.mod h1:FDnDOHt5Yx4p3FaHcioFT0QjDOtgUpvjeZqAs+NVZZA= +github.com/klauspost/cpuid v1.2.1/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= +github.com/klauspost/reedsolomon v1.9.2/go.mod h1:CwCi+NUr9pqSVktrkN+Ondf06rkhYZ/pcNv7fu+8Un4= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= +github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= +github.com/lestrrat-go/envload v0.0.0-20180220234015-a3eb8ddeffcc/go.mod h1:kopuH9ugFRkIXf3YoqHKyrJ9YfUFsckUU9S7B+XP+is= +github.com/lestrrat-go/file-rotatelogs v2.4.0+incompatible/go.mod h1:ZQnN8lSECaebrkQytbHj4xNgtg8CR7RYXnPok8e0EHA= +github.com/lestrrat-go/strftime v1.0.3/go.mod h1:E1nN3pCbtMSu1yjSVeyuRFVm/U0xoR76fd03sz+Qz4g= +github.com/libp2p/go-buffer-pool v0.0.2/go.mod h1:MvaB6xw5vOrDl8rYZGLFdKAuk/hRoRZd1Vi32+RXyFM= +github.com/lightninglabs/gozmq v0.0.0-20191113021534-d20a764486bf/go.mod h1:vxmQPeIQxPf6Jf9rM8R+B4rKBqLA2AjttNxkFBL2Plk= +github.com/lightstep/lightstep-tracer-common/golang/gogo v0.0.0-20190605223551-bc2310a04743/go.mod h1:qklhhLq1aX+mtWk9cPHPzaBjWImj5ULL6C7HFJtXQMM= +github.com/lightstep/lightstep-tracer-go v0.18.1/go.mod h1:jlF1pusYV4pidLvZ+XD0UBX0ZE6WURAspgAczcDHrL4= +github.com/logrusorgru/aurora v2.0.3+incompatible/go.mod h1:7rIyQOR62GCctdiQpZ/zOJlFyk6y+94wXzv6RNZgaR4= +github.com/ltcsuite/lnd/queue v1.0.3/go.mod h1:L0MMGRrsJFPHhTInek8YgW2v7NyB6pXrAh6Bbg2D7u8= +github.com/ltcsuite/lnd/ticker v1.0.1/go.mod h1:WZKpekfDVAVv7Gsrr0GAWC/U1XURfGesFg9sQYJbeL4= +github.com/ltcsuite/ltcd v0.20.1-beta/go.mod h1:ZFQaYdYULIuTQiWqs7AUiHD2XhDFeeHW1IH+UYMdABU= +github.com/ltcsuite/ltclog v0.0.0-20160817181405-73889fb79bd6/go.mod h1:0vobaAoyUrwaVFd11+PtAx4afDrzzyFopOaky5ytLBw= +github.com/ltcsuite/ltcutil v0.0.0-20190425235716-9e5f4b9a998d/go.mod h1:8Vg/LTOO0KYa/vlHWJ6XZAevPQThGH5sufO0Hrou/lA= +github.com/ltcsuite/ltcutil v0.0.0-20191227053721-6bec450ea6ad/go.mod h1:8Vg/LTOO0KYa/vlHWJ6XZAevPQThGH5sufO0Hrou/lA= +github.com/ltcsuite/ltcutil v1.0.2-beta/go.mod h1:G1JGpaqtMm0mPtheTryXnDd9a4KAFuGevdQirlJO1Nw= +github.com/ltcsuite/ltcwallet v0.11.1-beta/go.mod h1:NDOrqKG1Wo5f9WbKzEW0oQFRcFrA6znu+zFYgmFvyJE= +github.com/ltcsuite/ltcwallet/wallet/txauthor v1.0.0/go.mod h1:4kj4pIFY9uVuroAn6rjLaFdMTxxXrwQwvU3iw8qurOg= +github.com/ltcsuite/ltcwallet/wallet/txrules v1.0.0/go.mod h1:H/FiHbbfd9+TPn9ao1Ier7rBosT5j2ejIbHvZqHSEVU= +github.com/ltcsuite/ltcwallet/wallet/txsizes v1.0.0/go.mod h1:BVSZSGrQP4MXD7Y3vVVZ1TiabQmzmkeYngSfz7DD34o= +github.com/ltcsuite/ltcwallet/walletdb v1.2.0/go.mod h1:C4GeXkLjUw1zkKiUwTvqSKE0eJmFjM7FZBjjw6TglJw= +github.com/ltcsuite/ltcwallet/wtxmgr v1.0.0/go.mod h1:mEc+C10DLTHG6iaDnBUlulZGADd1QMe+gZOiCNo/qcg= +github.com/ltcsuite/neutrino v0.11.0/go.mod h1:22zulMl4XMtJJb/7Z8YR3oud1EqfbQ2oSYE4gMnNVfM= +github.com/lyft/protoc-gen-validate v0.0.13/go.mod h1:XbGvPuh87YZc5TdIa2/I4pLk0QoUACkjt2znoq26NVQ= +github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= +github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= +github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +github.com/mattn/go-colorable v0.1.0/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= +github.com/mattn/go-ieproxy v0.0.0-20190610004146-91bb50d98149/go.mod h1:31jz6HNzdxOmlERGGEc4v/dMssOfmp2p5bT/okiKFFc= +github.com/mattn/go-ieproxy v0.0.0-20190702010315-6dee0af9227d/go.mod h1:31jz6HNzdxOmlERGGEc4v/dMssOfmp2p5bT/okiKFFc= +github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-isatty v0.0.5-0.20180830101745-3fb116b82035/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= +github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84= +github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE= +github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= +github.com/mattn/go-runewidth v0.0.3/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= +github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= +github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= +github.com/mimoo/StrobeGo v0.0.0-20181016162300-f8f6d4d2b643/go.mod h1:43+3pMjjKimDBf5Kr4ZFNGbLql1zKkbImw+fZbw3geM= +github.com/minio/highwayhash v1.0.0/go.mod h1:xQboMTeM9nY9v/LlAOxFctujiv5+Aq2hR5dxBpaMbdc= +github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= +github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= +github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= +github.com/mitchellh/go-testing-interface v1.14.1/go.mod h1:gfgS7OtZj6MA4U1UrDRp04twqAjfvlZyCfX3sDjEym8= +github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg= +github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY= +github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/mr-tron/base58 v1.2.0/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= +github.com/mtibben/percent v0.2.1/go.mod h1:KG9uO+SZkUp+VkRHsCdYQV3XSZrrSpR3O9ibNBTZrns= +github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/naoina/go-stringutil v0.1.0/go.mod h1:XJ2SJL9jCtBh+P9q5btrd/Ylo8XwT/h1USek5+NqSA0= +github.com/naoina/toml v0.1.2-0.20170918210437-9fafd6967416/go.mod h1:NBIhNtsFMo3G2szEBne+bO4gS192HuIYRqfvOWb4i1E= +github.com/nats-io/jwt v0.3.0/go.mod h1:fRYCDE99xlTsqUzISS1Bi75UBJ6ljOJQOAAu5VglpSg= +github.com/nats-io/jwt v0.3.2/go.mod h1:/euKqTS1ZD+zzjYrY7pseZrTtWQSjujC7xjPc8wL6eU= +github.com/nats-io/nats-server/v2 v2.1.2/go.mod h1:Afk+wRZqkMQs/p45uXdrVLuab3gwv3Z8C4HTBu8GD/k= +github.com/nats-io/nats.go v1.9.1/go.mod h1:ZjDU1L/7fJ09jvUSRVBR2e7+RnLiiIQyqyzEE/Zbp4w= +github.com/nats-io/nkeys v0.1.0/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w= +github.com/nats-io/nkeys v0.1.3/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w= +github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c= +github.com/nkovacs/streamquote v0.0.0-20170412213628-49af9bddb229/go.mod h1:0aYXnNPJ8l7uZxf45rWW1a/uME32OF0rhiYGNQ2oF2E= +github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= +github.com/oklog/oklog v0.3.2/go.mod h1:FCV+B7mhrz4o+ueLpx+KqkyXRGMWOYEvfiXtdGtbWGs= +github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA= +github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= +github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= +github.com/olekukonko/tablewriter v0.0.1/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= +github.com/olekukonko/tablewriter v0.0.2-0.20190409134802-7e037d187b0c/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= +github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.10.1/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= +github.com/onsi/gomega v1.4.1/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= +github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= +github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= +github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk= +github.com/openconfig/gnmi v0.0.0-20190823184014-89b2bf29312c/go.mod h1:t+O9It+LKzfOAhKTT5O0ehDix+MTqbtT0T9t+7zzOvc= +github.com/openconfig/reference v0.0.0-20190727015836-8dfd928c9696/go.mod h1:ym2A+zigScwkSEb/cVQB0/ZMpU3rqiH6X7WRRsxgOGw= +github.com/opentracing-contrib/go-observer v0.0.0-20170622124052-a52f23424492/go.mod h1:Ngi6UdF0k5OKD5t5wlmGhe/EDKPoUM3BXZSSfIuJbis= +github.com/opentracing/basictracer-go v1.0.0/go.mod h1:QfBfYuafItcjQuMwinw9GhYKwFXS9KnPs5lxoYwgW74= +github.com/opentracing/opentracing-go v1.0.2/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= +github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= +github.com/openzipkin-contrib/zipkin-go-opentracing v0.4.5/go.mod h1:/wsWhb9smxSfWAKL3wpBW7V8scJMt8N8gnaMCS9E/cA= +github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw= +github.com/openzipkin/zipkin-go v0.2.1/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4= +github.com/openzipkin/zipkin-go v0.2.2/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4= +github.com/otiai10/copy v1.0.2/go.mod h1:c7RpqBkwMom4bYTSkLSym4VSJz/XtncWRAj/J4PEIMY= +github.com/otiai10/curr v0.0.0-20150429015615-9b4961190c95/go.mod h1:9qAhocn7zKJG+0mI8eUu6xqkFDYS2kb2saOteoSB3cE= +github.com/otiai10/curr v0.0.0-20190513014714-f5a3d24e5776/go.mod h1:3HNVkVOU7vZeFXocWuvtcS0XSFLcf2XUSDHkq9t1jU4= +github.com/otiai10/mint v1.2.4/go.mod h1:d+b7n/0R3tdyUYYylALXpWQ/kTN+QobSq/4SRGBkR3M= +github.com/otiai10/mint v1.3.0/go.mod h1:F5AjcsTsWUqX+Na9fpHb52P8pcRX2CI6A3ctIT91xUo= +github.com/pact-foundation/pact-go v1.0.4/go.mod h1:uExwJY4kCzNPcHRj+hCR/HBbOOIwwtUjcrb0b5/5kLM= +github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= +github.com/pborman/uuid v0.0.0-20170112150404-1b00554d8222/go.mod h1:VyrYX9gd7irzKovcSS6BIIEwPRkP2Wm2m9ufcdFSJ34= +github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k= +github.com/pborman/uuid v1.2.1 h1:+ZZIw58t/ozdjRaXh/3awHfmWRbzYxJoAdNJxe/3pvw= +github.com/pborman/uuid v1.2.1/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k= +github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= +github.com/pelletier/go-toml v1.6.0/go.mod h1:5N711Q9dKgbdkxHL+MEfF31hpT7l0S0s/t2kKREewys= +github.com/performancecopilot/speed v3.0.0+incompatible/go.mod h1:/CLtqpZ5gBg1M9iaPbIdPPGyKcA8hKdoy6hAWba7Yac= +github.com/peterh/liner v1.1.0/go.mod h1:CRroGNssyjTd/qIG2FyxByd2S8JEAZXBl4qUrZf8GS0= +github.com/peterh/liner v1.1.1-0.20190123174540-a2c9a5303de7/go.mod h1:CRroGNssyjTd/qIG2FyxByd2S8JEAZXBl4qUrZf8GS0= +github.com/pierrec/lz4 v0.0.0-20190327172049-315a67e90e41/go.mod h1:3/3N9NVKO0jef7pBehbT1qWhCMrIgbYNnFAZCqQ5LRc= +github.com/pierrec/lz4 v1.0.2-0.20190131084431-473cd7ce01a1/go.mod h1:3/3N9NVKO0jef7pBehbT1qWhCMrIgbYNnFAZCqQ5LRc= +github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/profile v1.2.1/go.mod h1:hJw3o1OdXxsrSjjVksARp5W95eeEaEfptyVZyv6JUPA= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= +github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs= +github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso= +github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= +github.com/prometheus/client_golang v1.1.0/go.mod h1:I1FGZT9+L76gKKOs5djB6ezCbFQP1xR9D75/vuwEF3g= +github.com/prometheus/client_golang v1.3.0/go.mod h1:hJaj2vgQTGQmVCsAACORcieXFeDPbaTKGT+JTgUa3og= +github.com/prometheus/client_golang v1.5.1/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.1.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= +github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.6.0/go.mod h1:eBmuwkDJBwy6iBfxCBob6t6dR6ENT/y+J+Zk0j9GMYc= +github.com/prometheus/common v0.7.0/go.mod h1:DjGbpBbp5NYNiECxcL/VnbXCCaQpKd3tt26CguLLsqA= +github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= +github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.0.3/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ= +github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= +github.com/prometheus/tsdb v0.6.2-0.20190402121629-4f204dcbc150/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= +github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= +github.com/rakyll/statik v0.1.6/go.mod h1:OEi9wJV/fMUAGx1eNjq75DKDsJVuEv1U0oYdX6GX8Zs= +github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= +github.com/rcrowley/go-metrics v0.0.0-20200313005456-10cdbea86bc0/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= +github.com/rjeczalik/notify v0.9.1/go.mod h1:rKwnCoCGeuQnwBtTSPL9Dad03Vh2n40ePRrjvIXnJho= +github.com/rjeczalik/notify v0.9.2 h1:MiTWrPj55mNDHEiIX5YUSKefw/+lCQVoAFmD6oQm5w8= +github.com/rjeczalik/notify v0.9.2/go.mod h1:aErll2f0sUX9PXZnVNyeiObbmTlk5jnMoCa4QEjJeqM= +github.com/robertkrimen/otto v0.0.0-20180617131154-15f95af6e78d/go.mod h1:xvqspoSXJTIpemEonrMDFq6XzwHYYgToXWj5eRX1OtY= +github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= +github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/rs/cors v0.0.0-20160617231935-a62a804a8a00/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU= +github.com/rs/cors v1.7.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU= +github.com/rs/xhandler v0.0.0-20160618193221-ed27b6fd6521/go.mod h1:RvLn4FgxWubrpZHtQLnOf6EwhN2hEMusxZOhcW9H3UQ= +github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= +github.com/samuel/go-zookeeper v0.0.0-20190923202752-2cc03de413da/go.mod h1:gi+0XIa01GRL2eRQVjQkKGqKF3SF9vZR/HnPullcV2E= +github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= +github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= +github.com/shengdoushi/base58 v1.0.0 h1:tGe4o6TmdXFJWoI31VoSWvuaKxf0Px3gqa3sUWhAxBs= +github.com/shengdoushi/base58 v1.0.0/go.mod h1:m5uIILfzcKMw6238iWAhP4l3s5+uXyF3+bJKUNhAL9I= +github.com/shirou/gopsutil v2.20.5+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA= +github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= +github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= +github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= +github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= +github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= +github.com/snikch/goodman v0.0.0-20171125024755-10e37e294daa/go.mod h1:oJyF+mSPHbB5mVY2iO9KV3pTt/QbIkGaO8gQ2WrDbP4= +github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= +github.com/sony/gobreaker v0.4.1/go.mod h1:ZKptC7FHNvhBz7dN2LGjPVBz2sZJmc0/PkyDJOjmxWY= +github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= +github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= +github.com/spf13/afero v1.2.1/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk= +github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= +github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= +github.com/spf13/cobra v1.0.0/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE= +github.com/spf13/cobra v1.1.1/go.mod h1:WnodtKOvamDL/PwE2M4iKs8aMDBZ5Q5klgD3qfVJQMI= +github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= +github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo= +github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE= +github.com/spf13/viper v1.6.3/go.mod h1:jUMtyi0/lB5yZH/FjyGAoH7IMNrIhlBf6pXZmbMDvzw= +github.com/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg= +github.com/spf13/viper v1.7.1/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg= +github.com/status-im/keycard-go v0.0.0-20190316090335-8537d3370df4/go.mod h1:RZLeN1LMWmRsyYjvAu+I6Dm9QmlDaIIt+Y+4Kd7Tp+Q= +github.com/steakknife/bloomfilter v0.0.0-20180922174646-6819c0d2a570/go.mod h1:8OR4w3TdeIHIh1g6EMY5p0gVNOovcWC+1vpc7naMuAw= +github.com/steakknife/hamming v0.0.0-20180906055917-c99c65617cd3/go.mod h1:hpGUWaI9xL8pRQCTXQgocU38Qw1g0Us7n5PxxTwTCYU= +github.com/streadway/amqp v0.0.0-20190404075320-75d898a42a94/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= +github.com/streadway/amqp v0.0.0-20190827072141-edfb9018d271/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= +github.com/streadway/handy v0.0.0-20190108123426-d5acb3125c2a/go.mod h1:qNTQ5P5JnDBl6z3cMAg/SywNDC5ABu5ApDIw6lUbRmI= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= +github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= +github.com/syndtr/goleveldb v1.0.1-0.20190923125748-758128399b1d/go.mod h1:9OrXJhf154huy1nPWmuSrkgjPUtUNhA+Zmy+6AESzuA= +github.com/tebeka/strftime v0.1.5/go.mod h1:29/OidkoWHdEKZqzyDLUyC+LmgDgdHo4WAFCDT7D/Ig= +github.com/tecbot/gorocksdb v0.0.0-20191217155057-f0fad39f321c/go.mod h1:ahpPrc7HpcfEWDQRZEmnXMzHY03mLDYMCxeDzy46i+8= +github.com/templexxx/cpufeat v0.0.0-20180724012125-cef66df7f161/go.mod h1:wM7WEvslTq+iOEAMDLSzhVuOt5BRZ05WirO+b09GHQU= +github.com/templexxx/xor v0.0.0-20181023030647-4e92f724b73b/go.mod h1:5XA7W9S6mni3h5uvOC75dA3m9CCCaS83lltmc0ukdi4= +github.com/tendermint/btcd v0.1.1/go.mod h1:DC6/m53jtQzr/NFmMNEu0rxf18/ktVoVtMrnDD5pN+U= +github.com/tendermint/crypto v0.0.0-20191022145703-50d29ede1e15/go.mod h1:z4YtwM70uOnk8h0pjJYlj3zdYwi9l03By6iAIF5j/Pk= +github.com/tendermint/go-amino v0.14.1/go.mod h1:i/UKE5Uocn+argJJBb12qTZsCDBcAYMbR92AaJVmKso= +github.com/tendermint/go-amino v0.15.1/go.mod h1:TQU0M1i/ImAo+tYpZi73AU3V/dKeCoMC9Sphe2ZwGME= +github.com/tendermint/go-amino v0.16.0/go.mod h1:TQU0M1i/ImAo+tYpZi73AU3V/dKeCoMC9Sphe2ZwGME= +github.com/tendermint/iavl v0.14.1/go.mod h1:QmfViflFiXzxKLQE4tAUuWQHq+RSuQFxablW5oJZ6sE= +github.com/tendermint/tendermint v0.33.5/go.mod h1:0yUs9eIuuDq07nQql9BmI30FtYGcEC60Tu5JzB5IezM= +github.com/tendermint/tendermint v0.33.9/go.mod h1:0yUs9eIuuDq07nQql9BmI30FtYGcEC60Tu5JzB5IezM= +github.com/tendermint/tm-db v0.5.1/go.mod h1:g92zWjHpCYlEvQXvy9M168Su8V1IBEeawpXVVBaK4f4= +github.com/teris-io/shortid v0.0.0-20171029131806-771a37caa5cf/go.mod h1:M8agBzgqHIhgj7wEn9/0hJUZcrvt9VY+Ln+S1I5Mha0= +github.com/terra-project/core v0.4.2/go.mod h1:U8uN91QNHhKiCMRZtPpvQ637IJt2udDjhzIO3rUhUqE= +github.com/tidwall/gjson v1.6.3/go.mod h1:BaHyNc5bjzYkPqgLq7mdVzeiRtULKULXLgZFKsxEHI0= +github.com/tidwall/match v1.0.1/go.mod h1:LujAq0jyVjBy028G1WhWfIzbpQfMO8bBZ6Tyb0+pL9E= +github.com/tidwall/pretty v1.0.2/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= +github.com/tjfoc/gmsm v1.0.1/go.mod h1:XxO4hdhhrzAd+G4CjDqaOkd0hUzmtPR/d3EiBBMn/wc= +github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= +github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= +github.com/tyler-smith/go-bip39 v1.0.1-0.20181017060643-dbb3b84ba2ef/go.mod h1:sJ5fKU0s6JVwZjjcUEX2zFOnvq0ASQ2K9Zr6cf67kNs= +github.com/tyler-smith/go-bip39 v1.0.2 h1:+t3w+KwLXO6154GNJY+qUtIxLTmFjfUmpguQT1OlOT8= +github.com/tyler-smith/go-bip39 v1.0.2/go.mod h1:sJ5fKU0s6JVwZjjcUEX2zFOnvq0ASQ2K9Zr6cf67kNs= +github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= +github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= +github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= +github.com/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/XcUArI= +github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= +github.com/valyala/fasttemplate v1.0.1/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8= +github.com/wsddn/go-ecdh v0.0.0-20161211032359-48726bab9208/go.mod h1:IotVbo4F+mw0EzQ08zFqg7pK3FebNXpaMsRy2RT+Ees= +github.com/xdg/scram v0.0.0-20180814205039-7eeb5667e42c/go.mod h1:lB8K/P019DLNhemzwFU4jHLhdvlE6uDZjXFejJXr49I= +github.com/xdg/stringprep v1.0.0/go.mod h1:Jhud4/sHMO4oL310DaZAKk9ZaJ08SJfe+sJh0HrGL1Y= +github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= +github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= +github.com/xtaci/kcp-go v5.4.5+incompatible/go.mod h1:bN6vIwHQbfHaHtFpEssmWsN45a+AZwO7eyRCmEIbtvE= +github.com/xtaci/lossyconn v0.0.0-20190602105132-8df528c0c9ae/go.mod h1:gXtu8J62kEgmN++bm9BVICuT/e8yiLI2KFobd/TRFsE= +github.com/ybbus/jsonrpc v2.1.2+incompatible/go.mod h1:XJrh1eMSzdIYFbM08flv0wp5G35eRniyeGut1z+LSiE= +github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/zondax/hid v0.9.0/go.mod h1:l5wttcP0jwtdLjqjMMWFVEE7d1zO0jvSPA9OPZxWpEM= +go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= +go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= +go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738/go.mod h1:dnLIgRNXwCJa5e+c6mIZCrds/GIG4ncV9HhK5PX7jPg= +go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= +go.opencensus.io v0.20.2/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= +go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= +go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= +go.opencensus.io v0.22.1/go.mod h1:Ap50jQcDJrx6rB6VgeeFPtuPIf3wMRvRfrfYDO6+BmA= +go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= +go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= +go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= +go.uber.org/atomic v1.6.0 h1:Ezj3JGmsOnG1MoRWQkPBsKLe9DwWD9QeXzTRzzldNVk= +go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= +go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= +go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4= +go.uber.org/multierr v1.5.0 h1:KCa4XfM8CWFCpxXRGok+Q0SS/0XBhMDbHHGABQLvD2A= +go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU= +go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee h1:0mgffUl7nfd+FpvXMVz4IDEaUSmT1ysygQC7qYo7sG4= +go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= +go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= +go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM= +go.uber.org/zap v1.14.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM= +go.uber.org/zap v1.15.0/go.mod h1:Mb2vm2krFEG5DV0W9qcHBYFtp/Wku1cvYaqPsS/WYfc= +go.uber.org/zap v1.16.0 h1:uFRZXykJGK9lLY4HtgSw44DnIcAM+kRBP7x5m+NpAOM= +go.uber.org/zap v1.16.0/go.mod h1:MA8QOfq0BHJwdXa996Y4dYkAqRKB8/1K1QMMZVaNZjQ= +golang.org/x/crypto v0.0.0-20170930174604-9419663f5a44/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190404164418-38d8ce5564a5/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE= +golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20191202143827-86a70503ff7e/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20191206172530-e9b2fee46413/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200115085410-6d4e4cb37c7d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200406173513-056763e48d71/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200429183012-4b2356b1ed79/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad h1:DN0cp81fZ3njFcrLCytUHRSUkqBjfTo4Tx9RJTWs0EY= +golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= +golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= +golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= +golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= +golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= +golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= +golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190930215403-16217165b5de h1:5hukYrvBGR8/eNkX5mdUezrA6JiaEZDtJb9Ei+1LlBs= +golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= +golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= +golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= +golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= +golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/mod v0.2.0 h1:KU7oHjnv3XNWfa5COkzUifxZmxp1TyI7ImMXqFxLwvQ= +golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/net v0.0.0-20180719180050-a680a1efc54d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181011144130-49bb7cea24b1/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181106065722-10aee1819953/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190125091013-d26f9f9a57f3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190206173232-65e2d4e15006/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= +golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= +golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190912160710-24e19bdeb0f2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20201010224723-4f7140c49acb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201224014010-6772e930b67b h1:iFwSg7t5GZmB/Q5TjiEAsdoLDrdJRC1RiF2WhuV29Qw= +golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180926160741-c2ed4eda69e7/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190130150945-aca44879d564/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190712062909-fae7ac547cb7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190801041406-cbf593c0f2f3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190804053845-51ab0e2deafa/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190912141932-bc967efca4b8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191220142924-d4481acd189f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201013132646-2da7054afaeb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68 h1:nxC68pudNYkKU6jWhgrqdreuFiOQWj1Fs7T3VrH4Pjw= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= +golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20190912185636-87d9f09c5d89/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20200103221440-774c71fcf114/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200601175630-2caf76543d99 h1:deddXmhOJb/bvD/4M/j2AUMrhHeh6GkqykJSCWyTNVk= +golang.org/x/tools v0.0.0-20200601175630-2caf76543d99/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/api v0.3.1/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk= +google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= +google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= +google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= +google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= +google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20180831171423-11092d34479b/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20190201180003-4b09977fb922/go.mod h1:L3J43x8/uS+qIUoksaLKe6OS3nUKxOKuIFz1sl2/jx4= +google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190530194941-fb225487d101/go.mod h1:z3L6/3dTEVtUr6QSP8miRzeRqwQOioJ9I66odjN4I7s= +google.golang.org/genproto v0.0.0-20190716160619-c506a9f90610/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= +google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= +google.golang.org/genproto v0.0.0-20200825200019-8632dd797987 h1:PDIOdWxZ8eRizhKa1AAvY53xsvLB1cWorMjslvY3VA8= +google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/grpc v1.16.0/go.mod h1:0JHn/cJsOMiMfNA9+DeHDlAU7KAAB5GDlYFpa9MZMio= +google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= +google.golang.org/grpc v1.18.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= +google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= +google.golang.org/grpc v1.20.0/go.mod h1:chYK+tFQF0nDUGJgXMSgLCQk3phJEuONr2DCgLDdAQM= +google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= +google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= +google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= +google.golang.org/grpc v1.22.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.23.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= +google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= +google.golang.org/grpc v1.28.1/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= +google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.37.0 h1:uSZWeQJX5j11bIQ4AJoj+McDBo29cY1MCoC1wO3ts+c= +google.golang.org/grpc v1.37.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= +google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= +google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= +google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= +google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= +google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= +google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= +google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0 h1:bxAC2xTBsZGibn2RTntX0oH50xLsqy1OxA9tTL3p/lk= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= +gopkg.in/bsm/ratelimit.v1 v1.0.0-20160220154919-db14e161995a/go.mod h1:KF9sEfUPAXdG8Oev9e99iLGnl2uJMjc5B+4y3O7x610= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw= +gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= +gopkg.in/gcfg.v1 v1.2.3/go.mod h1:yesOnuUOFQAhST5vPY4nbZsb/huCgGGXlipJsBn0b3o= +gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/jcmturner/aescts.v1 v1.0.1/go.mod h1:nsR8qBOg+OucoIW+WMhB3GspUQXq9XorLnQb9XtvcOo= +gopkg.in/jcmturner/dnsutils.v1 v1.0.1/go.mod h1:m3v+5svpVOhtFAP/wSz+yzh4Mc0Fg7eRhxkJMWSIz9Q= +gopkg.in/jcmturner/goidentity.v3 v3.0.0/go.mod h1:oG2kH0IvSYNIu80dVAyu/yoefjq1mNfM5bm88whjWx4= +gopkg.in/jcmturner/gokrb5.v7 v7.2.3/go.mod h1:l8VISx+WGYp+Fp7KRbsiUuXTTOnxIc3Tuvyavf11/WM= +gopkg.in/jcmturner/rpc.v1 v1.1.0/go.mod h1:YIdkC4XfD6GXbzje11McwsDuOlZQSb9W4vfLvuNnlv8= +gopkg.in/mgo.v2 v2.0.0-20190816093944-a6b53ec6cb22/go.mod h1:yeKp02qBN3iKW1OzL3MGk2IdtZzaj7SFntXj72NppTA= +gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce/go.mod h1:5AcXVHNjg+BDxry382+8OKon8SEWiKktQR07RKPsv1c= +gopkg.in/olebedev/go-duktape.v3 v3.0.0-20200619000410-60c24ae608a6/go.mod h1:uAJfkITjFhyEEuUfm7bsmCZRbW5WRq8s9EY8HZ6hCns= +gopkg.in/redis.v4 v4.2.4/go.mod h1:8KREHdypkCEojGKQcjMqAODMICIVwZAONWq8RowTITA= +gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= +gopkg.in/sourcemap.v1 v1.0.5/go.mod h1:2RlvNNSMglmRrcvhfuzp4hQHwOtjxlbjX7UPY/GXb78= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= +gopkg.in/urfave/cli.v1 v1.20.0/go.mod h1:vuBzUtMdQeixQj8LVd+/98pzhxNGQoyuPBlsXHOQNO0= +gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI= +gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU= +gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= +honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.1-2019.2.3 h1:3JgtbtFHMiCmsznwGVTUWbgGov+pVqnlf1dEJTNAXeM= +honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= +rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= +sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= +sourcegraph.com/sourcegraph/appdash v0.0.0-20190731080439-ebfcffb1b5c0/go.mod h1:hI742Nqp5OhwiqlzhgfbWU4mW4yO10fP+LoT9WOswdU= diff --git a/tokens/tron/trondev/main.go b/tokens/tron/trondev/main.go new file mode 100644 index 00000000..8358dba2 --- /dev/null +++ b/tokens/tron/trondev/main.go @@ -0,0 +1,444 @@ +package main + +import ( + "context" + "crypto/sha256" + "fmt" + "log" + "math/big" + "strings" + "time" + + "github.com/golang/protobuf/ptypes" + "google.golang.org/grpc" + + tronaddress "github.com/fbsobreira/gotron-sdk/pkg/address" + "github.com/fbsobreira/gotron-sdk/pkg/client" + troncommon "github.com/fbsobreira/gotron-sdk/pkg/common" + "github.com/fbsobreira/gotron-sdk/pkg/proto/api" + "github.com/fbsobreira/gotron-sdk/pkg/proto/core" + proto "github.com/golang/protobuf/proto" + + "github.com/anyswap/CrossChain-Bridge/common" +) + +func checkError(err error) { + if err != nil { + log.Fatal(err) + } +} + +func divide() { + fmt.Printf("\n\n============================================================\n\n") +} + +//var mainnetendpoint = "3.225.171.164:50051" +var mainnetendpoint = "grpc.trongrid.io:50051" +var testnetendpoint = "grpc.shasta.trongrid.io:50051" +var timeout = time.Second * 15 + +func main() { + // GetCode() + + // BuildSwapinTx() + + // ScanBlock() + + // GetTxArgs() + + // GetContractCode() + + // GetTransaction() + + ParseAddress() + + // MarshalUnmarshalTx() + + // GetSmartContractLog() +} + +func ParseAddress() { + addr := "TEtNLh69XnK9Fs8suCogK3sRrWJbQHah4k" + fmt.Printf("tron to tron: %v\n", anyToTron(addr)) + fmt.Printf("tron to eth: %v\n", anyToEth(addr)) + fmt.Printf("tron to eth to eth: %v\n", anyToEth(anyToEth(addr))) +} + +func ethToTron(ethAddress string) (string, error) { + intaddr, ok := new(big.Int).SetString(ethAddress, 16) + if ok { + ethAddress = common.BigToAddress(intaddr).String() + } + bz, _ := troncommon.FromHex(ethAddress) + tronaddr := tronaddress.Address(append([]byte{0x41}, bz...)) + return tronaddr.String(), nil +} + +func tronToEth(tronAddress string) (string, error) { + addr, err := tronaddress.Base58ToAddress(tronAddress) + if err != nil || len(addr) == 0 { + return "", err + } + ethaddr := common.BytesToAddress(addr.Bytes()) + return ethaddr.String(), nil +} + +func anyToTron(address string) string { + addr, err := tronaddress.Base58ToAddress(address) + if err != nil { + address, err = ethToTron(address) + if err != nil { + return "" + } + } else { + address = addr.String() + } + return address +} + +func anyToEth(address string) string { + tronaddr := anyToTron(address) + address, _ = tronToEth(tronaddr) + return address +} + +func GetTransaction() { + cli := client.NewGrpcClientWithTimeout(testnetendpoint, timeout) + err := cli.Start(grpc.WithInsecure()) + checkError(err) + defer cli.Stop() + + /* + res, err := cli.GetNowBlock() + checkError(err) + fmt.Printf("Block number: %+v\n", res.BlockHeader.RawData.Number) + + divide() + */ + /* + Test private key + d8ea0b60ec7585c5b42742102e3d7b19eddbd54b0d538aca86e81d3e00886795 + ETH address + 0x35eE5830f802FD21780514A33420cA2c500d2232 + Tron address + TEtNLh69XnK9Fs8suCogK3sRrWJbQHah4k + */ + + /* + acct, err := cli.GetAccount("TEtNLh69XnK9Fs8suCogK3sRrWJbQHah4k") + checkError(err) + fmt.Printf("Account: %+v\n", acct) + fmt.Printf("Account balance: %v\n", acct.Balance) + fmt.Printf("Account votes: %v\n", acct.Votes) + fmt.Printf("Account frozen: %v\n", acct.Frozen) + fmt.Printf("Account account resource:: %v\n", acct.AccountResource) + */ + /* + 查询未激活的地址会报 error: account not found + 向未激活的账户转账会多扣除发送者 0.1 trx ($ 0.008) + */ + /* + unit = sun + 1 trx = 1e6 sun + balance 是可用余额,不包括 frozen 部分 + */ + /* + 所有的交易都需要带宽,系统分配的带宽每天只有 5000, 冻结 trx 获得更多带宽 + 操作合约需要能量,冻结 trx 获得能量 + 也可以租赁,17 trx = 1000 trx * 7 天 (贵爆了?) + 冻结 trx 获得票数,可以投票 + */ + + /* + TRC10 + TRC20 就是 ERC20 + ERC20 test token + TN3EZa6J6XekTgVcP4N4R43dTZmFE7zDud + TRC20 test token + TQCeH8Bc7zcJv6DjdCYWQuMX4Rzmc3gcs2 + */ + /* + divide() + contractAddress := "TQCeH8Bc7zcJv6DjdCYWQuMX4Rzmc3gcs2" + balance, err := cli.TRC20ContractBalance("TEtNLh69XnK9Fs8suCogK3sRrWJbQHah4k", contractAddress) + checkError(err) + fmt.Printf("Token balance: %+v\n", balance) + + divide() + + totalSupplyMethodSignature := "0x18160ddd" + result, err := cli.TRC20Call("", contractAddress, totalSupplyMethodSignature, true, 0) // true, 0 表示 read + checkError(err) + totalSupply := new(big.Int).SetBytes(result.GetConstantResult()[0]) + fmt.Printf("Token total supply: %v\n", totalSupply) + */ + + divide() + // f1ca51fac8b21527443068a56dd6b01a625d3f283534f10645a7932c73b1bae3 普通转账 + // c0391bd5fe5913df182282b4c07df0aa26f476c8286dc965eb4a780b5b690984 TRC20 转账 + //txinfo, err := cli.GetTransactionInfoByID("f1ca51fac8b21527443068a56dd6b01a625d3f283534f10645a7932c73b1bae3") + txinfo, err := cli.GetTransactionInfoByID("c0391bd5fe5913df182282b4c07df0aa26f476c8286dc965eb4a780b5b690984") + // txinfo, err := cli.GetTransactionInfoByID("aa1d7b84277097c3fe8657a663e01eec11f3b5cfcdf2dea41f5593784637fab7") + //txinfo, err := cli.GetTransactionInfoByID("0802edce3c7bd11b4d995eac84a7b235594f12088493264f3fd4d9f4bd991b57") + //txinfo, err := cli.GetTransactionInfoByID("b034937d9e2975170b73b6cc3f9f7857f813ab26f9560fd3785f9e8c1e7085ca") + checkError(err) + fmt.Printf("Transaction info: %+v\n", txinfo) + fmt.Printf("Transaction info contract result: %v\n", new(big.Int).SetBytes(txinfo.GetContractResult()[0])) + fmt.Printf("Transaction block: %+v\n", txinfo.BlockNumber) + fmt.Printf("Transaction time: %+v\n", txinfo.BlockTimeStamp) + fmt.Printf("Transaction contract result: %+v\n", txinfo.ContractResult) + fmt.Printf("Transaction receipt: %+v\n", txinfo.Receipt) + + txlog := txinfo.GetLog() + fmt.Printf("Transaction log length: %v\n", len(txlog)) + /* + fmt.Printf("Transaction log: %v\n", txlog[0]) + fmt.Printf("Transaction log address: %v\n", tronaddress.Address(append([]byte{0x41}, txlog[0].GetAddress()...))) // 合约地址 + fmt.Printf("Transaction log topics: %X\n", txlog[0].GetTopics()[0]) // trc20TransferEventSignature DDF252AD1BE2C89B69C2B068FC378DAA952BA7F163C4A11628F55A4DF523B3EF + fmt.Printf("Transaction log topics: %X\n", txlog[0].GetTopics()[1]) // from + fmt.Printf("Transaction log topics: %X\n", txlog[0].GetTopics()[2]) // to + fmt.Printf("Transaction log data: %X\n", txlog[0].GetData()) + */ + + divide() + //tx, err := cli.GetTransactionByID("f1ca51fac8b21527443068a56dd6b01a625d3f283534f10645a7932c73b1bae3") + //tx, err := cli.GetTransactionByID("c0391bd5fe5913df182282b4c07df0aa26f476c8286dc965eb4a780b5b690984") + // tx, err := cli.GetTransactionByID("aa1d7b84277097c3fe8657a663e01eec11f3b5cfcdf2dea41f5593784637fab7") + // tx, err := cli.GetTransactionByID("0802edce3c7bd11b4d995eac84a7b235594f12088493264f3fd4d9f4bd991b57") + tx, err := cli.GetTransactionByID("b034937d9e2975170b73b6cc3f9f7857f813ab26f9560fd3785f9e8c1e7085ca") + checkError(err) + fmt.Printf("Transaction raw data: %+v\n", tx.GetRawData()) + fmt.Printf("Transaction expiration: %+v\n", tx.GetRawData().GetExpiration()) + fmt.Printf("Transaction fee limit: %v\n", tx.GetRawData().GetFeeLimit()) + fmt.Printf("Transaction: %+v\n", tx) + fmt.Printf("Transaction Ret: %+v\n", tx.GetRet()[0]) + fmt.Printf("Transaction Ret Success: %+v\n", (tx.GetRet()[0].GetRet() == core.Transaction_Result_SUCESS)) + fmt.Printf("Contract Ret: %+v\n", tx.GetRet()[0].GetContractRet()) + fmt.Printf("Contract Ret Default: %+v\n", (tx.GetRet()[0].GetContractRet() == core.Transaction_Result_DEFAULT)) + fmt.Printf("Contract Ret Success: %+v\n", (tx.GetRet()[0].GetContractRet() == core.Transaction_Result_SUCCESS)) + fmt.Printf("Contract Ret Out Of Energy: %+v\n", (tx.GetRet()[0].GetContractRet() == core.Transaction_Result_OUT_OF_ENERGY)) + if len(tx.RawData.Contract) != 1 { + checkError(fmt.Errorf("Invalid contract")) + } + contract := tx.RawData.Contract[0] + switch contract.Type { + case core.Transaction_Contract_TransferContract: + // 普通转账 + var c core.TransferContract + err = ptypes.UnmarshalAny(contract.GetParameter(), &c) + checkError(err) + fmt.Printf("Trigger smart contract: %+v\n", c) + fmt.Printf("To address: %v\n", tronaddress.Address(c.ToAddress)) + fmt.Printf("From address: %v\n", tronaddress.Address(c.OwnerAddress)) + fmt.Printf("Transfer value: %v\n", big.NewInt(c.Amount)) + case core.Transaction_Contract_TransferAssetContract: + // TRC10 + checkError(fmt.Errorf("TRC10 transfer not supported")) + case core.Transaction_Contract_TriggerSmartContract: + // TRC20 + var c core.TriggerSmartContract + err = ptypes.UnmarshalAny(contract.GetParameter(), &c) + checkError(err) + fmt.Printf("Trigger smart contract: %+v\n", c) + fmt.Printf("Contract address: %v\n", tronaddress.Address(c.ContractAddress)) + fmt.Printf("Data: %X\n", c.Data) + + default: + return + } + + // 构造交易 + // TransferContract 普通转账 + /* + from := "TEtNLh69XnK9Fs8suCogK3sRrWJbQHah4k" + to := "TXexdzdZv3z5mJP1yzTeEc4LZwcBvenmZc" + divide() + contract := &core.TransferContract{} + contract.OwnerAddress, err = troncommon.DecodeCheck(from) + checkError(err) + contract.ToAddress, err = troncommon.DecodeCheck(to) + checkError(err) + contract.Amount = 1000 + fmt.Printf("Contract: %+v\n", contract) + + ctx, cancel := context.WithTimeout(context.Background(), timeout) + defer cancel() + tx, err := cli.Client.CreateTransaction2(ctx, contract) + checkError(err) + fmt.Printf("Tx: %+v\n", tx) + fmt.Printf("Txid: %X\n", tx.Txid) + */ + + // TRC20 转账 + // TriggerSmartContract 合约交易 + /* + divide() + tokenAddress := "TQCeH8Bc7zcJv6DjdCYWQuMX4Rzmc3gcs2" + trc20tx, err := cli.TRC20Send(from, to, tokenAddress, big.NewInt(1000), 0) + checkError(err) + fmt.Printf("TRC20: %+v\n", trc20tx) + fmt.Printf("TRC20 txid: %X\n", trc20tx.Txid) + */ +} + +func BuildSwapinTx() { + cli := client.NewGrpcClientWithTimeout(testnetendpoint, timeout) + err := cli.Start(grpc.WithInsecure()) + checkError(err) + defer cli.Stop() + + divide() + + from := "TEtNLh69XnK9Fs8suCogK3sRrWJbQHah4k" + contract := "TBssYqEV8BxJJDhGsf7pUkfPZxGbt2JU2M" + method := "Swapin" + param := `[{"string":"0xbeea0dfefc66107a3b1922f75a67ddd1d577a36ed0099e84a381e7a71774501e"},{"address":"TEtNLh69XnK9Fs8suCogK3sRrWJbQHah4k"},{"uint256":"1"}]` + + tx, err := cli.TriggerConstantContract(from, contract, method, param) + checkError(err) + fmt.Printf("Tx: %+v\n", tx) +} + +func GetCode() { + cli := client.NewGrpcClientWithTimeout(testnetendpoint, timeout) + err := cli.Start(grpc.WithInsecure()) + checkError(err) + defer cli.Stop() + + divide() + + contractDesc, err := tronaddress.Base58ToAddress("TQCeH8Bc7zcJv6DjdCYWQuMX4Rzmc3gcs2") + checkError(err) + message := new(api.BytesMessage) + message.Value = contractDesc + ctx, cancel := context.WithTimeout(context.Background(), timeout) + defer cancel() + sm, err := cli.Client.GetContract(ctx, message) + checkError(err) + fmt.Printf("Bytecode: %X\n", sm.Bytecode) +} + +func ScanBlock() { + cli := client.NewGrpcClientWithTimeout(testnetendpoint, timeout) + //cli := client.NewGrpcClientWithTimeout(mainnetendpoint, timeout) + err := cli.Start(grpc.WithInsecure()) + checkError(err) + defer cli.Stop() + + divide() + + var step int = 10 + var start, end int64 + longSleep := time.Second * 2 + shortSleep := time.Millisecond * 400 + start = 13689800 // TODO Load latest scanned + end = start + int64(step) + for { + res, err := cli.GetBlockByLimitNext(start, end) + checkError(err) + fmt.Printf("Blocks: %+v\n", len(res.Block)) + l := len(res.Block) + if l > 0 { + fmt.Printf("%v - %v\n", res.Block[0].BlockHeader.RawData.Number, res.Block[l-1].BlockHeader.RawData.Number) + } + // TODO process tx + for _, block := range res.Block { + txexts := make([]*api.TransactionExtention, 0) + txexts = block.Transactions + for _, txext := range txexts { + var tx *core.Transaction + tx = txext.Transaction + fmt.Printf("tx: %+v/n", tx) + } + } + + // TODO Add latest scanned + start = start + int64(len(res.Block)) + end = start + int64(step) + if len(res.Block) < step { + time.Sleep(longSleep) + } else { + time.Sleep(shortSleep) + } + } +} + +func GetTxArgs() { + divide() + cli := client.NewGrpcClientWithTimeout(testnetendpoint, timeout) + //cli := client.NewGrpcClientWithTimeout(mainnetendpoint, timeout) + err := cli.Start(grpc.WithInsecure()) + checkError(err) + defer cli.Stop() + //tx, err := cli.GetTransactionByID("0xc0391bd5fe5913df182282b4c07df0aa26f476c8286dc965eb4a780b5b690984") + //tx, err := cli.GetTransactionByID("c7effb1b0b86f4a22dcce26208027a21ef903685655a2d75e4819a63b903f0e7") + //tx, err := cli.GetTransactionByID("013e79e7dd5229909dea401d498e2e474dacbe7cfa8fda57a19a17c610d22df9") + tx, err := cli.GetTransactionByID("b034937d9e2975170b73b6cc3f9f7857f813ab26f9560fd3785f9e8c1e7085ca") + checkError(err) + fmt.Printf("Tx: %+v", tx) + rawData, err := proto.Marshal(tx.GetRawData()) + checkError(err) + h256h := sha256.New() + h256h.Write(rawData) + hash := h256h.Sum(nil) + txhash := troncommon.ToHex(hash) + txhash = strings.TrimPrefix(txhash, "0x") + + fmt.Printf("Tx hash: %v\n", txhash) + + ret := tx.GetRet() + crt := ret[0].ContractRet + fmt.Printf("%v\n", crt) + + var contract core.TriggerSmartContract + err = ptypes.UnmarshalAny(tx.GetRawData().GetContract()[0].GetParameter(), &contract) + checkError(err) + fmt.Printf("\nContract: %+v\n", contract) + data := tx.GetRawData().GetData() + fmt.Printf("\nData: %X\n", data) + fmt.Printf("\nData: %X\n", contract.Data) +} + +func GetContractCode() { + divide() + contractDesc, err := tronaddress.Base58ToAddress("TQCeH8Bc7zcJv6DjdCYWQuMX4Rzmc3gcs2") + checkError(err) + + ctx, cancel := context.WithTimeout(context.Background(), timeout) + defer cancel() + cli := client.NewGrpcClientWithTimeout(testnetendpoint, timeout) + //cli := client.NewGrpcClientWithTimeout(mainnetendpoint, timeout) + err = cli.Start(grpc.WithInsecure()) + checkError(err) + defer cli.Stop() + sm, err := cli.Client.GetContract(ctx, client.GetMessageBytes(contractDesc)) + checkError(err) + fmt.Printf("SM: %X", sm.GetBytecode()) +} + +func MarshalUnmarshalTx() { + cli := client.NewGrpcClientWithTimeout(testnetendpoint, timeout) + err := cli.Start(grpc.WithInsecure()) + checkError(err) + defer cli.Stop() + + divide() + + from := "TEtNLh69XnK9Fs8suCogK3sRrWJbQHah4k" + contract := "TBssYqEV8BxJJDhGsf7pUkfPZxGbt2JU2M" + method := "Swapin" + param := `[{"string":"0xbeea0dfefc66107a3b1922f75a67ddd1d577a36ed0099e84a381e7a71774501e"},{"address":"TEtNLh69XnK9Fs8suCogK3sRrWJbQHah4k"},{"uint256":"1"}]` + + tx, err := cli.TriggerConstantContract(from, contract, method, param) + checkError(err) + fmt.Printf("Tx: %+v\n", tx.Transaction) + + txmsg, err := proto.Marshal(tx.Transaction) + checkError(err) + fmt.Printf("txmsg: %X\n", txmsg) + + var decodedTx core.Transaction + err = proto.Unmarshal(txmsg, &decodedTx) + checkError(err) + fmt.Printf("Decoded tx:\n%+v\n", &decodedTx) +} diff --git a/tokens/tron/trondev/trondev b/tokens/tron/trondev/trondev new file mode 100755 index 00000000..ffbb5e63 Binary files /dev/null and b/tokens/tron/trondev/trondev differ diff --git a/tokens/tron/trontools/trontools b/tokens/tron/trontools/trontools new file mode 100755 index 00000000..09d6d12a Binary files /dev/null and b/tokens/tron/trontools/trontools differ diff --git a/tokens/tron/trontools/trontools.go b/tokens/tron/trontools/trontools.go new file mode 100644 index 00000000..42bcc857 --- /dev/null +++ b/tokens/tron/trontools/trontools.go @@ -0,0 +1,139 @@ +package main + +import ( + "encoding/hex" + "fmt" + "log" + "os" + "strings" + + "github.com/urfave/cli/v2" + + tronaddress "github.com/fbsobreira/gotron-sdk/pkg/address" + + "github.com/anyswap/CrossChain-Bridge/common" + "github.com/anyswap/CrossChain-Bridge/tools/crypto" +) + +/* + +pubkey to address +./trontools pubkeyToAddress --pubkey 04d38309dfdfd9adf129287b68cf2e1f1124e0cbc40cc98f94e5f2d23c26712fa3b33d63280dd1448319a6a4f4111722d6b3a730ebe07652ed2b3770947b3de2e2 +TXSxUhgSoHkHNLgip2kQRHXVT6BqoaqtvX + +tron to eth +./trontools tronToEth --tron TXSxUhgSoHkHNLgip2kQRHXVT6BqoaqtvX +0xEB9A2A3502A78B27842DD2FB09E9514E3CE597ED + +eth to tron +./trontools ethToTron --eth 0xEB9A2A3502A78B27842DD2FB09E9514E3CE597ED +TXSxUhgSoHkHNLgip2kQRHXVT6BqoaqtvX + +*/ + +var app = cli.NewApp() + +func initApp() { + // Initialize the CLI app and start action + app.Commands = []*cli.Command{ + ethToTronCommand, + tronToEthCommand, + pubkeyToAddressCommand, + } +} + +func main() { + initApp() + if err := app.Run(os.Args); err != nil { + log.Println(err) + os.Exit(1) + } +} + +var ( + ethFlag = &cli.StringFlag{ + Name: "eth", + Usage: "eth address", + Value: "", + } + tronFlag = &cli.StringFlag{ + Name: "tron", + Usage: "tron address", + Value: "", + } + pubkeyFlag = &cli.StringFlag{ + Name: "pubkey", + Usage: "pubkey hex", + Value: "", + } +) + +var ( + ethToTronCommand = &cli.Command{ + Action: ethToTron, + Name: "ethToTron", + Usage: "convert eth address to tron address", + ArgsUsage: " ", + Description: ``, + Flags: []cli.Flag{ + ethFlag, + }, + } + tronToEthCommand = &cli.Command{ + Action: tronToEth, + Name: "tronToEth", + Usage: "convert tron address to eth address", + ArgsUsage: " ", + Description: ``, + Flags: []cli.Flag{ + tronFlag, + }, + } + pubkeyToAddressCommand = &cli.Command{ + Action: pubkeyToAddress, + Name: "pubkeyToAddress", + Usage: "convert pubkey hex to tron address", + ArgsUsage: " ", + Description: ``, + Flags: []cli.Flag{ + pubkeyFlag, + }, + } +) + +func ethToTron(ctx *cli.Context) error { + ethAddress := ctx.String(ethFlag.Name) + + tronaddr := tronaddress.Address(append([]byte{0x41}, common.HexToAddress(ethAddress).Bytes()...)) + fmt.Println(tronaddr.String()) + return nil +} + +func tronToEth(ctx *cli.Context) error { + tronAddress := ctx.String(tronFlag.Name) + addr, err := tronaddress.Base58ToAddress(tronAddress) + if err != nil { + return err + } + ethaddr := common.BytesToAddress(addr.Bytes()) + fmt.Println(ethaddr.String()) + return nil +} + +func pubkeyToAddress(ctx *cli.Context) error { + pubkeyhex := ctx.String(pubkeyFlag.Name) + pubkeyhex = strings.TrimPrefix(pubkeyhex, "0x") + bz, err := hex.DecodeString(pubkeyhex) + if err != nil { + return err + } + ecdsaPub, err := crypto.UnmarshalPubkey(bz) + if err != nil { + return err + } + ethAddress := crypto.PubkeyToAddress(*ecdsaPub) + fmt.Printf("%X\n", ethAddress) + tronaddr := tronaddress.Address(append([]byte{0x41}, ethAddress.Bytes()...)) + fmt.Println(tronaddr) + return nil +} diff --git a/tokens/tron/verifycontractaddress.go b/tokens/tron/verifycontractaddress.go new file mode 100644 index 00000000..5f466180 --- /dev/null +++ b/tokens/tron/verifycontractaddress.go @@ -0,0 +1,176 @@ +package tron + +import ( + "bytes" + "fmt" + "math/big" + + "github.com/anyswap/CrossChain-Bridge/common" + "github.com/anyswap/CrossChain-Bridge/log" + "github.com/anyswap/CrossChain-Bridge/tokens" + "github.com/anyswap/CrossChain-Bridge/tokens/btc" +) + +var ( + // ExtCodeParts extended func hashes and log topics + ExtCodeParts map[string][]byte + + // first 4 bytes of `Keccak256Hash([]byte("Swapin(bytes32,address,uint256)"))` + swapinFuncHash = common.FromHex("0xec126c77") + logSwapinTopic = common.FromHex("0x05d0634fe981be85c22e2942a880821b70095d84e152c3ea3c17a4e4250d9d61") + + // first 4 bytes of `Keccak256Hash([]byte("Swapout(uint256,string)"))` + mBTCSwapoutFuncHash = common.FromHex("0xad54056d") + mBTCLogSwapoutTopic = common.FromHex("0x9c92ad817e5474d30a4378deface765150479363a897b0590fbb12ae9d89396b") + + // first 4 bytes of `Keccak256Hash([]byte("Swapout(uint256,address)"))` + mETHSwapoutFuncHash = common.FromHex("0x628d6cba") + mETHLogSwapoutTopic = common.FromHex("0x6b616089d04950dc06c45c6dd787d657980543f89651aec47924752c7d16c888") +) + +var mBTCExtCodeParts = map[string][]byte{ + // Extended interfaces + "SwapinFuncHash": swapinFuncHash, + "LogSwapinTopic": logSwapinTopic, + "SwapoutFuncHash": mBTCSwapoutFuncHash, + "LogSwapoutTopic": mBTCLogSwapoutTopic, +} + +var mETHExtCodeParts = map[string][]byte{ + // Extended interfaces + "SwapinFuncHash": swapinFuncHash, + "LogSwapinTopic": logSwapinTopic, + "SwapoutFuncHash": mETHSwapoutFuncHash, + "LogSwapoutTopic": mETHLogSwapoutTopic, +} + +var erc20CodeParts = map[string][]byte{ + // Erc20 interfaces + "name": common.FromHex("0x06fdde03"), + "symbol": common.FromHex("0x95d89b41"), + "decimals": common.FromHex("0x313ce567"), + "totalSupply": common.FromHex("0x18160ddd"), + "balanceOf": common.FromHex("0x70a08231"), + "transfer": common.FromHex("0xa9059cbb"), + "transferFrom": common.FromHex("0x23b872dd"), + "approve": common.FromHex("0x095ea7b3"), + "allowance": common.FromHex("0xdd62ed3e"), + "LogTransfer": common.FromHex("0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"), + "LogApproval": common.FromHex("0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925"), +} + +func (b *Bridge) getContractCode(contract string) (code []byte, err error) { + return b.GetCode(contract) +} + +// VerifyContractCode verify contract code +func (b *Bridge) VerifyContractCode(contract string, codePartsSlice ...map[string][]byte) (err error) { + code, err := b.getContractCode(contract) + if err != nil { + return err + } + return VerifyContractCodeParts(code, codePartsSlice...) +} + +// VerifyContractCodeParts verify contract code parts +func VerifyContractCodeParts(code []byte, codePartsSlice ...map[string][]byte) (err error) { + for _, codeParts := range codePartsSlice { + for key, part := range codeParts { + if !bytes.Contains(code, part) { + return fmt.Errorf("contract byte code miss '%v' bytes '%x'", key, part) + } + } + } + return nil +} + +// VerifyTrc20ContractCode verify erc20 contract code +func VerifyTrc20ContractCode(code []byte) (err error) { + return VerifyContractCodeParts(code, erc20CodeParts) +} + +// VerifySwapContractCode verify swap contract code +func VerifySwapContractCode(code []byte) (err error) { + return VerifyContractCodeParts(code, ExtCodeParts, erc20CodeParts) +} + +// VerifyTrc20ContractAddress verify erc20 contract +// For proxy contract delegating erc20 contract, verify its contract code hash +func (b *Bridge) VerifyTrc20ContractAddress(contract, codeHash string, isProxy bool) (err error) { + code, err := b.getContractCode(contract) + if err != nil { + return err + } + if !isProxy { + err = VerifyTrc20ContractCode(code) + if err != nil { + return err + } + } else if codeHash == "" { + return fmt.Errorf("proxy contract of erc20 must specify code hash") + } + if codeHash != "" { + calcedCodeHash := common.Keccak256Hash(code).String() + if codeHash != calcedCodeHash { + return fmt.Errorf("code hash mismatch. contract=%v, have=%v, want=%v", contract, codeHash, calcedCodeHash) + } + } + return nil +} + +// VerifyMbtcContractAddress verify mbtc contract +func (b *Bridge) VerifyMbtcContractAddress(contract string) (err error) { + return b.VerifyContractCode(contract, ExtCodeParts, erc20CodeParts) +} + +// InitExtCodeParts init extended code parts +func InitExtCodeParts() { + InitExtCodePartsWithFlag(tokens.IsSwapoutToStringAddress) +} + +// InitExtCodePartsWithFlag init extended code parts with flag +func InitExtCodePartsWithFlag(isMbtc bool) { + switch { + case isMbtc: + ExtCodeParts = mBTCExtCodeParts + default: + ExtCodeParts = mETHExtCodeParts + } + log.Info("init extented code parts", "isMBTC", isMbtc) +} + +func isMbtcSwapout() bool { + return btc.BridgeInstance != nil +} + +func getSwapinFuncHash() []byte { + return ExtCodeParts["SwapinFuncHash"] +} + +func getSwapoutFuncHash() []byte { + return ExtCodeParts["SwapoutFuncHash"] +} + +func getLogSwapoutTopic() []byte { + return ExtCodeParts["LogSwapoutTopic"] +} + +// ParseTransferTxInput parse transfer tx input +func ParseTransferTxInput(input *[]byte) (toaddr string, value *big.Int, err error) { + if input == nil || len(*input) < 4 { + return "", nil, tokens.ErrTxWithWrongInput + } + data := *input + funcHash := data[:4] + transferFuncHash := erc20CodeParts["transfer"] + if !bytes.Equal(funcHash, transferFuncHash) { + return "", nil, tokens.ErrTxFuncHashMismatch + } + encData := data[4:] + if len(encData) != 64 { + return "", nil, tokens.ErrTxIncompatible + } + toaddr = common.BytesToAddress(common.GetData(encData, 0, 32)).String() + value = common.GetBigInt(encData, 32, 32) + return toaddr, value, nil +} diff --git a/tokens/tron/verifytx.go b/tokens/tron/verifytx.go new file mode 100644 index 00000000..604fec9b --- /dev/null +++ b/tokens/tron/verifytx.go @@ -0,0 +1,376 @@ +package tron + +import ( + "bytes" + "crypto/sha256" + "errors" + "fmt" + "math/big" + "strings" + + tronaddress "github.com/fbsobreira/gotron-sdk/pkg/address" + "github.com/fbsobreira/gotron-sdk/pkg/common" + "github.com/fbsobreira/gotron-sdk/pkg/proto/core" + proto "github.com/golang/protobuf/proto" + "github.com/golang/protobuf/ptypes" + + "github.com/anyswap/CrossChain-Bridge/log" + "github.com/anyswap/CrossChain-Bridge/tokens" + "github.com/anyswap/CrossChain-Bridge/tokens/eth" +) + +func addSwapInfoConsiderError(swapInfo *tokens.TxSwapInfo, err error, swapInfos *[]*tokens.TxSwapInfo, errs *[]error) { + if !tokens.ShouldRegisterSwapForError(err) { + return + } + *swapInfos = append(*swapInfos, swapInfo) + *errs = append(*errs, err) +} + +// VerifyMsgHash verify msg hash +func (b *Bridge) VerifyMsgHash(rawTx interface{}, msgHash []string) (err error) { + tx, ok := rawTx.(*core.Transaction) + if !ok { + return errors.New("verify msg hash tx type error") + } + + if len(msgHash) < 1 { + return errors.New("no msg hash") + } + mh := msgHash[0] + + mh = strings.TrimPrefix(mh, "0x") + txhash := CalcTxHash(tx) + + if strings.EqualFold(txhash, mh) == false { + return errors.New("msg hash not match") + } + return nil +} + +func CalcTxHash(tx *core.Transaction) string { + rawData, err := proto.Marshal(tx.GetRawData()) + if err != nil { + return "" + } + + h256h := sha256.New() + h256h.Write(rawData) + hash := h256h.Sum(nil) + txhash := common.ToHex(hash) + + txhash = strings.TrimPrefix(txhash, "0x") + return txhash +} + +func GetTxData(tx *core.Transaction) []byte { + rawData, err := proto.Marshal(tx.GetRawData()) + if err != nil { + return []byte{} + } + return rawData +} + +// VerifyTransaction impl +func (b *Bridge) VerifyTransaction(pairID, txHash string, allowUnstable bool) (*tokens.TxSwapInfo, error) { + if !b.IsSrc { + swapInfos, errs := b.verifySwapoutTxWithHash(txHash, allowUnstable) + // swapinfos have already aggregated + for i, swapInfo := range swapInfos { + if strings.EqualFold(swapInfo.PairID, pairID) { + return swapInfo, errs[i] + } + } + log.Warn("No swapInfo", "errors", errs) + } else { + swapInfos, errs := b.verifySwapinTxWithHash(txHash, allowUnstable) + // swapinfos have already aggregated + for i, swapInfo := range swapInfos { + if strings.EqualFold(swapInfo.PairID, pairID) { + return swapInfo, errs[i] + } + } + log.Warn("No swapInfo", "errors", errs) + } + return &tokens.TxSwapInfo{}, errors.New("Cannot generate swapinfo") +} + +type TransactionExtention struct { + *core.Transaction + Txid []byte + BlockNumber uint64 + BlockTime uint64 +} + +func (b *Bridge) verifySwapinTx(txext *TransactionExtention, allowUnstable bool) (swapInfos []*tokens.TxSwapInfo, errs []error) { + tx := txext.Transaction + + ret := tx.GetRet() + if len(ret) != 1 { + return []*tokens.TxSwapInfo{&tokens.TxSwapInfo{}}, []error{errors.New("Tron tx return not found")} + } + if txret := ret[0].GetRet(); txret != core.Transaction_Result_SUCESS { + return []*tokens.TxSwapInfo{&tokens.TxSwapInfo{}}, []error{fmt.Errorf("Tron tx not success: %v", txret)} + } + + if cret := ret[0].GetContractRet(); cret != core.Transaction_Result_SUCCESS { + return []*tokens.TxSwapInfo{&tokens.TxSwapInfo{}}, []error{fmt.Errorf("Tron contract not success: %v", cret)} + } + + if err := b.VerifyMsgHash(tx, []string{fmt.Sprintf("%X", txext.Txid)}); err != nil { + addSwapInfoConsiderError(nil, err, &swapInfos, &errs) + return + } + + tokenPairsConfig := tokens.GetTokenPairsConfig() + + swapInfo := &tokens.TxSwapInfo{ + Hash: CalcTxHash(tx), + Height: txext.BlockNumber, + Timestamp: txext.BlockTime, + } + + if len(tx.RawData.Contract) != 1 { + addSwapInfoConsiderError(nil, errors.New("Tron contract is not 1"), &swapInfos, &errs) + return + } + contract := tx.RawData.Contract[0] + switch contract.Type { + case core.Transaction_Contract_TransferContract: + // 普通转账 + var c core.TransferContract + err := ptypes.UnmarshalAny(contract.GetParameter(), &c) + if err != nil { + addSwapInfoConsiderError(nil, errors.New("Tx inconsistent"), &swapInfos, &errs) + return + } + toAddress := fmt.Sprintf("%v", tronaddress.Address(c.ToAddress)) + for _, tokenPair := range tokenPairsConfig { + token := tokenPair.SrcToken + if tokenPair.PairID == "TRX" { + depositAddress := token.DepositAddress + if strings.EqualFold(toAddress, depositAddress) { + swapInfo.PairID = tokenPair.PairID + } + } + } + if swapInfo.PairID == "" { + addSwapInfoConsiderError(nil, errors.New("Invalid TRX swapin"), &swapInfos, &errs) + return + } + swapInfo.TxTo = toAddress + swapInfo.To = toAddress + swapInfo.From = fmt.Sprintf("%v", tronaddress.Address(c.OwnerAddress)) + swapInfo.Bind, _ = tronToEth(swapInfo.From) + swapInfo.Value = big.NewInt(c.Amount) + case core.Transaction_Contract_TransferAssetContract: + // TRC10 swapin not supported + addSwapInfoConsiderError(nil, errors.New("TRC10 not supported"), &swapInfos, &errs) + return + case core.Transaction_Contract_TriggerSmartContract: + // TRC20 + var c core.TriggerSmartContract + err := ptypes.UnmarshalAny(contract.GetParameter(), &c) + if err != nil { + addSwapInfoConsiderError(nil, errors.New("Tx inconsistent"), &swapInfos, &errs) + return + } + contractAddress := fmt.Sprintf("%v", tronaddress.Address(c.ContractAddress)) + for _, tokenPair := range tokenPairsConfig { + token := tokenPair.SrcToken + if token.IsTrc20() { + depositAddress := token.DepositAddress + tokenContractAddress := token.ContractAddress + inputData := c.Data + checkToAddress, _ := tronToEth(depositAddress) + from := fmt.Sprintf("%v", tronaddress.Address(c.OwnerAddress)) + _, to, value, err := eth.ParseErc20SwapinTxInput(&inputData, checkToAddress) + if err != nil { + addSwapInfoConsiderError(swapInfo, err, &swapInfos, &errs) + break + } + //transferTo, _ := ethToTron(to) + transferTo, _ := ethToTron(to) + if EqualAddress(tokenContractAddress, contractAddress) && EqualAddress(depositAddress, transferTo) { + txStatus := b.GetTransactionStatus(fmt.Sprintf("%+X", txext.Txid)) + recpt, ok := txStatus.Receipt.(*core.TransactionInfo) + if !ok { + addSwapInfoConsiderError(swapInfo, errors.New("Get tron tx receipt error"), &swapInfos, &errs) + break + } + txlogs := recpt.GetLog() + if len(txlogs) < 1 { + addSwapInfoConsiderError(swapInfo, errors.New("No contract log"), &swapInfos, &errs) + break + } + logfrom, logto, logamount, err := checkTrc20TransferLog(txlogs, contractAddress) + if err != nil { + addSwapInfoConsiderError(swapInfo, err, &swapInfos, &errs) + break + } + if EqualAddress(logfrom, from) == false || EqualAddress(logto, depositAddress) == false || logamount.Cmp(value) != 0 { + addSwapInfoConsiderError(swapInfo, errors.New("Contract log mismatch"), &swapInfos, &errs) + break + } + + swapInfo.PairID = tokenPair.PairID + swapInfo.From = from + swapInfo.Bind, _ = tronToEth(swapInfo.From) // Use eth format + swapInfo.TxTo = contractAddress + swapInfo.Value = value + } + } + } + if swapInfo.PairID == "" { + addSwapInfoConsiderError(nil, errors.New("Invalid TRC20 swapin"), &swapInfos, &errs) + return + } + default: + addSwapInfoConsiderError(nil, errors.New("Unknown error"), &swapInfos, &errs) + return + } + + swapInfos = append(swapInfos, swapInfo) + errs = append(errs, nil) + return swapInfos, errs +} + +func checkTrc20TransferLog(txlogs []*core.TransactionInfo_Log, contractAddress string) (logfrom, logto string, logamount *big.Int, err error) { + logamount = new(big.Int) + hasAddr := false + for _, txlog := range txlogs { + addr := txlog.GetAddress() + if EqualAddress(tronaddress.Address(addr).String(), contractAddress) { + hasAddr = true + topics := txlog.GetTopics() + if len(topics) < 3 { + return "", "", nil, errors.New("Log topic number error") + } + if bytes.Equal(topics[0], erc20CodeParts["LogTransfer"]) == false { + return "", "", nil, errors.New("Log topic is not log transfer") + } + logfrom = fmt.Sprintf("%x", topics[1]) + logto = fmt.Sprintf("%x", topics[2]) + amthex := fmt.Sprintf("%x", txlog.GetData()) + logamount, _ = logamount.SetString(amthex, 16) + break + } + } + if hasAddr == false { + return "", "", nil, errors.New("Logs do not contain contract address") + } + return +} + +func (b *Bridge) verifySwapinTxWithHash(txid string, allowUnstable bool) (swapInfos []*tokens.TxSwapInfo, errs []error) { + tx, err := b.GetTransaction(txid) + if err != nil { + return []*tokens.TxSwapInfo{&tokens.TxSwapInfo{}}, []error{err} + } + txres, ok := tx.(*core.Transaction) + if !ok { + return []*tokens.TxSwapInfo{&tokens.TxSwapInfo{}}, []error{errors.New("Tron transaction type error")} + } + status := b.GetTransactionStatus(txid) + if status == nil { + return []*tokens.TxSwapInfo{&tokens.TxSwapInfo{}}, []error{errors.New("Tron transaction not success")} + } + txext := &TransactionExtention{ + Transaction: txres, + BlockNumber: status.BlockHeight, + BlockTime: status.BlockTime, + } + txext.Txid, _ = common.FromHex(txid) + return b.verifySwapinTx(txext, allowUnstable) +} + +func (b *Bridge) verifySwapoutTx(txext *TransactionExtention, allowUnstable bool) (swapInfos []*tokens.TxSwapInfo, errs []error) { + tx := txext.Transaction + ret := tx.GetRet() + if len(ret) != 1 { + return nil, []error{errors.New("Tron tx return not found")} + } + if txret := ret[0].GetRet(); txret != core.Transaction_Result_SUCESS { + return nil, []error{fmt.Errorf("Tron tx not success: %+v", txret)} + } + if cret := ret[0].GetContractRet(); cret != core.Transaction_Result_SUCCESS { + return nil, []error{fmt.Errorf("Tron tx contract not success: %+v", cret)} + } + swapInfo := &tokens.TxSwapInfo{ + Hash: CalcTxHash(tx), + Height: txext.BlockNumber, + Timestamp: txext.BlockTime, + } + + tokenPairsConfig := tokens.GetTokenPairsConfig() + + if len(tx.RawData.Contract) != 1 { + addSwapInfoConsiderError(nil, errors.New("Invalid tron contract"), &swapInfos, &errs) + return + } + contract := tx.RawData.Contract[0] + switch contract.Type { + case core.Transaction_Contract_TriggerSmartContract: + var c core.TriggerSmartContract + err := ptypes.UnmarshalAny(contract.GetParameter(), &c) + if err != nil { + addSwapInfoConsiderError(nil, errors.New("Tx inconsistent"), &swapInfos, &errs) + return + } + contractAddress := fmt.Sprintf("%v", tronaddress.Address(c.ContractAddress)) + for _, tokenPair := range tokenPairsConfig { + token := tokenPair.DestToken + tokenContractAddress := token.ContractAddress + if strings.EqualFold(tokenContractAddress, contractAddress) { + swapInfo.PairID = tokenPair.PairID + } + } + if swapInfo.PairID == "" { + addSwapInfoConsiderError(nil, errors.New("Invalid swapout"), &swapInfos, &errs) + return + } + inputData := c.Data + from := fmt.Sprintf("%v", tronaddress.Address(c.OwnerAddress)) + bindAddress, value, err := eth.ParseSwapoutTxInput(&inputData) + if err != nil { + addSwapInfoConsiderError(swapInfo, err, &swapInfos, &errs) + return + } + swapInfo.From = from + swapInfo.TxTo = contractAddress + swapInfo.Bind = bindAddress + swapInfo.Value = value + default: + addSwapInfoConsiderError(nil, errors.New("Unknown error"), &swapInfos, &errs) + return + } + + swapInfos = append(swapInfos, swapInfo) + errs = append(errs, nil) + return nil, nil +} + +func (b *Bridge) verifySwapoutTxWithHash(txid string, allowUnstable bool) (swapInfos []*tokens.TxSwapInfo, errs []error) { + tx, err := b.GetTransaction(txid) + if err != nil { + return nil, []error{err} + } + txres, ok := tx.(*core.Transaction) + if !ok { + return nil, []error{errors.New("Tron transaction type error")} + } + status := b.GetTransactionStatus(txid) + if status == nil || status.Receipt == nil { + return nil, []error{errors.New("Tron transaction failed")} + } + if status == nil { + return []*tokens.TxSwapInfo{&tokens.TxSwapInfo{}}, []error{errors.New("Tron transaction type error")} + } + txext := &TransactionExtention{ + Transaction: txres, + BlockNumber: status.BlockHeight, + BlockTime: status.BlockTime, + } + txext.Txid, _ = common.FromHex(txid) + return b.verifySwapoutTx(txext, allowUnstable) +} diff --git a/tokens/types.go b/tokens/types.go index 77b77f61..0bea8dec 100644 --- a/tokens/types.go +++ b/tokens/types.go @@ -2,6 +2,7 @@ package tokens import ( "crypto/ecdsa" + "crypto/ed25519" "errors" "fmt" "math/big" @@ -67,6 +68,13 @@ type BlocknetCoreAPIArgs struct { DisableTLS bool } +type KeyType string + +const ( + ECDSAKeyType KeyType = "ecdsa" + ED25519KeyType KeyType = "ed25519" +) + // TokenConfig struct type TokenConfig struct { ID string `json:",omitempty"` @@ -92,11 +100,14 @@ type TokenConfig struct { DefaultGasLimit uint64 `json:",omitempty"` + PrivateKeyType KeyType `json:"ecdsa"` + // use private key address instead - DcrmAddressKeyStore string `json:"-"` - DcrmAddressPassword string `json:"-"` - DcrmAddressKeyFile string `json:"-"` - dcrmAddressPriKey *ecdsa.PrivateKey + DcrmAddressKeyStore string `json:"-"` + DcrmAddressPassword string `json:"-"` + DcrmAddressKeyFile string `json:"-"` + dcrmAddressPriKey *ecdsa.PrivateKey + dcrmAddressED25519PriKey *ed25519.PrivateKey // calced value maxSwap *big.Int @@ -104,6 +115,8 @@ type TokenConfig struct { maxSwapFee *big.Int minSwapFee *big.Int bigValThreshhold *big.Int + + Unit string // Cosmos coin unit denom } // IsErc20 return if token is erc20 @@ -116,6 +129,16 @@ func (c *TokenConfig) IsProxyErc20() bool { return strings.EqualFold(c.ID, "ProxyERC20") } +// IsTrc20 return if token is trc20 +func (c *TokenConfig) IsTrc20() bool { + return strings.EqualFold(c.ID, "ERC20") || strings.EqualFold(c.ID, "TRC20") || c.IsProxyErc20() || c.IsProxyTrc20() +} + +// IsProxyTrc20 return if token is proxy contract of trc20 +func (c *TokenConfig) IsProxyTrc20() bool { + return strings.EqualFold(c.ID, "ProxyTRC20") +} + // SwapType type type SwapType uint32 @@ -177,11 +200,13 @@ type TxSwapInfo struct { // TxStatus struct type TxStatus struct { - Receipt interface{} `json:"receipt,omitempty"` - Confirmations uint64 `json:"confirmations"` - BlockHeight uint64 `json:"block_height"` - BlockHash string `json:"block_hash"` - BlockTime uint64 `json:"block_time"` + Receipt interface{} `json:"receipt,omitempty"` + PrioriFinalized bool `json:"priori_finalized,omitempty"` + CustomeCheckStable func(uint64) int + Confirmations uint64 `json:"confirmations"` + BlockHeight uint64 `json:"block_height"` + BlockHash string `json:"block_hash"` + BlockTime uint64 `json:"block_time"` } // SwapInfo struct @@ -194,6 +219,11 @@ type SwapInfo struct { Identifier string `json:"identifier,omitempty"` } +type Marshalable interface { + MarshalJSON() ([]byte, error) + UnmarshalJSON(data []byte) error +} + // BuildTxArgs struct type BuildTxArgs struct { SwapInfo `json:"swapInfo,omitempty"` @@ -209,8 +239,11 @@ type BuildTxArgs struct { // GetExtraArgs get extra args func (args *BuildTxArgs) GetExtraArgs() *BuildTxArgs { return &BuildTxArgs{ - SwapInfo: args.SwapInfo, - Extra: args.Extra, + SwapInfo: args.SwapInfo, + From: args.From, + To: args.To, + OriginValue: args.OriginValue, + Extra: args.Extra, } } @@ -224,8 +257,9 @@ func (args *BuildTxArgs) GetTxNonce() uint64 { // AllExtras struct type AllExtras struct { - BtcExtra *BtcExtraArgs `json:"btcExtra,omitempty"` - EthExtra *EthExtraArgs `json:"ethExtra,omitempty"` + BtcExtra *BtcExtraArgs `json:"btcExtra,omitempty"` + EthExtra *EthExtraArgs `json:"ethExtra,omitempty"` + TronExtra *TronExtraArgs `json:"tronExtra,omitempty"` } // EthExtraArgs struct @@ -248,6 +282,11 @@ type BtcExtraArgs struct { PreviousOutPoints []*BtcOutPoint `json:"previousOutPoints,omitempty"` } +// TronExtraArgs struct +type TronExtraArgs struct { + RawTx string `json:"rawTx,omitempty"` +} + // P2shAddressInfo struct type P2shAddressInfo struct { BindAddress string @@ -360,6 +399,11 @@ func (c *TokenConfig) GetDcrmAddressPrivateKey() *ecdsa.PrivateKey { return c.dcrmAddressPriKey } +// GetDcrmAddressED25519PrivateKey get private key +func (c *TokenConfig) GetDcrmAddressED25519PrivateKey() *ed25519.PrivateKey { + return c.dcrmAddressED25519PriKey +} + // LoadDcrmAddressPrivateKey load private key func (c *TokenConfig) LoadDcrmAddressPrivateKey() error { if c.DcrmAddressKeyFile != "" { diff --git a/worker/common.go b/worker/common.go index b1fed448..ac3800d5 100644 --- a/worker/common.go +++ b/worker/common.go @@ -217,6 +217,20 @@ func verifySwapTransaction(bridge tokens.CrossChainBridge, pairID, txid, bind st return swapInfo, err } +func dcrmSignTransaction(bridge tokens.CrossChainBridge, rawTx interface{}, args *tokens.BuildTxArgs) (signedTx interface{}, txHash string, err error) { + maxRetryDcrmSignCount := 5 + for i := 0; i < maxRetryDcrmSignCount; i++ { + signedTx, txHash, err = bridge.DcrmSignTransaction(rawTx, args.GetExtraArgs()) + if err == nil { + break + } + } + if err != nil { + return nil, "", err + } + return signedTx, txHash, nil +} + func sendSignedTransaction(bridge tokens.CrossChainBridge, signedTx interface{}, txid, pairID, bind string, isSwapin, isReplace bool) (err error) { var ( txHash string diff --git a/worker/stable.go b/worker/stable.go index 59d86fd8..1f4d378a 100644 --- a/worker/stable.go +++ b/worker/stable.go @@ -89,7 +89,8 @@ func processSwapoutStable(swap *mongodb.MgoSwapResult) (err error) { func getSwapTxStatus(resBridge tokens.CrossChainBridge, swap *mongodb.MgoSwapResult) *tokens.TxStatus { txStatus := resBridge.GetTransactionStatus(swap.SwapTx) - if txStatus != nil && txStatus.BlockHeight > 0 { + //if txStatus != nil && txStatus.BlockHeight > 0 { + if txStatus != nil { return txStatus } for _, oldSwapTx := range swap.OldSwapTxs { @@ -109,12 +110,35 @@ func processSwapStable(swap *mongodb.MgoSwapResult, isSwapin bool) (err error) { oldSwapTx := swap.SwapTx resBridge := tokens.GetCrossChainBridge(!isSwapin) txStatus := getSwapTxStatus(resBridge, swap) + if txStatus.CustomeCheckStable != nil { + // Custome check stable logic + // For blockchains like Tron, which can tell tx is conditionally finailized + // but only cannot provide an Eth style RPCTxReceipt + switch txStatus.CustomeCheckStable(*resBridge.GetChainConfig().Confirmations) { + case 0: + // stable + logWorker("transaction is stable", "txid", swap.TxID) + return markSwapResultStable(swap.TxID, swap.PairID, swap.Bind, isSwapin) + case 1: + // fail + logWorker("transaction failed", "txid", swap.TxID) + return markSwapResultFailed(swap.TxID, swap.PairID, swap.Bind, isSwapin) + default: + // unstable + logWorker("transaction is unstable", "txid", swap.TxID) + return nil + } + } if txStatus == nil || txStatus.BlockHeight == 0 { if swap.SwapHeight == 0 { return processUpdateSwapHeight(resBridge, swap) } return nil } + if txStatus != nil && txStatus.PrioriFinalized { + // For blockchains like Cosmos, which can tell tx is finailized at this stage + return markSwapResultStable(swap.TxID, swap.PairID, swap.Bind, isSwapin) + } if swap.SwapHeight != 0 { if txStatus.Confirmations < *resBridge.GetChainConfig().Confirmations { diff --git a/worker/swap.go b/worker/swap.go index 2cfea644..73be49c8 100644 --- a/worker/swap.go +++ b/worker/swap.go @@ -238,6 +238,7 @@ func processHistory(res *mongodb.MgoSwapResult, isSwapin bool) error { } resBridge := tokens.GetCrossChainBridge(!isSwapin) swapType := getSwapType(isSwapin) + if _, err := resBridge.GetTransaction(history.matchTx); err == nil { matchTx := &MatchTx{ SwapTx: history.matchTx, @@ -245,6 +246,7 @@ func processHistory(res *mongodb.MgoSwapResult, isSwapin bool) error { SwapType: swapType, SwapNonce: history.nonce, } + _ = updateSwapResult(txid, pairID, bind, matchTx) logWorker("swap", "ignore swapped swap", "txid", txid, "pairID", pairID, "bind", bind, "matchTx", history.matchTx, "isSwapin", isSwapin) return errAlreadySwapped