├── .gitignore ├── README.md ├── ad_campaign ├── db_storage.go ├── geth_storage.go ├── routes.go └── service.go ├── app ├── bootstrap.go └── routes.go ├── config ├── config.pro_net.yaml ├── config.test_net.yaml └── global.yaml ├── contract ├── ChangeableRateCrowdsale.go ├── HoQuBounty.go ├── HoQuClaim.go ├── PrivatePlacement.go ├── ad │ └── HoQuAdCampaign.go ├── bin │ └── abigen ├── burner │ └── HoQuBurner.go ├── claim │ └── HoQuClaim.go ├── config │ └── HoQuConfig.go ├── platform │ └── HoQuPlatform.go ├── rater │ └── HoQuRater.go └── storage │ └── HoQuStorage.go ├── data ├── docs │ ├── index.html │ └── swagger.json ├── keys │ ├── testnet_alternative │ └── testnet_main └── test │ └── platform.txt ├── geth ├── ad_contract.go ├── bounty.go ├── burner.go ├── claim.go ├── config.go ├── init.go ├── platform.go ├── presale.go ├── priv_place.go ├── rater.go ├── sale.go ├── storage.go ├── token.go └── transactor.go ├── http ├── bounty_routes.go ├── burner_routes.go ├── claim_routes.go ├── config_routes.go ├── platform │ ├── company_routes.go │ ├── identification_routes.go │ ├── network_routes.go │ ├── stats_routes.go │ └── tracker_routes.go ├── platform_routes.go ├── presale_routes.go ├── rater_routes.go ├── sale_routes.go ├── storage_routes.go ├── token_routes.go ├── transactor_routes.go └── wallet_routes.go ├── lead ├── db_storage.go ├── geth_storage.go ├── routes.go └── service.go ├── main.go ├── models ├── bounty.go ├── claim.go ├── common.go ├── config.go ├── platform.go ├── platform_ad.go ├── platform_company.go ├── platform_identification.go ├── platform_lead.go ├── platform_network.go ├── platform_offer.go ├── platform_stats.go ├── platform_tariff.go ├── platform_tariff_group.go ├── platform_tracker.go ├── platform_user.go ├── presale.go ├── requests.go ├── sale.go ├── storage.go ├── token.go └── wallet.go ├── offer ├── db_storage.go ├── geth_storage.go ├── routes.go └── service.go ├── requests.http ├── sdk ├── app │ ├── config.go │ ├── env.go │ └── logger.go ├── db │ └── connection_manager.go ├── entity │ ├── http.go │ ├── service.go │ ├── storage.go │ └── storage_stack.go ├── geth │ ├── contract.go │ ├── metamask │ │ ├── auth.go │ │ ├── model.go │ │ └── routes.go │ ├── sign.go │ └── wallet.go ├── http │ ├── middleware │ │ ├── exec_time.go │ │ ├── req_input.go │ │ ├── req_output.go │ │ └── sign.go │ ├── rest │ │ └── responder.go │ └── router.go ├── libs │ └── exec_tracker.go ├── models │ ├── contract_event.go │ └── rest_response.go └── tracing │ ├── jaeger.go │ └── middleware.go ├── tariff ├── db_storage.go ├── geth_storage.go ├── routes.go └── service.go ├── tariff_group ├── db_storage.go ├── geth_storage.go ├── routes.go └── service.go ├── user ├── db_storage.go ├── geth_storage.go ├── routes.go └── service.go └── vendor └── vendor.json /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | vendor/* 3 | !vendor/vendor.json 4 | config/local* 5 | hoqu-geth-api* 6 | data/keys/* 7 | !data/keys/testnet* -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # HOQU blockchain API by GoLang 2 | 3 | Provides all projects the opportunity to access Ethereum blockchain through RESTful API. 4 | 5 | ## Installation 6 | 7 | Install [GoLang](https://www.goinggo.net/2016/05/installing-go-and-your-workspace.html) and setup local environment 8 | Install [Ethereum command line tools](https://www.ethereum.org/cli) 9 | 10 | ### Install govendor 11 | 12 | ```console 13 | go get -u github.com/kardianos/govendor 14 | ``` 15 | 16 | Sync vendor packages 17 | 18 | ```console 19 | govendor sync 20 | ``` 21 | 22 | Build HOQU API 23 | 24 | ```console 25 | cd $GOPATH/src/hoqu-geth-api 26 | go build 27 | ``` 28 | 29 | ## Execution (test node via rinkeby.infura.io) 30 | 31 | Run API 32 | 33 | ```console 34 | ./hoqu-geth-api 35 | ``` 36 | 37 | ## Execution (production with own node) 38 | 39 | Run Geth node 40 | 41 | Use IPC endpoint provided by geth in your pro_net config (geth -> endpoint) 42 | 43 | Run API 44 | 45 | ```console 46 | APPLICATION_ENV=pro_net ./hoqu-geth-api 47 | ``` 48 | 49 | ## Development 50 | 51 | ### Generate new go bindings for solidity contracts 52 | 53 | If you are going to modify solidity contracts or contracts are changed in main solidity repository follow next steps. 54 | 55 | Install [Solidity compiler](http://solidity.readthedocs.io/en/develop/installing-solidity.html) 56 | 57 | copy HOQU contracts to sol 58 | 59 | ```console 60 | cd $GOPATH/src/hoqu-geth-api 61 | rsync -vax vendor/github.com/hoqu-io/platform/contracts/ sol/ 62 | ``` 63 | 64 | copy zeppelin contracts to sol 65 | 66 | ```console 67 | cd $GOPATH/src/hoqu-geth-api 68 | rsync -vax vendor/github.com/OpenZeppelin/zeppelin-solidity/contracts/ sol/zeppelin/ 69 | ``` 70 | 71 | Install native Ethereum go node 72 | 73 | ```console 74 | go get github.com/ethereum/go-ethereum 75 | ``` 76 | 77 | Build Geth and utils 78 | 79 | ```console 80 | cd $GOPATH/src/github.com/ethereum/go-ethereum/ 81 | make 82 | make all 83 | ``` 84 | 85 | Generate go bindings from solidity contract (if sol sources modified) 86 | 87 | ```console 88 | $GOPATH/src/github.com/ethereum/go-ethereum/build/bin/abigen --sol sol/HoQuPlatform.sol --pkg=platform --out=contract/platform/HoQuPlatform.go 89 | ``` 90 | 91 | Alternatively you can generate go bindings from assembled solidity contract 92 | 93 | ```console 94 | $GOPATH/src/hoqu-geth-api/contract/bin/abigen --sol sol/HoQuPlatform.sol --pkg=platform --out=contract/platform/HoQuPlatform.go 95 | $GOPATH/src/hoqu-geth-api/contract/bin/abigen --sol sol/HoQuStorage.sol --pkg=platform --out=contract/storage/HoQuStorage.go 96 | $GOPATH/src/hoqu-geth-api/contract/bin/abigen --sol sol/HoQuConfig.sol --pkg=platform --out=contract/config/HoQuConfig.go 97 | $GOPATH/src/hoqu-geth-api/contract/bin/abigen --sol sol/HoQuAdCampaign.sol --pkg=ad --out=contract/ad/HoQuAdCampaign.go 98 | $GOPATH/src/hoqu-geth-api/contract/bin/abigen --sol sol/HoQuRater.sol --pkg=rater --out=contract/rater/HoQuRater.go 99 | ``` 100 | 101 | ### Generate API documentation 102 | 103 | Install [go-swagger](https://github.com/go-swagger/go-swagger) 104 | 105 | Generate swagger.json 106 | 107 | ```console 108 | cd $GOPATH/src/hoqu-geth-api 109 | swagger generate spec -o ./data/docs/swagger.json 110 | ``` 111 | -------------------------------------------------------------------------------- /ad_campaign/geth_storage.go: -------------------------------------------------------------------------------- 1 | package ad_campaign 2 | 3 | import ( 4 | "hoqu-geth-api/geth" 5 | "sync" 6 | "context" 7 | "fmt" 8 | "hoqu-geth-api/models" 9 | "hoqu-geth-api/sdk/entity" 10 | ) 11 | 12 | var ( 13 | gs *GethStorage 14 | gsOnce sync.Once 15 | ) 16 | 17 | type GethStorage struct { 18 | *entity.Storage 19 | HoquPlatform *geth.HoquPlatform 20 | HoquStorage *geth.HoQuStorage 21 | HoquConfig *geth.HoQuConfig 22 | } 23 | 24 | func NewGethStorage(nm string, hp *geth.HoquPlatform, hs *geth.HoQuStorage, hc *geth.HoQuConfig) *GethStorage { 25 | return &GethStorage{ 26 | Storage: entity.NewStorage(nm), 27 | HoquPlatform: hp, 28 | HoquStorage: hs, 29 | HoquConfig: hc, 30 | } 31 | } 32 | 33 | func InitGethStorage() (err error) { 34 | gsOnce.Do(func() { 35 | err = geth.InitGeth() 36 | gs = NewGethStorage( 37 | "ethereum: ad_campaign", 38 | geth.GetHoquPlatform(), 39 | geth.GetHoQuStorage(), 40 | geth.GetHoQuConfig(), 41 | ) 42 | }) 43 | return 44 | } 45 | 46 | func GetGethStorage() *GethStorage { 47 | return gs 48 | } 49 | 50 | func (s *GethStorage) Op(ctx context.Context, opName string, input interface{}, output interface{}) (err error) { 51 | span, spanCtx := s.CreateSpan(ctx, opName, input) 52 | defer s.CloseSpan(span, output, &err) 53 | 54 | switch opName { 55 | case entity.CREATE: 56 | err = s.Create(spanCtx, input.(*models.AddAdCampaignRequest), output.(*models.CreateAdCampaignResponseData)) 57 | case entity.SET_STATUS: 58 | err = s.SetStatus(spanCtx, input.(*models.SetStatusRequest), output.(*models.TxSuccessData)) 59 | case entity.GET_BY_ID: 60 | err = s.GetById(spanCtx, input.(*models.IdRequest), output.(*models.AdCampaignSuccessData)) 61 | default: 62 | err = fmt.Errorf("%s: op %s is not supported", s.GetName(), opName) 63 | } 64 | 65 | return 66 | } 67 | 68 | func (s *GethStorage) Create(spanCtx context.Context, input *models.AddAdCampaignRequest, output *models.CreateAdCampaignResponseData) error { 69 | 70 | offReq := &models.IdRequest{ 71 | Id: input.OfferId, 72 | } 73 | offer, err := s.HoquStorage.GetOffer(offReq) 74 | if err != nil { 75 | output.Failed = true 76 | return err 77 | } 78 | 79 | deployParams := &models.DeployAdContractRequest{ 80 | OwnerId: input.OwnerId, 81 | OfferId: input.OfferId, 82 | AdId: input.Id.String(), 83 | BeneficiaryAddress: input.BeneficiaryAddress, 84 | PayerAddress: offer.PayerAddress, 85 | } 86 | contractAddress, tx, err := geth.DeployAdCampaign(deployParams) 87 | if err != nil { 88 | output.Failed = true 89 | return err 90 | } 91 | 92 | adToStorageReq := &models.AddAdToStorageRequest{ 93 | OwnerId: input.OwnerId, 94 | OfferId: input.OfferId, 95 | AdId: input.Id.String(), 96 | ContractAddress: contractAddress.String(), 97 | } 98 | 99 | _, err = s.HoquPlatform.AddAdCampaign(adToStorageReq) 100 | if err != nil { 101 | output.Failed = true 102 | return err 103 | } 104 | 105 | _, err = s.HoquConfig.AddOwner(adToStorageReq.ContractAddress) 106 | if err != nil { 107 | output.Failed = true 108 | return err 109 | } 110 | 111 | output.Tx = tx.Hash().String() 112 | output.ContractAddress = contractAddress.String() 113 | return nil 114 | } 115 | 116 | func (s *GethStorage) SetStatus(spanCtx context.Context, input *models.SetStatusRequest, output *models.TxSuccessData) error { 117 | tx, err := s.HoquPlatform.SetAdCampaignStatus(input) 118 | if err != nil { 119 | return err 120 | } 121 | 122 | output.Tx = tx.String() 123 | return nil 124 | } 125 | 126 | func (s *GethStorage) GetById(spanCtx context.Context, input *models.IdRequest, output *models.AdCampaignSuccessData) error { 127 | adCampaign, err := s.HoquStorage.GetAdCampaign(input.Id) 128 | if err != nil { 129 | return err 130 | } 131 | 132 | adcontract, err := geth.GetAdCampaign(adCampaign.ContractAddress) 133 | if err != nil { 134 | return err 135 | } 136 | 137 | adId, err := adcontract.AdId() 138 | if err != nil { 139 | return err 140 | } 141 | 142 | offId, err := adcontract.OfferId() 143 | if err != nil { 144 | return err 145 | } 146 | 147 | affId, err := adcontract.AffiliateId() 148 | if err != nil { 149 | return err 150 | } 151 | 152 | baddr, err := adcontract.BeneficiaryAddress() 153 | if err != nil { 154 | return err 155 | } 156 | 157 | paddr, err := adcontract.PayerAddress() 158 | if err != nil { 159 | return err 160 | } 161 | 162 | ad := &models.AdCampaign{ 163 | ID: input.Id, 164 | AdId: adId.String(), 165 | CreatedAt: adCampaign.CreatedAt, 166 | OwnerId: affId.String(), 167 | OfferId: offId.String(), 168 | ContractAddress: adCampaign.ContractAddress, 169 | BeneficiaryAddress: baddr.String(), 170 | PayerAddress: paddr.String(), 171 | Status: adCampaign.Status, 172 | } 173 | 174 | output.Ad = ad 175 | output.Update = true 176 | s.OpDone(spanCtx) 177 | return nil 178 | } -------------------------------------------------------------------------------- /ad_campaign/routes.go: -------------------------------------------------------------------------------- 1 | package ad_campaign 2 | 3 | import ( 4 | "github.com/gin-gonic/gin" 5 | "hoqu-geth-api/models" 6 | "hoqu-geth-api/sdk/http/middleware" 7 | "hoqu-geth-api/sdk/entity" 8 | ) 9 | 10 | func InitAdCampaignRoutes(routerGroup *gin.RouterGroup) { 11 | r := routerGroup.Group("/ad") 12 | { 13 | r.POST("/add", middleware.SignRequired(), postAddAdCampaignAction) 14 | r.POST("/status", middleware.SignRequired(), postSetAdCampaignStatusAction) 15 | r.GET("/:id", getAdCampaignAction) 16 | } 17 | } 18 | 19 | // swagger:route POST /platform/ad/add ad_campaigns addAdCampaign 20 | // 21 | // Add AdCampaign. 22 | // 23 | // The Ad is a campaign of the affiliate to promote particular offer. 24 | // The Ad is created by the affiliate. All widgets placed on affiliate website should be linked to particular Ad. 25 | // The affiliate can specify money receiver address (beneficiary) per each Ad. 26 | // 27 | // Consumes: 28 | // - application/json 29 | // Produces: 30 | // - application/json 31 | // Responses: 32 | // 200: AddAdCampaignSuccessResponse 33 | // 400: RestErrorResponse 34 | // 35 | func postAddAdCampaignAction(ctx *gin.Context) { 36 | entity.HttpBindAction(ctx, &models.AddAdCampaignRequest{}, &models.CreateAdCampaignResponseData{}, GetService().Create) 37 | } 38 | 39 | // swagger:route POST /platform/ad/status ad_campaigns setAdCampaignStatus 40 | // 41 | // Set AdCampaign Status. 42 | // 43 | // Consumes: 44 | // - application/json 45 | // Produces: 46 | // - application/json 47 | // Responses: 48 | // 200: TxSuccessResponse 49 | // 400: RestErrorResponse 50 | // 51 | func postSetAdCampaignStatusAction(ctx *gin.Context) { 52 | entity.SetAction(ctx, &models.SetStatusRequest{}, GetService().SetStatus) 53 | } 54 | 55 | // swagger:route GET /platform/ad/:id ad_campaigns getAdCampaign 56 | // 57 | // Get AdCampaign by ID. 58 | // 59 | // Produces: 60 | // - application/json 61 | // Responses: 62 | // 200: AdCampaignSuccessData 63 | // 400: RestErrorResponse 64 | // 65 | func getAdCampaignAction(ctx *gin.Context) { 66 | id := ctx.Param("id") 67 | entity.GetByIdAction(ctx, id, &models.AdCampaignSuccessData{}, GetService().GetById) 68 | } 69 | -------------------------------------------------------------------------------- /ad_campaign/service.go: -------------------------------------------------------------------------------- 1 | package ad_campaign 2 | 3 | import ( 4 | "hoqu-geth-api/sdk/entity" 5 | "sync" 6 | "context" 7 | "hoqu-geth-api/models" 8 | "github.com/satori/go.uuid" 9 | ) 10 | 11 | var ( 12 | s *Service 13 | sOnce sync.Once 14 | ) 15 | 16 | type Service struct { 17 | *entity.Service 18 | } 19 | 20 | func NewService(storage entity.StorageInterface) *Service { 21 | return &Service{ 22 | Service: entity.NewService(storage, true), 23 | } 24 | } 25 | 26 | func InitService() (err error) { 27 | sOnce.Do(func() { 28 | err = InitDbStorage() 29 | if err != nil { 30 | return 31 | } 32 | s = NewService(GetDbStorage()) 33 | 34 | err = InitGethStorage() 35 | if err != nil { 36 | return 37 | } 38 | s.AppendStorage(GetGethStorage()) 39 | }) 40 | return 41 | } 42 | 43 | func GetService() *Service { 44 | return s 45 | } 46 | 47 | func (s *Service) Create(ctx context.Context, input interface{}, output interface{}) error { 48 | req := input.(*models.AddAdCampaignRequest) 49 | resp := output.(*models.CreateAdCampaignResponseData) 50 | id, err := uuid.NewV2('A') 51 | if err != nil { 52 | return err 53 | } 54 | 55 | req.Id = id 56 | resp.Id = id.String() 57 | 58 | return s.Service.Create(ctx, req, output) 59 | } -------------------------------------------------------------------------------- /app/bootstrap.go: -------------------------------------------------------------------------------- 1 | package app 2 | 3 | import ( 4 | sdkApp "hoqu-geth-api/sdk/app" 5 | "hoqu-geth-api/geth" 6 | "github.com/sirupsen/logrus" 7 | "hoqu-geth-api/sdk/tracing" 8 | "hoqu-geth-api/offer" 9 | "hoqu-geth-api/tariff" 10 | "hoqu-geth-api/ad_campaign" 11 | "hoqu-geth-api/lead" 12 | "hoqu-geth-api/user" 13 | "hoqu-geth-api/tariff_group" 14 | ) 15 | 16 | func Bootstrap() { 17 | sdkApp.InitConfig() 18 | sdkApp.InitLogger() 19 | if err := geth.InitGeth(); err != nil { 20 | logrus.Fatal(err) 21 | } 22 | 23 | if err := tracing.Init(); err != nil { 24 | logrus.Fatal(err) 25 | } 26 | 27 | if err := user.InitService(); err != nil { 28 | logrus.Fatal(err) 29 | } 30 | 31 | if err := offer.InitService(); err != nil { 32 | logrus.Fatal(err) 33 | } 34 | 35 | if err := ad_campaign.InitService(); err != nil { 36 | logrus.Fatal(err) 37 | } 38 | 39 | if err := lead.InitService(); err != nil { 40 | logrus.Fatal(err) 41 | } 42 | 43 | if err := tariff_group.InitService(); err != nil { 44 | logrus.Fatal(err) 45 | } 46 | 47 | if err := tariff.InitService(); err != nil { 48 | logrus.Fatal(err) 49 | } 50 | } -------------------------------------------------------------------------------- /app/routes.go: -------------------------------------------------------------------------------- 1 | // Package classification HOQU blockchain API by GoLang. 2 | // 3 | // Provides all projects the opportunity to access Ethereum blockchain through RESTful API. 4 | // 5 | // Schemes: http, https 6 | // BasePath: / 7 | // Version: 1.1.7 8 | // License: MIT http://opensource.org/licenses/MIT 9 | // Contact: Denis Degterin https://github.com/hoqu-io/hoqu-geth-api 10 | // 11 | // Consumes: 12 | // - application/json 13 | // 14 | // Produces: 15 | // - application/json 16 | // 17 | // Security: 18 | // - hash 19 | // - jwt 20 | // 21 | // SecurityDefinitions: 22 | // hash: 23 | // type: apiKey 24 | // name: X-Sign 25 | // in: header 26 | // jwt: 27 | // type: apiKey 28 | // name: X-Authorization 29 | // in: header 30 | // 31 | // swagger:meta 32 | 33 | package app 34 | 35 | import ( 36 | sdkHttp "hoqu-geth-api/sdk/http" 37 | "github.com/gin-gonic/gin" 38 | "sync" 39 | "hoqu-geth-api/sdk/geth/metamask" 40 | "hoqu-geth-api/http" 41 | ) 42 | 43 | var routerOnceInitializer sync.Once 44 | 45 | func Run() error { 46 | return sdkHttp.Run(initRoutes) 47 | } 48 | 49 | func initRoutes(router *gin.Engine) { 50 | routerOnceInitializer.Do(func() { 51 | sdkHttp.UseTracing(router) 52 | 53 | metamask.AddMetamaskAuthRoutes(router) 54 | 55 | http.InitWalletRoutes(router) 56 | http.InitTokenRoutes(router) 57 | http.InitPresaleRoutes(router) 58 | http.InitSaleRoutes(router) 59 | http.InitBountyRoutes(router) 60 | http.InitClaimRoutes(router) 61 | http.InitBurnerRoutes(router) 62 | http.InitHoQuConfigRoutes(router) 63 | http.InitHoQuStorageRoutes(router) 64 | http.InitHoquPlatformRoutes(router) 65 | http.InitHoQuRaterRoutes(router) 66 | http.InitHoQuTransactorRoutes(router) 67 | }) 68 | } 69 | -------------------------------------------------------------------------------- /config/config.pro_net.yaml: -------------------------------------------------------------------------------- 1 | server: 2 | url: https://geth-api.hoqu.io 3 | geth: 4 | endpoint: /home/node/.ethereum/geth.ipc 5 | main: 6 | key_file: data/keys/main 7 | addr: 8 | token: 0x1b957dc4aefeed3b4a2351a6a6d5cbfbba0cecfa 9 | privPlace: 0x7ceb828497922646c2b0bd23ba199d753219f64c 10 | presale: 0x903E7414cb54e44766dCf03e4aB424FDf9259D78 11 | sale: 0xF37c4A962e70d813A4D9825942141Cd9Bc5169Fd 12 | bounty: 0x7dc8C210540be4EaA3Bb194B4D9B4907E0Dae04f 13 | claim: 0xac5dc571f0314edd797e3ba026f6592945b53eb9 14 | burner: 0x818e2ad435764b80ee844cf7b2e8036e0a4b7c83 15 | start_block: 16 | token: 4273100 17 | privPlace: 4273100 18 | presale: 4538755 19 | sale: 4631026 20 | bounty: 4643425 21 | -------------------------------------------------------------------------------- /config/config.test_net.yaml: -------------------------------------------------------------------------------- 1 | server: 2 | port: 8888 3 | url: http://geth-api-test.hoqu.io 4 | geth: 5 | endpoint: https://rinkeby.infura.io 6 | main: 7 | pass: nhbybnb123 8 | security: 9 | sign: test-hash -------------------------------------------------------------------------------- /config/global.yaml: -------------------------------------------------------------------------------- 1 | project: 2 | name: hoqu-geth-api 3 | server: 4 | host: 0.0.0.0 5 | port: 8080 6 | url: http://geth-node.hoqu.io 7 | tracer: 8 | enabled: false 9 | jaeger: 10 | host: tracer-agent.hoqu.io:6831 11 | geth: 12 | endpoint: https://rinkeby.infura.io 13 | nonce_gap: 15 14 | nonce_replacement_timeout: 180 15 | gas_price: 50 16 | gas_limit: 95000 17 | tx_delay: 1 18 | main: 19 | key_file: data/keys/testnet_main 20 | pass: key_pass_here 21 | addr: 22 | token: 0xd75f3e1765d4f3479b25bde50320fd164224e977 23 | privPlace: 0x020225f157d4e99055356597556d0f6fb06d1184 24 | presale: 0x4095b16300B89ecB2cDa7f0AB6C01a783b91Db4F 25 | sale: 0xd0eE519E170f272EEB2f1e895E95A719B858D998 26 | bounty: 0x839b3D7Bf114921cCE7162c2Ad49260Bf618A1bB 27 | claim: 0x639D010dC63c2d98aa506418a7BD7fdA470FCF28 28 | burner: 0x403a78940972758427e6d83017ceaa7d0bc5ac92 29 | conf: 0x3807b7a05Cf95574EECC38600D4eD9Dc1c5f9025 30 | storage: 0x0e4416C32DAAB477a3F2C7f8FFF1f2c7153F76A1 31 | rater: 0xbCec7066cf3580ecdCBeA564b03dcf7B1956504F 32 | platform: 0x1796426d98E8f863290176250c46f6399f2ea8d9 33 | transactor: 0xcA1dA63f241981D9D26a74bbAc2fA0B7851763d2 34 | start_block: 35 | token: 857820 36 | privPlace: 857820 37 | presale: 857820 38 | sale: 857820 39 | bounty: 857820 40 | claim: 1603404 41 | conf: 857820 42 | platform: 857820 43 | claim: 44 | batch_limit: 3 45 | batch_timeout: 1 46 | meta_auth: 47 | banner: HOQU Platform 48 | security: 49 | sign: simple-string-by-default 50 | db: 51 | driver: mysql 52 | dsn: hoqu_api:qwerty@(localhost:3306)/hoqu_api?charset=utf8&parseTime=True&loc=Local -------------------------------------------------------------------------------- /contract/bin/abigen: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hoqu-io/hoqu-geth-api/869315fd1b6ce6974f56d8d125fae5957bbc42f8/contract/bin/abigen -------------------------------------------------------------------------------- /data/docs/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | HOQU API documentation 5 | 6 | 7 | 8 | 9 | 12 | 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /data/keys/testnet_alternative: -------------------------------------------------------------------------------- 1 | {"address":"92b5ae365272b50495a6c21cad35652071ff7497","crypto":{"cipher":"aes-128-ctr","ciphertext":"519b770ee5d78e84e00aec96bb3368bcf76b2814acc32316dafe6de3280a0cd5","cipherparams":{"iv":"25cd272fed457ee6b0e88dd441170ea8"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"e82f38692b0f1358ecb277c670ccce98c11731be733323d776c91941f2c2a49c"},"mac":"22ca1fcbddedbd64c65f8af1950d0e30603cf957a62bd6f60489cfe3cbe51afe"},"id":"fe68d759-296e-4d81-abb3-2d1cb52a9508","version":3} -------------------------------------------------------------------------------- /data/keys/testnet_main: -------------------------------------------------------------------------------- 1 | {"address":"11d56d0b2c676e3966fd7b8f0eba9d009bce4383","crypto":{"cipher":"aes-128-ctr","ciphertext":"1533f6998d733674d6f91a795948c836cd54b0da0634bdda73e1465783e51521","cipherparams":{"iv":"2e4c13a7a90172e6d483548ee955319a"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"ab9385571ae2f84332c6905e8595326848a2bc4737b2f5da4f0a98709ee51ade"},"mac":"f29eafd8eb4df1b0e861c8b1b0b552f39c851e8c0511d1fecf75cde99373edb2"},"id":"563dba71-60ba-4a99-b45b-598b21902b67","version":3} -------------------------------------------------------------------------------- /data/test/platform.txt: -------------------------------------------------------------------------------- 1 | user -- test affiliate: 2 | 0x2aD0a91C6e8199Aa4B264e417521eA6bb1636f53 3 | 634822f6-e8c5-21e8-a655-ac220b4e0f6c 4 | 5 | user -- test merchant 6 | 0x7Eb46773851aAb328D353cAF1A7b3D418DBAEFF3 7 | 6fc90187-e8c5-21e8-a655-ac220b4e0f6c 8 | 9 | user -- test network 10 | 0xb13a95F74fB189bD66545F732f715E5C7175c615 11 | 780dffab-e8c5-21e8-a655-ac220b4e0f6c 12 | 13 | user -- test tracker 14 | 0x92b5ae365272B50495a6C21cAD35652071Ff7497 15 | 824f9a02-e8c5-21e8-a655-ac220b4e0f6c 16 | 17 | network -- HOQU Net 18 | ab6766e8-e8c5-21e8-a64e-ac220b4e0f6c 19 | 20 | tracker -- HOQU Tracker 21 | bd543b80-e8c5-21e8-a654-ac220b4e0f6c 22 | 23 | offer -- HOQU Test offer 24 | dba72602-e8c5-21e8-a64f-ac220b4e0f6c 25 | 368 HQX 26 | |--> tariff group 27 | f2b1d498-e8c5-21e8-a654-ac220b4e0f6c 28 | |--> tariff 29 | 1963d23f-e8c6-21e8-a654-ac220b4e0f6c 30 | order: 0.05 percent 31 | |--> tariff 32 | 258da530-e8c6-21e8-a654-ac220b4e0f6c 33 | callback: 500 HQX fixed 34 | 35 | ad campaign -- for HOQU Test offer 36 | 55862910-e8c6-21e8-a641-ac220b4e0f6c 37 | |--> contract 38 | 0x7EedA95E5f655CC7440F91340e1F7f7958133fFF 39 | |--> lead 40 | d4482d64-e8c6-21e8-a64c-ac220b4e0f6c 41 | -------------------------------------------------------------------------------- /geth/ad_contract.go: -------------------------------------------------------------------------------- 1 | package geth 2 | 3 | import ( 4 | "hoqu-geth-api/contract/ad" 5 | "github.com/ethereum/go-ethereum/common" 6 | "errors" 7 | "fmt" 8 | "hoqu-geth-api/sdk/geth" 9 | "github.com/ethereum/go-ethereum/core/types" 10 | "hoqu-geth-api/models" 11 | "github.com/satori/go.uuid" 12 | "time" 13 | ) 14 | 15 | type HoQuAdCampaign struct { 16 | *geth.Contract 17 | HoQuAdCampaign *ad.HoQuAdCampaign 18 | } 19 | 20 | func GetAdCampaign(addr string) (*HoQuAdCampaign, error) { 21 | c := geth.NewContract(addr) 22 | c.InitEvents(ad.HoQuAdCampaignABI) 23 | 24 | s, err := ad.NewHoQuAdCampaign(c.Address, c.Wallet.Connection) 25 | if err != nil { 26 | return nil, errors.New(fmt.Sprintf("Failed to instantiate a HoQu Ad Campaign contract: %v", err)) 27 | } 28 | 29 | return &HoQuAdCampaign{ 30 | Contract: c, 31 | HoQuAdCampaign: s, 32 | }, nil 33 | } 34 | 35 | func DeployAdCampaign(params *models.DeployAdContractRequest) (*common.Address, *types.Transaction, error) { 36 | aid, err := uuid.FromString(params.AdId) 37 | if err != nil { 38 | return nil, nil, err 39 | } 40 | 41 | oid, err := uuid.FromString(params.OwnerId) 42 | if err != nil { 43 | return nil, nil, err 44 | } 45 | 46 | offid, err := uuid.FromString(params.OfferId) 47 | if err != nil { 48 | return nil, nil, err 49 | } 50 | 51 | w := GetHoquPlatform().Contract.Wallet 52 | opts, err := w.GetTransactOpts() 53 | if err != nil { 54 | w.OnFailTransaction(err) 55 | return nil, nil, err 56 | } 57 | 58 | address, tx, _, err := ad.DeployHoQuAdCampaign( 59 | opts, 60 | w.Connection, 61 | GetHoQuConfig().Address, 62 | GetHoQuTransactor().Address, 63 | GetHoQuStorage().Address, 64 | GetHoQuRater().Address, 65 | aid, 66 | offid, 67 | oid, 68 | common.HexToAddress(params.BeneficiaryAddress), 69 | common.HexToAddress(params.PayerAddress), 70 | ) 71 | if err != nil { 72 | w.OnFailTransaction(err) 73 | return nil, nil, fmt.Errorf("failed to deploy HoQuAdCampaign contract: %v", err) 74 | } 75 | 76 | w.OnSuccessTransaction() 77 | return &address, tx, nil 78 | } 79 | 80 | func (adc *HoQuAdCampaign) AdId() (uuid.UUID, error) { 81 | id, err := adc.HoQuAdCampaign.AdId(nil) 82 | if err != nil { 83 | return uuid.UUID{}, err 84 | } 85 | 86 | return uuid.FromBytes(id[:]) 87 | } 88 | 89 | func (adc *HoQuAdCampaign) OfferId() (uuid.UUID, error) { 90 | id, err := adc.HoQuAdCampaign.OfferId(nil) 91 | if err != nil { 92 | return uuid.UUID{}, err 93 | } 94 | 95 | return uuid.FromBytes(id[:]) 96 | } 97 | 98 | func (adc *HoQuAdCampaign) AffiliateId() (uuid.UUID, error) { 99 | id, err := adc.HoQuAdCampaign.AffiliateId(nil) 100 | if err != nil { 101 | return uuid.UUID{}, err 102 | } 103 | 104 | return uuid.FromBytes(id[:]) 105 | } 106 | 107 | func (adc *HoQuAdCampaign) BeneficiaryAddress() (common.Address, error) { 108 | return adc.HoQuAdCampaign.BeneficiaryAddress(nil) 109 | } 110 | 111 | func (adc *HoQuAdCampaign) PayerAddress() (common.Address, error) { 112 | return adc.HoQuAdCampaign.PayerAddress(nil) 113 | } 114 | 115 | func (adc *HoQuAdCampaign) GetLead(id string) (*models.Lead, error) { 116 | lid, err := uuid.FromString(id) 117 | if err != nil { 118 | return nil, err 119 | } 120 | 121 | lead, err := adc.HoQuAdCampaign.Leads(nil, lid) 122 | if err != nil { 123 | return nil, err 124 | } 125 | 126 | intermediaries := make(map[string]float32) 127 | for num := uint8(0); num < lead.NumOfIntermediaries; num++ { 128 | addr, err := adc.HoQuAdCampaign.GetLeadIntermediaryAddress(nil, lid, num) 129 | if err != nil { 130 | return nil, err 131 | } 132 | percent, err := adc.HoQuAdCampaign.GetLeadIntermediaryPercent(nil, lid, num) 133 | if err != nil { 134 | return nil, err 135 | } 136 | intermediaries[addr.String()] = float32(percent) / 1e6 137 | } 138 | 139 | aid, err := adc.AdId() 140 | if err != nil { 141 | return nil, err 142 | } 143 | 144 | tid, err := uuid.FromBytes(lead.TrackerId[:]) 145 | if err != nil { 146 | return nil, err 147 | } 148 | 149 | leadData := &models.Lead{ 150 | ID: id, 151 | CreatedAt: time.Unix(lead.CreatedAt.Int64(), 0), 152 | AdId: aid.String(), 153 | TrackerId: tid.String(), 154 | Intermediaries: intermediaries, 155 | Meta: lead.Meta, 156 | DataUrl: lead.DataUrl, 157 | Price: lead.Price.String(), 158 | Status: models.Status(lead.Status), 159 | } 160 | 161 | return leadData, nil 162 | } 163 | -------------------------------------------------------------------------------- /geth/bounty.go: -------------------------------------------------------------------------------- 1 | package geth 2 | 3 | import ( 4 | "hoqu-geth-api/contract" 5 | "github.com/ethereum/go-ethereum/common" 6 | "github.com/spf13/viper" 7 | "errors" 8 | "fmt" 9 | "math/big" 10 | "hoqu-geth-api/sdk/geth" 11 | "hoqu-geth-api/models" 12 | sdkModels "hoqu-geth-api/sdk/models" 13 | "github.com/ethereum/go-ethereum/core/types" 14 | "github.com/ethereum/go-ethereum/accounts/abi/bind" 15 | "github.com/sirupsen/logrus" 16 | ) 17 | 18 | var bounty *Bounty 19 | 20 | type Bounty struct { 21 | *geth.Contract 22 | Bounty *contract.HoQuBounty 23 | } 24 | 25 | func InitBounty() error { 26 | c := geth.NewContract(viper.GetString("geth.addr.bounty")) 27 | c.InitEvents(contract.HoQuBountyABI) 28 | 29 | s, err := contract.NewHoQuBounty(c.Address, c.Wallet.Connection) 30 | if err != nil { 31 | return errors.New(fmt.Sprintf("Failed to instantiate a Bounty contract: %v", err)) 32 | } 33 | 34 | bounty = &Bounty{ 35 | Contract: c, 36 | Bounty: s, 37 | } 38 | 39 | return nil 40 | } 41 | 42 | func GetBounty() *Bounty { 43 | return bounty 44 | } 45 | 46 | func (s *Bounty) Deploy(params *models.BountyDeployParams) (*common.Address, *types.Transaction, error) { 47 | tokenAddr := GetToken().Address 48 | 49 | address, tx, _, err := contract.DeployHoQuBounty( 50 | s.Wallet.Account, 51 | s.Wallet.Connection, 52 | tokenAddr, 53 | common.HexToAddress(params.BankAddress), 54 | common.HexToAddress(params.BeneficiaryAddress), 55 | ) 56 | if err != nil { 57 | return nil, nil, fmt.Errorf("failed to deploy contract: %v", err) 58 | } 59 | return &address, tx, nil 60 | } 61 | 62 | func (s *Bounty) Balance(addr string) (*big.Int, error) { 63 | return s.Bounty.Tokens(nil, common.HexToAddress(addr)) 64 | } 65 | 66 | func (s *Bounty) Summary() (*models.BountySummary, error) { 67 | issued, err := s.Bounty.IssuedTokensAmount(nil) 68 | if err != nil { 69 | return nil, err 70 | } 71 | 72 | receivers, err := s.Bounty.GetReceiversCount(&bind.CallOpts{ 73 | From: s.Wallet.Account.From, 74 | }) 75 | if err != nil { 76 | return nil, err 77 | } 78 | 79 | isFin, err := s.Bounty.IsFinished(&bind.CallOpts{ 80 | From: s.Wallet.Account.From, 81 | }) 82 | if err != nil { 83 | return nil, err 84 | } 85 | 86 | return &models.BountySummary{ 87 | IssuedTokensAmount: issued.String(), 88 | ReceiversCount: receivers, 89 | IsFinished: isFin, 90 | }, nil 91 | } 92 | 93 | func (s *Bounty) Approved(addr string) (bool, error) { 94 | return s.Bounty.Approved(nil, common.HexToAddress(addr)) 95 | } 96 | 97 | func (s *Bounty) Events(request *sdkModels.Events) ([]sdkModels.ContractEvent, error) { 98 | events, err := s.GetEventsByTopics( 99 | request, 100 | viper.GetInt64("geth.start_block.bounty"), 101 | ) 102 | if err != nil { 103 | return nil, err 104 | } 105 | 106 | for key, event := range events { 107 | switch { 108 | case event.Name == "TokenBought" || event.Name == "TokenAdded" || event.Name == "TokenToppedUp" || event.Name == "TokenSubtracted": 109 | events[key].Args = models.TokenAddedEventArgs{ 110 | Address: common.BytesToAddress(event.RawArgs[0]).String(), 111 | TokenAmount: common.BytesToHash(event.RawArgs[1]).Big().String(), 112 | EtherAmount: common.BytesToHash(event.RawArgs[2]).Big().String(), 113 | } 114 | case event.Name == "TokenSent" || event.Name == "TokenAddedByBounty": 115 | events[key].Args = models.TokenSentEventAgrs{ 116 | Address: common.BytesToAddress(event.RawArgs[0]).String(), 117 | TokenAmount: common.BytesToHash(event.RawArgs[1]).Big().String(), 118 | } 119 | default: 120 | return nil, fmt.Errorf("unknown event type: %s", event.Name) 121 | } 122 | } 123 | 124 | return events, nil 125 | } 126 | 127 | func (s *Bounty) AddByBounty(addr string, tokens string) (common.Hash, error) { 128 | tokensAmount, ok := big.NewInt(0).SetString(tokens, 0) 129 | if !ok { 130 | return common.Hash{}, fmt.Errorf("wrong number provided: %s", tokens) 131 | } 132 | 133 | opts, err := s.Wallet.GetTransactOpts() 134 | if err != nil { 135 | s.Wallet.OnFailTransaction(err) 136 | return common.Hash{}, err 137 | } 138 | 139 | tx, err := s.Bounty.AddByBounty(opts, common.HexToAddress(addr), tokensAmount) 140 | if err != nil { 141 | s.Wallet.OnFailTransaction(err) 142 | 143 | if s.Wallet.ValidateRepeatableTransaction(err) { 144 | logrus.Warn("Repeat AddByBounty to ", addr) 145 | 146 | return s.AddByBounty(addr, tokens) 147 | } 148 | 149 | return common.Hash{}, err 150 | } 151 | s.Wallet.OnSuccessTransaction() 152 | 153 | return tx.Hash(), nil 154 | } 155 | 156 | func (s *Bounty) Approve(addr string) (common.Hash, error) { 157 | opts, err := s.Wallet.GetTransactOpts() 158 | if err != nil { 159 | s.Wallet.OnFailTransaction(err) 160 | return common.Hash{}, err 161 | } 162 | 163 | tx, err := s.Bounty.Approve(opts, common.HexToAddress(addr)) 164 | if err != nil { 165 | s.Wallet.OnFailTransaction(err) 166 | 167 | if s.Wallet.ValidateRepeatableTransaction(err) { 168 | logrus.Warn("Repeat Approve to ", addr) 169 | 170 | return s.Approve(addr) 171 | } 172 | 173 | return common.Hash{}, err 174 | } 175 | s.Wallet.OnSuccessTransaction() 176 | 177 | return tx.Hash(), nil 178 | } 179 | -------------------------------------------------------------------------------- /geth/burner.go: -------------------------------------------------------------------------------- 1 | package geth 2 | 3 | import ( 4 | "hoqu-geth-api/contract/burner" 5 | "github.com/ethereum/go-ethereum/common" 6 | "github.com/spf13/viper" 7 | "errors" 8 | "fmt" 9 | "math/big" 10 | "hoqu-geth-api/sdk/geth" 11 | "github.com/ethereum/go-ethereum/core/types" 12 | "github.com/sirupsen/logrus" 13 | ) 14 | 15 | var burn *Burner 16 | 17 | type Burner struct { 18 | *geth.Contract 19 | Burner *burner.HoQuBurner 20 | } 21 | 22 | func InitBurner() error { 23 | c := geth.NewContract(viper.GetString("geth.addr.burner")) 24 | 25 | s, err := burner.NewHoQuBurner(c.Address, c.Wallet.Connection) 26 | if err != nil { 27 | return errors.New(fmt.Sprintf("Failed to instantiate a Burner contract: %v", err)) 28 | } 29 | 30 | burn = &Burner{ 31 | Contract: c, 32 | Burner: s, 33 | } 34 | 35 | return nil 36 | } 37 | 38 | func GetBurner() *Burner { 39 | return burn 40 | } 41 | 42 | func (s *Burner) Deploy() (*common.Address, *types.Transaction, error) { 43 | tokenAddr := GetToken().Address 44 | 45 | address, tx, _, err := burner.DeployHoQuBurner( 46 | s.Wallet.Account, 47 | s.Wallet.Connection, 48 | tokenAddr, 49 | ) 50 | if err != nil { 51 | return nil, nil, fmt.Errorf("failed to deploy contract: %v", err) 52 | } 53 | return &address, tx, nil 54 | } 55 | 56 | func (s *Burner) BurnFrom(addr string, tokens string) (common.Hash, error) { 57 | tokensAmount, ok := big.NewInt(0).SetString(tokens, 0) 58 | if !ok { 59 | return common.Hash{}, fmt.Errorf("wrong number provided: %s", tokens) 60 | } 61 | 62 | opts, err := s.Wallet.GetTransactOpts() 63 | if err != nil { 64 | s.Wallet.OnFailTransaction(err) 65 | return common.Hash{}, err 66 | } 67 | 68 | tx, err := s.Burner.BurnFrom(opts, common.HexToAddress(addr), tokensAmount) 69 | if err != nil { 70 | s.Wallet.OnFailTransaction(err) 71 | 72 | if s.Wallet.ValidateRepeatableTransaction(err) { 73 | logrus.Warn("Repeat BurnFrom to ", addr) 74 | 75 | return s.BurnFrom(addr, tokens) 76 | } 77 | 78 | return common.Hash{}, err 79 | } 80 | s.Wallet.OnSuccessTransaction() 81 | 82 | return tx.Hash(), nil 83 | } 84 | -------------------------------------------------------------------------------- /geth/config.go: -------------------------------------------------------------------------------- 1 | package geth 2 | 3 | import ( 4 | platform "hoqu-geth-api/contract/config" 5 | "github.com/ethereum/go-ethereum/common" 6 | "github.com/spf13/viper" 7 | "errors" 8 | "fmt" 9 | "hoqu-geth-api/sdk/geth" 10 | "hoqu-geth-api/models" 11 | sdkModels "hoqu-geth-api/sdk/models" 12 | "github.com/ethereum/go-ethereum/core/types" 13 | ) 14 | 15 | var config *HoQuConfig 16 | 17 | type HoQuConfig struct { 18 | *geth.Contract 19 | HoQuConfig *platform.HoQuConfig 20 | } 21 | 22 | func initHoQuConfig() error { 23 | c := geth.NewContract(viper.GetString("geth.addr.conf")) 24 | c.InitEvents(platform.HoQuConfigABI) 25 | 26 | s, err := platform.NewHoQuConfig(c.Address, c.Wallet.Connection) 27 | if err != nil { 28 | return errors.New(fmt.Sprintf("Failed to instantiate a HoQu Platform Config contract: %v", err)) 29 | } 30 | 31 | config = &HoQuConfig{ 32 | Contract: c, 33 | HoQuConfig: s, 34 | } 35 | 36 | return nil 37 | } 38 | 39 | func GetHoQuConfig() *HoQuConfig { 40 | return config 41 | } 42 | 43 | func (s *HoQuConfig) Deploy(params *models.ConfigDeployParams) (*common.Address, *types.Transaction, error) { 44 | opts, err := s.Wallet.GetTransactOpts() 45 | if err != nil { 46 | s.Wallet.OnFailTransaction(err) 47 | return nil, nil, err 48 | } 49 | 50 | address, tx, _, err := platform.DeployHoQuConfig( 51 | opts, 52 | s.Wallet.Connection, 53 | common.HexToAddress(params.CommissionWallet), 54 | ) 55 | if err != nil { 56 | s.Wallet.OnFailTransaction(err) 57 | return nil, nil, fmt.Errorf("failed to deploy HoQuConfig contract: %v", err) 58 | } 59 | 60 | s.Wallet.OnSuccessTransaction() 61 | return &address, tx, nil 62 | } 63 | 64 | func (s *HoQuConfig) Events(request *sdkModels.Events) ([]sdkModels.ContractEvent, error) { 65 | events, err := s.GetEventsByTopics( 66 | request, 67 | viper.GetInt64("geth.start_block.conf"), 68 | ) 69 | if err != nil { 70 | return nil, err 71 | } 72 | 73 | for key, event := range events { 74 | switch { 75 | case event.Name == "SystemOwnerAdded": 76 | events[key].Args = models.SystemOwnerAddedEventArgs{ 77 | NewOwner: common.BytesToAddress(event.RawArgs[0]).String(), 78 | } 79 | case event.Name == "SystemOwnerChanged": 80 | events[key].Args = models.SystemOwnerChangedEventArgs{ 81 | PreviousOwner: common.BytesToAddress(event.RawArgs[0]).String(), 82 | NewOwner: common.BytesToAddress(event.RawArgs[1]).String(), 83 | } 84 | case event.Name == "SystemOwnerDeleted": 85 | events[key].Args = models.SystemOwnerDeletedEventArgs{ 86 | DeletedOwner: common.BytesToAddress(event.RawArgs[0]).String(), 87 | } 88 | case event.Name == "CommissionWalletChanged": 89 | events[key].Args = models.CommissionWalletChangedEventArgs{ 90 | ChangedBy: common.BytesToAddress(event.RawArgs[0]).String(), 91 | CommissionWallet: common.BytesToAddress(event.RawArgs[1]).String(), 92 | } 93 | case event.Name == "CommissionChanged": 94 | events[key].Args = models.CommissionChangedEventArgs{ 95 | ChangedBy: common.BytesToAddress(event.RawArgs[0]).String(), 96 | Commission: common.BytesToHash(event.RawArgs[1]).Big().String(), 97 | } 98 | default: 99 | return nil, fmt.Errorf("unknown event type: %s", event.Name) 100 | } 101 | } 102 | 103 | return events, nil 104 | } 105 | 106 | func (s *HoQuConfig) AddOwner(addr string) (common.Hash, error) { 107 | opts, err := s.Wallet.GetTransactOpts() 108 | if err != nil { 109 | s.Wallet.OnFailTransaction(err) 110 | return common.Hash{}, err 111 | } 112 | 113 | tx, err := s.HoQuConfig.AddOwner(opts, common.HexToAddress(addr)) 114 | if err != nil { 115 | s.Wallet.OnFailTransaction(err) 116 | return common.Hash{}, err 117 | } 118 | 119 | s.Wallet.OnSuccessTransaction() 120 | return tx.Hash(), nil 121 | } 122 | -------------------------------------------------------------------------------- /geth/init.go: -------------------------------------------------------------------------------- 1 | package geth 2 | 3 | import ( 4 | "github.com/spf13/viper" 5 | "hoqu-geth-api/sdk/geth" 6 | "hoqu-geth-api/sdk/geth/metamask" 7 | "sync" 8 | ) 9 | 10 | var gOnce sync.Once 11 | 12 | func InitGeth() (err error) { 13 | gOnce.Do(func() { 14 | err = geth.InitWallet( 15 | viper.GetString("geth.endpoint"), 16 | viper.GetString("geth.main.key_file"), 17 | viper.GetString("geth.main.pass"), 18 | ) 19 | if err != nil { 20 | return 21 | } 22 | 23 | metamask.InitAuth(viper.GetString("geth.meta_auth.banner")) 24 | 25 | if err = InitToken(); err != nil { 26 | return 27 | } 28 | 29 | if err = InitPrivatePlacement(); err != nil { 30 | return 31 | } 32 | 33 | if err = InitPresale(); err != nil { 34 | return 35 | } 36 | 37 | if err = InitSale(); err != nil { 38 | return 39 | } 40 | 41 | if err = InitBounty(); err != nil { 42 | return 43 | } 44 | 45 | if err = InitClaim(); err != nil { 46 | return 47 | } 48 | 49 | if err = InitBurner(); err != nil { 50 | return 51 | } 52 | 53 | if err = initHoQuConfig(); err != nil { 54 | return 55 | } 56 | 57 | if err = initHoQuStorage(); err != nil { 58 | return 59 | } 60 | 61 | if err = initHoQuRater(); err != nil { 62 | return 63 | } 64 | 65 | if err = initHoquPlatform(); err != nil { 66 | return 67 | } 68 | 69 | if err = initHoQuTransactor(); err != nil { 70 | return 71 | } 72 | }) 73 | return 74 | } 75 | -------------------------------------------------------------------------------- /geth/priv_place.go: -------------------------------------------------------------------------------- 1 | package geth 2 | 3 | import ( 4 | "hoqu-geth-api/contract" 5 | "github.com/ethereum/go-ethereum/common" 6 | "github.com/spf13/viper" 7 | "errors" 8 | "fmt" 9 | "hoqu-geth-api/sdk/geth" 10 | "github.com/ethereum/go-ethereum/accounts/abi/bind" 11 | ) 12 | 13 | var privPlace *PrivatePlacement 14 | 15 | type PrivatePlacement struct { 16 | *geth.Contract 17 | PrivatePlacement *contract.PrivatePlacement 18 | } 19 | 20 | func InitPrivatePlacement() error { 21 | c := geth.NewContract(viper.GetString("geth.addr.privPlace")) 22 | c.InitEvents(contract.ClaimableCrowdsaleABI) 23 | 24 | pp, err := contract.NewPrivatePlacement(c.Address, c.Wallet.Connection) 25 | if err != nil { 26 | return errors.New(fmt.Sprintf("Failed to instantiate a PrivatePlacement contract: %v", err)) 27 | } 28 | 29 | privPlace = &PrivatePlacement{ 30 | Contract: c, 31 | PrivatePlacement: pp, 32 | } 33 | 34 | return nil 35 | } 36 | 37 | func GetPrivatePlacement() *PrivatePlacement { 38 | return privPlace 39 | } 40 | 41 | func (t *PrivatePlacement) TokenAddr() (common.Address, error) { 42 | return t.PrivatePlacement.Token(&bind.CallOpts{ 43 | From: t.Wallet.Account.From, 44 | }) 45 | } 46 | -------------------------------------------------------------------------------- /geth/rater.go: -------------------------------------------------------------------------------- 1 | package geth 2 | 3 | import ( 4 | "hoqu-geth-api/contract/rater" 5 | "github.com/ethereum/go-ethereum/common" 6 | "github.com/spf13/viper" 7 | "errors" 8 | "fmt" 9 | "hoqu-geth-api/sdk/geth" 10 | "github.com/ethereum/go-ethereum/core/types" 11 | ) 12 | 13 | var r *HoQuRater 14 | 15 | type HoQuRater struct { 16 | *geth.Contract 17 | HoQuRater *rater.HoQuRater 18 | } 19 | 20 | func initHoQuRater() error { 21 | c := geth.NewContract(viper.GetString("geth.addr.rater")) 22 | c.InitEvents(rater.HoQuRaterABI) 23 | 24 | s, err := rater.NewHoQuRater(c.Address, c.Wallet.Connection) 25 | if err != nil { 26 | return errors.New(fmt.Sprintf("Failed to instantiate a HoQu Platform Rater contract: %v", err)) 27 | } 28 | 29 | r = &HoQuRater{ 30 | Contract: c, 31 | HoQuRater: s, 32 | } 33 | 34 | return nil 35 | } 36 | 37 | func GetHoQuRater() *HoQuRater { 38 | return r 39 | } 40 | 41 | func (s *HoQuRater) Deploy() (*common.Address, *types.Transaction, error) { 42 | address, tx, _, err := rater.DeployHoQuRater( 43 | s.Wallet.Account, 44 | s.Wallet.Connection, 45 | GetHoQuConfig().Address, 46 | GetHoQuStorage().Address, 47 | ) 48 | if err != nil { 49 | return nil, nil, fmt.Errorf("failed to deploy HoQuRater contract: %v", err) 50 | } 51 | return &address, tx, nil 52 | } 53 | -------------------------------------------------------------------------------- /geth/token.go: -------------------------------------------------------------------------------- 1 | package geth 2 | 3 | import ( 4 | "hoqu-geth-api/contract" 5 | "github.com/ethereum/go-ethereum/common" 6 | "github.com/spf13/viper" 7 | "errors" 8 | "fmt" 9 | "math/big" 10 | "hoqu-geth-api/sdk/geth" 11 | "github.com/ethereum/go-ethereum/core/types" 12 | sdkModels "hoqu-geth-api/sdk/models" 13 | "hoqu-geth-api/models" 14 | ) 15 | 16 | var token *Token 17 | 18 | type Token struct { 19 | *geth.Contract 20 | Token *contract.HoQuToken 21 | } 22 | 23 | func InitToken() error { 24 | c := geth.NewContract(viper.GetString("geth.addr.token")) 25 | c.InitEvents(contract.HoQuTokenABI) 26 | 27 | t, err := contract.NewHoQuToken(c.Address, c.Wallet.Connection) 28 | if err != nil { 29 | return errors.New(fmt.Sprintf("Failed to instantiate a Token contract: %v", err)) 30 | } 31 | 32 | token = &Token{ 33 | Contract: c, 34 | Token: t, 35 | } 36 | 37 | return nil 38 | } 39 | 40 | func (t *Token) Deploy(totSupply string) (*common.Address, *types.Transaction, error) { 41 | totSupplyEth, ok := big.NewInt(0).SetString(totSupply, 0) 42 | if !ok { 43 | return nil, nil, fmt.Errorf("wrong number provided: %s", totSupply) 44 | } 45 | 46 | address, tx, _, err := contract.DeployHoQuToken( 47 | t.Wallet.Account, 48 | t.Wallet.Connection, 49 | totSupplyEth, 50 | ) 51 | if err != nil { 52 | return nil, nil, fmt.Errorf("failed to deploy HoQuToken contract: %v", err) 53 | } 54 | return &address, tx, nil 55 | } 56 | 57 | func GetToken() *Token { 58 | return token 59 | } 60 | 61 | func (t *Token) Balance(addr string) (*big.Int, error) { 62 | return t.Token.BalanceOf(nil, common.HexToAddress(addr)) 63 | } 64 | 65 | func (t *Token) Allowance(owner string, spender string) (*big.Int, error) { 66 | return t.Token.Allowance(nil, common.HexToAddress(owner), common.HexToAddress(spender)) 67 | } 68 | 69 | func (t *Token) Events(request *sdkModels.Events) ([]sdkModels.ContractEvent, error) { 70 | events, err := t.GetEventsByTopics( 71 | request, 72 | viper.GetInt64("geth.start_block.token"), 73 | ) 74 | if err != nil { 75 | return nil, err 76 | } 77 | 78 | resEvents := make([]sdkModels.ContractEvent, 0) 79 | 80 | for _, event := range events { 81 | addr := common.BytesToAddress(event.RawArgs[0]) 82 | 83 | switch { 84 | case event.Name == "Transfer": 85 | event.Args = models.TokenTransferEventArgs{ 86 | From: addr.String(), 87 | To: common.BytesToAddress(event.RawArgs[1]).String(), 88 | Amount: common.BytesToHash(event.RawArgs[2]).Big().String(), 89 | } 90 | case event.Name == "Approval": 91 | event.Args = models.TokenApprovalEventArgs{ 92 | Owner: addr.String(), 93 | Spender: common.BytesToAddress(event.RawArgs[1]).String(), 94 | Amount: common.BytesToHash(event.RawArgs[2]).Big().String(), 95 | } 96 | default: 97 | return nil, fmt.Errorf("unknown event type: %s", event.Name) 98 | } 99 | 100 | resEvents = append(resEvents, event) 101 | } 102 | 103 | return resEvents, nil 104 | } 105 | 106 | func (t *Token) Holders(request *sdkModels.Events) (map[string]string, error) { 107 | request.EventNames = []string{"Transfer"} 108 | events, err := t.GetEventsByTopics( 109 | request, 110 | viper.GetInt64("geth.start_block.token"), 111 | ) 112 | if err != nil { 113 | return nil, err 114 | } 115 | 116 | holdersBalances := make(map[string]string) 117 | 118 | for _, event := range events { 119 | from := common.BytesToAddress(event.RawArgs[0]) 120 | to := common.BytesToAddress(event.RawArgs[1]) 121 | 122 | if _, ok := holdersBalances[from.String()]; !ok { 123 | balf, err := t.Balance(from.String()) 124 | if err != nil { 125 | return nil, err 126 | } 127 | 128 | holdersBalances[from.String()] = balf.String() 129 | } 130 | 131 | if _, ok := holdersBalances[to.String()]; !ok { 132 | bal, err := t.Balance(to.String()) 133 | if err != nil { 134 | return nil, err 135 | } 136 | 137 | holdersBalances[to.String()] = bal.String() 138 | } 139 | } 140 | 141 | return holdersBalances, nil 142 | } 143 | -------------------------------------------------------------------------------- /geth/transactor.go: -------------------------------------------------------------------------------- 1 | package geth 2 | 3 | import ( 4 | transactor "hoqu-geth-api/contract/ad" 5 | "github.com/ethereum/go-ethereum/common" 6 | "github.com/spf13/viper" 7 | "errors" 8 | "fmt" 9 | "hoqu-geth-api/sdk/geth" 10 | "github.com/ethereum/go-ethereum/core/types" 11 | ) 12 | 13 | var ht *HoQuTransactor 14 | 15 | type HoQuTransactor struct { 16 | *geth.Contract 17 | HoQuTransactor *transactor.HoQuTransactor 18 | } 19 | 20 | func initHoQuTransactor() error { 21 | c := geth.NewContract(viper.GetString("geth.addr.transactor")) 22 | c.InitEvents(transactor.HoQuTransactorABI) 23 | 24 | s, err := transactor.NewHoQuTransactor(c.Address, c.Wallet.Connection) 25 | if err != nil { 26 | return errors.New(fmt.Sprintf("Failed to instantiate a HoQu Platform Transactor contract: %v", err)) 27 | } 28 | 29 | ht = &HoQuTransactor{ 30 | Contract: c, 31 | HoQuTransactor: s, 32 | } 33 | 34 | return nil 35 | } 36 | 37 | func GetHoQuTransactor() *HoQuTransactor { 38 | return ht 39 | } 40 | 41 | func (s *HoQuTransactor) Deploy() (*common.Address, *types.Transaction, error) { 42 | address, tx, _, err := transactor.DeployHoQuTransactor( 43 | s.Wallet.Account, 44 | s.Wallet.Connection, 45 | GetHoQuConfig().Address, 46 | GetToken().Address, 47 | ) 48 | if err != nil { 49 | return nil, nil, fmt.Errorf("failed to deploy HoQuTransactor contract: %v", err) 50 | } 51 | return &address, tx, nil 52 | } 53 | -------------------------------------------------------------------------------- /http/bounty_routes.go: -------------------------------------------------------------------------------- 1 | package http 2 | 3 | import ( 4 | "github.com/gin-gonic/gin" 5 | "hoqu-geth-api/sdk/http/rest" 6 | "hoqu-geth-api/geth" 7 | "hoqu-geth-api/models" 8 | "hoqu-geth-api/sdk/http/middleware" 9 | ) 10 | 11 | func InitBountyRoutes(router *gin.Engine) { 12 | bounty := router.Group("/bounty") 13 | { 14 | bounty.POST("/deploy", middleware.SignRequired(), postDeployBountyAction) 15 | bounty.GET("/summary", getBountySummaryAction) 16 | bounty.GET("/balance/:address", getBountyTokensBalanceAction) 17 | bounty.POST("/balances", postBountyTokensBalancesAction) 18 | bounty.GET("/approved/:address", getBountyApprovedAction) 19 | bounty.POST("/approved", postBountyApprovedManyAction) 20 | bounty.POST("/add", middleware.SignRequired(), postBountyAddAction) 21 | } 22 | } 23 | 24 | func postDeployBountyAction(c *gin.Context) { 25 | request := &models.BountyDeployParams{} 26 | err := c.BindJSON(request) 27 | if err != nil { 28 | rest.NewResponder(c).ErrorValidation(err.Error()) 29 | return 30 | } 31 | 32 | addr, tx, err := geth.GetBounty().Deploy(request) 33 | if err != nil { 34 | rest.NewResponder(c).Error(err.Error()) 35 | return 36 | } 37 | 38 | rest.NewResponder(c).Success(gin.H{ 39 | "address": addr.String(), 40 | "tx": tx.Hash().String(), 41 | }) 42 | } 43 | 44 | func getBountySummaryAction(c *gin.Context) { 45 | sum, err := geth.GetBounty().Summary() 46 | if err != nil { 47 | rest.NewResponder(c).Error(err.Error()) 48 | return 49 | } 50 | 51 | rest.NewResponder(c).Success(gin.H{ 52 | "summary": sum, 53 | }) 54 | } 55 | 56 | func getBountyTokensBalanceAction(c *gin.Context) { 57 | addr := c.Param("address") 58 | bal, err := geth.GetBounty().Balance(addr) 59 | if err != nil { 60 | rest.NewResponder(c).Error(err.Error()) 61 | return 62 | } 63 | 64 | rest.NewResponder(c).Success(gin.H{ 65 | "balance": bal.String(), 66 | }) 67 | } 68 | 69 | func postBountyTokensBalancesAction(c *gin.Context) { 70 | request := &models.Addresses{} 71 | err := c.BindJSON(request) 72 | if err != nil { 73 | rest.NewResponder(c).ErrorValidation(err.Error()) 74 | return 75 | } 76 | 77 | bals := map[string]string{} 78 | for _, addr := range request.Addresses { 79 | bal, err := geth.GetBounty().Balance(addr) 80 | if err != nil { 81 | rest.NewResponder(c).Error(err.Error()) 82 | return 83 | } 84 | bals[addr] = bal.String() 85 | } 86 | 87 | rest.NewResponder(c).Success(gin.H{ 88 | "balances": bals, 89 | }) 90 | } 91 | 92 | func getBountyApprovedAction(c *gin.Context) { 93 | addr := c.Param("address") 94 | approved, err := geth.GetBounty().Approved(addr) 95 | if err != nil { 96 | rest.NewResponder(c).Error(err.Error()) 97 | return 98 | } 99 | 100 | rest.NewResponder(c).Success(gin.H{ 101 | "approved": approved, 102 | }) 103 | } 104 | 105 | func postBountyApprovedManyAction(c *gin.Context) { 106 | request := &models.Addresses{} 107 | err := c.BindJSON(request) 108 | if err != nil { 109 | rest.NewResponder(c).ErrorValidation(err.Error()) 110 | return 111 | } 112 | 113 | approvedMap := map[string]bool{} 114 | for _, addr := range request.Addresses { 115 | approved, err := geth.GetBounty().Approved(addr) 116 | if err != nil { 117 | rest.NewResponder(c).Error(err.Error()) 118 | return 119 | } 120 | approvedMap[addr] = approved 121 | } 122 | 123 | rest.NewResponder(c).Success(gin.H{ 124 | "approved": approvedMap, 125 | }) 126 | } 127 | 128 | func postBountyAddAction(c *gin.Context) { 129 | request := &models.AddressWithAmount{} 130 | err := c.BindJSON(request) 131 | if err != nil { 132 | rest.NewResponder(c).ErrorValidation(err.Error()) 133 | return 134 | } 135 | 136 | tx, err := geth.GetBounty().AddByBounty(request.Address, request.Amount) 137 | if err != nil { 138 | rest.NewResponder(c).Error(err.Error()) 139 | return 140 | } 141 | 142 | rest.NewResponder(c).Success(gin.H{ 143 | "tx": tx.String(), 144 | }) 145 | } 146 | 147 | -------------------------------------------------------------------------------- /http/burner_routes.go: -------------------------------------------------------------------------------- 1 | package http 2 | 3 | import ( 4 | "github.com/gin-gonic/gin" 5 | "hoqu-geth-api/sdk/http/rest" 6 | "hoqu-geth-api/geth" 7 | "hoqu-geth-api/models" 8 | "hoqu-geth-api/sdk/http/middleware" 9 | ) 10 | 11 | func InitBurnerRoutes(router *gin.Engine) { 12 | claim := router.Group("/burner") 13 | { 14 | claim.POST("/deploy", middleware.SignRequired(), postDeployBurnerAction) 15 | claim.POST("/burn", middleware.SignRequired(), postBurnFromAction) 16 | } 17 | } 18 | 19 | func postDeployBurnerAction(c *gin.Context) { 20 | addr, tx, err := geth.GetBurner().Deploy() 21 | if err != nil { 22 | rest.NewResponder(c).Error(err.Error()) 23 | return 24 | } 25 | 26 | rest.NewResponder(c).Success(gin.H{ 27 | "address": addr.String(), 28 | "tx": tx.Hash().String(), 29 | }) 30 | } 31 | 32 | func postBurnFromAction(c *gin.Context) { 33 | request := &models.AddressWithAmount{} 34 | err := c.BindJSON(request) 35 | if err != nil { 36 | rest.NewResponder(c).ErrorValidation(err.Error()) 37 | return 38 | } 39 | 40 | tx, err := geth.GetBurner().BurnFrom(request.Address, request.Amount) 41 | if err != nil { 42 | rest.NewResponder(c).Error(err.Error()) 43 | return 44 | } 45 | 46 | rest.NewResponder(c).Success(gin.H{ 47 | "tx": tx.String(), 48 | }) 49 | } 50 | 51 | 52 | -------------------------------------------------------------------------------- /http/claim_routes.go: -------------------------------------------------------------------------------- 1 | package http 2 | 3 | import ( 4 | "github.com/gin-gonic/gin" 5 | "hoqu-geth-api/sdk/http/rest" 6 | "hoqu-geth-api/geth" 7 | "hoqu-geth-api/models" 8 | "hoqu-geth-api/sdk/http/middleware" 9 | "github.com/ethereum/go-ethereum/common" 10 | models2 "hoqu-geth-api/sdk/models" 11 | ) 12 | 13 | func InitClaimRoutes(router *gin.Engine) { 14 | claim := router.Group("/claim") 15 | { 16 | claim.POST("/deploy", middleware.SignRequired(), postDeployClaimAction) 17 | claim.POST("/batch", middleware.SignRequired(), postClaimBatchAction) 18 | claim.POST("/one", middleware.SignRequired(), postClaimOneAction) 19 | claim.POST("/transactions", postClaimTransactionsAction) 20 | } 21 | } 22 | 23 | func postDeployClaimAction(c *gin.Context) { 24 | request := &models.ClaimDeployParams{} 25 | err := c.BindJSON(request) 26 | if err != nil { 27 | rest.NewResponder(c).ErrorValidation(err.Error()) 28 | return 29 | } 30 | 31 | addr, tx, err := geth.GetClaim().Deploy(request) 32 | if err != nil { 33 | rest.NewResponder(c).Error(err.Error()) 34 | return 35 | } 36 | 37 | rest.NewResponder(c).Success(gin.H{ 38 | "address": addr.String(), 39 | "tx": tx.Hash().String(), 40 | }) 41 | } 42 | 43 | func postClaimBatchAction(c *gin.Context) { 44 | request := &models.AddressWithAmount{} 45 | err := c.BindJSON(request) 46 | if err != nil { 47 | rest.NewResponder(c).ErrorValidation(err.Error()) 48 | return 49 | } 50 | 51 | id := geth.GetClaim().BatchId 52 | tx, err := geth.GetClaim().ClaimAddress(request.Address, request.Amount) 53 | if err != nil { 54 | rest.NewResponder(c).Error(err.Error()) 55 | return 56 | } 57 | 58 | if tx.String() == (common.Hash{}).String() { 59 | rest.NewResponder(c).Success(gin.H{ 60 | "id": id.String(), 61 | }) 62 | } else { 63 | rest.NewResponder(c).Success(gin.H{ 64 | "id": id.String(), 65 | "tx": tx.String(), 66 | }) 67 | } 68 | } 69 | 70 | func postClaimOneAction(c *gin.Context) { 71 | request := &models.AddressWithAmount{} 72 | err := c.BindJSON(request) 73 | if err != nil { 74 | rest.NewResponder(c).ErrorValidation(err.Error()) 75 | return 76 | } 77 | 78 | tx, err := geth.GetClaim().ClaimOne(request.Address, request.Amount) 79 | if err != nil { 80 | rest.NewResponder(c).Error(err.Error()) 81 | return 82 | } 83 | 84 | rest.NewResponder(c).Success(gin.H{ 85 | "tx": tx.String(), 86 | }) 87 | } 88 | 89 | func postClaimTransactionsAction(c *gin.Context) { 90 | request := &models2.Events{} 91 | err := c.BindJSON(request) 92 | if err != nil { 93 | rest.NewResponder(c).ErrorValidation(err.Error()) 94 | return 95 | } 96 | 97 | events, err := geth.GetClaim().Events(request) 98 | if err != nil { 99 | rest.NewResponder(c).Error(err.Error()) 100 | return 101 | } 102 | 103 | rest.NewResponder(c).Success(gin.H{ 104 | "transactions": events, 105 | }) 106 | } 107 | -------------------------------------------------------------------------------- /http/config_routes.go: -------------------------------------------------------------------------------- 1 | package http 2 | 3 | import ( 4 | "github.com/gin-gonic/gin" 5 | "hoqu-geth-api/sdk/http/rest" 6 | "hoqu-geth-api/geth" 7 | "hoqu-geth-api/models" 8 | "hoqu-geth-api/sdk/http/middleware" 9 | ) 10 | 11 | func InitHoQuConfigRoutes(router *gin.Engine) { 12 | config := router.Group("/config", middleware.SignRequired()) 13 | { 14 | config.POST("/deploy", postDeployHoQuConfigAction) 15 | config.POST("/owners/add", postAddOwnersAction) 16 | } 17 | } 18 | 19 | func postDeployHoQuConfigAction(c *gin.Context) { 20 | request := &models.ConfigDeployParams{} 21 | err := c.BindJSON(request) 22 | if err != nil { 23 | rest.NewResponder(c).ErrorValidation(err.Error()) 24 | return 25 | } 26 | 27 | addr, tx, err := geth.GetHoQuConfig().Deploy(request) 28 | if err != nil { 29 | rest.NewResponder(c).Error(err.Error()) 30 | return 31 | } 32 | 33 | rest.NewResponder(c).Success(gin.H{ 34 | "address": addr.String(), 35 | "tx": tx.Hash().String(), 36 | }) 37 | } 38 | 39 | func postAddOwnersAction(c *gin.Context) { 40 | request := &models.Addresses{} 41 | err := c.BindJSON(request) 42 | if err != nil { 43 | rest.NewResponder(c).ErrorValidation(err.Error()) 44 | return 45 | } 46 | 47 | txs := map[string]string{} 48 | for _, addr := range request.Addresses { 49 | tx, err := geth.GetHoQuConfig().AddOwner(addr) 50 | if err != nil { 51 | rest.NewResponder(c).Error(err.Error()) 52 | return 53 | } 54 | txs[addr] = tx.String() 55 | } 56 | 57 | rest.NewResponder(c).Success(gin.H{ 58 | "txs": txs, 59 | }) 60 | } -------------------------------------------------------------------------------- /http/platform/company_routes.go: -------------------------------------------------------------------------------- 1 | package platform 2 | 3 | import ( 4 | "github.com/gin-gonic/gin" 5 | "hoqu-geth-api/sdk/http/rest" 6 | "hoqu-geth-api/geth" 7 | "hoqu-geth-api/models" 8 | "hoqu-geth-api/sdk/http/middleware" 9 | ) 10 | 11 | func InitCompanyRoutes(routerGroup *gin.RouterGroup) { 12 | r := routerGroup.Group("/company") 13 | { 14 | r.POST("/register", middleware.SignRequired(), postRegisterCompanyAction) 15 | r.POST("/status", middleware.SignRequired(), postSetCompanyStatusAction) 16 | r.GET("/:id", getCompanyAction) 17 | } 18 | } 19 | 20 | // swagger:route POST /platform/company/register companies registerCompany 21 | // 22 | // Register Company. 23 | // 24 | // Consumes: 25 | // - application/json 26 | // Produces: 27 | // - application/json 28 | // Responses: 29 | // 200: AddSuccessResponse 30 | // 400: RestErrorResponse 31 | // 32 | func postRegisterCompanyAction(c *gin.Context) { 33 | request := &models.RegisterCompanyRequest{} 34 | err := c.BindJSON(request) 35 | if err != nil { 36 | rest.NewResponder(c).ErrorValidation(err.Error()) 37 | return 38 | } 39 | 40 | tx, id, err := geth.GetHoquPlatform().RegisterCompany(request) 41 | if err != nil { 42 | rest.NewResponder(c).Error(err.Error()) 43 | return 44 | } 45 | 46 | rest.NewResponder(c).Success(gin.H{ 47 | "tx": tx.String(), 48 | "id": id, 49 | }) 50 | } 51 | 52 | // swagger:route POST /platform/company/status companies setCompanyStatus 53 | // 54 | // Set Company Status. 55 | // 56 | // Consumes: 57 | // - application/json 58 | // Produces: 59 | // - application/json 60 | // Responses: 61 | // 200: TxSuccessResponse 62 | // 400: RestErrorResponse 63 | // 64 | func postSetCompanyStatusAction(c *gin.Context) { 65 | request := &models.SetStatusRequest{} 66 | err := c.BindJSON(request) 67 | if err != nil { 68 | rest.NewResponder(c).ErrorValidation(err.Error()) 69 | return 70 | } 71 | 72 | tx, err := geth.GetHoquPlatform().SetCompanyStatus(request) 73 | if err != nil { 74 | rest.NewResponder(c).Error(err.Error()) 75 | return 76 | } 77 | 78 | rest.NewResponder(c).Success(gin.H{ 79 | "tx": tx.String(), 80 | }) 81 | } 82 | 83 | // swagger:route GET /platform/company/:id companies getCompany 84 | // 85 | // Get Company by ID. 86 | // 87 | // Produces: 88 | // - application/json 89 | // Responses: 90 | // 200: CompanyDataResponse 91 | // 400: RestErrorResponse 92 | // 93 | func getCompanyAction(c *gin.Context) { 94 | id := c.Param("id") 95 | 96 | company, err := geth.GetHoQuStorage().GetCompany(id) 97 | if err != nil { 98 | rest.NewResponder(c).Error(err.Error()) 99 | return 100 | } 101 | 102 | rest.NewResponder(c).Success(gin.H{ 103 | "Company": company, 104 | }) 105 | } 106 | -------------------------------------------------------------------------------- /http/platform/identification_routes.go: -------------------------------------------------------------------------------- 1 | package platform 2 | 3 | import ( 4 | "github.com/gin-gonic/gin" 5 | "hoqu-geth-api/sdk/http/rest" 6 | "hoqu-geth-api/geth" 7 | "hoqu-geth-api/models" 8 | "hoqu-geth-api/sdk/http/middleware" 9 | ) 10 | 11 | func InitIdentificationRoutes(routerGroup *gin.RouterGroup) { 12 | r := routerGroup.Group("/identification") 13 | { 14 | r.POST("/add", middleware.SignRequired(), postAddIdentificationAction) 15 | r.POST("/kyc", middleware.SignRequired(), postAddKycReportAction) 16 | r.GET("/:id", getIdentificationAction) 17 | } 18 | } 19 | 20 | // swagger:route POST /platform/identification/add identifications addIdentification 21 | // 22 | // Add Identification. 23 | // 24 | // Consumes: 25 | // - application/json 26 | // Produces: 27 | // - application/json 28 | // Responses: 29 | // 200: AddSuccessResponse 30 | // 400: RestErrorResponse 31 | // 32 | func postAddIdentificationAction(c *gin.Context) { 33 | request := &models.AddIdentificationRequest{} 34 | err := c.BindJSON(request) 35 | if err != nil { 36 | rest.NewResponder(c).ErrorValidation(err.Error()) 37 | return 38 | } 39 | 40 | tx, id, err := geth.GetHoquPlatform().AddIdentification(request) 41 | if err != nil { 42 | rest.NewResponder(c).Error(err.Error()) 43 | return 44 | } 45 | 46 | rest.NewResponder(c).Success(gin.H{ 47 | "tx": tx.String(), 48 | "id": id, 49 | }) 50 | } 51 | 52 | // swagger:route POST /platform/identification/kyc identifications addKyc 53 | // 54 | // Add KYC report. 55 | // 56 | // Each Identification has KYC level which reflects his trust level. 57 | // Identification KYC level can be changed only by KYC reports. 58 | // 59 | // Consumes: 60 | // - application/json 61 | // Produces: 62 | // - application/json 63 | // Responses: 64 | // 200: TxSuccessResponse 65 | // 400: RestErrorResponse 66 | // 67 | func postAddKycReportAction(c *gin.Context) { 68 | request := &models.AddKycReportRequest{} 69 | err := c.BindJSON(request) 70 | if err != nil { 71 | rest.NewResponder(c).ErrorValidation(err.Error()) 72 | return 73 | } 74 | 75 | tx, err := geth.GetHoquPlatform().AddKycReport(request) 76 | if err != nil { 77 | rest.NewResponder(c).Error(err.Error()) 78 | return 79 | } 80 | 81 | rest.NewResponder(c).Success(gin.H{ 82 | "tx": tx.String(), 83 | }) 84 | } 85 | 86 | // swagger:route GET /platform/identification/:id identifications getIdentification 87 | // 88 | // Get Identification by ID. 89 | // 90 | // Produces: 91 | // - application/json 92 | // Responses: 93 | // 200: IdentificationDataResponse 94 | // 400: RestErrorResponse 95 | // 96 | func getIdentificationAction(c *gin.Context) { 97 | id := c.Param("id") 98 | 99 | identification, err := geth.GetHoQuStorage().GetIdentification(id) 100 | if err != nil { 101 | rest.NewResponder(c).Error(err.Error()) 102 | return 103 | } 104 | 105 | rest.NewResponder(c).Success(gin.H{ 106 | "identification": identification, 107 | }) 108 | } 109 | -------------------------------------------------------------------------------- /http/platform/network_routes.go: -------------------------------------------------------------------------------- 1 | package platform 2 | 3 | import ( 4 | "github.com/gin-gonic/gin" 5 | "hoqu-geth-api/sdk/http/rest" 6 | "hoqu-geth-api/geth" 7 | "hoqu-geth-api/models" 8 | "hoqu-geth-api/sdk/http/middleware" 9 | ) 10 | 11 | func InitNetworkRoutes(routerGroup *gin.RouterGroup) { 12 | r := routerGroup.Group("/network") 13 | { 14 | r.POST("/register", middleware.SignRequired(), postRegisterNetworkAction) 15 | r.POST("/status", middleware.SignRequired(), postSetNetworkStatusAction) 16 | r.GET("/:id", getNetworkAction) 17 | } 18 | } 19 | 20 | // swagger:route POST /platform/network/register networks registerNetwork 21 | // 22 | // Register Network. 23 | // 24 | // The Network is an essential part of a platform. 25 | // All offers can be accessible only through networks. 26 | // Merchants should join networks as well as Affiliates to communicate with each other. 27 | // 28 | // Consumes: 29 | // - application/json 30 | // Produces: 31 | // - application/json 32 | // Responses: 33 | // 200: AddSuccessResponse 34 | // 400: RestErrorResponse 35 | // 36 | func postRegisterNetworkAction(c *gin.Context) { 37 | request := &models.RegisterNetworkRequest{} 38 | err := c.BindJSON(request) 39 | if err != nil { 40 | rest.NewResponder(c).ErrorValidation(err.Error()) 41 | return 42 | } 43 | 44 | tx, id, err := geth.GetHoquPlatform().RegisterNetwork(request) 45 | if err != nil { 46 | rest.NewResponder(c).Error(err.Error()) 47 | return 48 | } 49 | 50 | rest.NewResponder(c).Success(gin.H{ 51 | "tx": tx.String(), 52 | "id": id, 53 | }) 54 | } 55 | 56 | // swagger:route POST /platform/network/status networks setNetworkStatus 57 | // 58 | // Set Network Status. 59 | // 60 | // Consumes: 61 | // - application/json 62 | // Produces: 63 | // - application/json 64 | // Responses: 65 | // 200: TxSuccessResponse 66 | // 400: RestErrorResponse 67 | // 68 | func postSetNetworkStatusAction(c *gin.Context) { 69 | request := &models.SetStatusRequest{} 70 | err := c.BindJSON(request) 71 | if err != nil { 72 | rest.NewResponder(c).ErrorValidation(err.Error()) 73 | return 74 | } 75 | 76 | tx, err := geth.GetHoquPlatform().SetNetworkStatus(request) 77 | if err != nil { 78 | rest.NewResponder(c).Error(err.Error()) 79 | return 80 | } 81 | 82 | rest.NewResponder(c).Success(gin.H{ 83 | "tx": tx.String(), 84 | }) 85 | } 86 | 87 | // swagger:route GET /platform/network/:id networks getNetwork 88 | // 89 | // Get Network by ID. 90 | // 91 | // Produces: 92 | // - application/json 93 | // Responses: 94 | // 200: NetworkDataResponse 95 | // 400: RestErrorResponse 96 | // 97 | func getNetworkAction(c *gin.Context) { 98 | id := c.Param("id") 99 | 100 | network, err := geth.GetHoQuStorage().GetNetwork(id) 101 | if err != nil { 102 | rest.NewResponder(c).Error(err.Error()) 103 | return 104 | } 105 | 106 | rest.NewResponder(c).Success(gin.H{ 107 | "network": network, 108 | }) 109 | } 110 | -------------------------------------------------------------------------------- /http/platform/stats_routes.go: -------------------------------------------------------------------------------- 1 | package platform 2 | 3 | import ( 4 | "github.com/gin-gonic/gin" 5 | "hoqu-geth-api/sdk/http/rest" 6 | "hoqu-geth-api/geth" 7 | ) 8 | 9 | func InitStatsRoutes(routerGroup *gin.RouterGroup) { 10 | r := routerGroup.Group("/stats") 11 | { 12 | r.GET("/:id", getStatsAction) 13 | } 14 | } 15 | 16 | // swagger:route GET /platform/stats/:id stats getStats 17 | // 18 | // Get Stats by ID. 19 | // 20 | // Produces: 21 | // - application/json 22 | // Responses: 23 | // 200: StatsDataResponse 24 | // 400: RestErrorResponse 25 | // 26 | func getStatsAction(c *gin.Context) { 27 | id := c.Param("id") 28 | 29 | stats, err := geth.GetHoQuStorage().GetStats(id) 30 | if err != nil { 31 | rest.NewResponder(c).Error(err.Error()) 32 | return 33 | } 34 | 35 | rest.NewResponder(c).Success(gin.H{ 36 | "stats": stats, 37 | }) 38 | } 39 | -------------------------------------------------------------------------------- /http/platform/tracker_routes.go: -------------------------------------------------------------------------------- 1 | package platform 2 | 3 | import ( 4 | "github.com/gin-gonic/gin" 5 | "hoqu-geth-api/sdk/http/rest" 6 | "hoqu-geth-api/geth" 7 | "hoqu-geth-api/models" 8 | "hoqu-geth-api/sdk/http/middleware" 9 | ) 10 | 11 | func InitTrackerRoutes(routerGroup *gin.RouterGroup) { 12 | r := routerGroup.Group("/tracker") 13 | { 14 | r.POST("/register", middleware.SignRequired(), postRegisterTrackerAction) 15 | r.POST("/status", middleware.SignRequired(), postSetTrackerStatusAction) 16 | r.GET("/:id", getTrackerAction) 17 | } 18 | } 19 | 20 | // swagger:route POST /platform/tracker/register trackers registerTracker 21 | // 22 | // Register Tracker. 23 | // 24 | // The Tracker is an application which receives visitor's requests to show the appropriate widget. 25 | // All widgets can be created in terms of appropriate Ad (affiliate promotion campaign). 26 | // If visitor interacts with a widget the Tracker creates the Lead and push it to Blockchain. 27 | // 28 | // Consumes: 29 | // - application/json 30 | // Produces: 31 | // - application/json 32 | // Responses: 33 | // 200: AddSuccessResponse 34 | // 400: RestErrorResponse 35 | // 36 | func postRegisterTrackerAction(c *gin.Context) { 37 | request := &models.RegisterTrackerRequest{} 38 | err := c.BindJSON(request) 39 | if err != nil { 40 | rest.NewResponder(c).ErrorValidation(err.Error()) 41 | return 42 | } 43 | 44 | tx, id, err := geth.GetHoquPlatform().RegisterTracker(request) 45 | if err != nil { 46 | rest.NewResponder(c).Error(err.Error()) 47 | return 48 | } 49 | 50 | rest.NewResponder(c).Success(gin.H{ 51 | "tx": tx.String(), 52 | "id": id, 53 | }) 54 | } 55 | 56 | // swagger:route POST /platform/tracker/status trackers setTrackerStatus 57 | // 58 | // Set Tracker Status. 59 | // 60 | // Consumes: 61 | // - application/json 62 | // Produces: 63 | // - application/json 64 | // Responses: 65 | // 200: TxSuccessResponse 66 | // 400: RestErrorResponse 67 | // 68 | func postSetTrackerStatusAction(c *gin.Context) { 69 | request := &models.SetStatusRequest{} 70 | err := c.BindJSON(request) 71 | if err != nil { 72 | rest.NewResponder(c).ErrorValidation(err.Error()) 73 | return 74 | } 75 | 76 | tx, err := geth.GetHoquPlatform().SetTrackerStatus(request) 77 | if err != nil { 78 | rest.NewResponder(c).Error(err.Error()) 79 | return 80 | } 81 | 82 | rest.NewResponder(c).Success(gin.H{ 83 | "tx": tx.String(), 84 | }) 85 | } 86 | 87 | // swagger:route GET /platform/tracker/:id trackers getTracker 88 | // 89 | // Get Tracker by ID. 90 | // 91 | // Produces: 92 | // - application/json 93 | // Responses: 94 | // 200: TrackerDataResponse 95 | // 400: RestErrorResponse 96 | // 97 | func getTrackerAction(c *gin.Context) { 98 | id := c.Param("id") 99 | 100 | tracker, err := geth.GetHoQuStorage().GetTracker(id) 101 | if err != nil { 102 | rest.NewResponder(c).Error(err.Error()) 103 | return 104 | } 105 | 106 | rest.NewResponder(c).Success(gin.H{ 107 | "tracker": tracker, 108 | }) 109 | } 110 | -------------------------------------------------------------------------------- /http/platform_routes.go: -------------------------------------------------------------------------------- 1 | package http 2 | 3 | import ( 4 | "github.com/gin-gonic/gin" 5 | "hoqu-geth-api/sdk/http/rest" 6 | "hoqu-geth-api/geth" 7 | "hoqu-geth-api/sdk/http/middleware" 8 | "hoqu-geth-api/http/platform" 9 | models2 "hoqu-geth-api/sdk/models" 10 | "hoqu-geth-api/offer" 11 | "hoqu-geth-api/tariff" 12 | "hoqu-geth-api/ad_campaign" 13 | "hoqu-geth-api/lead" 14 | "hoqu-geth-api/user" 15 | "hoqu-geth-api/tariff_group" 16 | ) 17 | 18 | func InitHoquPlatformRoutes(router *gin.Engine) { 19 | r := router.Group("/platform") 20 | { 21 | r.POST("/deploy", middleware.SignRequired(), postDeployHoquPlatformAction) 22 | r.POST("/events", postPlatformEventsAction) 23 | user.InitUserRoutes(r) 24 | platform.InitIdentificationRoutes(r) 25 | platform.InitStatsRoutes(r) 26 | platform.InitCompanyRoutes(r) 27 | platform.InitNetworkRoutes(r) 28 | platform.InitTrackerRoutes(r) 29 | offer.InitOfferRoutes(r) 30 | ad_campaign.InitAdCampaignRoutes(r) 31 | lead.InitLeadRoutes(r) 32 | tariff.InitTariffRoutes(r) 33 | tariff_group.InitTariffGroupRoutes(r) 34 | } 35 | } 36 | 37 | func postDeployHoquPlatformAction(c *gin.Context) { 38 | addr, tx, err := geth.GetHoquPlatform().Deploy() 39 | if err != nil { 40 | rest.NewResponder(c).Error(err.Error()) 41 | return 42 | } 43 | 44 | _, err = geth.GetHoQuConfig().AddOwner(addr.String()) 45 | if err != nil { 46 | rest.NewResponder(c).Error(err.Error()) 47 | return 48 | } 49 | 50 | rest.NewResponder(c).Success(gin.H{ 51 | "address": addr.String(), 52 | "tx": tx.Hash().String(), 53 | }) 54 | } 55 | 56 | // swagger:route POST /platform/events platform events 57 | // 58 | // Get HOQU platform events. 59 | // 60 | // Consumes: 61 | // - application/json 62 | // Produces: 63 | // - application/json 64 | // Responses: 65 | // 200: ContractEventResponse 66 | // 400: RestErrorResponse 67 | // 68 | func postPlatformEventsAction(c *gin.Context) { 69 | request := &models2.Events{} 70 | err := c.BindJSON(request) 71 | if err != nil { 72 | rest.NewResponder(c).ErrorValidation(err.Error()) 73 | return 74 | } 75 | 76 | events, err := geth.GetHoquPlatform().Events(request) 77 | if err != nil { 78 | rest.NewResponder(c).Error(err.Error()) 79 | return 80 | } 81 | 82 | rest.NewResponder(c).Success(gin.H{ 83 | "events": events, 84 | }) 85 | } 86 | -------------------------------------------------------------------------------- /http/presale_routes.go: -------------------------------------------------------------------------------- 1 | package http 2 | 3 | import ( 4 | "github.com/gin-gonic/gin" 5 | "hoqu-geth-api/sdk/http/rest" 6 | "hoqu-geth-api/geth" 7 | "hoqu-geth-api/models" 8 | "hoqu-geth-api/sdk/http/middleware" 9 | models2 "hoqu-geth-api/sdk/models" 10 | ) 11 | 12 | func InitPresaleRoutes(router *gin.Engine) { 13 | presale := router.Group("/presale") 14 | { 15 | presale.POST("/deploy", middleware.SignRequired(), postDeployAction) 16 | presale.GET("/summary", getSummaryAction) 17 | presale.GET("/balance/:address", getClaimableTokensBalanceAction) 18 | presale.POST("/balances", postClaimableTokensBalancesAction) 19 | presale.GET("/approved/:address", getApprovedAction) 20 | presale.POST("/approved", postApprovedManyAction) 21 | presale.POST("/transactions", postPresaleTransactionsAction) 22 | presale.POST("/add", middleware.SignRequired(), postAddAction) 23 | presale.POST("/topup", middleware.SignRequired(), postTopUpAction) 24 | presale.POST("/approve", middleware.SignRequired(), postApproveAction) 25 | } 26 | } 27 | 28 | func postDeployAction(c *gin.Context) { 29 | request := &models.PresaleDeployParams{} 30 | err := c.BindJSON(request) 31 | if err != nil { 32 | rest.NewResponder(c).ErrorValidation(err.Error()) 33 | return 34 | } 35 | 36 | addr, tx, err := geth.GetPresale().Deploy(request) 37 | if err != nil { 38 | rest.NewResponder(c).Error(err.Error()) 39 | return 40 | } 41 | 42 | rest.NewResponder(c).Success(gin.H{ 43 | "address": addr.String(), 44 | "tx": tx.Hash().String(), 45 | }) 46 | } 47 | 48 | func getSummaryAction(c *gin.Context) { 49 | sum, err := geth.GetPresale().Summary() 50 | if err != nil { 51 | rest.NewResponder(c).Error(err.Error()) 52 | return 53 | } 54 | 55 | rest.NewResponder(c).Success(gin.H{ 56 | "summary": sum, 57 | }) 58 | } 59 | 60 | func getClaimableTokensBalanceAction(c *gin.Context) { 61 | addr := c.Param("address") 62 | bal, err := geth.GetPresale().Balance(addr) 63 | if err != nil { 64 | rest.NewResponder(c).Error(err.Error()) 65 | return 66 | } 67 | 68 | rest.NewResponder(c).Success(gin.H{ 69 | "balance": bal.String(), 70 | }) 71 | } 72 | 73 | func postClaimableTokensBalancesAction(c *gin.Context) { 74 | request := &models.Addresses{} 75 | err := c.BindJSON(request) 76 | if err != nil { 77 | rest.NewResponder(c).ErrorValidation(err.Error()) 78 | return 79 | } 80 | 81 | bals := map[string]string{} 82 | for _, addr := range request.Addresses { 83 | bal, err := geth.GetPresale().Balance(addr) 84 | if err != nil { 85 | rest.NewResponder(c).Error(err.Error()) 86 | return 87 | } 88 | bals[addr] = bal.String() 89 | } 90 | 91 | rest.NewResponder(c).Success(gin.H{ 92 | "balances": bals, 93 | }) 94 | } 95 | 96 | func getApprovedAction(c *gin.Context) { 97 | addr := c.Param("address") 98 | approved, err := geth.GetPresale().Approved(addr) 99 | if err != nil { 100 | rest.NewResponder(c).Error(err.Error()) 101 | return 102 | } 103 | 104 | rest.NewResponder(c).Success(gin.H{ 105 | "approved": approved, 106 | }) 107 | } 108 | 109 | func postApprovedManyAction(c *gin.Context) { 110 | request := &models.Addresses{} 111 | err := c.BindJSON(request) 112 | if err != nil { 113 | rest.NewResponder(c).ErrorValidation(err.Error()) 114 | return 115 | } 116 | 117 | approvedMap := map[string]bool{} 118 | for _, addr := range request.Addresses { 119 | approved, err := geth.GetPresale().Approved(addr) 120 | if err != nil { 121 | rest.NewResponder(c).Error(err.Error()) 122 | return 123 | } 124 | approvedMap[addr] = approved 125 | } 126 | 127 | rest.NewResponder(c).Success(gin.H{ 128 | "approved": approvedMap, 129 | }) 130 | } 131 | 132 | func postPresaleTransactionsAction(c *gin.Context) { 133 | request := &models2.Events{} 134 | err := c.BindJSON(request) 135 | if err != nil { 136 | rest.NewResponder(c).ErrorValidation(err.Error()) 137 | return 138 | } 139 | 140 | events, err := geth.GetPresale().Events(request) 141 | if err != nil { 142 | rest.NewResponder(c).Error(err.Error()) 143 | return 144 | } 145 | 146 | rest.NewResponder(c).Success(gin.H{ 147 | "transactions": events, 148 | }) 149 | } 150 | 151 | func postAddAction(c *gin.Context) { 152 | request := &models.AddressWithAmount{} 153 | err := c.BindJSON(request) 154 | if err != nil { 155 | rest.NewResponder(c).ErrorValidation(err.Error()) 156 | return 157 | } 158 | 159 | tx, err := geth.GetPresale().Add(request.Address, request.Amount) 160 | if err != nil { 161 | rest.NewResponder(c).Error(err.Error()) 162 | return 163 | } 164 | 165 | rest.NewResponder(c).Success(gin.H{ 166 | "tx": tx.String(), 167 | }) 168 | } 169 | 170 | func postTopUpAction(c *gin.Context) { 171 | request := &models.AddressWithAmount{} 172 | err := c.BindJSON(request) 173 | if err != nil { 174 | rest.NewResponder(c).ErrorValidation(err.Error()) 175 | return 176 | } 177 | 178 | tx, err := geth.GetPresale().TopUp(request.Address, request.Amount) 179 | if err != nil { 180 | rest.NewResponder(c).Error(err.Error()) 181 | return 182 | } 183 | 184 | rest.NewResponder(c).Success(gin.H{ 185 | "tx": tx.String(), 186 | }) 187 | } 188 | 189 | func postApproveAction(c *gin.Context) { 190 | request := &models.Address{} 191 | err := c.BindJSON(request) 192 | if err != nil { 193 | rest.NewResponder(c).ErrorValidation(err.Error()) 194 | return 195 | } 196 | 197 | tx, err := geth.GetPresale().Approve(request.Address) 198 | if err != nil { 199 | rest.NewResponder(c).Error(err.Error()) 200 | return 201 | } 202 | 203 | rest.NewResponder(c).Success(gin.H{ 204 | "tx": tx.String(), 205 | }) 206 | } 207 | -------------------------------------------------------------------------------- /http/rater_routes.go: -------------------------------------------------------------------------------- 1 | package http 2 | 3 | import ( 4 | "github.com/gin-gonic/gin" 5 | "hoqu-geth-api/sdk/http/rest" 6 | "hoqu-geth-api/geth" 7 | "hoqu-geth-api/sdk/http/middleware" 8 | ) 9 | 10 | func InitHoQuRaterRoutes(router *gin.Engine) { 11 | config := router.Group("/rater", middleware.SignRequired()) 12 | { 13 | config.POST("/deploy", postDeployHoQuRaterAction) 14 | } 15 | } 16 | 17 | func postDeployHoQuRaterAction(c *gin.Context) { 18 | addr, tx, err := geth.GetHoQuRater().Deploy() 19 | if err != nil { 20 | rest.NewResponder(c).Error(err.Error()) 21 | return 22 | } 23 | 24 | _, err = geth.GetHoQuConfig().AddOwner(addr.String()) 25 | if err != nil { 26 | rest.NewResponder(c).Error(err.Error()) 27 | return 28 | } 29 | 30 | rest.NewResponder(c).Success(gin.H{ 31 | "address": addr.String(), 32 | "tx": tx.Hash().String(), 33 | }) 34 | } 35 | -------------------------------------------------------------------------------- /http/storage_routes.go: -------------------------------------------------------------------------------- 1 | package http 2 | 3 | import ( 4 | "github.com/gin-gonic/gin" 5 | "hoqu-geth-api/sdk/http/rest" 6 | "hoqu-geth-api/geth" 7 | "hoqu-geth-api/sdk/http/middleware" 8 | ) 9 | 10 | func InitHoQuStorageRoutes(router *gin.Engine) { 11 | config := router.Group("/storage", middleware.SignRequired()) 12 | { 13 | config.POST("/deploy", postDeployHoQuStorageAction) 14 | } 15 | } 16 | 17 | func postDeployHoQuStorageAction(c *gin.Context) { 18 | addr, tx, err := geth.GetHoQuStorage().Deploy() 19 | if err != nil { 20 | rest.NewResponder(c).Error(err.Error()) 21 | return 22 | } 23 | 24 | _, err = geth.GetHoQuConfig().AddOwner(addr.String()) 25 | if err != nil { 26 | rest.NewResponder(c).Error(err.Error()) 27 | return 28 | } 29 | 30 | rest.NewResponder(c).Success(gin.H{ 31 | "address": addr.String(), 32 | "tx": tx.Hash().String(), 33 | }) 34 | } -------------------------------------------------------------------------------- /http/token_routes.go: -------------------------------------------------------------------------------- 1 | package http 2 | 3 | import ( 4 | "github.com/gin-gonic/gin" 5 | "hoqu-geth-api/geth" 6 | "hoqu-geth-api/sdk/http/rest" 7 | "hoqu-geth-api/models" 8 | "hoqu-geth-api/sdk/http/middleware" 9 | sdkModels "hoqu-geth-api/sdk/models" 10 | ) 11 | 12 | func InitTokenRoutes(router *gin.Engine) { 13 | hqx := router.Group("/hqx") 14 | { 15 | hqx.POST("/deploy", middleware.SignRequired(), postDeployTokenAction) 16 | hqx.GET("/balance/:address", getHqxBalanceAction) 17 | hqx.POST("/balances", getHqxBalancesAction) 18 | hqx.POST("/allowance", getHqxAllowanceAction) 19 | hqx.POST("/transactions", postTokenTransactionsAction) 20 | hqx.POST("/holders", postTokenHoldersAction) 21 | } 22 | } 23 | 24 | func postDeployTokenAction(c *gin.Context) { 25 | request := &models.TokenDeployParams{} 26 | err := c.BindJSON(request) 27 | if err != nil { 28 | rest.NewResponder(c).ErrorValidation(err.Error()) 29 | return 30 | } 31 | 32 | addr, tx, err := geth.GetToken().Deploy(request.TotalSupply) 33 | if err != nil { 34 | rest.NewResponder(c).Error(err.Error()) 35 | return 36 | } 37 | 38 | rest.NewResponder(c).Success(gin.H{ 39 | "address": addr.String(), 40 | "tx": tx.Hash().String(), 41 | }) 42 | } 43 | 44 | // swagger:route GET /hqx/balance/:address platform getHqxBalance 45 | // 46 | // Get HQX balance 47 | // 48 | // Get particular Ethereum address HQX balance. 49 | // 50 | // Consumes: 51 | // - application/json 52 | // Produces: 53 | // - application/json 54 | // Responses: 55 | // 200: GetBalanceSuccessResponse 56 | // 400: RestErrorResponse 57 | // 58 | func getHqxBalanceAction(c *gin.Context) { 59 | addr := c.Param("address") 60 | bal, err := geth.GetToken().Balance(addr) 61 | if err != nil { 62 | rest.NewResponder(c).Error(err.Error()) 63 | return 64 | } 65 | 66 | rest.NewResponder(c).Success(gin.H{ 67 | "address": addr, 68 | "balance": bal.String(), 69 | }) 70 | } 71 | 72 | // swagger:route GET /hqx/allowance platform getHqxAllowance 73 | // 74 | // Get HQX allowance 75 | // 76 | // Get allowance given by owner of HQX tokens to spender. 77 | // 78 | // Consumes: 79 | // - application/json 80 | // Produces: 81 | // - application/json 82 | // Responses: 83 | // 200: GetAllowanceSuccessResponse 84 | // 400: RestErrorResponse 85 | // 86 | func getHqxAllowanceAction(c *gin.Context) { 87 | request := &models.AllowanceRequest{} 88 | err := c.BindJSON(request) 89 | if err != nil { 90 | rest.NewResponder(c).ErrorValidation(err.Error()) 91 | return 92 | } 93 | 94 | allowance, err := geth.GetToken().Allowance(request.Owner, request.Spender) 95 | if err != nil { 96 | rest.NewResponder(c).Error(err.Error()) 97 | return 98 | } 99 | 100 | rest.NewResponder(c).Success(gin.H{ 101 | "allowance": allowance.String(), 102 | }) 103 | } 104 | 105 | // swagger:route POST /hqx/balances platform getHqxBalances 106 | // 107 | // Get HQX balances 108 | // 109 | // Get HQX balances for list of Ethereum addresses. 110 | // 111 | // Consumes: 112 | // - application/json 113 | // Produces: 114 | // - application/json 115 | // Responses: 116 | // 200: GetBalancesSuccessResponse 117 | // 400: RestErrorResponse 118 | // 119 | func getHqxBalancesAction(c *gin.Context) { 120 | request := &models.Addresses{} 121 | err := c.BindJSON(request) 122 | if err != nil { 123 | rest.NewResponder(c).ErrorValidation(err.Error()) 124 | return 125 | } 126 | 127 | bals := map[string]string{} 128 | for _, addr := range request.Addresses { 129 | bal, err := geth.GetToken().Balance(addr) 130 | if err != nil { 131 | rest.NewResponder(c).Error(err.Error()) 132 | return 133 | } 134 | bals[addr] = bal.String() 135 | } 136 | 137 | rest.NewResponder(c).Success(gin.H{ 138 | "balances": bals, 139 | }) 140 | } 141 | 142 | func postTokenTransactionsAction(c *gin.Context) { 143 | request := &sdkModels.Events{} 144 | err := c.BindJSON(request) 145 | if err != nil { 146 | rest.NewResponder(c).ErrorValidation(err.Error()) 147 | return 148 | } 149 | 150 | events, err := geth.GetToken().Events(request) 151 | if err != nil { 152 | rest.NewResponder(c).Error(err.Error()) 153 | return 154 | } 155 | 156 | rest.NewResponder(c).Success(gin.H{ 157 | "transactions": events, 158 | }) 159 | } 160 | 161 | func postTokenHoldersAction(c *gin.Context) { 162 | request := &sdkModels.Events{} 163 | err := c.BindJSON(request) 164 | if err != nil { 165 | rest.NewResponder(c).ErrorValidation(err.Error()) 166 | return 167 | } 168 | 169 | holders, err := geth.GetToken().Holders(request) 170 | if err != nil { 171 | rest.NewResponder(c).Error(err.Error()) 172 | return 173 | } 174 | 175 | rest.NewResponder(c).Success(gin.H{ 176 | "count": len(holders), 177 | "holders": holders, 178 | }) 179 | } -------------------------------------------------------------------------------- /http/transactor_routes.go: -------------------------------------------------------------------------------- 1 | package http 2 | 3 | import ( 4 | "github.com/gin-gonic/gin" 5 | "hoqu-geth-api/sdk/http/rest" 6 | "hoqu-geth-api/geth" 7 | "hoqu-geth-api/sdk/http/middleware" 8 | ) 9 | 10 | func InitHoQuTransactorRoutes(router *gin.Engine) { 11 | config := router.Group("/transactor", middleware.SignRequired()) 12 | { 13 | config.POST("/deploy", postDeployHoQuTransactorAction) 14 | } 15 | } 16 | 17 | func postDeployHoQuTransactorAction(c *gin.Context) { 18 | addr, tx, err := geth.GetHoQuTransactor().Deploy() 19 | if err != nil { 20 | rest.NewResponder(c).Error(err.Error()) 21 | return 22 | } 23 | 24 | _, err = geth.GetHoQuConfig().AddOwner(addr.String()) 25 | if err != nil { 26 | rest.NewResponder(c).Error(err.Error()) 27 | return 28 | } 29 | 30 | rest.NewResponder(c).Success(gin.H{ 31 | "address": addr.String(), 32 | "tx": tx.Hash().String(), 33 | }) 34 | } 35 | -------------------------------------------------------------------------------- /http/wallet_routes.go: -------------------------------------------------------------------------------- 1 | package http 2 | 3 | import ( 4 | "github.com/gin-gonic/gin" 5 | "hoqu-geth-api/sdk/http/rest" 6 | sdkGeth "hoqu-geth-api/sdk/geth" 7 | "hoqu-geth-api/models" 8 | "github.com/ethereum/go-ethereum/common" 9 | ) 10 | 11 | func InitWalletRoutes(router *gin.Engine) { 12 | eth := router.Group("/eth") 13 | { 14 | eth.GET("/balance/:address", getEthBalanceAction) 15 | eth.POST("/balances", getEthBalancesAction) 16 | eth.GET("/block", getLatestBlockHeaderAction) 17 | eth.GET("/block/:hash", getBlockHeaderByHashAction) 18 | } 19 | } 20 | 21 | // swagger:route GET /eth/balance/:address ethereum getEthBalance 22 | // 23 | // Get ETH balance 24 | // 25 | // Get particular Ethereum address balance. 26 | // 27 | // Consumes: 28 | // - application/json 29 | // Produces: 30 | // - application/json 31 | // Responses: 32 | // 200: GetBalanceSuccessResponse 33 | // 400: RestErrorResponse 34 | // 35 | func getEthBalanceAction(c *gin.Context) { 36 | addr := c.Param("address") 37 | bal, err := sdkGeth.GetWallet().BalanceAt(addr) 38 | if err != nil { 39 | rest.NewResponder(c).Error(err.Error()) 40 | return 41 | } 42 | 43 | rest.NewResponder(c).Success(gin.H{ 44 | "address": addr, 45 | "balance": bal.String(), 46 | }) 47 | } 48 | 49 | // swagger:route POST /eth/balances ethereum getEthBalances 50 | // 51 | // Get ETH balances 52 | // 53 | // Get balances for list of Ethereum addresses. 54 | // 55 | // Consumes: 56 | // - application/json 57 | // Produces: 58 | // - application/json 59 | // Responses: 60 | // 200: GetBalancesSuccessResponse 61 | // 400: RestErrorResponse 62 | // 63 | func getEthBalancesAction(c *gin.Context) { 64 | request := &models.Addresses{} 65 | err := c.BindJSON(request) 66 | if err != nil { 67 | rest.NewResponder(c).ErrorValidation(err.Error()) 68 | return 69 | } 70 | 71 | bals := map[string]string{} 72 | for _, addr := range request.Addresses { 73 | bal, err := sdkGeth.GetWallet().BalanceAt(addr) 74 | if err != nil { 75 | rest.NewResponder(c).Error(err.Error()) 76 | return 77 | } 78 | bals[addr] = bal.String() 79 | } 80 | 81 | rest.NewResponder(c).Success(gin.H{ 82 | "balances": bals, 83 | }) 84 | } 85 | 86 | // swagger:route GET /eth/block ethereum getEthLastBlock 87 | // 88 | // Get last block 89 | // 90 | // Get last Ethereum block data. 91 | // 92 | // Consumes: 93 | // - application/json 94 | // Produces: 95 | // - application/json 96 | // Responses: 97 | // 200: GetBlockSuccessResponse 98 | // 400: RestErrorResponse 99 | // 100 | func getBlockHeaderByHashAction(c *gin.Context) { 101 | hash := c.Param("hash") 102 | b, err := sdkGeth.GetWallet().GetBlockHeaderByHash(common.HexToHash(hash)) 103 | if err != nil { 104 | rest.NewResponder(c).Error(err.Error()) 105 | return 106 | } 107 | 108 | rest.NewResponder(c).Success(gin.H{ 109 | "number": b.Number.String(), 110 | "hash": b.Hash().String(), 111 | "timestamp": b.Time.String(), 112 | "raw": b, 113 | }) 114 | } 115 | 116 | // swagger:route GET /eth/block/:hash ethereum getEthBlockByHash 117 | // 118 | // Get block by hash 119 | // 120 | // Get Ethereum block data by its hash. 121 | // 122 | // Consumes: 123 | // - application/json 124 | // Produces: 125 | // - application/json 126 | // Responses: 127 | // 200: GetBlockSuccessResponse 128 | // 400: RestErrorResponse 129 | // 130 | func getLatestBlockHeaderAction(c *gin.Context) { 131 | b, err := sdkGeth.GetWallet().GetBlockHeaderByNumber(nil) 132 | if err != nil { 133 | rest.NewResponder(c).Error(err.Error()) 134 | return 135 | } 136 | 137 | rest.NewResponder(c).Success(gin.H{ 138 | "number": b.Number.String(), 139 | "hash": b.Hash().String(), 140 | "timestamp": b.Time.String(), 141 | "raw": b, 142 | }) 143 | } 144 | -------------------------------------------------------------------------------- /lead/geth_storage.go: -------------------------------------------------------------------------------- 1 | package lead 2 | 3 | import ( 4 | "hoqu-geth-api/geth" 5 | "sync" 6 | "context" 7 | "fmt" 8 | "hoqu-geth-api/models" 9 | "hoqu-geth-api/sdk/entity" 10 | ) 11 | 12 | var ( 13 | gs *GethStorage 14 | gsOnce sync.Once 15 | ) 16 | 17 | type GethStorage struct { 18 | *entity.Storage 19 | HoquPlatform *geth.HoquPlatform 20 | HoquStorage *geth.HoQuStorage 21 | } 22 | 23 | func NewGethStorage(nm string, hp *geth.HoquPlatform, hs *geth.HoQuStorage) *GethStorage { 24 | return &GethStorage{ 25 | Storage: entity.NewStorage(nm), 26 | HoquPlatform: hp, 27 | HoquStorage: hs, 28 | } 29 | } 30 | 31 | func InitGethStorage() (err error) { 32 | gsOnce.Do(func() { 33 | err = geth.InitGeth() 34 | gs = NewGethStorage( 35 | "ethereum: lead", 36 | geth.GetHoquPlatform(), 37 | geth.GetHoQuStorage(), 38 | ) 39 | }) 40 | return 41 | } 42 | 43 | func GetGethStorage() *GethStorage { 44 | return gs 45 | } 46 | 47 | func (s *GethStorage) Op(ctx context.Context, opName string, input interface{}, output interface{}) (err error) { 48 | span, spanCtx := s.CreateSpan(ctx, opName, input) 49 | defer s.CloseSpan(span, output, &err) 50 | 51 | switch opName { 52 | case entity.CREATE: 53 | err = s.Create(spanCtx, input.(*models.AddLeadRequest), output.(*models.CreateResponseData)) 54 | case entity.SET_STATUS: 55 | err = s.SetStatus(spanCtx, input.(*models.SetLeadStatusRequest), output.(*models.TxSuccessData)) 56 | case SET_PRICE: 57 | err = s.SetPrice(spanCtx, input.(*models.SetLeadPriceRequest), output.(*models.TxSuccessData)) 58 | case entity.SET_URL: 59 | err = s.SetDataUrl(spanCtx, input.(*models.SetLeadDataUrlRequest), output.(*models.TxSuccessData)) 60 | case ADD_INTERMEDIARY: 61 | err = s.AddIntermediary(spanCtx, input.(*models.AddLeadIntermediaryRequest), output.(*models.TxSuccessData)) 62 | case TRANSACT: 63 | err = s.Transact(spanCtx, input.(*models.TransactLeadRequest), output.(*models.TxSuccessData)) 64 | case entity.GET_BY_ID: 65 | err = s.GetById(spanCtx, input.(*models.TransactLeadRequest), output.(*models.LeadSuccessData)) 66 | default: 67 | err = fmt.Errorf("%s: op %s is not supported", s.GetName(), opName) 68 | } 69 | 70 | return 71 | } 72 | 73 | func (s *GethStorage) Create(spanCtx context.Context, input *models.AddLeadRequest, output *models.CreateResponseData) error { 74 | tx, err := s.HoquPlatform.AddLead(input) 75 | if err != nil { 76 | output.Failed = true 77 | return err 78 | } 79 | 80 | output.Tx = tx.String() 81 | return nil 82 | } 83 | 84 | func (s *GethStorage) SetStatus(spanCtx context.Context, input *models.SetLeadStatusRequest, output *models.TxSuccessData) error { 85 | tx, err := s.HoquPlatform.SetLeadStatus(input) 86 | if err != nil { 87 | return err 88 | } 89 | 90 | output.Tx = tx.String() 91 | return nil 92 | } 93 | 94 | func (s *GethStorage) SetPrice(spanCtx context.Context, input *models.SetLeadPriceRequest, output *models.TxSuccessData) error { 95 | tx, err := s.HoquPlatform.SetLeadPrice(input) 96 | if err != nil { 97 | return err 98 | } 99 | 100 | output.Tx = tx.String() 101 | return nil 102 | } 103 | 104 | func (s *GethStorage) SetDataUrl(spanCtx context.Context, input *models.SetLeadDataUrlRequest, output *models.TxSuccessData) error { 105 | tx, err := s.HoquPlatform.SetLeadDataUrl(input) 106 | if err != nil { 107 | return err 108 | } 109 | 110 | output.Tx = tx.String() 111 | return nil 112 | } 113 | 114 | func (s *GethStorage) AddIntermediary(spanCtx context.Context, input *models.AddLeadIntermediaryRequest, output *models.TxSuccessData) error { 115 | tx, err := s.HoquPlatform.AddLeadIntermediary(input) 116 | if err != nil { 117 | return err 118 | } 119 | 120 | output.Tx = tx.String() 121 | return nil 122 | } 123 | 124 | func (s *GethStorage) Transact(spanCtx context.Context, input *models.TransactLeadRequest, output *models.TxSuccessData) error { 125 | tx, err := s.HoquPlatform.TransactLead(input.Id, input.AdId) 126 | if err != nil { 127 | return err 128 | } 129 | 130 | output.Tx = tx.String() 131 | return nil 132 | } 133 | 134 | func (s *GethStorage) GetById(spanCtx context.Context, input *models.TransactLeadRequest, output *models.LeadSuccessData) error { 135 | ad, err := s.HoquStorage.GetAdCampaign(input.AdId) 136 | if err != nil { 137 | return err 138 | } 139 | 140 | adContract, err := geth.GetAdCampaign(ad.ContractAddress) 141 | if err != nil { 142 | return err 143 | } 144 | 145 | lead, err := adContract.GetLead(input.Id) 146 | if err != nil { 147 | return err 148 | } 149 | 150 | output.Lead = lead 151 | output.Update = true 152 | s.OpDone(spanCtx) 153 | return nil 154 | } -------------------------------------------------------------------------------- /lead/routes.go: -------------------------------------------------------------------------------- 1 | package lead 2 | 3 | import ( 4 | "github.com/gin-gonic/gin" 5 | "hoqu-geth-api/models" 6 | "hoqu-geth-api/sdk/http/middleware" 7 | "hoqu-geth-api/sdk/entity" 8 | ) 9 | 10 | func InitLeadRoutes(routerGroup *gin.RouterGroup) { 11 | r := routerGroup.Group("/lead") 12 | { 13 | r.POST("/add", middleware.SignRequired(), postAddLeadAction) 14 | r.POST("/status", middleware.SignRequired(), postSetLeadStatusAction) 15 | r.POST("/price", middleware.SignRequired(), postSetLeadPriceAction) 16 | r.POST("/url", middleware.SignRequired(), postSetLeadDataUrlAction) 17 | r.POST("/intermediary", middleware.SignRequired(), postAddLeadIntermediaryAction) 18 | r.POST("/transact", middleware.SignRequired(), postTransactAction) 19 | r.POST("/get", getLeadAction) 20 | } 21 | } 22 | 23 | // swagger:route POST /platform/lead/add leads addLead 24 | // 25 | // Add Lead. 26 | // 27 | // Consumes: 28 | // - application/json 29 | // Produces: 30 | // - application/json 31 | // Responses: 32 | // 200: AddSuccessResponse 33 | // 400: RestErrorResponse 34 | // 35 | func postAddLeadAction(ctx *gin.Context) { 36 | entity.CreateAction(ctx, &models.AddLeadRequest{}, GetService().Create) 37 | } 38 | 39 | // swagger:route POST /platform/lead/status leads setLeadStatus 40 | // 41 | // Set Lead Status. 42 | // 43 | // Consumes: 44 | // - application/json 45 | // Produces: 46 | // - application/json 47 | // Responses: 48 | // 200: TxSuccessResponse 49 | // 400: RestErrorResponse 50 | // 51 | func postSetLeadStatusAction(ctx *gin.Context) { 52 | entity.SetAction(ctx, &models.SetLeadStatusRequest{}, GetService().SetStatus) 53 | } 54 | 55 | // swagger:route POST /platform/lead/price leads setLeadPrice 56 | // 57 | // Set Lead Price. 58 | // 59 | // Consumes: 60 | // - application/json 61 | // Produces: 62 | // - application/json 63 | // Responses: 64 | // 200: TxSuccessResponse 65 | // 400: RestErrorResponse 66 | // 67 | func postSetLeadPriceAction(ctx *gin.Context) { 68 | entity.SetAction(ctx, &models.SetLeadPriceRequest{}, GetService().SetPrice) 69 | } 70 | 71 | // swagger:route POST /platform/lead/url leads setLeadDataUrl 72 | // 73 | // Set Lead Data URL. 74 | // 75 | // Consumes: 76 | // - application/json 77 | // Produces: 78 | // - application/json 79 | // Responses: 80 | // 200: TxSuccessResponse 81 | // 400: RestErrorResponse 82 | // 83 | func postSetLeadDataUrlAction(ctx *gin.Context) { 84 | entity.SetAction(ctx, &models.SetLeadDataUrlRequest{}, GetService().SetUrl) 85 | } 86 | 87 | // swagger:route POST /platform/lead/intermediary leads addLeadIntermediary 88 | // 89 | // Add Lead Intermediary. 90 | // 91 | // Each intermediary is a money receiver when selling the lead. 92 | // Warning! Lead owner shouldn't be in this list. Owner receives the rest of amount. 93 | // 94 | // Consumes: 95 | // - application/json 96 | // Produces: 97 | // - application/json 98 | // Responses: 99 | // 200: TxSuccessResponse 100 | // 400: RestErrorResponse 101 | // 102 | func postAddLeadIntermediaryAction(ctx *gin.Context) { 103 | entity.SetAction(ctx, &models.AddLeadIntermediaryRequest{}, GetService().AddIntermediary) 104 | } 105 | 106 | // swagger:route POST /platform/lead/transact leads transactLead 107 | // 108 | // Sell Lead. 109 | // 110 | // Consumes: 111 | // - application/json 112 | // Produces: 113 | // - application/json 114 | // Responses: 115 | // 200: TxSuccessResponse 116 | // 400: RestErrorResponse 117 | // 118 | func postTransactAction(ctx *gin.Context) { 119 | entity.SetAction(ctx, &models.TransactLeadRequest{}, GetService().Transact) 120 | } 121 | 122 | // swagger:route POST /platform/lead/get leads getLead 123 | // 124 | // Get Lead by ID. 125 | // 126 | // Produces: 127 | // - application/json 128 | // Responses: 129 | // 200: LeadDataResponse 130 | // 400: RestErrorResponse 131 | // 132 | func getLeadAction(ctx *gin.Context) { 133 | entity.HttpBindAction(ctx, &models.TransactLeadRequest{}, &models.LeadSuccessData{}, GetService().GetById) 134 | } 135 | -------------------------------------------------------------------------------- /lead/service.go: -------------------------------------------------------------------------------- 1 | package lead 2 | 3 | import ( 4 | "hoqu-geth-api/sdk/entity" 5 | "sync" 6 | "context" 7 | "hoqu-geth-api/models" 8 | "github.com/satori/go.uuid" 9 | "strings" 10 | ) 11 | 12 | const ( 13 | ADD_INTERMEDIARY = "add_intermediary" 14 | TRANSACT = "transact" 15 | SET_PRICE = "set_price" 16 | ) 17 | 18 | var ( 19 | s *Service 20 | sOnce sync.Once 21 | ) 22 | 23 | type Service struct { 24 | *entity.Service 25 | } 26 | 27 | func NewService(storage entity.StorageInterface) *Service { 28 | return &Service{ 29 | Service: entity.NewService(storage, true), 30 | } 31 | } 32 | 33 | func InitService() (err error) { 34 | sOnce.Do(func() { 35 | err = InitDbStorage() 36 | if err != nil { 37 | return 38 | } 39 | s = NewService(GetDbStorage()) 40 | 41 | err = InitGethStorage() 42 | if err != nil { 43 | return 44 | } 45 | s.AppendStorage(GetGethStorage()) 46 | }) 47 | return 48 | } 49 | 50 | func GetService() *Service { 51 | return s 52 | } 53 | 54 | func (s *Service) Create(ctx context.Context, input interface{}, output interface{}) error { 55 | req := input.(*models.AddLeadRequest) 56 | resp := output.(*models.CreateResponseData) 57 | id, err := uuid.NewV2('L') 58 | if err != nil { 59 | return err 60 | } 61 | 62 | req.Id = id 63 | resp.Id = id.String() 64 | req.DataUrl = strings.Replace(req.DataUrl, ":id", id.String(), 1) 65 | 66 | return s.Service.Create(ctx, req, output) 67 | } 68 | 69 | func (s *Service) AddIntermediary(ctx context.Context, input interface{}, output interface{}) error { 70 | return s.Op(ctx, ADD_INTERMEDIARY, input, output) 71 | } 72 | 73 | func (s *Service) Transact(ctx context.Context, input interface{}, output interface{}) error { 74 | return s.Op(ctx, TRANSACT, input, output) 75 | } 76 | 77 | func (s *Service) SetPrice(ctx context.Context, input interface{}, output interface{}) error { 78 | return s.Op(ctx, SET_PRICE, input, output) 79 | } 80 | -------------------------------------------------------------------------------- /main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "hoqu-geth-api/app" 5 | ) 6 | 7 | func init() { 8 | app.Bootstrap() 9 | } 10 | 11 | func main() { 12 | app.Run() 13 | } 14 | -------------------------------------------------------------------------------- /models/bounty.go: -------------------------------------------------------------------------------- 1 | package models 2 | 3 | type BountyDeployParams struct { 4 | BankAddress string `json:"bankAddress"` 5 | BeneficiaryAddress string `json:"beneficiaryAddress"` 6 | } 7 | 8 | type BountySummary struct { 9 | IssuedTokensAmount string `json:"issuedTokensAmount"` 10 | ReceiversCount uint32 `json:"receiversCount"` 11 | IsFinished bool `json:"isFinished"` 12 | } 13 | -------------------------------------------------------------------------------- /models/claim.go: -------------------------------------------------------------------------------- 1 | package models 2 | 3 | type ClaimDeployParams struct { 4 | BankAddress string `json:"bankAddress"` 5 | ClaimMultimple bool `json:"claimMultimple"` 6 | } 7 | -------------------------------------------------------------------------------- /models/common.go: -------------------------------------------------------------------------------- 1 | package models 2 | 3 | // swagger:parameters getUser getOffer getTariff getAd 4 | type IdRequest struct { 5 | // id of entity 6 | // example: a6fdb91a-149d-11e8-b642-0ed5f89f718b 7 | Id string `json:"id"` 8 | } 9 | 10 | type CreateResponseData struct { 11 | // id of created entity 12 | // example: a6fdb91a-149d-11e8-b642-0ed5f89f718b 13 | Id string `json:"id"` 14 | // Ethereum transaction hash 15 | // example: 0x23682ef776bfb465433e8f6a6e84eab71f039f039e86933aeca20ee46d01d576 16 | Tx string `json:"tx"` 17 | Failed bool `json:"-"` 18 | } 19 | 20 | // Success 21 | // 22 | // swagger:response 23 | type AddSuccessResponse struct { 24 | // in: body 25 | Body struct { 26 | Data CreateResponseData `json:"data"` 27 | } 28 | } 29 | 30 | type TxSuccessData struct { 31 | // Ethereum transaction hash 32 | // example: 0x23682ef776bfb465433e8f6a6e84eab71f039f039e86933aeca20ee46d01d576 33 | Tx string `json:"tx"` 34 | } 35 | 36 | // Success 37 | // 38 | // swagger:response 39 | type TxSuccessResponse struct { 40 | // in: body 41 | Body struct { 42 | Data TxSuccessData `json:"data"` 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /models/config.go: -------------------------------------------------------------------------------- 1 | package models 2 | 3 | type ConfigDeployParams struct { 4 | CommissionWallet string `json:"commissionWallet"` 5 | } 6 | 7 | type SystemOwnerAddedEventArgs struct { 8 | NewOwner string `json:"newOwner"` 9 | } 10 | 11 | type SystemOwnerChangedEventArgs struct { 12 | PreviousOwner string `json:"previousOwner"` 13 | NewOwner string `json:"newOwner"` 14 | } 15 | 16 | type SystemOwnerDeletedEventArgs struct { 17 | DeletedOwner string `json:"deletedOwner"` 18 | } 19 | 20 | type CommissionWalletChangedEventArgs struct { 21 | ChangedBy string `json:"changedBy"` 22 | CommissionWallet string `json:"commissionWallet"` 23 | } 24 | 25 | type CommissionChangedEventArgs struct { 26 | ChangedBy string `json:"changedBy"` 27 | Commission string `json:"commission"` 28 | } 29 | -------------------------------------------------------------------------------- /models/platform.go: -------------------------------------------------------------------------------- 1 | package models 2 | 3 | // status, one of 0:NotExists, 1:Created, 2:Pending, 3:Active, 4:Done, 5:Declined 4 | // swagger:model 5 | // example: 3 6 | type Status uint8 7 | 8 | const ( 9 | STATUS_NOT_EXIST = Status(0) 10 | STATUS_CREATED = Status(1) 11 | STATUS_PENDING = Status(2) 12 | STATUS_ACTIVE = Status(3) 13 | STATUS_DONE = Status(4) 14 | STATUS_DECLINED = Status(5) 15 | 16 | KYC_UNDEFINED = uint8(0) 17 | KYC_TIER1 = uint8(1) 18 | KYC_TIER2 = uint8(2) 19 | KYC_TIER3 = uint8(3) 20 | KYC_TIER4 = uint8(4) 21 | KYC_TIER5 = uint8(5) 22 | ) 23 | 24 | // swagger:parameters setAdStatus setOfferStatus setUserStatus setTrackerStatus setNetworkStatus setCompanyStatus 25 | type SetStatusParams struct { 26 | // in: body 27 | Body SetStatusRequest `json:"body"` 28 | } 29 | 30 | type SetStatusRequest struct { 31 | // id of entity 32 | // example: a6fdb91a-149d-11e8-b642-0ed5f89f718b 33 | Id string `json:"id"` 34 | // example: 3 35 | Status Status `json:"status"` 36 | } 37 | 38 | // swagger:parameters setOfferName 39 | type SetNameParams struct { 40 | // in: body 41 | Body SetNameRequest `json:"body"` 42 | } 43 | 44 | type SetNameRequest struct { 45 | // id of entity 46 | // example: a6fdb91a-149d-11e8-b642-0ed5f89f718b 47 | Id string `json:"id"` 48 | // example: HoQu LLC 49 | Name string `json:"name"` 50 | } 51 | 52 | // swagger:parameters addOfferTariff 53 | type IdWithChildIdParams struct { 54 | // in: body 55 | Body IdWithChildIdRequest `json:"body"` 56 | } 57 | 58 | type IdWithChildIdRequest struct { 59 | // id of entity 60 | // example: a6fdb91a-149d-11e8-b642-0ed5f89f718b 61 | Id string `json:"id"` 62 | // id of child entity 63 | // example: a6fdb91a-149d-11e8-b642-0ed5f89f718b 64 | ChildId string `json:"childId"` 65 | } 66 | 67 | type OnlyAddressEventArgs struct { 68 | OwnerAddress string `json:"ownerAddress"` 69 | Id string `json:"id"` 70 | } 71 | 72 | type StatusChangedEventArgs struct { 73 | OwnerAddress string `json:"ownerAddress"` 74 | Id string `json:"id"` 75 | Status uint8 `json:"status"` 76 | } 77 | 78 | type IdWithNameEventArgs struct { 79 | OwnerAddress string `json:"ownerAddress"` 80 | Id string `json:"id"` 81 | Name string `json:"name"` 82 | } 83 | 84 | type IdWithChildIdEventArgs struct { 85 | OwnerAddress string `json:"ownerAddress"` 86 | Id string `json:"id"` 87 | ChildId string `json:"childId"` 88 | } 89 | -------------------------------------------------------------------------------- /models/platform_ad.go: -------------------------------------------------------------------------------- 1 | package models 2 | 3 | import ( 4 | "time" 5 | "github.com/satori/go.uuid" 6 | ) 7 | 8 | // swagger:parameters addAd 9 | type AddAdCampaignParams struct { 10 | // in: body 11 | Body AddAdCampaignRequest `json:"body"` 12 | } 13 | 14 | type AddAdCampaignRequest struct { 15 | Id uuid.UUID `json:"-"` 16 | // the ID of an User owned the entity 17 | // example: a6fdb91a-149d-11e8-b642-0ed5f89f718b 18 | OwnerId string `json:"ownerId"` 19 | // the ID of an Offer the entity is linked to 20 | // example: a6fdb91a-149d-11e8-b642-0ed5f89f718b 21 | OfferId string `json:"offerId"` 22 | // Ethereum address of the beneficiary (Ad money receiver) 23 | // example: 0xED2F74E1fb73b775E6e35720869Ae7A7f4D755aD 24 | BeneficiaryAddress string `json:"beneficiaryAddress"` 25 | } 26 | 27 | type DeployAdContractRequest struct { 28 | // the ID of an User owned the entity 29 | // example: a6fdb91a-149d-11e8-b642-0ed5f89f718b 30 | OwnerId string `json:"ownerId"` 31 | // the ID of an Offer the entity is linked to 32 | // example: a6fdb91a-149d-11e8-b642-0ed5f89f718b 33 | OfferId string `json:"offerId"` 34 | // the ID of an Ad Campaign 35 | // example: a6fdb91a-149d-11e8-b642-0ed5f89f718b 36 | AdId string `json:"adId"` 37 | // Ethereum address of the beneficiary (Ad money receiver) 38 | // example: 0xED2F74E1fb73b775E6e35720869Ae7A7f4D755aD 39 | BeneficiaryAddress string `json:"beneficiaryAddress"` 40 | // Ethereum address of the Offer payer (who will pay for leads) 41 | // example: 0xED2F74E1fb73b775E6e35720869Ae7A7f4D755aD 42 | PayerAddress string `json:"payerAddress"` 43 | } 44 | 45 | type AddAdToStorageRequest struct { 46 | // the ID of an Ad Campaign 47 | // example: a6fdb91a-149d-11e8-b642-0ed5f89f718b 48 | AdId string `json:"adId"` 49 | // the ID of an User owned the entity 50 | // example: a6fdb91a-149d-11e8-b642-0ed5f89f718b 51 | OwnerId string `json:"ownerId"` 52 | // the ID of an Offer the entity is linked to 53 | // example: a6fdb91a-149d-11e8-b642-0ed5f89f718b 54 | OfferId string `json:"offerId"` 55 | // Ethereum address of the contract serving the ad campaign 56 | // example: 0xED2F74E1fb73b775E6e35720869Ae7A7f4D755aD 57 | ContractAddress string `json:"contractAddress"` 58 | } 59 | 60 | type AdAddedEventArgs struct { 61 | OwnerAddress string `json:"ownerAddress"` 62 | Id string `json:"id"` 63 | ContractAddress string `json:"contractAddress"` 64 | } 65 | 66 | type CreateAdCampaignResponseData struct { 67 | // id of created entity 68 | // example: a6fdb91a-149d-11e8-b642-0ed5f89f718b 69 | Id string `json:"id"` 70 | // Ethereum transaction hash 71 | // example: 0x23682ef776bfb465433e8f6a6e84eab71f039f039e86933aeca20ee46d01d576 72 | Tx string `json:"tx"` 73 | // Ethereum address of the contract serving the ad campaign 74 | // example: 0xED2F74E1fb73b775E6e35720869Ae7A7f4D755aD 75 | ContractAddress string `json:"contractAddress"` 76 | Failed bool `json:"-"` 77 | } 78 | 79 | // Success 80 | // 81 | // swagger:response 82 | type AddAdCampaignSuccessResponse struct { 83 | // in: body 84 | Body struct { 85 | Data CreateAdCampaignResponseData `json:"data"` 86 | } 87 | } 88 | 89 | type AdCampaignSuccessData struct { 90 | Ad *AdCampaign `json:"Ad"` 91 | Update bool `json:"-"` 92 | } 93 | 94 | // Success 95 | // 96 | // swagger:response 97 | type AdDataResponse struct { 98 | // in: body 99 | Body struct { 100 | Data AdCampaignSuccessData `json:"data"` 101 | } 102 | } 103 | 104 | // Ad Model 105 | // 106 | // swagger:model 107 | type AdCampaign struct { 108 | ID string `json:"id" gorm:"type:char(36)"` 109 | // the ID of an Ad Campaign from Ad Contract 110 | // example: a6fdb91a-149d-11e8-b642-0ed5f89f718b 111 | AdId string `json:"adId"` 112 | // ISO8601 datetime format 113 | // example: 2009-11-13T10:39:35Z 114 | CreatedAt time.Time `json:"createdAt"` 115 | // the ID of an User owned the entity 116 | // example: a6fdb91a-149d-11e8-b642-0ed5f89f718b 117 | OwnerId string `json:"ownerId"` 118 | // the ID of an Offer the entity is linked to 119 | // example: a6fdb91a-149d-11e8-b642-0ed5f89f718b 120 | OfferId string `json:"offerId"` 121 | // Ethereum address of the beneficiary (Ad money receiver) 122 | // example: 0xED2F74E1fb73b775E6e35720869Ae7A7f4D755aD 123 | BeneficiaryAddress string `json:"beneficiaryAddress"` 124 | // Ethereum address of the Offer payer (who will pay for leads) 125 | // example: 0xED2F74E1fb73b775E6e35720869Ae7A7f4D755aD 126 | PayerAddress string `json:"payerAddress"` 127 | // Ethereum address of the contract serving the ad campaign 128 | // example: 0xED2F74E1fb73b775E6e35720869Ae7A7f4D755aD 129 | ContractAddress string `json:"contractAddress"` 130 | // example: 3 131 | Status Status `json:"status"` 132 | } 133 | 134 | // Ad Model 135 | // 136 | // swagger:model 137 | type AdStorageData struct { 138 | // ISO8601 datetime format 139 | // example: 2009-11-13T10:39:35Z 140 | CreatedAt time.Time `json:"createdAt"` 141 | // the ID of an User owned the entity 142 | // example: a6fdb91a-149d-11e8-b642-0ed5f89f718b 143 | OwnerId string `json:"ownerId"` 144 | // the ID of an Offer the entity is linked to 145 | // example: a6fdb91a-149d-11e8-b642-0ed5f89f718b 146 | OfferId string `json:"offerId"` 147 | // Ethereum address of the contract serving the ad campaign 148 | // example: 0xED2F74E1fb73b775E6e35720869Ae7A7f4D755aD 149 | ContractAddress string `json:"contractAddress"` 150 | // example: 3 151 | Status Status `json:"status"` 152 | } 153 | -------------------------------------------------------------------------------- /models/platform_company.go: -------------------------------------------------------------------------------- 1 | package models 2 | 3 | // swagger:parameters registerCompany 4 | type RegisterCompanyParams struct { 5 | // in: body 6 | Body RegisterCompanyRequest `json:"body"` 7 | } 8 | 9 | type RegisterCompanyRequest struct { 10 | // the ID of an User owned the entity 11 | // example: a6fdb91a-149d-11e8-b642-0ed5f89f718b 12 | OwnerId string `json:"ownerId"` 13 | // the name of the company 14 | // example: HOQU LLC 15 | Name string `json:"name"` 16 | // the company description URL 17 | DataUrl string `json:"dataUrl"` 18 | } 19 | 20 | // swagger:parameters getCompany 21 | type GetCompanyParams struct { 22 | // an ID of the requested entity 23 | // example: a6fdb91a-149d-11e8-b642-0ed5f89f718b 24 | // in: query 25 | Id string `json:"id"` 26 | } 27 | 28 | // Success 29 | // 30 | // swagger:response 31 | type CompanyDataResponse struct { 32 | // in: body 33 | Body struct { 34 | Data struct { 35 | Lead CompanyData `json:"Company"` 36 | } `json:"data"` 37 | } 38 | } 39 | 40 | // Company Model 41 | // 42 | // swagger:model 43 | type CompanyData struct { 44 | // unix timestamp 45 | // example: 1518957879 46 | CreatedAt string `json:"createdAt"` 47 | // the ID of an User owned the entity 48 | // example: a6fdb91a-149d-11e8-b642-0ed5f89f718b 49 | OwnerId string `json:"ownerId"` 50 | // the name of the company 51 | // example: HOQU LLC 52 | Name string `json:"name"` 53 | // the company description URL 54 | DataUrl string `json:"dataUrl"` 55 | // example: 3 56 | Status Status `json:"status"` 57 | } 58 | -------------------------------------------------------------------------------- /models/platform_identification.go: -------------------------------------------------------------------------------- 1 | package models 2 | 3 | // swagger:parameters addIdentification 4 | type AddIdentificationParams struct { 5 | // in: body 6 | Body AddIdentificationRequest `json:"body"` 7 | } 8 | 9 | type AddIdentificationRequest struct { 10 | // an ID of the user 11 | // example: a6fdb91a-149d-11e8-b642-0ed5f89f718b 12 | UserId string `json:"userId"` 13 | // identification type 14 | // example: person|company 15 | IdType string `json:"idType"` 16 | // name 17 | // example: John Snow 18 | Name string `json:"name"` 19 | // an ID of the company for company type identifications 20 | // example: a6fdb91a-149d-11e8-b642-0ed5f89f718b 21 | CompanyId string `json:"companyId"` 22 | } 23 | 24 | // swagger:parameters addKyc 25 | type AddKycReportParams struct { 26 | // in: body 27 | Body AddKycReportRequest `json:"body"` 28 | } 29 | 30 | type AddKycReportRequest struct { 31 | // an ID of the identification 32 | // example: a6fdb91a-149d-11e8-b642-0ed5f89f718b 33 | Id string `json:"id"` 34 | // Meta data of the report in string format (JSON for example) 35 | Meta string `json:"meta"` 36 | // Higher the level more trust this user has from other participants 37 | // example: 3 38 | KycLevel uint8 `json:"kycLevel"` 39 | // the URL with full report data 40 | DataUrl string `json:"dataUrl"` 41 | } 42 | 43 | type IdentificationAddedEventArgs struct { 44 | OwnerAddress string `json:"ownerAddress"` 45 | Id string `json:"id"` 46 | UserId string `json:"userId"` 47 | Name string `json:"name"` 48 | } 49 | 50 | type KycReportAddedEventArgs struct { 51 | OwnerAddress string `json:"ownerAddress"` 52 | KycLevel uint8 `json:"kycLevel"` 53 | Id string `json:"id"` 54 | UserId string `json:"userId"` 55 | } 56 | 57 | type KycReport struct { 58 | CreatedAt string `json:"createdAt"` 59 | Meta string `json:"meta"` 60 | KycLevel uint8 `json:"kycLevel"` 61 | DataUrl string `json:"dataUrl"` 62 | } 63 | 64 | // swagger:parameters getIdentification 65 | type GetIdentificationParams struct { 66 | // an ID of the requested entity 67 | // example: a6fdb91a-149d-11e8-b642-0ed5f89f718b 68 | // in: query 69 | Id string `json:"id"` 70 | } 71 | 72 | // Success 73 | // 74 | // swagger:response 75 | type IdentificationDataResponse struct { 76 | // in: body 77 | Body struct { 78 | Data struct { 79 | Identification IdentificationData `json:"identification"` 80 | } `json:"data"` 81 | } 82 | } 83 | 84 | // User Model 85 | // 86 | // swagger:model 87 | type IdentificationData struct { 88 | // unix timestamp 89 | // example: 1518957879 90 | CreatedAt string `json:"createdAt"` 91 | // an ID of the user 92 | // example: a6fdb91a-149d-11e8-b642-0ed5f89f718b 93 | UserId string `json:"userId"` 94 | // identification type 95 | // example: person|company 96 | IdType string `json:"idType"` 97 | // name 98 | // example: John Snow 99 | Name string `json:"name"` 100 | // an ID of the company for company type identifications 101 | // example: a6fdb91a-149d-11e8-b642-0ed5f89f718b 102 | CompanyId string `json:"companyId"` 103 | // a list of all KYC reports 104 | KycReports map[uint16]KycReport `json:"kycReports"` 105 | // example: 3 106 | Status Status `json:"status"` 107 | } 108 | -------------------------------------------------------------------------------- /models/platform_network.go: -------------------------------------------------------------------------------- 1 | package models 2 | 3 | // swagger:parameters registerNetwork 4 | type RegisterNetworkParams struct { 5 | // in: body 6 | Body RegisterNetworkRequest `json:"body"` 7 | } 8 | 9 | type RegisterNetworkRequest struct { 10 | // the ID of an User owned the entity 11 | // example: a6fdb91a-149d-11e8-b642-0ed5f89f718b 12 | OwnerId string `json:"ownerId"` 13 | // the name of the network 14 | // example: HOQU Net 15 | Name string `json:"name"` 16 | // the company description URL 17 | DataUrl string `json:"dataUrl"` 18 | } 19 | 20 | // swagger:parameters getNetwork 21 | type GetNetworkParams struct { 22 | // an ID of the requested entity 23 | // example: a6fdb91a-149d-11e8-b642-0ed5f89f718b 24 | // in: query 25 | Id string `json:"id"` 26 | } 27 | 28 | // Success 29 | // 30 | // swagger:response 31 | type NetworkDataResponse struct { 32 | // in: body 33 | Body struct { 34 | Data struct { 35 | Network NetworkData `json:"Network"` 36 | } `json:"data"` 37 | } 38 | } 39 | 40 | // Network Model 41 | // 42 | // swagger:model 43 | type NetworkData struct { 44 | // unix timestamp 45 | // example: 1518957879 46 | CreatedAt string `json:"createdAt"` 47 | // the ID of an User owned the entity 48 | // example: a6fdb91a-149d-11e8-b642-0ed5f89f718b 49 | OwnerId string `json:"ownerId"` 50 | // the name of the Network 51 | Name string `json:"name"` 52 | // the Network full data URL 53 | DataUrl string `json:"dataUrl"` 54 | // example: 3 55 | Status Status `json:"status"` 56 | } 57 | -------------------------------------------------------------------------------- /models/platform_offer.go: -------------------------------------------------------------------------------- 1 | package models 2 | 3 | import ( 4 | "github.com/satori/go.uuid" 5 | "github.com/jinzhu/gorm" 6 | "encoding/json" 7 | "time" 8 | ) 9 | 10 | // swagger:parameters addOffer 11 | type AddOfferParams struct { 12 | // in: body 13 | Body AddOfferRequest `json:"body"` 14 | } 15 | 16 | type AddOfferRequest struct { 17 | Id uuid.UUID `json:"-"` 18 | // the ID of an User owned the entity 19 | // example: a6fdb91a-149d-11e8-b642-0ed5f89f718b 20 | OwnerId string `json:"ownerId"` 21 | // the ID of the Network the offer is linked to 22 | // example: a6fdb91a-149d-11e8-b642-0ed5f89f718b 23 | NetworkId string `json:"networkId"` 24 | // the ID of a Merchant owning this offer 25 | // example: a6fdb91a-149d-11e8-b642-0ed5f89f718b 26 | MerchantId string `json:"merchantId"` 27 | // Ethereum address of the Offer payer (who will pay for leads) 28 | // example: 0xED2F74E1fb73b775E6e35720869Ae7A7f4D755aD 29 | PayerAddress string `json:"payerAddress"` 30 | // the name of the Offer 31 | Name string `json:"name"` 32 | // the offer full data URL 33 | DataUrl string `json:"dataUrl"` 34 | } 35 | 36 | // swagger:parameters setOfferPayerAddress 37 | type SetOfferPayerAddressParams struct { 38 | // in: body 39 | Body SetOfferPayerAddressRequest `json:"body"` 40 | } 41 | 42 | type SetOfferPayerAddressRequest struct { 43 | // id of the offer 44 | // example: a6fdb91a-149d-11e8-b642-0ed5f89f718b 45 | Id string `json:"id"` 46 | // Ethereum address of the Offer payer (who will pay for leads) 47 | // example: 0xED2F74E1fb73b775E6e35720869Ae7A7f4D755aD 48 | PayerAddress string `json:"payerAddress"` 49 | } 50 | 51 | // swagger:parameters addOfferTariffGroup 52 | type AddOfferTariffGroupParams struct { 53 | // in: body 54 | Body IdWithChildIdRequest `json:"body"` 55 | } 56 | 57 | type OfferSuccessData struct { 58 | Offer *Offer `json:"Offer"` 59 | Update bool `json:"-"` 60 | } 61 | 62 | // Success 63 | // 64 | // swagger:response 65 | type OfferDataResponse struct { 66 | // in: body 67 | Body struct { 68 | Data OfferSuccessData `json:"data"` 69 | } 70 | } 71 | 72 | // Offer Model 73 | // 74 | // swagger:model 75 | type Offer struct { 76 | ID string `json:"id" gorm:"type:char(36)"` 77 | // ISO8601 datetime format 78 | // example: 2009-11-13T10:39:35Z 79 | CreatedAt time.Time `json:"createdAt"` 80 | // the ID of an User owned the entity 81 | // example: a6fdb91a-149d-11e8-b642-0ed5f89f718b 82 | OwnerId string `json:"ownerId" gorm:"type:char(36)"` 83 | // the ID of the Network the offer is linked to 84 | // example: a6fdb91a-149d-11e8-b642-0ed5f89f718b 85 | NetworkId string `json:"networkId" gorm:"type:char(36)"` 86 | // the ID of a Merchant owning this offer 87 | // example: a6fdb91a-149d-11e8-b642-0ed5f89f718b 88 | MerchantId string `json:"merchantId" gorm:"type:char(36)"` 89 | // Ethereum address of the Offer payer (who will pay for leads) 90 | // example: 0xED2F74E1fb73b775E6e35720869Ae7A7f4D755aD 91 | PayerAddress string `json:"payerAddress"` 92 | // the name of the Offer 93 | Name string `json:"name"` 94 | // the offer full data URL 95 | DataUrl string `json:"dataUrl"` 96 | // the cost of the leads in HQX 97 | // example: ["a6fdb91a-149d-11e8-b642-0ed5f89f718b"] 98 | TariffGroups []string `json:"tariffGroups" gorm:"-"` 99 | TariffGroupsJson string `json:"-" gorm:"tariffGroups;type:text"` 100 | // example: 3 101 | Status Status `json:"status"` 102 | } 103 | 104 | func (model *Offer) BeforeSave(scope *gorm.Scope) error { 105 | tj, err := json.Marshal(model.TariffGroups) 106 | if err != nil { 107 | return err 108 | } 109 | 110 | model.TariffGroupsJson = string(tj) 111 | return nil 112 | } 113 | 114 | func (model *Offer) AfterFind(scope *gorm.Scope) error { 115 | return json.Unmarshal([]byte(model.TariffGroupsJson), &model.TariffGroups) 116 | } 117 | -------------------------------------------------------------------------------- /models/platform_stats.go: -------------------------------------------------------------------------------- 1 | package models 2 | 3 | // swagger:parameters getStats 4 | type GetStatsParams struct { 5 | // an ID of the requested entity 6 | // example: a6fdb91a-149d-11e8-b642-0ed5f89f718b 7 | // in: query 8 | Id string `json:"id"` 9 | } 10 | 11 | // Success 12 | // 13 | // swagger:response 14 | type StatsDataResponse struct { 15 | // in: body 16 | Body struct { 17 | Data struct { 18 | Stats StatsData `json:"Stats"` 19 | } `json:"data"` 20 | } 21 | } 22 | 23 | // Stats Model 24 | // 25 | // swagger:model 26 | type StatsData struct { 27 | // current rating 28 | // example: 650 29 | Rating uint64 `json:"rating"` 30 | // the total volume in HQX 31 | // example: 542332 32 | Volume uint64 `json:"volume"` 33 | // number of related members 34 | // example: 34 35 | Members uint64 `json:"members"` 36 | // reserved stat for future needs 37 | // example: 500 38 | Alfa uint64 `json:"alfa"` 39 | // reserved stat for future needs 40 | // example: 245 41 | Beta uint64 `json:"beta"` 42 | // example: 3 43 | Status Status `json:"status"` 44 | } 45 | -------------------------------------------------------------------------------- /models/platform_tariff.go: -------------------------------------------------------------------------------- 1 | package models 2 | 3 | import ( 4 | "github.com/satori/go.uuid" 5 | "time" 6 | ) 7 | 8 | // swagger:parameters addTariff 9 | type AddTariffParams struct { 10 | // in: body 11 | Body AddTariffRequest `json:"body"` 12 | } 13 | 14 | type AddTariffRequest struct { 15 | Id uuid.UUID `json:"-"` 16 | // the ID of a Tariff Group 17 | // example: a6fdb91a-149d-11e8-b642-0ed5f89f718b 18 | TariffGroupId string `json:"tariffGroupId"` 19 | // the name of the Tariff 20 | Name string `json:"name"` 21 | // the name of the action when tariff is applied 22 | Action string `json:"action"` 23 | // the method of lead price calculation 24 | // example: percent|fixed 25 | CalcMethod string `json:"calcMethod"` 26 | // the price of a lead calculated by the tariff in wei 27 | // or the percent value 28 | // example: 25000000000000000 29 | Price string `json:"price"` 30 | } 31 | 32 | type TariffSuccessData struct { 33 | Tariff *Tariff `json:"Tariff"` 34 | Update bool `json:"-"` 35 | } 36 | 37 | // Success 38 | // 39 | // swagger:response 40 | type TariffDataResponse struct { 41 | // in: body 42 | Body struct { 43 | Data TariffSuccessData `json:"data"` 44 | } 45 | } 46 | 47 | // Tariff Model 48 | // 49 | // swagger:model 50 | type Tariff struct { 51 | ID string `json:"id" gorm:"type:char(36)"` 52 | // ISO8601 datetime format 53 | // example: 2009-11-13T10:39:35Z 54 | CreatedAt time.Time `json:"createdAt"` 55 | // the ID of a Tariff Group 56 | // example: a6fdb91a-149d-11e8-b642-0ed5f89f718b 57 | TariffGroupId string `json:"tariffGroupId"` 58 | // the name of the Tariff 59 | Name string `json:"name"` 60 | // the name of the action when tariff is applied 61 | Action string `json:"action"` 62 | // the method of lead price calculation 63 | // example: percent|fixed 64 | CalcMethod string `json:"calcMethod"` 65 | // the price of a lead calculated by the tariff in wei 66 | // or the percent value 67 | // example: 25000000000000000 68 | Price string `json:"price"` 69 | // example: 3 70 | Status Status `json:"status"` 71 | } 72 | -------------------------------------------------------------------------------- /models/platform_tariff_group.go: -------------------------------------------------------------------------------- 1 | package models 2 | 3 | import ( 4 | "github.com/satori/go.uuid" 5 | "time" 6 | "github.com/jinzhu/gorm" 7 | "encoding/json" 8 | ) 9 | 10 | // swagger:parameters addTariffGroup 11 | type AddTariffGroupParams struct { 12 | // in: body 13 | Body AddTariffGroupRequest `json:"body"` 14 | } 15 | 16 | type AddTariffGroupRequest struct { 17 | Id uuid.UUID `json:"-"` 18 | // the ID of an User owned the entity 19 | // example: a6fdb91a-149d-11e8-b642-0ed5f89f718b 20 | OwnerId string `json:"ownerId"` 21 | // the name of the TariffGroup 22 | Name string `json:"name"` 23 | } 24 | 25 | type TariffGroupSuccessData struct { 26 | TariffGroup *TariffGroup `json:"TariffGroup"` 27 | Update bool `json:"-"` 28 | } 29 | 30 | // Success 31 | // 32 | // swagger:response 33 | type TariffGroupDataResponse struct { 34 | // in: body 35 | Body struct { 36 | Data TariffGroupSuccessData `json:"data"` 37 | } 38 | } 39 | 40 | // TariffGroup Model 41 | // 42 | // swagger:model 43 | type TariffGroup struct { 44 | ID string `json:"id" gorm:"type:char(36)"` 45 | // ISO8601 datetime format 46 | // example: 2009-11-13T10:39:35Z 47 | CreatedAt time.Time `json:"createdAt"` 48 | // the ID of an User owned the entity 49 | // example: a6fdb91a-149d-11e8-b642-0ed5f89f718b 50 | OwnerId string `json:"ownerId"` 51 | // the name of the TariffGroup 52 | Name string `json:"name"` 53 | // a list of tariff ids related to the offer 54 | // example: ["a6fdb91a-149d-11e8-b642-0ed5f89f718b"] 55 | Tariffs []string `json:"tariffs" gorm:"-"` 56 | TariffsJson string `json:"-" gorm:"tariffs;type:text"` 57 | // example: 3 58 | Status Status `json:"status"` 59 | } 60 | 61 | func (model *TariffGroup) BeforeSave(scope *gorm.Scope) error { 62 | tj, err := json.Marshal(model.Tariffs) 63 | if err != nil { 64 | return err 65 | } 66 | 67 | model.TariffsJson = string(tj) 68 | return nil 69 | } 70 | 71 | func (model *TariffGroup) AfterFind(scope *gorm.Scope) error { 72 | return json.Unmarshal([]byte(model.TariffsJson), &model.Tariffs) 73 | } 74 | -------------------------------------------------------------------------------- /models/platform_tracker.go: -------------------------------------------------------------------------------- 1 | package models 2 | 3 | // swagger:parameters registerTracker 4 | type RegisterTrackerParams struct { 5 | // in: body 6 | Body RegisterTrackerRequest `json:"body"` 7 | } 8 | 9 | type RegisterTrackerRequest struct { 10 | // the ID of an User owned the entity 11 | // example: a6fdb91a-149d-11e8-b642-0ed5f89f718b 12 | OwnerId string `json:"ownerId"` 13 | // the ID of the Network the tracker is working for (can be empty) 14 | // example: a6fdb91a-149d-11e8-b642-0ed5f89f718b 15 | NetworkId string `json:"networkId"` 16 | // the name of the Tracker 17 | Name string `json:"name"` 18 | // the Tracker full data URL 19 | DataUrl string `json:"dataUrl"` 20 | } 21 | 22 | // swagger:parameters getTracker 23 | type GetTrackerParams struct { 24 | // an ID of the requested entity 25 | // example: a6fdb91a-149d-11e8-b642-0ed5f89f718b 26 | // in: query 27 | Id string `json:"id"` 28 | } 29 | 30 | // Success 31 | // 32 | // swagger:response 33 | type TrackerDataResponse struct { 34 | // in: body 35 | Body struct { 36 | Data struct { 37 | Tracker TrackerData `json:"Tracker"` 38 | } `json:"data"` 39 | } 40 | } 41 | 42 | // Tracker Model 43 | // 44 | // swagger:model 45 | type TrackerData struct { 46 | // unix timestamp 47 | // example: 1518957879 48 | CreatedAt string `json:"createdAt"` 49 | // the ID of an User owned the entity 50 | // example: a6fdb91a-149d-11e8-b642-0ed5f89f718b 51 | OwnerId string `json:"ownerId"` 52 | // the ID of the Network the tracker is working for (can be empty) 53 | // example: a6fdb91a-149d-11e8-b642-0ed5f89f718b 54 | NetworkId string `json:"networkId"` 55 | // the name of the Tracker 56 | Name string `json:"name"` 57 | // the Tracker full data URL 58 | DataUrl string `json:"dataUrl"` 59 | // example: 3 60 | Status Status `json:"status"` 61 | } 62 | -------------------------------------------------------------------------------- /models/platform_user.go: -------------------------------------------------------------------------------- 1 | package models 2 | 3 | import ( 4 | "time" 5 | "github.com/satori/go.uuid" 6 | "github.com/jinzhu/gorm" 7 | "encoding/json" 8 | ) 9 | 10 | // swagger:parameters registerUser 11 | type RegisterUserParams struct { 12 | // in: body 13 | Body RegisterUserRequest `json:"body"` 14 | } 15 | 16 | type RegisterUserRequest struct { 17 | Id uuid.UUID `json:"-"` 18 | // Ethereum address of the user 19 | // example: 0xED2F74E1fb73b775E6e35720869Ae7A7f4D755aD 20 | Address string `json:"address"` 21 | // user role 22 | // example: affiliate 23 | Role string `json:"role"` 24 | // all private data available only for that user is encrypted by his public key 25 | PubKey string `json:"pubKey"` 26 | } 27 | 28 | // swagger:parameters addUserAddress 29 | type AddUserAddressParams struct { 30 | // in: body 31 | Body AddUserAddressRequest `json:"body"` 32 | } 33 | 34 | type AddUserAddressRequest struct { 35 | // an ID of the user 36 | // example: a6fdb91a-149d-11e8-b642-0ed5f89f718b 37 | Id string `json:"id"` 38 | // Ethereum address of the user 39 | // example: 0xED2F74E1fb73b775E6e35720869Ae7A7f4D755aD 40 | Address string `json:"address"` 41 | } 42 | 43 | type UserRegisteredEventArgs struct { 44 | OwnerAddress string `json:"ownerAddress"` 45 | Id string `json:"id"` 46 | Role string `json:"role"` 47 | } 48 | 49 | type UserAddressAddedEventArgs struct { 50 | OwnerAddress string `json:"ownerAddress"` 51 | AdditionalAddress string `json:"additionalAddress"` 52 | Id string `json:"id"` 53 | } 54 | 55 | 56 | type UserSuccessData struct { 57 | User *User `json:"User"` 58 | Update bool `json:"-"` 59 | } 60 | 61 | // Success 62 | // 63 | // swagger:response 64 | type UserDataResponse struct { 65 | // in: body 66 | Body struct { 67 | Data UserSuccessData `json:"data"` 68 | } 69 | } 70 | 71 | // User Model 72 | // 73 | // swagger:model 74 | type User struct { 75 | ID string `json:"id" gorm:"type:char(36)"` 76 | // ISO8601 datetime format 77 | // example: 2009-11-13T10:39:35Z 78 | CreatedAt time.Time `json:"createdAt"` 79 | // a list of Ethereum addresses of the user 80 | // example: ["0xED2F74E1fb73b775E6e35720869Ae7A7f4D755aD"] 81 | Addresses map[uint8]string `json:"addresses" gorm:"-"` 82 | AddressesJson string `json:"-" gorm:"addresses;type:text"` 83 | // user role 84 | // example: affiliate 85 | Role string `json:"role"` 86 | // Higher the level more trust this user has from other participants 87 | // example: 3 88 | KycLevel uint8 `json:"kycLevel"` 89 | // all private data available only for that user is encrypted by his public key 90 | PubKey string `json:"pubKey"` 91 | // example: 3 92 | Status Status `json:"status"` 93 | } 94 | 95 | func (model *User) BeforeSave(scope *gorm.Scope) error { 96 | tj, err := json.Marshal(model.Addresses) 97 | if err != nil { 98 | return err 99 | } 100 | 101 | model.AddressesJson = string(tj) 102 | return nil 103 | } 104 | 105 | func (model *User) AfterFind(scope *gorm.Scope) error { 106 | return json.Unmarshal([]byte(model.AddressesJson), &model.Addresses) 107 | } 108 | -------------------------------------------------------------------------------- /models/presale.go: -------------------------------------------------------------------------------- 1 | package models 2 | 3 | type PresaleDeployParams struct { 4 | BankAddress string `json:"bankAddress"` 5 | BeneficiaryAddress string `json:"beneficiaryAddress"` 6 | TokenRate string `json:"tokenRate"` 7 | MinBuyableAmount string `json:"minBuyableAmount"` 8 | MaxTokensAmount string `json:"maxTokensAmount"` 9 | EndDate int64 `json:"endDate"` 10 | } 11 | 12 | type TokenAddedEventArgs struct { 13 | Address string `json:"address"` 14 | TokenAmount string `json:"tokenAmount"` 15 | EtherAmount string `json:"ethAmount"` 16 | } 17 | 18 | type TokenSentEventAgrs struct { 19 | Address string `json:"address"` 20 | TokenAmount string `json:"tokenAmount"` 21 | } 22 | 23 | type Summary struct { 24 | Address string `json:"address"` 25 | MinBuyableAmount string `json:"minBuyableAmount"` 26 | MaxTokensAmount string `json:"maxTokensAmount"` 27 | IssuedTokensAmount string `json:"issuedTokensAmount"` 28 | TokenRate string `json:"tokenRate"` 29 | ReceiversCount uint32 `json:"receiversCount"` 30 | IsFinished bool `json:"isFinished"` 31 | } 32 | -------------------------------------------------------------------------------- /models/requests.go: -------------------------------------------------------------------------------- 1 | package models 2 | 3 | type Address struct { 4 | Address string `json:"address"` 5 | } 6 | 7 | type Addresses struct { 8 | Addresses []string `json:"addresses"` 9 | } 10 | 11 | type AddressWithAmount struct { 12 | Address string `json:"address"` 13 | Amount string `json:"amount"` 14 | } 15 | -------------------------------------------------------------------------------- /models/sale.go: -------------------------------------------------------------------------------- 1 | package models 2 | 3 | type SaleDeployParams struct { 4 | BankAddress string `json:"bankAddress"` 5 | BeneficiaryAddress string `json:"beneficiaryAddress"` 6 | TokenRate string `json:"tokenRate"` 7 | MinBuyableAmount string `json:"minBuyableAmount"` 8 | MaxTokensAmount string `json:"maxTokensAmount"` 9 | EndDate int64 `json:"endDate"` 10 | } 11 | 12 | type SaleSummary struct { 13 | Address string `json:"address"` 14 | MaxTokensAmount string `json:"maxTokensAmount"` 15 | IssuedTokensAmount string `json:"issuedTokensAmount"` 16 | NextBoundaryAmount string `json:"nextBoundaryAmount"` 17 | TokenRate string `json:"tokenRate"` 18 | ReceiversCount uint32 `json:"receiversCount"` 19 | IsFinished bool `json:"isFinished"` 20 | } 21 | -------------------------------------------------------------------------------- /models/storage.go: -------------------------------------------------------------------------------- 1 | package models 2 | 3 | type StorageDeployParams struct { 4 | ConfigAddress string `json:"configAddress"` 5 | } 6 | -------------------------------------------------------------------------------- /models/token.go: -------------------------------------------------------------------------------- 1 | package models 2 | 3 | type TokenDeployParams struct { 4 | TotalSupply string `json:"totalSupply"` 5 | } 6 | 7 | type TokenTransferEventArgs struct { 8 | From string `json:"from"` 9 | To string `json:"to"` 10 | Amount string `json:"amount"` 11 | } 12 | 13 | type TokenApprovalEventArgs struct { 14 | Owner string `json:"owner"` 15 | Spender string `json:"spender"` 16 | Amount string `json:"amount"` 17 | } 18 | 19 | // swagger:parameters getHqxBalance 20 | type GetHqxBalanceParams struct { 21 | // Ethereum address 22 | // example: 0xED2F74E1fb73b775E6e35720869Ae7A7f4D755aD 23 | // in: query 24 | Address string `json:"address"` 25 | } 26 | 27 | // swagger:parameters getHqxBalances 28 | type HqxAddressesParams struct { 29 | // in: body 30 | Body Addresses `json:"body"` 31 | } 32 | 33 | // swagger:parameters getHqxAllowance 34 | type HqxAllowanceParams struct { 35 | // in: body 36 | Body AllowanceRequest `json:"body"` 37 | } 38 | 39 | type AllowanceRequest struct { 40 | // Ethereum address of token's owner 41 | // example: 0xED2F74E1fb73b775E6e35720869Ae7A7f4D755aD 42 | Owner string `json:"owner"` 43 | // Ethereum address of a spender 44 | // example: 0xED2F74E1fb73b775E6e35720869Ae7A7f4D755aD 45 | Spender string `json:"spender"` 46 | } 47 | 48 | // Success 49 | // 50 | // swagger:response 51 | type GetAllowanceSuccessResponse struct { 52 | // in: body 53 | Body struct { 54 | Data struct { 55 | // HQX allowance in wei 56 | // example: 42340000000000000000 57 | Allowance string `json:"allowance"` 58 | } `json:"data"` 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /models/wallet.go: -------------------------------------------------------------------------------- 1 | package models 2 | 3 | import "github.com/ethereum/go-ethereum/core/types" 4 | 5 | // swagger:parameters getEthBalance 6 | type GetEthBalanceParams struct { 7 | // Ethereum address 8 | // example: 0xED2F74E1fb73b775E6e35720869Ae7A7f4D755aD 9 | // in: query 10 | Address string `json:"address"` 11 | } 12 | 13 | // swagger:parameters getEthBalances 14 | type EthAddressesParams struct { 15 | // in: body 16 | Body Addresses `json:"body"` 17 | } 18 | 19 | // Success 20 | // 21 | // swagger:response 22 | type GetBalanceSuccessResponse struct { 23 | // in: body 24 | Body struct { 25 | Data struct { 26 | // Ethereum address 27 | // example: 0xED2F74E1fb73b775E6e35720869Ae7A7f4D755aD 28 | Address string `json:"address"` 29 | // Ethereum address balance 30 | // example: 42340000000000000000 31 | Balance string `json:"balance"` 32 | } `json:"data"` 33 | } 34 | } 35 | 36 | // Success 37 | // 38 | // swagger:response 39 | type GetBalancesSuccessResponse struct { 40 | // in: body 41 | Body struct { 42 | Data struct { 43 | // Ethereum address balances list 44 | // example: {"0xED2F74E1fb73b775E6e35720869Ae7A7f4D755aD": "42340000000000000000"} 45 | Balances map[string]string `json:"balances"` 46 | } `json:"data"` 47 | } 48 | } 49 | 50 | // Success 51 | // 52 | // swagger:response 53 | type GetBlockSuccessResponse struct { 54 | // in: body 55 | Body struct { 56 | Data struct { 57 | // Block number 58 | // example: 5349009 59 | Number string `json:"number"` 60 | // Block hash 61 | // example: 0x43dbc6e17450307c226e78cc1146a15662fb2ff16369d0e5c24652576b9d8e5e 62 | Hash string `json:"hash"` 63 | // Block creation timestamp 64 | // example: 1522415005 65 | Timestamp string `json:"timestamp"` 66 | // Block raw data 67 | Raw *types.Header `json:"raw"` 68 | } `json:"data"` 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /offer/geth_storage.go: -------------------------------------------------------------------------------- 1 | package offer 2 | 3 | import ( 4 | "hoqu-geth-api/geth" 5 | "sync" 6 | "context" 7 | "fmt" 8 | "hoqu-geth-api/models" 9 | "hoqu-geth-api/sdk/entity" 10 | ) 11 | 12 | var ( 13 | gs *GethStorage 14 | gsOnce sync.Once 15 | ) 16 | 17 | type GethStorage struct { 18 | *entity.Storage 19 | HoquPlatform *geth.HoquPlatform 20 | HoquStorage *geth.HoQuStorage 21 | } 22 | 23 | func NewGethStorage(nm string, hp *geth.HoquPlatform, hs *geth.HoQuStorage) *GethStorage { 24 | return &GethStorage{ 25 | Storage: entity.NewStorage(nm), 26 | HoquPlatform: hp, 27 | HoquStorage: hs, 28 | } 29 | } 30 | 31 | func InitGethStorage() (err error) { 32 | gsOnce.Do(func() { 33 | err = geth.InitGeth() 34 | gs = NewGethStorage( 35 | "ethereum: offer", 36 | geth.GetHoquPlatform(), 37 | geth.GetHoQuStorage(), 38 | ) 39 | }) 40 | return 41 | } 42 | 43 | func GetGethStorage() *GethStorage { 44 | return gs 45 | } 46 | 47 | func (s *GethStorage) Op(ctx context.Context, opName string, input interface{}, output interface{}) (err error) { 48 | span, spanCtx := s.CreateSpan(ctx, opName, input) 49 | defer s.CloseSpan(span, output, &err) 50 | 51 | switch opName { 52 | case entity.CREATE: 53 | err = s.Create(spanCtx, input.(*models.AddOfferRequest), output.(*models.CreateResponseData)) 54 | case entity.SET_STATUS: 55 | err = s.SetStatus(spanCtx, input.(*models.SetStatusRequest), output.(*models.TxSuccessData)) 56 | case entity.SET_NAME: 57 | err = s.SetName(spanCtx, input.(*models.SetNameRequest), output.(*models.TxSuccessData)) 58 | case SET_PAYER_ADDRESS: 59 | err = s.SetPayerAddress(spanCtx, input.(*models.SetOfferPayerAddressRequest), output.(*models.TxSuccessData)) 60 | case entity.ADD_CHILD_BY_ID: 61 | err = s.AddOfferTariffGroup(spanCtx, input.(*models.IdWithChildIdRequest), output.(*models.TxSuccessData)) 62 | case entity.GET_BY_ID: 63 | err = s.GetById(spanCtx, input.(*models.IdRequest), output.(*models.OfferSuccessData)) 64 | default: 65 | err = fmt.Errorf("%s: op %s is not supported", s.GetName(), opName) 66 | } 67 | 68 | return 69 | } 70 | 71 | func (s *GethStorage) Create(spanCtx context.Context, input *models.AddOfferRequest, output *models.CreateResponseData) error { 72 | tx, err := s.HoquPlatform.AddOffer(input) 73 | if err != nil { 74 | output.Failed = true 75 | return err 76 | } 77 | 78 | output.Tx = tx.String() 79 | return nil 80 | } 81 | 82 | func (s *GethStorage) SetStatus(spanCtx context.Context, input *models.SetStatusRequest, output *models.TxSuccessData) error { 83 | tx, err := s.HoquPlatform.SetOfferStatus(input) 84 | if err != nil { 85 | return err 86 | } 87 | 88 | output.Tx = tx.String() 89 | return nil 90 | } 91 | 92 | func (s *GethStorage) SetName(spanCtx context.Context, input *models.SetNameRequest, output *models.TxSuccessData) error { 93 | tx, err := s.HoquPlatform.SetOfferName(input) 94 | if err != nil { 95 | return err 96 | } 97 | 98 | output.Tx = tx.String() 99 | return nil 100 | } 101 | 102 | func (s *GethStorage) SetPayerAddress(spanCtx context.Context, input *models.SetOfferPayerAddressRequest, output *models.TxSuccessData) error { 103 | tx, err := s.HoquPlatform.SetOfferPayerAddress(input) 104 | if err != nil { 105 | return err 106 | } 107 | 108 | output.Tx = tx.String() 109 | return nil 110 | } 111 | 112 | func (s *GethStorage) AddOfferTariffGroup(spanCtx context.Context, input *models.IdWithChildIdRequest, output *models.TxSuccessData) error { 113 | tx, err := s.HoquPlatform.AddOfferTariffGroup(input) 114 | if err != nil { 115 | return err 116 | } 117 | 118 | output.Tx = tx.String() 119 | return nil 120 | } 121 | 122 | func (s *GethStorage) GetById(spanCtx context.Context, input *models.IdRequest, output *models.OfferSuccessData) error { 123 | offer, err := s.HoquStorage.GetOffer(input) 124 | if err != nil { 125 | return err 126 | } 127 | 128 | output.Offer = offer 129 | output.Update = true 130 | s.OpDone(spanCtx) 131 | return nil 132 | } -------------------------------------------------------------------------------- /offer/routes.go: -------------------------------------------------------------------------------- 1 | package offer 2 | 3 | import ( 4 | "github.com/gin-gonic/gin" 5 | "hoqu-geth-api/models" 6 | "hoqu-geth-api/sdk/http/middleware" 7 | "hoqu-geth-api/sdk/entity" 8 | ) 9 | 10 | func InitOfferRoutes(routerGroup *gin.RouterGroup) { 11 | r := routerGroup.Group("/offer") 12 | { 13 | r.POST("/add", middleware.SignRequired(), postAddOfferAction) 14 | r.POST("/status", middleware.SignRequired(), postSetOfferStatusAction) 15 | r.POST("/name", middleware.SignRequired(), postSetOfferNameAction) 16 | r.POST("/payer_address", middleware.SignRequired(), postSetOfferPayerAddressAction) 17 | r.POST("/tariff_group", middleware.SignRequired(), postAddOfferTariffGroupAction) 18 | r.GET("/:id", getOfferAction) 19 | } 20 | } 21 | 22 | // swagger:route POST /platform/offer/add offers addOffer 23 | // 24 | // Add Offer. 25 | // 26 | // Consumes: 27 | // - application/json 28 | // Produces: 29 | // - application/json 30 | // Responses: 31 | // 200: AddSuccessResponse 32 | // 400: RestErrorResponse 33 | // 34 | func postAddOfferAction(ctx *gin.Context) { 35 | entity.CreateAction(ctx, &models.AddOfferRequest{}, GetService().Create) 36 | } 37 | 38 | // swagger:route POST /platform/offer/status offers setOfferStatus 39 | // 40 | // Set Offer Status. 41 | // 42 | // Consumes: 43 | // - application/json 44 | // Produces: 45 | // - application/json 46 | // Responses: 47 | // 200: TxSuccessResponse 48 | // 400: RestErrorResponse 49 | // 50 | func postSetOfferStatusAction(ctx *gin.Context) { 51 | entity.SetAction(ctx, &models.SetStatusRequest{}, GetService().SetStatus) 52 | } 53 | 54 | // swagger:route POST /platform/offer/name offers setOfferName 55 | // 56 | // Set Offer Name. 57 | // 58 | // Consumes: 59 | // - application/json 60 | // Produces: 61 | // - application/json 62 | // Responses: 63 | // 200: TxSuccessResponse 64 | // 400: RestErrorResponse 65 | // 66 | func postSetOfferNameAction(ctx *gin.Context) { 67 | entity.SetAction(ctx, &models.SetNameRequest{}, GetService().SetName) 68 | } 69 | 70 | // swagger:route POST /platform/offer/payer_address offers setOfferPayerAddress 71 | // 72 | // Set Offer Payer Address. 73 | // 74 | // Consumes: 75 | // - application/json 76 | // Produces: 77 | // - application/json 78 | // Responses: 79 | // 200: TxSuccessResponse 80 | // 400: RestErrorResponse 81 | // 82 | func postSetOfferPayerAddressAction(ctx *gin.Context) { 83 | entity.SetAction(ctx, &models.SetOfferPayerAddressRequest{}, GetService().SetPayerAddress) 84 | } 85 | 86 | // swagger:route POST /platform/offer/tariff_group offers addOfferTariffGroup 87 | // 88 | // Add Offer tariff. 89 | // 90 | // Consumes: 91 | // - application/json 92 | // Produces: 93 | // - application/json 94 | // Responses: 95 | // 200: TxSuccessResponse 96 | // 400: RestErrorResponse 97 | // 98 | func postAddOfferTariffGroupAction(ctx *gin.Context) { 99 | entity.SetAction(ctx, &models.IdWithChildIdRequest{}, GetService().AddChildById) 100 | } 101 | 102 | // swagger:route GET /platform/offer/:id offers getOffer 103 | // 104 | // Get Offer by ID. 105 | // 106 | // Produces: 107 | // - application/json 108 | // Responses: 109 | // 200: OfferDataResponse 110 | // 400: RestErrorResponse 111 | // 112 | func getOfferAction(ctx *gin.Context) { 113 | id := ctx.Param("id") 114 | entity.GetByIdAction(ctx, id, &models.OfferSuccessData{}, GetService().GetById) 115 | } 116 | -------------------------------------------------------------------------------- /offer/service.go: -------------------------------------------------------------------------------- 1 | package offer 2 | 3 | import ( 4 | "hoqu-geth-api/sdk/entity" 5 | "sync" 6 | "context" 7 | "hoqu-geth-api/models" 8 | "github.com/satori/go.uuid" 9 | "strings" 10 | ) 11 | 12 | const ( 13 | SET_PAYER_ADDRESS = "set_payer_address" 14 | ) 15 | 16 | var ( 17 | s *Service 18 | sOnce sync.Once 19 | ) 20 | 21 | type Service struct { 22 | *entity.Service 23 | } 24 | 25 | func NewService(storage entity.StorageInterface) *Service { 26 | return &Service{ 27 | Service: entity.NewService(storage, true), 28 | } 29 | } 30 | 31 | func InitService() (err error) { 32 | sOnce.Do(func() { 33 | err = InitDbStorage() 34 | if err != nil { 35 | return 36 | } 37 | s = NewService(GetDbStorage()) 38 | 39 | err = InitGethStorage() 40 | if err != nil { 41 | return 42 | } 43 | s.AppendStorage(GetGethStorage()) 44 | }) 45 | return 46 | } 47 | 48 | func GetService() *Service { 49 | return s 50 | } 51 | 52 | func (s *Service) Create(ctx context.Context, input interface{}, output interface{}) error { 53 | req := input.(*models.AddOfferRequest) 54 | resp := output.(*models.CreateResponseData) 55 | id, err := uuid.NewV2('O') 56 | if err != nil { 57 | return err 58 | } 59 | 60 | req.Id = id 61 | resp.Id = id.String() 62 | req.DataUrl = strings.Replace(req.DataUrl, ":id", id.String(), 1) 63 | 64 | return s.Service.Create(ctx, req, output) 65 | } 66 | 67 | func (s *Service) SetPayerAddress(ctx context.Context, input interface{}, output interface{}) error { 68 | return s.Op(ctx, SET_PAYER_ADDRESS, input, output) 69 | } -------------------------------------------------------------------------------- /sdk/app/config.go: -------------------------------------------------------------------------------- 1 | package app 2 | 3 | import ( 4 | "os" 5 | "fmt" 6 | "bytes" 7 | "io/ioutil" 8 | "path/filepath" 9 | 10 | "github.com/spf13/viper" 11 | "github.com/sirupsen/logrus" 12 | "github.com/gin-gonic/gin" 13 | ) 14 | 15 | func InitConfig() { 16 | setDefaults() 17 | bindEnvVariables() 18 | InitDefaultConfigFiles() 19 | verifyConfig() 20 | setReleaseMode() 21 | printAppState() 22 | } 23 | 24 | func InitDefaultConfigFiles() { 25 | dir, err := os.Getwd() 26 | 27 | if err != nil { 28 | logrus.Fatal(err) 29 | } 30 | 31 | viper.SetConfigType("yaml") 32 | 33 | files := []string{ 34 | dir + "/config/global.yaml", 35 | dir + fmt.Sprintf("/config/config.%s.yaml", viper.GetString(ENVNAME)), 36 | dir + "/config/local.yaml", 37 | } 38 | 39 | ReadAndMerge(files) 40 | } 41 | 42 | func ReadAndMerge(files []string) { 43 | for _, file := range files { 44 | data, err := ioutil.ReadFile(file) 45 | 46 | if err != nil && filepath.Base(file) != "local.yaml" { 47 | logrus.Panicf( 48 | "Can not load config file %s. An error message: %s", file, err, 49 | ) 50 | return 51 | } 52 | 53 | err = viper.MergeConfig(bytes.NewReader(data)) 54 | if err != nil { 55 | logrus.Panicf( 56 | "An error '%s' has occurred while parsing config file %s", 57 | err, 58 | file, 59 | ) 60 | } 61 | } 62 | } 63 | 64 | func setReleaseMode() { 65 | if Env() == PRONET_ENV { 66 | gin.SetMode(gin.ReleaseMode) 67 | } 68 | } 69 | 70 | func printAppState() { 71 | logrus.Infof("Application Environment. %s = %s", ENVNAME, Env()) 72 | logrus.Infof("Application runs with the following config:\n%+v\n", viper.AllSettings()) 73 | } 74 | 75 | func verifyConfig() { 76 | if !viper.IsSet("project.name") { 77 | logrus.Warn("Project name is not configured") 78 | } 79 | 80 | if !viper.IsSet("geth.main.key_file") { 81 | logrus.Warn("Main key file is not specified") 82 | } 83 | 84 | if !viper.IsSet("geth.main.pass") { 85 | logrus.Warn("Main key file password is not specified") 86 | } 87 | } 88 | 89 | func bindEnvVariables() { 90 | viper.BindEnv(ENVNAME) 91 | } 92 | 93 | func setDefaults() { 94 | viper.SetDefault(ENVNAME, TESTNET_ENV) 95 | } 96 | -------------------------------------------------------------------------------- /sdk/app/env.go: -------------------------------------------------------------------------------- 1 | package app 2 | 3 | import ( 4 | "os" 5 | ) 6 | 7 | const ( 8 | ENVNAME string = "APPLICATION_ENV" 9 | PRONET_ENV = "pro_net" 10 | TESTNET_ENV = "test_net" 11 | DEFAULT_ENV string = TESTNET_ENV 12 | ) 13 | 14 | var env string 15 | 16 | func init() { 17 | env = getAppEnv(DEFAULT_ENV) 18 | } 19 | 20 | func Env() string { 21 | return env 22 | } 23 | 24 | func getAppEnv(def string) (env string) { 25 | env = os.Getenv(ENVNAME) 26 | 27 | if env = os.Getenv(ENVNAME); env == "" { 28 | env = def 29 | } 30 | 31 | return 32 | } 33 | -------------------------------------------------------------------------------- /sdk/app/logger.go: -------------------------------------------------------------------------------- 1 | package app 2 | 3 | import ( 4 | "os" 5 | "github.com/sirupsen/logrus" 6 | ) 7 | 8 | func InitLogger() { 9 | //logrus.SetFormatter(&logrus.JSONFormatter{}) 10 | 11 | logrus.SetOutput(os.Stdout) 12 | 13 | logrus.SetLevel(logrus.InfoLevel) 14 | 15 | //levels := []logrus.Level{ 16 | // logrus.WarnLevel, 17 | // logrus.PanicLevel, 18 | // logrus.FatalLevel, 19 | // logrus.ErrorLevel, 20 | //} 21 | 22 | if env := Env(); env == TESTNET_ENV { 23 | //levels = append(levels, logrus.DebugLevel) 24 | //levels = append(levels, logrus.InfoLevel) 25 | logrus.SetLevel(logrus.DebugLevel) 26 | } 27 | 28 | // Add sentry log hook to send logs asynchronous 29 | //if viper.IsSet("log.sentry.dsn") { 30 | // if raven, err := raven2.New(viper.GetString("log.sentry.dsn")); err == nil { 31 | // raven.SetRelease(Version) 32 | // raven.SetEnvironment(Env()) 33 | // 34 | // if hook, err := logrus_sentry.NewWithClientSentryHook(raven, levels); err == nil { 35 | // hook.Timeout = 1000 * time.Millisecond 36 | // hook.StacktraceConfiguration.Enable = true 37 | // hook.StacktraceConfiguration.Level = log.ErrorLevel 38 | // log.AddHook(hook) 39 | // } 40 | // } 41 | //} 42 | } 43 | -------------------------------------------------------------------------------- /sdk/db/connection_manager.go: -------------------------------------------------------------------------------- 1 | package db 2 | 3 | import ( 4 | "hoqu-geth-api/sdk/app" 5 | _ "github.com/jinzhu/gorm/dialects/mysql" 6 | _ "github.com/jinzhu/gorm/dialects/postgres" 7 | "github.com/jinzhu/gorm" 8 | ) 9 | 10 | type ConnectionManager struct { 11 | dsn string 12 | driver string 13 | } 14 | 15 | func NewConnectionManager(driver, dsn string) *ConnectionManager { 16 | return &ConnectionManager{ 17 | dsn: dsn, 18 | driver: driver, 19 | } 20 | } 21 | 22 | func (st *ConnectionManager) NewConnection() (*gorm.DB, error) { 23 | db, err := gorm.Open(st.driver, st.dsn) 24 | 25 | if app.Env() == app.TESTNET_ENV { 26 | db.LogMode(true) 27 | } 28 | 29 | return db, err 30 | } 31 | -------------------------------------------------------------------------------- /sdk/entity/http.go: -------------------------------------------------------------------------------- 1 | package entity 2 | 3 | import ( 4 | "context" 5 | "github.com/gin-gonic/gin" 6 | "hoqu-geth-api/sdk/tracing" 7 | "hoqu-geth-api/sdk/http/rest" 8 | "hoqu-geth-api/models" 9 | ) 10 | 11 | type ServiceHandler func(ctx context.Context, input interface{}, output interface{}) error 12 | 13 | func CreateAction(ctx *gin.Context, input interface{}, handler ServiceHandler) { 14 | output := &models.CreateResponseData{} 15 | HttpBindAction(ctx, input, output, handler) 16 | } 17 | 18 | func SetAction(ctx *gin.Context, input interface{}, handler ServiceHandler) { 19 | output := &models.TxSuccessData{} 20 | HttpBindAction(ctx, input, output, handler) 21 | } 22 | 23 | func GetByIdAction(ctx *gin.Context, id string, output interface{}, handler ServiceHandler) { 24 | input := &models.IdRequest{ 25 | Id: id, 26 | } 27 | HttpAction(ctx, input, output, handler) 28 | } 29 | 30 | func HttpBindAction(ctx *gin.Context, input interface{}, output interface{}, handler ServiceHandler) { 31 | err := ctx.BindJSON(input) 32 | if err != nil { 33 | rest.NewResponder(ctx).ErrorValidation(err.Error()) 34 | return 35 | } 36 | 37 | HttpAction(ctx, input, output, handler) 38 | } 39 | 40 | func HttpAction(ctx *gin.Context, input interface{}, output interface{}, handler ServiceHandler) { 41 | err := handler(tracing.GetServerSpan(ctx), input, output) 42 | if err != nil { 43 | rest.NewResponder(ctx).Error(err.Error()) 44 | return 45 | } 46 | 47 | rest.NewResponder(ctx).Success(output) 48 | } -------------------------------------------------------------------------------- /sdk/entity/service.go: -------------------------------------------------------------------------------- 1 | package entity 2 | 3 | import "context" 4 | 5 | const ( 6 | CREATE = "create" 7 | GET_BY_ID = "get_by_id" 8 | SET_STATUS = "set_status" 9 | SET_NAME = "set_name" 10 | SET_URL = "set_url" 11 | ADD_CHILD_BY_ID = "add_child_by_id" 12 | 13 | OP_DONE = "op_done" 14 | ) 15 | 16 | type Service struct { 17 | storages *StorageStack 18 | continueOnError bool 19 | } 20 | 21 | func NewService(storage StorageInterface, coe bool) *Service { 22 | return &Service{ 23 | storages: NewStorageStack(storage), 24 | continueOnError: coe, 25 | } 26 | } 27 | 28 | func (s *Service) AppendStorage(storage StorageInterface) { 29 | s.storages.Append(storage) 30 | } 31 | 32 | func (s *Service) GetStorages() *StorageStack { 33 | return s.storages 34 | } 35 | 36 | func (s *Service) Create(ctx context.Context, input interface{}, output interface{}) error { 37 | return s.Op(ctx, CREATE, input, output) 38 | } 39 | 40 | func (s *Service) SetStatus(ctx context.Context, input interface{}, output interface{}) error { 41 | return s.Op(ctx, SET_STATUS, input, output) 42 | } 43 | 44 | func (s *Service) SetName(ctx context.Context, input interface{}, output interface{}) error { 45 | return s.Op(ctx, SET_NAME, input, output) 46 | } 47 | 48 | func (s *Service) SetUrl(ctx context.Context, input interface{}, output interface{}) error { 49 | return s.Op(ctx, SET_URL, input, output) 50 | } 51 | 52 | func (s *Service) AddChildById(ctx context.Context, input interface{}, output interface{}) error { 53 | return s.Op(ctx, ADD_CHILD_BY_ID, input, output) 54 | } 55 | 56 | func (s *Service) GetById(ctx context.Context, input interface{}, output interface{}) error { 57 | return s.Op(ctx, GET_BY_ID, input, output) 58 | } 59 | 60 | func (s *Service) Op(ctx context.Context, opName string, input interface{}, output interface{}) (err error) { 61 | defer func() { 62 | go s.afterOp(ctx, opName, input, output) 63 | }() 64 | 65 | opDone := false 66 | doneCtx := context.WithValue(ctx, OP_DONE, &opDone) 67 | 68 | st := s.GetStorages() 69 | for st != nil { 70 | err = st.GetStorage().Op(doneCtx, opName, input, output) 71 | if err != nil && !s.continueOnError { 72 | return 73 | } 74 | 75 | if opDone { 76 | return 77 | } 78 | 79 | st = st.Next 80 | } 81 | 82 | return 83 | } 84 | 85 | func (s *Service) afterOp(ctx context.Context, opName string, input interface{}, output interface{}) { 86 | opDone := false 87 | doneCtx := context.WithValue(ctx, OP_DONE, &opDone) 88 | 89 | st := s.GetStorages() 90 | for st != nil { 91 | st.GetStorage().AfterOp(doneCtx, opName, input, output) 92 | if opDone { 93 | return 94 | } 95 | 96 | st = st.Next 97 | } 98 | 99 | return 100 | } -------------------------------------------------------------------------------- /sdk/entity/storage.go: -------------------------------------------------------------------------------- 1 | package entity 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | "github.com/opentracing/opentracing-go" 7 | "github.com/opentracing/opentracing-go/log" 8 | "encoding/json" 9 | "hoqu-geth-api/sdk/app" 10 | ) 11 | 12 | type Storage struct { 13 | Name string 14 | } 15 | 16 | func NewStorage(nm string) *Storage { 17 | return &Storage{ 18 | Name: nm, 19 | } 20 | } 21 | 22 | type StorageInterface interface { 23 | Op(context.Context, string, interface{}, interface{}) error 24 | AfterOp(context.Context, string, interface{}, interface{}) 25 | OpDone(context.Context) 26 | CreateSpan(context.Context, string, interface{}) (opentracing.Span, context.Context) 27 | CloseSpan(opentracing.Span, interface{}, *error) 28 | GetName() string 29 | } 30 | 31 | func (s *Storage) Op(ctx context.Context, opName string, input interface{}, output interface{}) error { 32 | return fmt.Errorf("%s: op %s is not implemented", s.GetName(), opName) 33 | } 34 | 35 | func (s *Storage) AfterOp(ctx context.Context, opName string, input interface{}, output interface{}) { 36 | // Do nothing by default 37 | } 38 | 39 | func (s *Storage) OpDone(doneCtx context.Context) { 40 | opDone := doneCtx.Value(OP_DONE).(*bool) 41 | *opDone = true 42 | } 43 | 44 | func (s *Storage) CreateSpan(ctx context.Context, opName string, input interface{}) (span opentracing.Span, spanCtx context.Context) { 45 | span, spanCtx = opentracing.StartSpanFromContext(ctx, fmt.Sprintf("%s -> %s", s.GetName(), opName)) 46 | span.SetTag("app.env", app.Env()) 47 | span.SetTag("span.kind", "client") 48 | i, _ := json.Marshal(input) 49 | span.LogFields( 50 | log.String("op.input", string(i)), 51 | ) 52 | 53 | return 54 | } 55 | 56 | func (s *Storage) CloseSpan(span opentracing.Span, output interface{}, err *error) { 57 | o, _ := json.Marshal(output) 58 | span.LogFields( 59 | log.String("op.output", string(o)), 60 | ) 61 | 62 | if *err != nil { 63 | span.SetTag("error", true) 64 | span.LogFields( 65 | log.Error(*err), 66 | ) 67 | } 68 | 69 | span.Finish() 70 | } 71 | 72 | func (s *Storage) GetName() string { 73 | return s.Name 74 | } -------------------------------------------------------------------------------- /sdk/entity/storage_stack.go: -------------------------------------------------------------------------------- 1 | package entity 2 | 3 | type StorageStack struct { 4 | Next *StorageStack 5 | storage StorageInterface 6 | } 7 | 8 | func NewStorageStack(storage StorageInterface) *StorageStack { 9 | return &StorageStack{ 10 | Next: nil, 11 | storage: storage, 12 | } 13 | } 14 | 15 | func (s *StorageStack) Append(storage StorageInterface) { 16 | st := &StorageStack{ 17 | Next: nil, 18 | storage: storage, 19 | } 20 | s.Tail().Next = st 21 | } 22 | 23 | func (s *StorageStack) Tail() *StorageStack { 24 | t := s 25 | for t.Next != nil { 26 | t = t.Next 27 | } 28 | 29 | return t 30 | } 31 | 32 | func (s *StorageStack) GetStorage() StorageInterface { 33 | return s.storage 34 | } -------------------------------------------------------------------------------- /sdk/geth/contract.go: -------------------------------------------------------------------------------- 1 | package geth 2 | 3 | import ( 4 | "github.com/ethereum/go-ethereum/common" 5 | "github.com/ethereum/go-ethereum/accounts/abi" 6 | "strings" 7 | "context" 8 | "hoqu-geth-api/sdk/models" 9 | "fmt" 10 | "github.com/ethereum/go-ethereum" 11 | "math/big" 12 | "regexp" 13 | ) 14 | 15 | type Contract struct { 16 | Wallet *Wallet 17 | Address common.Address 18 | Abi abi.ABI 19 | Events map[string]string 20 | EventHashes map[string]string 21 | } 22 | 23 | func NewContract(addr string) *Contract { 24 | return &Contract{ 25 | Wallet: GetWallet(), 26 | Address: common.HexToAddress(addr), 27 | } 28 | } 29 | 30 | func (c *Contract) InitEvents(contractAbi string) (err error) { 31 | c.Abi, err = abi.JSON(strings.NewReader(contractAbi)) 32 | if err != nil { 33 | return 34 | } 35 | 36 | c.Events = make(map[string]string) 37 | c.EventHashes = make(map[string]string) 38 | for _, event := range c.Abi.Events { 39 | c.Events[event.Id().String()] = event.Name 40 | c.EventHashes[event.Name] = event.Id().String() 41 | } 42 | 43 | return 44 | } 45 | 46 | func (c *Contract) GetEventsByTopics(request *models.Events, fromBlock int64) ([]models.ContractEvent, error) { 47 | hashAddrs := make([]common.Hash, len(request.Addresses)) 48 | for _, addr := range request.Addresses { 49 | hashAddrs = append(hashAddrs, common.HexToHash(addr)) 50 | } 51 | 52 | hashEventNames := make([]common.Hash, len(request.EventNames)) 53 | for _, eventName := range request.EventNames { 54 | name, ok := c.EventHashes[eventName] 55 | if !ok { 56 | return nil, fmt.Errorf("unknown event name provided: %s", eventName) 57 | } 58 | hashEventNames = append(hashEventNames, common.HexToHash(name)) 59 | } 60 | 61 | query := ethereum.FilterQuery{ 62 | Addresses: []common.Address{ 63 | c.Address, 64 | }, 65 | Topics: [][]common.Hash{hashEventNames, hashAddrs}, 66 | FromBlock: big.NewInt(fromBlock), 67 | } 68 | 69 | if request.StartBlock != 0 { 70 | query.FromBlock = big.NewInt(request.StartBlock) 71 | } 72 | 73 | if request.EndBlock != 0 { 74 | query.ToBlock = big.NewInt(request.EndBlock) 75 | } 76 | 77 | res, err := c.Wallet.Connection.FilterLogs(context.TODO(), query) 78 | if err != nil { 79 | return []models.ContractEvent{}, err 80 | } 81 | 82 | events := make([]models.ContractEvent, len(res)) 83 | for key, eventLog := range res { 84 | name, ok := c.Events[eventLog.Topics[0].String()] 85 | if !ok { 86 | return events, fmt.Errorf("unknown event parsed: %s", eventLog.Topics[0].String()) 87 | } 88 | 89 | if len(eventLog.Data)%32 != 0 { 90 | return events, fmt.Errorf("wrong event unindexed data provided: %d", len(eventLog.Data)) 91 | } 92 | 93 | numOfIndexed := len(eventLog.Topics) - 1 94 | numOfUnindexed := len(eventLog.Data) / 32 95 | rawArgs := make([][]byte, numOfIndexed+numOfUnindexed) 96 | if numOfIndexed > 0 { 97 | for i, indData := range eventLog.Topics[1:] { 98 | rawArgs[i] = indData.Bytes() 99 | } 100 | } 101 | for i := 0; i < numOfUnindexed; i++ { 102 | rawArgs[numOfIndexed+i] = eventLog.Data[i*32:(i+1)*32] 103 | } 104 | 105 | block, err := c.Wallet.Connection.HeaderByHash(context.TODO(), eventLog.BlockHash) 106 | if err != nil { 107 | return events, err 108 | } 109 | 110 | events[key] = models.ContractEvent{ 111 | Name: name, 112 | RawArgs: rawArgs, 113 | TxHash: eventLog.TxHash, 114 | BlockNumber: eventLog.BlockNumber, 115 | BlockHash: eventLog.BlockHash, 116 | BlockTime: block.Time.String(), 117 | TxIndex: eventLog.TxIndex, 118 | Removed: eventLog.Removed, 119 | } 120 | } 121 | 122 | return events, nil 123 | } 124 | 125 | func (c *Contract) FilterString(inp string) string { 126 | reg, _ := regexp.Compile("[^\\s\\tA-Za-z0-9]+") 127 | 128 | return reg.ReplaceAllString(inp, "") 129 | } 130 | -------------------------------------------------------------------------------- /sdk/geth/metamask/auth.go: -------------------------------------------------------------------------------- 1 | package metamask 2 | 3 | import ( 4 | "fmt" 5 | "github.com/miguelmota/go-solidity-sha3" 6 | "math/big" 7 | "github.com/ethereum/go-ethereum/common" 8 | "github.com/satori/go.uuid" 9 | "hoqu-geth-api/sdk/geth" 10 | ) 11 | 12 | var auth *Auth 13 | 14 | type Auth struct { 15 | Banner string 16 | } 17 | 18 | func NewAuth(banner string) *Auth { 19 | return &Auth{ 20 | Banner: banner, 21 | } 22 | } 23 | 24 | func InitAuth(banner string) { 25 | auth = NewAuth(banner) 26 | } 27 | 28 | func GetAuth() *Auth { 29 | return auth 30 | } 31 | 32 | func (a *Auth) CreateChallenge(addr common.Address) ([]*TypedParam, error) { 33 | u, err := uuid.NewV4() 34 | if err != nil { 35 | return nil, err 36 | } 37 | 38 | challenge := solsha3.SoliditySHA3( 39 | append(addr.Bytes(), u[:]...), 40 | ) 41 | 42 | return a.getChallengeData(common.Bytes2Hex(challenge)), nil 43 | } 44 | 45 | func (a *Auth) RecoverSignerAddr(challenge, signed string) (common.Address, error) { 46 | hash, err := a.GetChallengeHash(challenge) 47 | if err != nil { 48 | return common.Address{}, err 49 | } 50 | 51 | sig := common.FromHex(signed) 52 | 53 | return geth.EcRecover(hash, sig) 54 | } 55 | 56 | func (a *Auth) GetChallengeHash(challenge string) ([]byte, error) { 57 | return a.GetTypedParamsHash( 58 | a.getChallengeData(challenge), 59 | ) 60 | } 61 | 62 | func (a *Auth) GetTypedParamsHash(params []*TypedParam) ([]byte, error) { 63 | schema := make([][]byte, 0) 64 | data := make([][]byte, 0) 65 | 66 | for _, param := range params { 67 | schema = append(schema, solsha3.String( 68 | fmt.Sprintf("%s %s", param.Type, param.Name), 69 | )) 70 | 71 | p, err := a.PackTypedParam(param) 72 | if err != nil { 73 | return nil, err 74 | } 75 | data = append(data, p) 76 | } 77 | 78 | return solsha3.SoliditySHA3( 79 | solsha3.SoliditySHA3(schema...), 80 | solsha3.SoliditySHA3(data...), 81 | ), nil 82 | } 83 | 84 | func (a *Auth) PackTypedParam(param *TypedParam) ([]byte, error) { 85 | switch { 86 | case param.Type == TypeString: 87 | return solsha3.String(param.Value.(string)), nil 88 | case param.Type == TypeAddress: 89 | return solsha3.Address(param.Value.(string)), nil 90 | case param.Type == TypeBytes32: 91 | return solsha3.Bytes32(param.Value.(string)), nil 92 | case param.Type == TypeBool: 93 | return solsha3.Bool(param.Value.(bool)), nil 94 | case param.Type == TypeUint || param.Type == TypeUint256: 95 | return solsha3.Uint256FromString(param.Value.(string)), nil 96 | case param.Type == TypeUint128: 97 | n := new(big.Int) 98 | n.SetString(param.Value.(string), 10) 99 | return solsha3.Uint128(n), nil 100 | case param.Type == TypeUint64: 101 | return solsha3.Uint64(param.Value.(uint64)), nil 102 | case param.Type == TypeUint32: 103 | return solsha3.Uint32(param.Value.(uint32)), nil 104 | case param.Type == TypeUint16: 105 | return solsha3.Uint16(param.Value.(uint16)), nil 106 | case param.Type == TypeUint8: 107 | return solsha3.Uint8(param.Value.(uint8)), nil 108 | case param.Type == TypeInt || param.Type == TypeInt256: 109 | n := new(big.Int) 110 | n.SetString(param.Value.(string), 10) 111 | return solsha3.Int256(n), nil 112 | case param.Type == TypeInt128: 113 | n := new(big.Int) 114 | n.SetString(param.Value.(string), 10) 115 | return solsha3.Int128(n), nil 116 | case param.Type == TypeInt64: 117 | return solsha3.Int64(param.Value.(int64)), nil 118 | case param.Type == TypeInt32: 119 | return solsha3.Int32(param.Value.(int32)), nil 120 | case param.Type == TypeInt16: 121 | return solsha3.Int16(param.Value.(int16)), nil 122 | case param.Type == TypeInt8: 123 | return solsha3.Int8(param.Value.(int8)), nil 124 | } 125 | 126 | return nil, fmt.Errorf("unknown type provided: %s", param.Type) 127 | } 128 | 129 | func (a *Auth) getChallengeData(challenge string) []*TypedParam { 130 | return []*TypedParam{ 131 | &TypedParam{ 132 | Name: "banner", 133 | Type: "string", 134 | Value: a.Banner, 135 | }, 136 | &TypedParam{ 137 | Name: "challenge", 138 | Type: "string", 139 | Value: challenge, 140 | }, 141 | } 142 | } 143 | -------------------------------------------------------------------------------- /sdk/geth/metamask/model.go: -------------------------------------------------------------------------------- 1 | package metamask 2 | 3 | const ( 4 | TypeString = "string" 5 | TypeAddress = "address" 6 | TypeBytes32 = "bytes32" 7 | TypeBool = "bool" 8 | TypeUint = "uint" 9 | TypeUint8 = "uint8" 10 | TypeUint16 = "uint16" 11 | TypeUint32 = "uint32" 12 | TypeUint64 = "uint64" 13 | TypeUint128 = "uint128" 14 | TypeUint256 = "uint256" 15 | TypeInt = "int" 16 | TypeInt8 = "int8" 17 | TypeInt16 = "int16" 18 | TypeInt32 = "int32" 19 | TypeInt64 = "int64" 20 | TypeInt128 = "int128" 21 | TypeInt256 = "int256" 22 | ) 23 | 24 | // TypedParam Model 25 | // 26 | // swagger:model 27 | type TypedParam struct { 28 | // param name 29 | // example: challenge 30 | Name string `json:"name"` 31 | // param type 32 | // example: string 33 | Type string `json:"type"` 34 | // param value 35 | // example: 7b9415e1dbbd526c8496f66e3646bbe886245581530d6dfedc9d1e3eb88d879e 36 | Value interface{} `json:"value"` 37 | } 38 | 39 | // swagger:parameters createChallenge 40 | type ChallengeParams struct { 41 | // in: body 42 | Body ChallengeRequest `json:"body"` 43 | } 44 | 45 | type ChallengeRequest struct { 46 | // Ethereum address of the signer 47 | // example: 0xED2F74E1fb73b775E6e35720869Ae7A7f4D755aD 48 | Address string `json:"address"` 49 | } 50 | 51 | // Success 52 | // 53 | // swagger:response 54 | type ChallengeSuccessResponse struct { 55 | // in: body 56 | Body struct { 57 | Data struct { 58 | Result []TypedParam `json:"result"` 59 | } `json:"data"` 60 | } 61 | } 62 | 63 | // swagger:parameters recoverSigner 64 | type RecoverParams struct { 65 | // in: body 66 | Body RecoverRequest `json:"body"` 67 | } 68 | 69 | type RecoverRequest struct { 70 | // Challenge value hash 71 | // example: 7b9415e1dbbd526c8496f66e3646bbe886245581530d6dfedc9d1e3eb88d879e 72 | Challenge string `json:"challenge"` 73 | // Signature hash 74 | // example: 0x5c71570e112156aec2091af830fe73256044a089b20d2aa209b93258504af2dd1eefa3bd584a701648fe24c79c4388671dad2470b74f67cfdd14c2f1dcb2fa0f1b 75 | Signature string `json:"sign"` 76 | } 77 | 78 | // Success 79 | // 80 | // swagger:response 81 | type RecoverSuccessResponse struct { 82 | // in: body 83 | Body struct { 84 | Data struct { 85 | // Ethereum address of the signer 86 | // example: 0xED2F74E1fb73b775E6e35720869Ae7A7f4D755aD 87 | Address string `json:"address"` 88 | } `json:"data"` 89 | } 90 | } -------------------------------------------------------------------------------- /sdk/geth/metamask/routes.go: -------------------------------------------------------------------------------- 1 | package metamask 2 | 3 | import ( 4 | "github.com/gin-gonic/gin" 5 | "hoqu-geth-api/sdk/http/rest" 6 | "github.com/ethereum/go-ethereum/common" 7 | ) 8 | 9 | func AddMetamaskAuthRoutes(gin *gin.Engine) { 10 | router := gin.Group("/metamask") 11 | { 12 | router.POST("challenge", postCreateChallenge) 13 | router.POST("recover", postRecoverSigner) 14 | } 15 | } 16 | 17 | // swagger:route POST /metamask/challenge metamask createChallenge 18 | // 19 | // Create challenge 20 | // 21 | // Create metamask challenge and return challenge data array 22 | // 23 | // Consumes: 24 | // - application/json 25 | // Produces: 26 | // - application/json 27 | // Responses: 28 | // 200: ChallengeSuccessResponse 29 | // 400: RestErrorResponse 30 | // 31 | func postCreateChallenge(c *gin.Context) { 32 | request := &ChallengeRequest{} 33 | err := c.BindJSON(request) 34 | if err != nil { 35 | rest.NewResponder(c).ErrorValidation(err.Error()) 36 | return 37 | } 38 | 39 | challenge, err := GetAuth().CreateChallenge( 40 | common.HexToAddress(request.Address), 41 | ) 42 | if err != nil { 43 | rest.NewResponder(c).Error(err.Error()) 44 | return 45 | } 46 | 47 | rest.NewResponder(c).Success(gin.H{ 48 | "result": challenge, 49 | }) 50 | } 51 | 52 | // swagger:route POST /metamask/recover metamask recoverSigner 53 | // 54 | // Recover signer 55 | // 56 | // Recover metamask challenge signer from result signature 57 | // 58 | // Consumes: 59 | // - application/json 60 | // Produces: 61 | // - application/json 62 | // Responses: 63 | // 200: RecoverSuccessResponse 64 | // 400: RestErrorResponse 65 | // 66 | func postRecoverSigner(c *gin.Context) { 67 | request := &RecoverRequest{} 68 | err := c.BindJSON(request) 69 | if err != nil { 70 | rest.NewResponder(c).ErrorValidation(err.Error()) 71 | return 72 | } 73 | 74 | addr, err := GetAuth().RecoverSignerAddr( 75 | request.Challenge, 76 | request.Signature, 77 | ) 78 | if err != nil { 79 | rest.NewResponder(c).Error(err.Error()) 80 | return 81 | } 82 | 83 | rest.NewResponder(c).Success(gin.H{ 84 | "address": addr, 85 | }) 86 | } 87 | -------------------------------------------------------------------------------- /sdk/geth/sign.go: -------------------------------------------------------------------------------- 1 | package geth 2 | 3 | import ( 4 | "github.com/ethereum/go-ethereum/common" 5 | "fmt" 6 | "github.com/ethereum/go-ethereum/crypto" 7 | ) 8 | 9 | func EcRecover(hash, sig []byte) (common.Address, error) { 10 | if len(sig) != 65 { 11 | return common.Address{}, fmt.Errorf("signature must be 65 bytes long") 12 | } 13 | if sig[64] != 27 && sig[64] != 28 { 14 | return common.Address{}, fmt.Errorf("invalid Ethereum signature (V is not 27 or 28)") 15 | } 16 | sig[64] -= 27 // Transform yellow paper V from 27/28 to 0/1 17 | 18 | pubBytes, err := crypto.Ecrecover(hash, sig) 19 | if err != nil { 20 | return common.Address{}, err 21 | } 22 | pubKey, err := crypto.UnmarshalPubkey(pubBytes) 23 | if err != nil { 24 | return common.Address{}, err 25 | } 26 | recoveredAddr := crypto.PubkeyToAddress(*pubKey) 27 | return recoveredAddr, nil 28 | } 29 | -------------------------------------------------------------------------------- /sdk/http/middleware/exec_time.go: -------------------------------------------------------------------------------- 1 | package middleware 2 | 3 | import ( 4 | "time" 5 | 6 | "github.com/sirupsen/logrus" 7 | "github.com/gin-gonic/gin" 8 | "github.com/spf13/cast" 9 | ) 10 | 11 | func ExecutionTime(ctx *gin.Context) { 12 | done, has := ctx.Get("done") 13 | if !has { 14 | return 15 | } 16 | 17 | ctx.Set("startTime", time.Now().Format(time.RFC3339Nano)) 18 | go tickExecTime(ctx, done.(chan bool)) 19 | ctx.Next() 20 | } 21 | 22 | func tickExecTime(ctx *gin.Context, done chan bool) { 23 | for { 24 | select { 25 | case <-done: 26 | startTime, _ := ctx.Get("startTime") 27 | st, err := time.Parse(time.RFC3339, cast.ToString(startTime)) 28 | if err == nil { 29 | logrus.Infof( 30 | "[%s] %s %s %d Executed withing %f seconds", 31 | time.Now().Format("02.01.2006 15:04:05"), 32 | ctx.Request.RequestURI, 33 | ctx.Request.Method, 34 | ctx.Writer.Status(), 35 | time.Now().Sub(st).Seconds(), 36 | ) 37 | } 38 | return 39 | case <-time.After(300 * time.Second): 40 | logrus.Warnf( 41 | "[%s] %s %s %d Executing too long", 42 | time.Now().Format("02.01.2006 15:04:05"), 43 | ctx.Request.RequestURI, 44 | ctx.Request.Method, 45 | ctx.Writer.Status(), 46 | ) 47 | return 48 | } 49 | } 50 | } -------------------------------------------------------------------------------- /sdk/http/middleware/req_input.go: -------------------------------------------------------------------------------- 1 | package middleware 2 | 3 | import ( 4 | "github.com/gin-gonic/gin" 5 | "github.com/satori/go.uuid" 6 | ) 7 | 8 | func ReqInput(ctx *gin.Context) { 9 | rid, _ := uuid.NewV4() 10 | ctx.Set("rid", rid.String()) 11 | ctx.Set("done", make(chan bool)) 12 | } 13 | -------------------------------------------------------------------------------- /sdk/http/middleware/req_output.go: -------------------------------------------------------------------------------- 1 | package middleware 2 | 3 | import ( 4 | "github.com/gin-gonic/gin" 5 | ) 6 | 7 | func ReqOutput(ctx *gin.Context) { 8 | ctx.Next() 9 | 10 | if done, exists := ctx.Get("done"); exists && done != nil { 11 | close(done.(chan bool)) 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /sdk/http/middleware/sign.go: -------------------------------------------------------------------------------- 1 | package middleware 2 | 3 | import ( 4 | "github.com/gin-gonic/gin" 5 | "net/http" 6 | "hoqu-geth-api/sdk/http/rest" 7 | "github.com/spf13/viper" 8 | "fmt" 9 | ) 10 | 11 | const SIGN_HEADER = "X-Sign" 12 | 13 | func SignRequired() gin.HandlerFunc { 14 | return func(c *gin.Context) { 15 | signHeader := c.GetHeader(SIGN_HEADER) 16 | if signHeader == "" { 17 | rest.NewResponder(c).ErrorAuthorization() 18 | return 19 | } 20 | 21 | if signHeader != viper.GetString("security.sign") { 22 | rest.NewResponder(c).ErrorWithCode( 23 | http.StatusUnauthorized, 24 | rest.ErrorAuthorization, 25 | fmt.Sprintf( 26 | "Incorrect signature, provided %v, expected %v", 27 | signHeader, 28 | viper.GetString("security.sign"), 29 | ), 30 | ) 31 | return 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /sdk/http/rest/responder.go: -------------------------------------------------------------------------------- 1 | package rest 2 | 3 | import ( 4 | "github.com/gin-gonic/gin" 5 | "net/http" 6 | "hoqu-geth-api/sdk/models" 7 | "github.com/sirupsen/logrus" 8 | ) 9 | 10 | const ( 11 | ErrorNoError = "NO_ERROR" 12 | ErrorDefault = "ERROR" 13 | ErrorValidation = "ERROR_VALIDATION" 14 | ErrorAuthorization = "ERROR_AUTHORIZATION" 15 | ) 16 | 17 | type Responder struct { 18 | context *gin.Context 19 | } 20 | 21 | func (resp Responder) Success(content interface{}) { 22 | data := &models.RestResponse{ 23 | Data: content, 24 | Error: models.RestError{ 25 | Code: ErrorNoError, 26 | }, 27 | } 28 | resp.context.Set("responseBody", data) 29 | resp.context.JSON(http.StatusOK, data) 30 | } 31 | 32 | func (resp Responder) Error(message interface{}) { 33 | resp.ErrorWithCode(http.StatusBadRequest, ErrorDefault, message) 34 | } 35 | 36 | func (resp Responder) ErrorValidation(message interface{}) { 37 | resp.ErrorWithCode(http.StatusPreconditionFailed, ErrorValidation, message) 38 | } 39 | 40 | func (resp Responder) ErrorAuthorization() { 41 | resp.ErrorWithCode(http.StatusUnauthorized, ErrorAuthorization, "Auth required") 42 | } 43 | func (resp Responder) ErrorWithCode(httpCode int, restCode string, message interface{}) { 44 | defer logrus.Errorf("Responding with error: %v", message) 45 | 46 | data := &models.RestResponse{ 47 | Error: models.RestError{ 48 | Code: restCode, 49 | Message: message, 50 | }, 51 | } 52 | resp.context.Set("responseBody", data) 53 | resp.context.JSON(httpCode, data) 54 | resp.context.Abort() 55 | } 56 | 57 | func NewResponder(c *gin.Context) *Responder { 58 | return &Responder{c} 59 | } 60 | -------------------------------------------------------------------------------- /sdk/http/router.go: -------------------------------------------------------------------------------- 1 | package http 2 | 3 | import ( 4 | "fmt" 5 | "sync" 6 | "github.com/gin-gonic/gin" 7 | "github.com/spf13/viper" 8 | "hoqu-geth-api/sdk/http/middleware" 9 | "hoqu-geth-api/sdk/tracing" 10 | ) 11 | 12 | var router *gin.Engine 13 | var routerOnceInitializer sync.Once 14 | 15 | func Run(initRouters func(engine *gin.Engine)) error { 16 | router = getRouter() 17 | initRouters(router) 18 | 19 | addr := fmt.Sprintf("%s:%d", viper.GetString("server.host"), viper.GetInt("server.port")) 20 | return router.Run(addr) 21 | } 22 | 23 | func UseTracing(router *gin.Engine) { 24 | router.Use(middleware.ReqInput, middleware.ExecutionTime, tracing.Middleware, middleware.ReqOutput) 25 | } 26 | 27 | func getRouter() *gin.Engine { 28 | routerOnceInitializer.Do(func() { 29 | router = gin.New() 30 | }) 31 | return router 32 | } 33 | -------------------------------------------------------------------------------- /sdk/libs/exec_tracker.go: -------------------------------------------------------------------------------- 1 | package libs 2 | 3 | import ( 4 | "time" 5 | log "github.com/sirupsen/logrus" 6 | ) 7 | 8 | type ExecTracker struct { 9 | name string 10 | start time.Time 11 | } 12 | 13 | func NewExecTracker(name string) *ExecTracker { 14 | log.Infof("%s started", name) 15 | return &ExecTracker{ 16 | name: name, 17 | start: time.Now(), 18 | } 19 | } 20 | 21 | func (et *ExecTracker) Stop() { 22 | log.Infof("%s finished in %v", et.name, time.Since(et.start)) 23 | } 24 | -------------------------------------------------------------------------------- /sdk/models/contract_event.go: -------------------------------------------------------------------------------- 1 | package models 2 | 3 | import ( 4 | "github.com/ethereum/go-ethereum/common" 5 | "hoqu-geth-api/models" 6 | ) 7 | 8 | // Success 9 | // 10 | // swagger:response 11 | type ContractEventResponse struct { 12 | // in: body 13 | Body struct { 14 | Data struct { 15 | Events struct{ 16 | // event name 17 | // example: LeadStatusChanged 18 | Name string `json:"name"` 19 | // event arguments, differ for each event 20 | Args struct{ 21 | // Ethereum address this events is linked to 22 | // example: 0xED2F74E1fb73b775E6e35720869Ae7A7f4D755aD 23 | OwnerAddress string `json:"ownerAddress"` 24 | // entity ID this event is linked to 25 | // example: a6fdb91a-149d-11e8-b642-0ed5f89f718b 26 | Id string `json:"id"` 27 | // new status of entity 28 | // example: 3 29 | Status models.Status `json:"status"` 30 | } `json:"args"` 31 | // Ethereum transaction hash 32 | // example: 0x23682ef776bfb465433e8f6a6e84eab71f039f039e86933aeca20ee46d01d576 33 | TxHash string `json:"transactionHash"` 34 | // Ethereum block number event was raised in 35 | // example: 4589232 36 | BlockNumber uint64 `json:"blockNumber"` 37 | BlockHash string `json:"blockHash"` 38 | BlockTime string `json:"blockTime"` 39 | TxIndex uint `json:"transactionIndex"` 40 | Removed bool `json:"removed"` 41 | } `json:"events"` 42 | } `json:"data"` 43 | } 44 | } 45 | 46 | type ContractEvent struct { 47 | Name string `json:"name"` 48 | Args interface{} `json:"args"` 49 | RawArgs [][]byte `json:"-"` 50 | TxHash common.Hash `json:"transactionHash"` 51 | BlockNumber uint64 `json:"blockNumber"` 52 | BlockHash common.Hash `json:"blockHash"` 53 | BlockTime string `json:"blockTime"` 54 | TxIndex uint `json:"transactionIndex"` 55 | Removed bool `json:"removed"` 56 | } 57 | 58 | // swagger:parameters events 59 | type EventsParams struct { 60 | // in: body 61 | Body Events `json:"body"` 62 | } 63 | 64 | type Events struct { 65 | // filter events by list of Ethereum addresses 66 | Addresses []string `json:"addresses"` 67 | // filter events by list of event names 68 | EventNames []string `json:"eventNames"` 69 | // get events from specified block 70 | StartBlock int64 `json:"startBlock"` 71 | // get events to specified block 72 | EndBlock int64 `json:"endBlock"` 73 | } -------------------------------------------------------------------------------- /sdk/models/rest_response.go: -------------------------------------------------------------------------------- 1 | package models 2 | 3 | type RestResponse struct { 4 | Data interface{} `json:"data"` 5 | Error RestError `json:"error"` 6 | } 7 | 8 | type RestError struct { 9 | Code string `json:"code"` 10 | Message interface{} `json:"message"` 11 | } 12 | 13 | // Error 14 | // 15 | // swagger:response 16 | type RestErrorResponse struct { 17 | // in: body 18 | Body struct { 19 | Error struct { 20 | // error code 21 | // example: VALIDATION_ERROR 22 | Code string `json:"code"` 23 | // error description 24 | // example: id should be in UUID format 25 | Message string `json:"message"` 26 | } `json:"error"` 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /sdk/tracing/jaeger.go: -------------------------------------------------------------------------------- 1 | package tracing 2 | 3 | import ( 4 | "io" 5 | "net/http" 6 | "github.com/opentracing/opentracing-go" 7 | "github.com/spf13/viper" 8 | "github.com/uber/jaeger-client-go" 9 | "github.com/uber/jaeger-client-go/config" 10 | "time" 11 | "net/http/httputil" 12 | "github.com/gin-gonic/gin" 13 | "fmt" 14 | "context" 15 | "strings" 16 | ) 17 | 18 | var ( 19 | tracer opentracing.Tracer 20 | closer io.Closer 21 | ) 22 | 23 | func Init() (err error) { 24 | if viper.GetBool("tracer.enabled") { 25 | tracer, closer, err = initJaeger(viper.GetString("project.name")) 26 | opentracing.SetGlobalTracer(tracer) 27 | } 28 | return err 29 | } 30 | 31 | func Stop() error { 32 | if viper.GetBool("tracer.enabled") { 33 | return closer.Close() 34 | } 35 | return nil 36 | } 37 | 38 | func initJaeger(service string) (opentracing.Tracer, io.Closer, error) { 39 | cfg := &config.Configuration{ 40 | ServiceName: service, 41 | Sampler: &config.SamplerConfig{ 42 | Type: jaeger.SamplerTypeConst, 43 | Param: 1, 44 | }, 45 | Reporter: &config.ReporterConfig{ 46 | BufferFlushInterval: time.Millisecond * 300, 47 | LogSpans: true, 48 | LocalAgentHostPort: viper.GetString("tracer.jaeger.host"), 49 | }, 50 | } 51 | return cfg.NewTracer(config.Logger(jaeger.StdLogger)) 52 | } 53 | 54 | func DumpResponse(res *http.Response) (string) { 55 | dump, err := httputil.DumpResponse(res, true) 56 | if err != nil { 57 | return err.Error() 58 | } 59 | 60 | if len(dump) == 0 { 61 | dump = []byte("Empty response") 62 | } 63 | 64 | return string(dump) 65 | } 66 | 67 | func DumpRequest(req *http.Request) (string) { 68 | dump, err := httputil.DumpRequest(req, true) 69 | if err != nil { 70 | return err.Error() 71 | } 72 | 73 | if len(dump) == 0 { 74 | dump = []byte("Empty request") 75 | } 76 | 77 | return string(dump) 78 | } 79 | 80 | func GetServerSpan(ctx *gin.Context) context.Context { 81 | v, has := ctx.Get("serverSpan") 82 | if !has { 83 | return context.Background() 84 | } 85 | return v.(context.Context) 86 | } 87 | 88 | func SpanName(ctx *gin.Context) string { 89 | parts := strings.Split(ctx.HandlerName(), "/") 90 | return fmt.Sprintf("%s", parts[len(parts) - 1]) 91 | } -------------------------------------------------------------------------------- /sdk/tracing/middleware.go: -------------------------------------------------------------------------------- 1 | package tracing 2 | 3 | import ( 4 | "time" 5 | 6 | "github.com/gin-gonic/gin" 7 | "github.com/gin-gonic/gin/json" 8 | "github.com/opentracing/opentracing-go" 9 | "github.com/opentracing/opentracing-go/ext" 10 | "github.com/opentracing/opentracing-go/log" 11 | "golang.org/x/net/context" 12 | "hoqu-geth-api/sdk/app" 13 | ) 14 | 15 | func Middleware(ctx *gin.Context) { 16 | done, has := ctx.Get("done") 17 | if !has { 18 | return 19 | } 20 | 21 | reqSpan, _ := opentracing.GlobalTracer().Extract( 22 | opentracing.HTTPHeaders, 23 | opentracing.HTTPHeadersCarrier(ctx.Request.Header), 24 | ) 25 | span := opentracing.GlobalTracer().StartSpan(SpanName(ctx), ext.RPCServerOption(reqSpan)) 26 | span.SetTag("app.env", app.Env()) 27 | 28 | reqDump := DumpRequest(ctx.Request) 29 | span.LogFields( 30 | log.String("http.incoming.request", reqDump), 31 | ) 32 | span.SetTag("http.incoming.method", ctx.Request.Method) 33 | span.SetTag("http.incoming.URI", ctx.Request.URL.String()) 34 | 35 | ctx.Set("serverSpan", opentracing.ContextWithSpan(context.Background(), span)) 36 | 37 | go tickTracing(ctx, span, done.(chan bool)) 38 | } 39 | 40 | func tickTracing(ctx *gin.Context, span opentracing.Span, done chan bool) { 41 | defer func() { 42 | span.SetTag("http.response.code", ctx.Writer.Status()) 43 | if resp, exists := ctx.Get("responseBody"); exists { 44 | respBody, _ := json.Marshal(resp) 45 | span.LogFields(log.String("http.response.body", string(respBody))) 46 | } 47 | 48 | span.Finish() 49 | }() 50 | 51 | for { 52 | select { 53 | case <-done: 54 | return 55 | case <-time.After(300 * time.Second): 56 | return 57 | } 58 | } 59 | } 60 | 61 | -------------------------------------------------------------------------------- /tariff/geth_storage.go: -------------------------------------------------------------------------------- 1 | package tariff 2 | 3 | import ( 4 | "hoqu-geth-api/geth" 5 | "sync" 6 | "context" 7 | "fmt" 8 | "hoqu-geth-api/models" 9 | "hoqu-geth-api/sdk/entity" 10 | ) 11 | 12 | var ( 13 | gs *GethStorage 14 | gsOnce sync.Once 15 | ) 16 | 17 | type GethStorage struct { 18 | *entity.Storage 19 | HoquPlatform *geth.HoquPlatform 20 | HoquStorage *geth.HoQuStorage 21 | } 22 | 23 | func NewGethStorage(nm string, hp *geth.HoquPlatform, hs *geth.HoQuStorage) *GethStorage { 24 | return &GethStorage{ 25 | Storage: entity.NewStorage(nm), 26 | HoquPlatform: hp, 27 | HoquStorage: hs, 28 | } 29 | } 30 | 31 | func InitGethStorage() (err error) { 32 | gsOnce.Do(func() { 33 | err = geth.InitGeth() 34 | gs = NewGethStorage( 35 | "ethereum: tariff", 36 | geth.GetHoquPlatform(), 37 | geth.GetHoQuStorage(), 38 | ) 39 | }) 40 | return 41 | } 42 | 43 | func GetGethStorage() *GethStorage { 44 | return gs 45 | } 46 | 47 | func (s *GethStorage) Op(ctx context.Context, opName string, input interface{}, output interface{}) (err error) { 48 | span, spanCtx := s.CreateSpan(ctx, opName, input) 49 | defer s.CloseSpan(span, output, &err) 50 | 51 | switch opName { 52 | case entity.CREATE: 53 | err = s.Create(spanCtx, input.(*models.AddTariffRequest), output.(*models.CreateResponseData)) 54 | case entity.SET_STATUS: 55 | err = s.SetStatus(spanCtx, input.(*models.SetStatusRequest), output.(*models.TxSuccessData)) 56 | case entity.GET_BY_ID: 57 | err = s.GetById(spanCtx, input.(*models.IdRequest), output.(*models.TariffSuccessData)) 58 | default: 59 | err = fmt.Errorf("%s: op %s is not supported", s.GetName(), opName) 60 | } 61 | 62 | return 63 | } 64 | 65 | func (s *GethStorage) Create(spanCtx context.Context, input *models.AddTariffRequest, output *models.CreateResponseData) error { 66 | tx, err := s.HoquPlatform.AddTariff(input) 67 | if err != nil { 68 | output.Failed = true 69 | return err 70 | } 71 | 72 | output.Tx = tx.String() 73 | return nil 74 | } 75 | 76 | func (s *GethStorage) SetStatus(spanCtx context.Context, input *models.SetStatusRequest, output *models.TxSuccessData) error { 77 | tx, err := s.HoquPlatform.SetTariffStatus(input) 78 | if err != nil { 79 | return err 80 | } 81 | 82 | output.Tx = tx.String() 83 | return nil 84 | } 85 | 86 | func (s *GethStorage) GetById(spanCtx context.Context, input *models.IdRequest, output *models.TariffSuccessData) error { 87 | tariff, err := s.HoquStorage.GetTariff(input) 88 | if err != nil { 89 | return err 90 | } 91 | 92 | output.Tariff = tariff 93 | output.Update = true 94 | s.OpDone(spanCtx) 95 | return nil 96 | } -------------------------------------------------------------------------------- /tariff/routes.go: -------------------------------------------------------------------------------- 1 | package tariff 2 | 3 | import ( 4 | "github.com/gin-gonic/gin" 5 | "hoqu-geth-api/models" 6 | "hoqu-geth-api/sdk/http/middleware" 7 | "hoqu-geth-api/sdk/entity" 8 | ) 9 | 10 | func InitTariffRoutes(routerGroup *gin.RouterGroup) { 11 | r := routerGroup.Group("/tariff") 12 | { 13 | r.POST("/add", middleware.SignRequired(), postAddTariffAction) 14 | r.POST("/status", middleware.SignRequired(), postSetTariffStatusAction) 15 | r.GET("/:id", getTariffAction) 16 | } 17 | } 18 | 19 | // swagger:route POST /platform/tariff/add tariffs addTariff 20 | // 21 | // Add Tariff. 22 | // 23 | // Consumes: 24 | // - application/json 25 | // Produces: 26 | // - application/json 27 | // Responses: 28 | // 200: AddSuccessResponse 29 | // 400: RestErrorResponse 30 | // 31 | func postAddTariffAction(ctx *gin.Context) { 32 | entity.CreateAction(ctx, &models.AddTariffRequest{}, GetService().Create) 33 | } 34 | 35 | // swagger:route POST /platform/tariff/status tariffs setTariffStatus 36 | // 37 | // Set Tariff Status. 38 | // 39 | // Consumes: 40 | // - application/json 41 | // Produces: 42 | // - application/json 43 | // Responses: 44 | // 200: TxSuccessResponse 45 | // 400: RestErrorResponse 46 | // 47 | func postSetTariffStatusAction(ctx *gin.Context) { 48 | entity.SetAction(ctx, &models.SetStatusRequest{}, GetService().SetStatus) 49 | } 50 | 51 | // swagger:route GET /platform/tariff/:id tariffs getTariff 52 | // 53 | // Get Tariff by ID. 54 | // 55 | // Produces: 56 | // - application/json 57 | // Responses: 58 | // 200: TariffDataResponse 59 | // 400: RestErrorResponse 60 | // 61 | func getTariffAction(ctx *gin.Context) { 62 | id := ctx.Param("id") 63 | entity.GetByIdAction(ctx, id, &models.TariffSuccessData{}, GetService().GetById) 64 | } 65 | -------------------------------------------------------------------------------- /tariff/service.go: -------------------------------------------------------------------------------- 1 | package tariff 2 | 3 | import ( 4 | "hoqu-geth-api/sdk/entity" 5 | "sync" 6 | "context" 7 | "hoqu-geth-api/models" 8 | "github.com/satori/go.uuid" 9 | ) 10 | 11 | var ( 12 | s *Service 13 | sOnce sync.Once 14 | ) 15 | 16 | type Service struct { 17 | *entity.Service 18 | } 19 | 20 | func NewService(storage entity.StorageInterface) *Service { 21 | return &Service{ 22 | Service: entity.NewService(storage, true), 23 | } 24 | } 25 | 26 | func InitService() (err error) { 27 | sOnce.Do(func() { 28 | err = InitDbStorage() 29 | if err != nil { 30 | return 31 | } 32 | s = NewService(GetDbStorage()) 33 | 34 | err = InitGethStorage() 35 | if err != nil { 36 | return 37 | } 38 | s.AppendStorage(GetGethStorage()) 39 | }) 40 | return 41 | } 42 | 43 | func GetService() *Service { 44 | return s 45 | } 46 | 47 | func (s *Service) Create(ctx context.Context, input interface{}, output interface{}) error { 48 | req := input.(*models.AddTariffRequest) 49 | resp := output.(*models.CreateResponseData) 50 | id, err := uuid.NewV2('T') 51 | if err != nil { 52 | return err 53 | } 54 | 55 | req.Id = id 56 | resp.Id = id.String() 57 | 58 | return s.Service.Create(ctx, req, output) 59 | } -------------------------------------------------------------------------------- /tariff_group/db_storage.go: -------------------------------------------------------------------------------- 1 | package tariff_group 2 | 3 | import ( 4 | "sync" 5 | "context" 6 | "fmt" 7 | "hoqu-geth-api/models" 8 | "hoqu-geth-api/sdk/entity" 9 | "hoqu-geth-api/sdk/db" 10 | "github.com/spf13/viper" 11 | "time" 12 | "github.com/opentracing/opentracing-go" 13 | "github.com/opentracing/opentracing-go/log" 14 | ) 15 | 16 | var ( 17 | ds *DbStorage 18 | dsOnce sync.Once 19 | ) 20 | 21 | type DbStorage struct { 22 | *entity.Storage 23 | db *db.ConnectionManager 24 | } 25 | 26 | func NewDbStorage(nm, driver, dsn string) *DbStorage { 27 | return &DbStorage{ 28 | Storage: entity.NewStorage(nm), 29 | db: db.NewConnectionManager(driver, dsn), 30 | } 31 | } 32 | 33 | func InitDbStorage() (err error) { 34 | dsOnce.Do(func() { 35 | ds = NewDbStorage( 36 | "db: tariff_group", 37 | viper.GetString("db.driver"), 38 | viper.GetString("db.dsn"), 39 | ) 40 | 41 | err = ds.AutoMigrate() 42 | }) 43 | return 44 | } 45 | 46 | func GetDbStorage() *DbStorage { 47 | return ds 48 | } 49 | 50 | func (s *DbStorage) AutoMigrate() error { 51 | conn, err := s.db.NewConnection() 52 | if err != nil { 53 | return err 54 | } 55 | defer conn.Close() 56 | 57 | conn.AutoMigrate(&models.TariffGroup{}) 58 | 59 | return nil 60 | } 61 | 62 | func (s *DbStorage) Op(ctx context.Context, opName string, input interface{}, output interface{}) (err error) { 63 | span, spanCtx := s.CreateSpan(ctx, opName, input) 64 | defer s.CloseSpan(span, output, &err) 65 | 66 | switch opName { 67 | case entity.CREATE: 68 | err = s.Create(spanCtx, input.(*models.AddTariffGroupRequest), output.(*models.CreateResponseData)) 69 | case entity.SET_STATUS: 70 | err = s.SetStatus(spanCtx, input.(*models.SetStatusRequest), output.(*models.TxSuccessData)) 71 | case entity.GET_BY_ID: 72 | err = s.GetById(spanCtx, input.(*models.IdRequest), output.(*models.TariffGroupSuccessData)) 73 | default: 74 | err = fmt.Errorf("%s: op %s is not supported", s.GetName(), opName) 75 | } 76 | 77 | return 78 | } 79 | 80 | func (s *DbStorage) AfterOp(ctx context.Context, opName string, input interface{}, output interface{}) { 81 | var err error 82 | span, spanCtx := s.CreateSpan(ctx, "after " + opName, input) 83 | defer s.CloseSpan(span, output, &err) 84 | 85 | switch opName { 86 | case entity.CREATE: 87 | err = s.AfterCreate(spanCtx, input.(*models.AddTariffGroupRequest), output.(*models.CreateResponseData)) 88 | case entity.GET_BY_ID: 89 | err = s.AfterGetById(spanCtx, input.(*models.IdRequest), output.(*models.TariffGroupSuccessData)) 90 | } 91 | } 92 | 93 | func (s *DbStorage) Create(spanCtx context.Context, input *models.AddTariffGroupRequest, output *models.CreateResponseData) error { 94 | conn, err := s.db.NewConnection() 95 | if err != nil { 96 | return err 97 | } 98 | defer conn.Close() 99 | 100 | m := models.TariffGroup{ 101 | ID: input.Id.String(), 102 | CreatedAt: time.Now(), 103 | OwnerId: input.OwnerId, 104 | Name: input.Name, 105 | Tariffs: make([]string, 0), 106 | Status: models.STATUS_CREATED, 107 | } 108 | if err = conn.Create(&m).Error; err != nil { 109 | return err 110 | } 111 | 112 | return nil 113 | } 114 | 115 | func (s *DbStorage) AfterCreate(spanCtx context.Context, input *models.AddTariffGroupRequest, output *models.CreateResponseData) error { 116 | if !output.Failed { 117 | return nil 118 | } 119 | 120 | conn, err := s.db.NewConnection() 121 | if err != nil { 122 | return err 123 | } 124 | defer conn.Close() 125 | 126 | m := models.TariffGroup{ 127 | ID: input.Id.String(), 128 | } 129 | res := conn.Delete(&m) 130 | 131 | if res.RecordNotFound() { 132 | opentracing.SpanFromContext(spanCtx).LogFields( 133 | log.String("message", res.Error.Error()), 134 | ) 135 | return nil 136 | } 137 | 138 | if res.Error != nil { 139 | return res.Error 140 | } 141 | 142 | opentracing.SpanFromContext(spanCtx).LogFields( 143 | log.String("message", "record deleted from DB"), 144 | ) 145 | return nil 146 | } 147 | 148 | func (s *DbStorage) SetStatus(spanCtx context.Context, input *models.SetStatusRequest, output *models.TxSuccessData) error { 149 | conn, err := s.db.NewConnection() 150 | if err != nil { 151 | return err 152 | } 153 | defer conn.Close() 154 | 155 | m := models.TariffGroup{ 156 | ID: input.Id, 157 | } 158 | res := conn.First(&m) 159 | 160 | if res.RecordNotFound() { 161 | opentracing.SpanFromContext(spanCtx).LogFields( 162 | log.String("message", res.Error.Error()), 163 | ) 164 | return nil 165 | } 166 | 167 | if res.Error != nil { 168 | return res.Error 169 | } 170 | 171 | m.Status = input.Status 172 | conn.Save(&m) 173 | return nil 174 | } 175 | 176 | func (s *DbStorage) GetById(spanCtx context.Context, input *models.IdRequest, output *models.TariffGroupSuccessData) error { 177 | conn, err := s.db.NewConnection() 178 | if err != nil { 179 | return err 180 | } 181 | defer conn.Close() 182 | 183 | m := models.TariffGroup{ 184 | ID: input.Id, 185 | } 186 | res := conn.First(&m) 187 | 188 | if res.RecordNotFound() { 189 | opentracing.SpanFromContext(spanCtx).LogFields( 190 | log.String("message", res.Error.Error()), 191 | ) 192 | return nil 193 | } 194 | 195 | if res.Error != nil { 196 | return res.Error 197 | } 198 | 199 | output.TariffGroup = &m 200 | s.OpDone(spanCtx) 201 | return nil 202 | } 203 | 204 | func (s *DbStorage) AfterGetById(spanCtx context.Context, input *models.IdRequest, output *models.TariffGroupSuccessData) error { 205 | if !output.Update { 206 | return nil 207 | } 208 | 209 | conn, err := s.db.NewConnection() 210 | if err != nil { 211 | return err 212 | } 213 | defer conn.Close() 214 | 215 | m := *output.TariffGroup 216 | if err = conn.Create(&m).Error; err != nil { 217 | return err 218 | } 219 | 220 | return nil 221 | } -------------------------------------------------------------------------------- /tariff_group/geth_storage.go: -------------------------------------------------------------------------------- 1 | package tariff_group 2 | 3 | import ( 4 | "hoqu-geth-api/geth" 5 | "sync" 6 | "context" 7 | "fmt" 8 | "hoqu-geth-api/models" 9 | "hoqu-geth-api/sdk/entity" 10 | ) 11 | 12 | var ( 13 | gs *GethStorage 14 | gsOnce sync.Once 15 | ) 16 | 17 | type GethStorage struct { 18 | *entity.Storage 19 | HoquPlatform *geth.HoquPlatform 20 | HoquStorage *geth.HoQuStorage 21 | } 22 | 23 | func NewGethStorage(nm string, hp *geth.HoquPlatform, hs *geth.HoQuStorage) *GethStorage { 24 | return &GethStorage{ 25 | Storage: entity.NewStorage(nm), 26 | HoquPlatform: hp, 27 | HoquStorage: hs, 28 | } 29 | } 30 | 31 | func InitGethStorage() (err error) { 32 | gsOnce.Do(func() { 33 | err = geth.InitGeth() 34 | gs = NewGethStorage( 35 | "ethereum: tariff_group", 36 | geth.GetHoquPlatform(), 37 | geth.GetHoQuStorage(), 38 | ) 39 | }) 40 | return 41 | } 42 | 43 | func GetGethStorage() *GethStorage { 44 | return gs 45 | } 46 | 47 | func (s *GethStorage) Op(ctx context.Context, opName string, input interface{}, output interface{}) (err error) { 48 | span, spanCtx := s.CreateSpan(ctx, opName, input) 49 | defer s.CloseSpan(span, output, &err) 50 | 51 | switch opName { 52 | case entity.CREATE: 53 | err = s.Create(spanCtx, input.(*models.AddTariffGroupRequest), output.(*models.CreateResponseData)) 54 | case entity.SET_STATUS: 55 | err = s.SetStatus(spanCtx, input.(*models.SetStatusRequest), output.(*models.TxSuccessData)) 56 | case entity.GET_BY_ID: 57 | err = s.GetById(spanCtx, input.(*models.IdRequest), output.(*models.TariffGroupSuccessData)) 58 | default: 59 | err = fmt.Errorf("%s: op %s is not supported", s.GetName(), opName) 60 | } 61 | 62 | return 63 | } 64 | 65 | func (s *GethStorage) Create(spanCtx context.Context, input *models.AddTariffGroupRequest, output *models.CreateResponseData) error { 66 | tx, err := s.HoquPlatform.AddTariffGroup(input) 67 | if err != nil { 68 | output.Failed = true 69 | return err 70 | } 71 | 72 | output.Tx = tx.String() 73 | return nil 74 | } 75 | 76 | func (s *GethStorage) SetStatus(spanCtx context.Context, input *models.SetStatusRequest, output *models.TxSuccessData) error { 77 | tx, err := s.HoquPlatform.SetTariffGroupStatus(input) 78 | if err != nil { 79 | return err 80 | } 81 | 82 | output.Tx = tx.String() 83 | return nil 84 | } 85 | 86 | func (s *GethStorage) GetById(spanCtx context.Context, input *models.IdRequest, output *models.TariffGroupSuccessData) error { 87 | tariffGroup, err := s.HoquStorage.GetTariffGroup(input) 88 | if err != nil { 89 | return err 90 | } 91 | 92 | output.TariffGroup = tariffGroup 93 | output.Update = true 94 | s.OpDone(spanCtx) 95 | return nil 96 | } -------------------------------------------------------------------------------- /tariff_group/routes.go: -------------------------------------------------------------------------------- 1 | package tariff_group 2 | 3 | import ( 4 | "github.com/gin-gonic/gin" 5 | "hoqu-geth-api/models" 6 | "hoqu-geth-api/sdk/http/middleware" 7 | "hoqu-geth-api/sdk/entity" 8 | ) 9 | 10 | func InitTariffGroupRoutes(routerGroup *gin.RouterGroup) { 11 | r := routerGroup.Group("/tariff_group") 12 | { 13 | r.POST("/add", middleware.SignRequired(), postAddTariffGroupAction) 14 | r.POST("/status", middleware.SignRequired(), postSetTariffGroupStatusAction) 15 | r.GET("/:id", getTariffGroupAction) 16 | } 17 | } 18 | 19 | // swagger:route POST /platform/tariff_group/add tariff_groups addTariffGroup 20 | // 21 | // Add TariffGroup. 22 | // 23 | // Consumes: 24 | // - application/json 25 | // Produces: 26 | // - application/json 27 | // Responses: 28 | // 200: AddSuccessResponse 29 | // 400: RestErrorResponse 30 | // 31 | func postAddTariffGroupAction(ctx *gin.Context) { 32 | entity.CreateAction(ctx, &models.AddTariffGroupRequest{}, GetService().Create) 33 | } 34 | 35 | // swagger:route POST /platform/tariff_group/status tariff_groups setTariffGroupStatus 36 | // 37 | // Set TariffGroup Status. 38 | // 39 | // Consumes: 40 | // - application/json 41 | // Produces: 42 | // - application/json 43 | // Responses: 44 | // 200: TxSuccessResponse 45 | // 400: RestErrorResponse 46 | // 47 | func postSetTariffGroupStatusAction(ctx *gin.Context) { 48 | entity.SetAction(ctx, &models.SetStatusRequest{}, GetService().SetStatus) 49 | } 50 | 51 | // swagger:route GET /platform/tariff_group/:id tariff_groups getTariffGroup 52 | // 53 | // Get TariffGroup by ID. 54 | // 55 | // Produces: 56 | // - application/json 57 | // Responses: 58 | // 200: TariffGroupDataResponse 59 | // 400: RestErrorResponse 60 | // 61 | func getTariffGroupAction(ctx *gin.Context) { 62 | id := ctx.Param("id") 63 | entity.GetByIdAction(ctx, id, &models.TariffGroupSuccessData{}, GetService().GetById) 64 | } 65 | -------------------------------------------------------------------------------- /tariff_group/service.go: -------------------------------------------------------------------------------- 1 | package tariff_group 2 | 3 | import ( 4 | "hoqu-geth-api/sdk/entity" 5 | "sync" 6 | "context" 7 | "hoqu-geth-api/models" 8 | "github.com/satori/go.uuid" 9 | ) 10 | 11 | var ( 12 | s *Service 13 | sOnce sync.Once 14 | ) 15 | 16 | type Service struct { 17 | *entity.Service 18 | } 19 | 20 | func NewService(storage entity.StorageInterface) *Service { 21 | return &Service{ 22 | Service: entity.NewService(storage, true), 23 | } 24 | } 25 | 26 | func InitService() (err error) { 27 | sOnce.Do(func() { 28 | err = InitDbStorage() 29 | if err != nil { 30 | return 31 | } 32 | s = NewService(GetDbStorage()) 33 | 34 | err = InitGethStorage() 35 | if err != nil { 36 | return 37 | } 38 | s.AppendStorage(GetGethStorage()) 39 | }) 40 | return 41 | } 42 | 43 | func GetService() *Service { 44 | return s 45 | } 46 | 47 | func (s *Service) Create(ctx context.Context, input interface{}, output interface{}) error { 48 | req := input.(*models.AddTariffGroupRequest) 49 | resp := output.(*models.CreateResponseData) 50 | id, err := uuid.NewV2('T') 51 | if err != nil { 52 | return err 53 | } 54 | 55 | req.Id = id 56 | resp.Id = id.String() 57 | 58 | return s.Service.Create(ctx, req, output) 59 | } -------------------------------------------------------------------------------- /user/geth_storage.go: -------------------------------------------------------------------------------- 1 | package user 2 | 3 | import ( 4 | "hoqu-geth-api/geth" 5 | "sync" 6 | "context" 7 | "fmt" 8 | "hoqu-geth-api/models" 9 | "hoqu-geth-api/sdk/entity" 10 | ) 11 | 12 | var ( 13 | gs *GethStorage 14 | gsOnce sync.Once 15 | ) 16 | 17 | type GethStorage struct { 18 | *entity.Storage 19 | HoquPlatform *geth.HoquPlatform 20 | HoquStorage *geth.HoQuStorage 21 | } 22 | 23 | func NewGethStorage(nm string, hp *geth.HoquPlatform, hs *geth.HoQuStorage) *GethStorage { 24 | return &GethStorage{ 25 | Storage: entity.NewStorage(nm), 26 | HoquPlatform: hp, 27 | HoquStorage: hs, 28 | } 29 | } 30 | 31 | func InitGethStorage() (err error) { 32 | gsOnce.Do(func() { 33 | err = geth.InitGeth() 34 | gs = NewGethStorage( 35 | "ethereum: user", 36 | geth.GetHoquPlatform(), 37 | geth.GetHoQuStorage(), 38 | ) 39 | }) 40 | return 41 | } 42 | 43 | func GetGethStorage() *GethStorage { 44 | return gs 45 | } 46 | 47 | func (s *GethStorage) Op(ctx context.Context, opName string, input interface{}, output interface{}) (err error) { 48 | span, spanCtx := s.CreateSpan(ctx, opName, input) 49 | defer s.CloseSpan(span, output, &err) 50 | 51 | switch opName { 52 | case entity.CREATE: 53 | err = s.Create(spanCtx, input.(*models.RegisterUserRequest), output.(*models.CreateResponseData)) 54 | case entity.SET_STATUS: 55 | err = s.SetStatus(spanCtx, input.(*models.SetStatusRequest), output.(*models.TxSuccessData)) 56 | case ADD_ADDRESS: 57 | err = s.AddUserAddress(spanCtx, input.(*models.AddUserAddressRequest), output.(*models.TxSuccessData)) 58 | case entity.GET_BY_ID: 59 | err = s.GetById(spanCtx, input.(*models.IdRequest), output.(*models.UserSuccessData)) 60 | default: 61 | err = fmt.Errorf("%s: op %s is not supported", s.GetName(), opName) 62 | } 63 | 64 | return 65 | } 66 | 67 | func (s *GethStorage) Create(spanCtx context.Context, input *models.RegisterUserRequest, output *models.CreateResponseData) error { 68 | tx, err := s.HoquPlatform.RegisterUser(input) 69 | if err != nil { 70 | output.Failed = true 71 | return err 72 | } 73 | 74 | output.Tx = tx.String() 75 | return nil 76 | } 77 | 78 | func (s *GethStorage) SetStatus(spanCtx context.Context, input *models.SetStatusRequest, output *models.TxSuccessData) error { 79 | tx, err := s.HoquPlatform.SetUserStatus(input) 80 | if err != nil { 81 | return err 82 | } 83 | 84 | output.Tx = tx.String() 85 | return nil 86 | } 87 | 88 | func (s *GethStorage) AddUserAddress(spanCtx context.Context, input *models.AddUserAddressRequest, output *models.TxSuccessData) error { 89 | tx, err := s.HoquPlatform.AddUserAddress(input) 90 | if err != nil { 91 | return err 92 | } 93 | 94 | output.Tx = tx.String() 95 | return nil 96 | } 97 | 98 | func (s *GethStorage) GetById(spanCtx context.Context, input *models.IdRequest, output *models.UserSuccessData) error { 99 | user, err := s.HoquStorage.GetUser(input) 100 | if err != nil { 101 | return err 102 | } 103 | 104 | output.User = user 105 | output.Update = true 106 | s.OpDone(spanCtx) 107 | return nil 108 | } 109 | -------------------------------------------------------------------------------- /user/routes.go: -------------------------------------------------------------------------------- 1 | package user 2 | 3 | import ( 4 | "github.com/gin-gonic/gin" 5 | "hoqu-geth-api/models" 6 | "hoqu-geth-api/sdk/http/middleware" 7 | "hoqu-geth-api/sdk/entity" 8 | ) 9 | 10 | func InitUserRoutes(routerGroup *gin.RouterGroup) { 11 | r := routerGroup.Group("/user") 12 | { 13 | r.POST("/register", middleware.SignRequired(), postRegisterUserAction) 14 | r.POST("/status", middleware.SignRequired(), postSetUserStatusAction) 15 | r.POST("/address", middleware.SignRequired(), postAddUserAddressAction) 16 | r.GET("/:id", getUserAction) 17 | } 18 | } 19 | 20 | // swagger:route POST /platform/user/register users registerUser 21 | // 22 | // Register User. 23 | // 24 | // Consumes: 25 | // - application/json 26 | // Produces: 27 | // - application/json 28 | // Responses: 29 | // 200: AddSuccessResponse 30 | // 400: RestErrorResponse 31 | // 32 | func postRegisterUserAction(ctx *gin.Context) { 33 | entity.CreateAction(ctx, &models.RegisterUserRequest{}, GetService().Create) 34 | } 35 | 36 | // swagger:route POST /platform/user/status users setUserStatus 37 | // 38 | // Set User Status. 39 | // 40 | // Consumes: 41 | // - application/json 42 | // Produces: 43 | // - application/json 44 | // Responses: 45 | // 200: TxSuccessResponse 46 | // 400: RestErrorResponse 47 | // 48 | func postSetUserStatusAction(ctx *gin.Context) { 49 | entity.SetAction(ctx, &models.SetStatusRequest{}, GetService().SetStatus) 50 | } 51 | 52 | // swagger:route POST /platform/user/address users addUserAddress 53 | // 54 | // Add User Ethereum Address. 55 | // 56 | // Each User can have several Ethereum addresses. 57 | // 58 | // Consumes: 59 | // - application/json 60 | // Produces: 61 | // - application/json 62 | // Responses: 63 | // 200: TxSuccessResponse 64 | // 400: RestErrorResponse 65 | // 66 | func postAddUserAddressAction(ctx *gin.Context) { 67 | entity.SetAction(ctx, &models.AddUserAddressRequest{}, GetService().AddAddress) 68 | } 69 | 70 | // swagger:route GET /platform/user/:id users getUser 71 | // 72 | // Get User by ID. 73 | // 74 | // Produces: 75 | // - application/json 76 | // Responses: 77 | // 200: UserDataResponse 78 | // 400: RestErrorResponse 79 | // 80 | func getUserAction(ctx *gin.Context) { 81 | id := ctx.Param("id") 82 | entity.GetByIdAction(ctx, id, &models.UserSuccessData{}, GetService().GetById) 83 | } 84 | -------------------------------------------------------------------------------- /user/service.go: -------------------------------------------------------------------------------- 1 | package user 2 | 3 | import ( 4 | "hoqu-geth-api/sdk/entity" 5 | "sync" 6 | "context" 7 | "hoqu-geth-api/models" 8 | "github.com/satori/go.uuid" 9 | ) 10 | 11 | const ( 12 | ADD_ADDRESS = "add_address" 13 | ) 14 | 15 | var ( 16 | s *Service 17 | sOnce sync.Once 18 | ) 19 | 20 | type Service struct { 21 | *entity.Service 22 | } 23 | 24 | func NewService(storage entity.StorageInterface) *Service { 25 | return &Service{ 26 | Service: entity.NewService(storage, true), 27 | } 28 | } 29 | 30 | func InitService() (err error) { 31 | sOnce.Do(func() { 32 | err = InitDbStorage() 33 | if err != nil { 34 | return 35 | } 36 | s = NewService(GetDbStorage()) 37 | 38 | err = InitGethStorage() 39 | if err != nil { 40 | return 41 | } 42 | s.AppendStorage(GetGethStorage()) 43 | }) 44 | return 45 | } 46 | 47 | func GetService() *Service { 48 | return s 49 | } 50 | 51 | func (s *Service) Create(ctx context.Context, input interface{}, output interface{}) error { 52 | req := input.(*models.RegisterUserRequest) 53 | resp := output.(*models.CreateResponseData) 54 | id, err := uuid.NewV2('U') 55 | if err != nil { 56 | return err 57 | } 58 | 59 | req.Id = id 60 | resp.Id = id.String() 61 | 62 | return s.Service.Create(ctx, req, output) 63 | } 64 | 65 | func (s *Service) AddAddress(ctx context.Context, input interface{}, output interface{}) error { 66 | return s.Op(ctx, ADD_ADDRESS, input, output) 67 | } --------------------------------------------------------------------------------