diff --git a/cmd/server/main.go b/cmd/server/main.go index 97475641..90cae54b 100644 --- a/cmd/server/main.go +++ b/cmd/server/main.go @@ -61,7 +61,6 @@ func main() { } func initEngine(strategyPath string, basicConfigPath string, secretPath string) { - logrus.Infof("secretPath: %s", secretPath) config.InitConfig(strategyPath, basicConfigPath, secretPath) if envirment.Environment.IsDevelopment() { diff --git a/common/model/sponsor.go b/common/model/sponsor.go index eb664c0f..e541b975 100644 --- a/common/model/sponsor.go +++ b/common/model/sponsor.go @@ -1,7 +1,5 @@ package model -import "math/big" - type DepositSponsorRequest struct { TimeStamp int64 `json:"time_stamp"` DepositAddress string `json:"deposit_address"` @@ -11,7 +9,7 @@ type DepositSponsorRequest struct { DepositSource string `json:"deposit_source"` } type WithdrawSponsorRequest struct { - Amount *big.Float + Amount float64 PayUserId string IsTestNet bool diff --git a/common/utils/util.go b/common/utils/util.go index 3333ccbd..a1b4253b 100644 --- a/common/utils/util.go +++ b/common/utils/util.go @@ -24,7 +24,7 @@ import ( var HexPattern = regexp.MustCompile(`^0x[a-fA-F\d]*$`) -const defaultStackSize = 4096 +const defaultStackSize = 10000 type EthCallReq struct { From common.Address `json:"from"` @@ -202,18 +202,20 @@ func GetCurrentGoroutineStack() string { n := runtime.Stack(buf[:], false) return string(buf[:n]) } -func DBTransactional(db *gorm.DB, handle func() error) (err error) { +func DBTransactional(db *gorm.DB, handle func(tx *gorm.DB) error) (err error) { tx := db.Begin() defer func() { if p := recover(); p != nil { tx.Rollback() - panic(p) + logrus.Errorf("TX ERROR [%s] ", GetCurrentGoroutineStack()) + err = xerrors.Errorf("TX ERROR [%v]", p) + //panic(p) } else if err != nil { tx.Rollback() } else { err = tx.Commit().Error } }() - err = handle() - return + err = handle(tx) + return err } diff --git a/docs/docs.go b/docs/docs.go index c6ae8568..cf7ffa79 100644 --- a/docs/docs.go +++ b/docs/docs.go @@ -18,23 +18,46 @@ const docTemplate = `{ "host": "{{.Host}}", "basePath": "{{.BasePath}}", "paths": { - "/api/auth": { + "/api/healthz": { + "get": { + "description": "Get Healthz", + "consumes": [ + "application/json" + ], + "tags": [ + "Healthz" + ], + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/api/v1/paymaster/{network}": { "post": { - "description": "Get AccessToken By ApiKey", + "description": "Paymaster JSON-RPC API", "consumes": [ "application/json" ], "tags": [ - "Auth" + "Paymaster" ], "parameters": [ { - "description": "AccessToken Model", - "name": "credential", + "type": "string", + "description": "Network", + "name": "network", + "in": "path", + "required": true + }, + { + "description": "JsonRpcRequest Model", + "name": "rpcRequest", "in": "body", "required": true, "schema": { - "$ref": "#/definitions/model.ClientCredential" + "$ref": "#/definitions/model.JsonRpcRequest" } } ], @@ -45,14 +68,37 @@ const docTemplate = `{ } } }, - "/api/healthz": { - "get": { - "description": "Get Healthz", + "/api/v1/paymaster_sponsor/deposit": { + "post": { + "description": "Deposit Sponsor", "consumes": [ "application/json" ], "tags": [ - "Healthz" + "DepositSponsor" + ], + "parameters": [ + { + "description": "DepositSponsorRequest Model", + "name": "request", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/model.DepositSponsorRequest" + } + }, + { + "type": "string", + "description": "relay Request Body Hash", + "name": "relay_hash", + "in": "header" + }, + { + "type": "string", + "description": "relay Request Body Hash", + "name": "relay_signature", + "in": "header" + } ], "responses": { "200": { @@ -61,36 +107,31 @@ const docTemplate = `{ } } }, - "/api/v1/paymaster/{network}": { + "/api/v1/paymaster_sponsor/withdraw": { "post": { - "security": [ - { - "JWT": [] - } - ], - "description": "Paymaster JSON-RPC API", + "description": "Withdraw Sponsor", "consumes": [ "application/json" ], "tags": [ - "Paymaster" + "Sponsor" ], "parameters": [ { - "type": "string", - "description": "Network", - "name": "network", - "in": "path", - "required": true - }, - { - "description": "JsonRpcRequest Model", - "name": "rpcRequest", + "description": "WithdrawSponsorRequest Model", + "name": "request", "in": "body", "required": true, "schema": { - "$ref": "#/definitions/model.JsonRpcRequest" + "$ref": "#/definitions/model.WithdrawSponsorRequest" } + }, + { + "type": "boolean", + "description": "Is Test Net", + "name": "is_test_net", + "in": "path", + "required": true } ], "responses": { @@ -102,10 +143,25 @@ const docTemplate = `{ } }, "definitions": { - "model.ClientCredential": { + "model.DepositSponsorRequest": { "type": "object", "properties": { - "apiKey": { + "deposit_address": { + "type": "string" + }, + "deposit_source": { + "type": "string" + }, + "is_test_net": { + "type": "boolean" + }, + "pay_user_id": { + "type": "string" + }, + "time_stamp": { + "type": "integer" + }, + "tx_hash": { "type": "string" } } @@ -127,6 +183,29 @@ const docTemplate = `{ "items": {} } } + }, + "model.WithdrawSponsorRequest": { + "type": "object", + "properties": { + "amount": { + "type": "number" + }, + "isTestNet": { + "type": "boolean" + }, + "payUserId": { + "type": "string" + }, + "txHash": { + "type": "string" + }, + "txInfo": { + "type": "object", + "additionalProperties": { + "type": "string" + } + } + } } }, "securityDefinitions": { diff --git a/docs/swagger.json b/docs/swagger.json index 9eede293..cec679ee 100644 --- a/docs/swagger.json +++ b/docs/swagger.json @@ -7,23 +7,46 @@ } }, "paths": { - "/api/auth": { + "/api/healthz": { + "get": { + "description": "Get Healthz", + "consumes": [ + "application/json" + ], + "tags": [ + "Healthz" + ], + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/api/v1/paymaster/{network}": { "post": { - "description": "Get AccessToken By ApiKey", + "description": "Paymaster JSON-RPC API", "consumes": [ "application/json" ], "tags": [ - "Auth" + "Paymaster" ], "parameters": [ { - "description": "AccessToken Model", - "name": "credential", + "type": "string", + "description": "Network", + "name": "network", + "in": "path", + "required": true + }, + { + "description": "JsonRpcRequest Model", + "name": "rpcRequest", "in": "body", "required": true, "schema": { - "$ref": "#/definitions/model.ClientCredential" + "$ref": "#/definitions/model.JsonRpcRequest" } } ], @@ -34,14 +57,37 @@ } } }, - "/api/healthz": { - "get": { - "description": "Get Healthz", + "/api/v1/paymaster_sponsor/deposit": { + "post": { + "description": "Deposit Sponsor", "consumes": [ "application/json" ], "tags": [ - "Healthz" + "DepositSponsor" + ], + "parameters": [ + { + "description": "DepositSponsorRequest Model", + "name": "request", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/model.DepositSponsorRequest" + } + }, + { + "type": "string", + "description": "relay Request Body Hash", + "name": "relay_hash", + "in": "header" + }, + { + "type": "string", + "description": "relay Request Body Hash", + "name": "relay_signature", + "in": "header" + } ], "responses": { "200": { @@ -50,36 +96,31 @@ } } }, - "/api/v1/paymaster/{network}": { + "/api/v1/paymaster_sponsor/withdraw": { "post": { - "security": [ - { - "JWT": [] - } - ], - "description": "Paymaster JSON-RPC API", + "description": "Withdraw Sponsor", "consumes": [ "application/json" ], "tags": [ - "Paymaster" + "Sponsor" ], "parameters": [ { - "type": "string", - "description": "Network", - "name": "network", - "in": "path", - "required": true - }, - { - "description": "JsonRpcRequest Model", - "name": "rpcRequest", + "description": "WithdrawSponsorRequest Model", + "name": "request", "in": "body", "required": true, "schema": { - "$ref": "#/definitions/model.JsonRpcRequest" + "$ref": "#/definitions/model.WithdrawSponsorRequest" } + }, + { + "type": "boolean", + "description": "Is Test Net", + "name": "is_test_net", + "in": "path", + "required": true } ], "responses": { @@ -91,10 +132,25 @@ } }, "definitions": { - "model.ClientCredential": { + "model.DepositSponsorRequest": { "type": "object", "properties": { - "apiKey": { + "deposit_address": { + "type": "string" + }, + "deposit_source": { + "type": "string" + }, + "is_test_net": { + "type": "boolean" + }, + "pay_user_id": { + "type": "string" + }, + "time_stamp": { + "type": "integer" + }, + "tx_hash": { "type": "string" } } @@ -116,6 +172,29 @@ "items": {} } } + }, + "model.WithdrawSponsorRequest": { + "type": "object", + "properties": { + "amount": { + "type": "number" + }, + "isTestNet": { + "type": "boolean" + }, + "payUserId": { + "type": "string" + }, + "txHash": { + "type": "string" + }, + "txInfo": { + "type": "object", + "additionalProperties": { + "type": "string" + } + } + } } }, "securityDefinitions": { diff --git a/docs/swagger.yaml b/docs/swagger.yaml index 052a2180..74ac051e 100644 --- a/docs/swagger.yaml +++ b/docs/swagger.yaml @@ -1,7 +1,17 @@ definitions: - model.ClientCredential: + model.DepositSponsorRequest: properties: - apiKey: + deposit_address: + type: string + deposit_source: + type: string + is_test_net: + type: boolean + pay_user_id: + type: string + time_stamp: + type: integer + tx_hash: type: string type: object model.JsonRpcRequest: @@ -16,28 +26,26 @@ definitions: items: {} type: array type: object + model.WithdrawSponsorRequest: + properties: + amount: + type: number + isTestNet: + type: boolean + payUserId: + type: string + txHash: + type: string + txInfo: + additionalProperties: + type: string + type: object + type: object info: contact: name: AAStar Support url: https://aastar.xyz paths: - /api/auth: - post: - consumes: - - application/json - description: Get AccessToken By ApiKey - parameters: - - description: AccessToken Model - in: body - name: credential - required: true - schema: - $ref: '#/definitions/model.ClientCredential' - responses: - "200": - description: OK - tags: - - Auth /api/healthz: get: consumes: @@ -68,10 +76,55 @@ paths: responses: "200": description: OK - security: - - JWT: [] tags: - Paymaster + /api/v1/paymaster_sponsor/deposit: + post: + consumes: + - application/json + description: Deposit Sponsor + parameters: + - description: DepositSponsorRequest Model + in: body + name: request + required: true + schema: + $ref: '#/definitions/model.DepositSponsorRequest' + - description: relay Request Body Hash + in: header + name: relay_hash + type: string + - description: relay Request Body Hash + in: header + name: relay_signature + type: string + responses: + "200": + description: OK + tags: + - DepositSponsor + /api/v1/paymaster_sponsor/withdraw: + post: + consumes: + - application/json + description: Withdraw Sponsor + parameters: + - description: WithdrawSponsorRequest Model + in: body + name: request + required: true + schema: + $ref: '#/definitions/model.WithdrawSponsorRequest' + - description: Is Test Net + in: path + name: is_test_net + required: true + type: boolean + responses: + "200": + description: OK + tags: + - Sponsor securityDefinitions: JWT: description: Type 'Bearer \' to correctly set the AccessToken diff --git a/envirment/app_config.go b/envirment/app_config.go index bbc91bd5..df93d99b 100644 --- a/envirment/app_config.go +++ b/envirment/app_config.go @@ -2,20 +2,13 @@ package envirment import ( "AAStarCommunity/EthPaymaster_BackService/common/model" - "fmt" - "k8s.io/apimachinery/pkg/util/yaml" "os" - "strings" "sync" ) var once sync.Once var Environment *model.Env -type Conf struct { - Jwt JWT -} - func init() { envName := model.DevEnv if len(os.Getenv(model.EnvKey)) > 0 { @@ -28,59 +21,3 @@ func init() { }(), } } - -var conf *Conf - -// GetAppConf read conf from file -func GetAppConf() *Conf { - once.Do(func() { - if conf == nil { - filePath := getConfFilePath() - conf = getConfiguration(filePath) - } - }) - return conf -} -func getConfFilePath() *string { - path := fmt.Sprintf("conf/appsettings.%s.yaml", strings.ToLower(Environment.Name)) - if _, err := os.Stat(path); err != nil && os.IsNotExist(err) { - path = fmt.Sprintf("config/appsettings.yaml") - } - return &path -} - -// getConfiguration -func getConfiguration(filePath *string) *Conf { - if file, err := os.ReadFile(*filePath); err != nil { - return mappingEnvToConf( - &Conf{ - Jwt: JWT{}, - }, - ) - } else { - c := Conf{} - err := yaml.Unmarshal(file, &c) - if err != nil { - return mappingEnvToConf(&c) - } - - return &c - } -} - -func mappingEnvToConf(conf *Conf) *Conf { - - // TODO: read from env - // e.g. if dummy := os.Getenv("dummy"); len(dummy) > 0 {conf.Dummy = dummy} - if jwtSecurity := os.Getenv("jwt__security"); len(jwtSecurity) > 0 { - conf.Jwt.Security = jwtSecurity - } - if jwtRealm := os.Getenv("jwt__realm"); len(jwtRealm) > 0 { - conf.Jwt.Security = jwtRealm - } - if jetIkey := os.Getenv("jwt__idkey"); len(jetIkey) > 0 { - conf.Jwt.Security = jetIkey - } - - return conf -} diff --git a/envirment/jwt.go b/envirment/jwt.go deleted file mode 100644 index 867c3460..00000000 --- a/envirment/jwt.go +++ /dev/null @@ -1,28 +0,0 @@ -package envirment - -import "sync" - -type JWT struct { - Security string - Realm string - IdKey string -} - -var jwt *JWT - -var onceJwt sync.Once - -// GetJwtKey represents jwt object -func GetJwtKey() *JWT { - onceJwt.Do(func() { - if jwt == nil { - j := GetAppConf().Jwt - jwt = &JWT{ - Security: j.Security, - Realm: j.Realm, - } - } - }) - - return jwt -} diff --git a/rpc_server/api/v1/paymaster.go b/rpc_server/api/v1/paymaster.go index af329106..07a61273 100644 --- a/rpc_server/api/v1/paymaster.go +++ b/rpc_server/api/v1/paymaster.go @@ -32,7 +32,6 @@ func init() { // @Param rpcRequest body model.JsonRpcRequest true "JsonRpcRequest Model" // @Router /api/v1/paymaster/{network} [post] // @Success 200 -// @Security JWT func Paymaster(ctx *gin.Context) { jsonRpcRequest := model.JsonRpcRequest{} diff --git a/rpc_server/api/v1/sponsor.go b/rpc_server/api/v1/sponsor.go index 2e89c82b..42f731ac 100644 --- a/rpc_server/api/v1/sponsor.go +++ b/rpc_server/api/v1/sponsor.go @@ -13,6 +13,7 @@ import ( "encoding/json" "errors" "fmt" + "github.com/ethereum/go-ethereum/accounts" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto" @@ -24,16 +25,16 @@ import ( "log" "math/big" "net/http" - "strconv" ) // DepositSponsor -// @Tags Sponsor +// @Tags DepositSponsor // @Description Deposit Sponsor // @Accept json // @Product json -// @Param request body DepositSponsorRequest true "DepositSponsorRequest Model -// @Param is_test_net path boolean true "Is Test Net" +// @Param request body model.DepositSponsorRequest true "DepositSponsorRequest Model" +// @Param relay_hash header string false "relay Request Body Hash" +// @Param relay_signature header string false "relay Request Body Hash" // @Router /api/v1/paymaster_sponsor/deposit [post] // @Success 200 func DepositSponsor(ctx *gin.Context) { @@ -44,6 +45,12 @@ func DepositSponsor(ctx *gin.Context) { response.SetHttpCode(http.StatusBadRequest).FailCode(ctx, http.StatusBadRequest, errStr) return } + if request.DepositSource != "dashboard" { + errStr := fmt.Sprintf("not Support Source") + response.SetHttpCode(http.StatusBadRequest).FailCode(ctx, http.StatusBadRequest, errStr) + return + } + //validate Signature inputJson, err := json.Marshal(request) if err != nil { response.SetHttpCode(http.StatusInternalServerError).FailCode(ctx, http.StatusInternalServerError, err.Error()) @@ -56,14 +63,13 @@ func DepositSponsor(ctx *gin.Context) { response.SetHttpCode(http.StatusBadRequest).FailCode(ctx, http.StatusBadRequest, "Deposit Source Error :Not Support Source") return } - err = ValidateSignature(ctx.GetHeader("relay_hash"), ctx.GetHeader("relay_signature"), inputJson, signerAddress) if err != nil { response.SetHttpCode(http.StatusBadRequest).FailCode(ctx, http.StatusBadRequest, err.Error()) return } + //validate Deposit sender, amount, err := validateDeposit(&request) - if err != nil { response.SetHttpCode(http.StatusBadRequest).FailCode(ctx, http.StatusBadRequest, err.Error()) return @@ -74,6 +80,8 @@ func DepositSponsor(ctx *gin.Context) { Amount: amount, TxHash: request.TxHash, PayUserId: request.PayUserId, + Source: request.DepositSource, + IsTestNet: request.IsTestNet, } result, err := sponsor_manager.DepositSponsor(&depositInput) if err != nil { @@ -96,7 +104,7 @@ func ValidateSignature(originHash string, signatureHex string, inputJson []byte, hashByte, _ := utils.DecodeStringWithPrefix(originHash) signatureByte, _ := utils.DecodeStringWithPrefix(signatureHex) - pubKey, err := crypto.SigToPub(hashByte, signatureByte) + pubKey, err := crypto.SigToPub(accounts.TextHash(hashByte), signatureByte) if err != nil { log.Fatalf("Failed to recover public key: %v", err) } @@ -105,7 +113,6 @@ func ValidateSignature(originHash string, signatureHex string, inputJson []byte, return xerrors.Errorf("Signer Address Not Match") } return nil - } func validateDeposit(request *model.DepositSponsorRequest) (sender *common.Address, amount *big.Float, err error) { txHash := request.TxHash @@ -114,7 +121,10 @@ func validateDeposit(request *model.DepositSponsorRequest) (sender *common.Addre return nil, nil, err } // check tx - _, err = sponsor_manager.GetLogByTxHash(txHash) + _, err = sponsor_manager.GetLogByTxHash(txHash, request.IsTestNet) + if err == nil { + return nil, nil, xerrors.Errorf("Transaction [%s] already exist", txHash) + } if err != nil { if !errors.Is(err, gorm.ErrRecordNotFound) { return nil, nil, err @@ -127,7 +137,6 @@ func validateDeposit(request *model.DepositSponsorRequest) (sender *common.Addre if tx.Type() != types.DynamicFeeTxType { return nil, nil, xerrors.Errorf("Tx Type is not DynamicFeeTxType") } - logrus.Info(tx.Type()) txSender, err := types.Sender(types.NewLondonSigner(tx.ChainId()), tx) if err != nil { logrus.Errorf("Get Sender Error [%v]", err) @@ -137,7 +146,6 @@ func validateDeposit(request *model.DepositSponsorRequest) (sender *common.Addre if request.IsTestNet { //Only ETH if tx.Value().Uint64() == 0 { - return nil, nil, xerrors.Errorf("Tx Value is 0") } if tx.To() == nil { @@ -147,19 +155,21 @@ func validateDeposit(request *model.DepositSponsorRequest) (sender *common.Addre return nil, nil, xerrors.Errorf("Tx To Address is not Sponsor Address") } value := tx.Value() - valueFloat := new(big.Float).SetInt(value) - amount, err = price_compoent.GetTokenCostInUsd(global_const.TokenTypeETH, valueFloat) + valueEth := utils.ConvertBalanceToEther(value) + logrus.Infof("ETH amount : %s", valueEth) + + amount, err = price_compoent.GetTokenCostInUsd(global_const.TokenTypeETH, valueEth) if err != nil { return nil, nil, err } } else { + return nil, nil, xerrors.Errorf("not Support MainNet Right Now") //contractAddress := tx.To() //chain_service.CheckContractAddressAccess(contractAddress,"") //Only Usdt } return sender, amount, nil - } func GetInfoByHash(txHash string, client *ethclient.Client) (*types.Transaction, error) { @@ -172,7 +182,6 @@ func GetInfoByHash(txHash string, client *ethclient.Client) (*types.Transaction, } return nil, err } - return tx, nil } @@ -181,7 +190,7 @@ func GetInfoByHash(txHash string, client *ethclient.Client) (*types.Transaction, // @Description Withdraw Sponsor // @Accept json // @Product json -// @Param request body WithdrawSponsorRequest true "WithdrawSponsorRequest Model" +// @Param request body model.WithdrawSponsorRequest true "WithdrawSponsorRequest Model" // @Param is_test_net path boolean true "Is Test Net" // @Router /api/v1/paymaster_sponsor/withdraw [post] // @Success 200 @@ -202,72 +211,3 @@ func WithdrawSponsor(ctx *gin.Context) { response.WithDataSuccess(ctx, result) return } - -type sponsorDepositTransaction struct { - TxHash string `json:"tx_hash"` - Amount string `json:"amount"` - UpdateType global_const.UpdateType `json:"update_type"` -} - -// GetSponsorDepositAndWithdrawTransactions -// @Tags Sponsor -// @Description Get Sponsor Deposit And Withdraw Transactions -// @Accept json -// @Product json -// @Param userId path string true "User Id" -// @Param is_test_net path boolean true "Is Test Net" -// @Router /api/v1/paymaster_sponsor/deposit_log -// @Success 200 -func GetSponsorDepositAndWithdrawTransactions(ctx *gin.Context) { - userId := ctx.Param("user_id") - textNet := ctx.Param("is_test_net") - // convertTOBool - isTestNet, _ := strconv.ParseBool(textNet) - response := model.GetResponse() - models, err := sponsor_manager.GetDepositAndWithDrawLog(userId, isTestNet) - if err != nil { - if errors.Is(err, gorm.ErrRecordNotFound) { - response.FailCode(ctx, 400, "No Deposit Transactions") - } - } - trans := make([]sponsorDepositTransaction, 0) - for _, depositModel := range models { - tran := sponsorDepositTransaction{ - TxHash: depositModel.TxHash, - Amount: depositModel.Amount.String(), - } - trans = append(trans, tran) - } - response.WithDataSuccess(ctx, trans) - return -} - -// GetSponsorMetaData -// @Tags Sponsor -// @Description Get Sponsor Balance -// @Accept json -// @Product json -// @Param userId path string true "User Id" -// @Router /api/v1/paymaster_sponsor/balance/{userId} -// @Success 200 -func GetSponsorMetaData(ctx *gin.Context) { - userId := ctx.Param("userId") - textNet := ctx.Param("is_test_net") - isTestNet, _ := strconv.ParseBool(textNet) - response := model.GetResponse() - balance, err := sponsor_manager.FindUserSponsorBalance(userId, isTestNet) - if err != nil { - if errors.Is(err, gorm.ErrRecordNotFound) { - response.FailCode(ctx, 400, "No Balance") - } - } - result := struct { - AvailableBalance string `json:"available_balance"` - SponsorAddress string `json:"sponsor_address"` - }{ - AvailableBalance: balance.AvailableBalance.String(), - SponsorAddress: balance.SponsorAddress, - } - response.WithDataSuccess(ctx, result) - return -} diff --git a/rpc_server/api/v1/sponsor_test.go b/rpc_server/api/v1/sponsor_test.go index fd324e84..9f58bc1c 100644 --- a/rpc_server/api/v1/sponsor_test.go +++ b/rpc_server/api/v1/sponsor_test.go @@ -1,9 +1,16 @@ package v1 import ( + "AAStarCommunity/EthPaymaster_BackService/common/global_const" "AAStarCommunity/EthPaymaster_BackService/common/model" "AAStarCommunity/EthPaymaster_BackService/config" "AAStarCommunity/EthPaymaster_BackService/sponsor_manager" + "crypto/sha256" + "encoding/hex" + "encoding/json" + "fmt" + "github.com/ethereum/go-ethereum/accounts" + "github.com/ethereum/go-ethereum/crypto" "testing" ) @@ -26,11 +33,42 @@ func TestValidateDeposit(t *testing.T) { } func TestValidateSignature(t *testing.T) { - originHash := "0x367428ad744c2fd80054283f7143b934d630433f9c40a411d91e65893dbabdf1" - signatureHex := "0x367428ad744c2fd80054283f7143b934d630433f9c40a411d91e65893dbabdf1" - inputJson := []byte("0x367428ad744c2fd80054283f7143b934d630433f9c40a411d91e65893dbabdf1") - signerAddress := "0xFD44DF0Fe211d5EFDBe1423483Fcb3FDeF84540f" - err := ValidateSignature(originHash, signatureHex, inputJson, signerAddress) + //Only For Test + //privateKeyHex: 95ecbd0ae2055889d6c40ed042ef846d091313541482e61129f48867cd15fc4a + //publicKey: 0401e57b7947d19b224a98700dea8bcff3dd556980823aca6182e12eebe64e42ecee690d4c2d6eee6bbf9f82423e38314beec2be0a6833741a917a8abaebf66a76 + //address: 0x3aCF4b1F443a088186Cbd66c5F81479C6e968eCA + request := &model.DepositSponsorRequest{ + DepositAddress: "0xFD44DF0Fe211d5EFDBe1423483Fcb3FDeF84540f", + TxHash: "0x367428ad744c2fd80054283f7143b934d630433f9c40a411d91e65893dbabdf1", + PayUserId: "5", + DepositSource: "dashboard", + IsTestNet: true, + } + + jsonData, err := json.Marshal(request) + if err != nil { + fmt.Println("Error marshalling JSON:", err) + return + } + hash := sha256.New() + hash.Write(jsonData) + hashByte := hash.Sum(nil) + hashHex := hex.EncodeToString(hashByte) + t.Logf("hash: %v", hashHex) + signerEoa, err := global_const.NewEoa("95ecbd0ae2055889d6c40ed042ef846d091313541482e61129f48867cd15fc4a") + if err != nil { + t.Error(err) + return + } + signatureByte, err := crypto.Sign(accounts.TextHash(hashByte), signerEoa.PrivateKey) + if err != nil { + t.Error(err) + return + } + signatureByteHex := hex.EncodeToString(signatureByte) + t.Logf("signatureByteHex: %v", signatureByteHex) + + err = ValidateSignature(hashHex, signatureByteHex, jsonData, "0x3aCF4b1F443a088186Cbd66c5F81479C6e968eCA") if err != nil { t.Error(err) return diff --git a/rpc_server/routers/routers_map.go b/rpc_server/routers/routers_map.go index a7ee55fe..92d397b5 100644 --- a/rpc_server/routers/routers_map.go +++ b/rpc_server/routers/routers_map.go @@ -12,10 +12,8 @@ func init() { PrivateRouterMaps = make([]RouterMap, 0) PrivateRouterMaps = append(PrivateRouterMaps, RouterMap{string(Paymaster), []RestfulMethod{POST}, v1.Paymaster}) PublicRouterMaps = append(PublicRouterMaps, RouterMap{string(Healthz), []RestfulMethod{GET, HEAD, OPTIONS}, api.Healthz}) - PublicRouterMaps = append(PublicRouterMaps, RouterMap{string(GetSponsorLog), []RestfulMethod{GET}, v1.GetSponsorDepositAndWithdrawTransactions}) PublicRouterMaps = append(PublicRouterMaps, RouterMap{string(DepositSponsor), []RestfulMethod{POST}, v1.DepositSponsor}) PublicRouterMaps = append(PublicRouterMaps, RouterMap{string(WithdrawSponsor), []RestfulMethod{POST}, v1.WithdrawSponsor}) - PublicRouterMaps = append(PublicRouterMaps, RouterMap{string(GetSponsorData), []RestfulMethod{GET}, v1.GetSponsorMetaData}) } type Path string diff --git a/sponsor_manager/sponsor_changelog_repository.go b/sponsor_manager/sponsor_changelog_repository.go index 768ed50d..882b6116 100644 --- a/sponsor_manager/sponsor_changelog_repository.go +++ b/sponsor_manager/sponsor_changelog_repository.go @@ -26,11 +26,7 @@ func (UserSponsorBalanceUpdateLogDBModel) TableName() string { func AddBalanceChangeLog(changeDbModel *UserSponsorBalanceUpdateLogDBModel) error { return relayDB.Create(changeDbModel).Error } -func LogBalanceChange(updateType global_const.UpdateType, balanceType global_const.BalanceType, data interface{}, amount *big.Float) { - //TODO - return -} func GetDepositAndWithDrawLog(userId string, IsTestNet bool) (models []*UserSponsorBalanceUpdateLogDBModel, err error) { tx := relayDB.Model(&UserSponsorBalanceUpdateLogDBModel{}).Where("pay_user_id = ?", userId).Where("is_test_net = ?", IsTestNet).Where("update_type in (?)", []global_const.UpdateType{global_const.UpdateTypeDeposit, global_const.UpdateTypeWithdraw}).Find(&models) if tx.Error != nil { diff --git a/sponsor_manager/sponsor_service.go b/sponsor_manager/sponsor_service.go index bc602900..fb5d612d 100644 --- a/sponsor_manager/sponsor_service.go +++ b/sponsor_manager/sponsor_service.go @@ -7,6 +7,7 @@ import ( "AAStarCommunity/EthPaymaster_BackService/config" "encoding/json" "errors" + "github.com/sirupsen/logrus" "golang.org/x/xerrors" "gorm.io/driver/postgres" "gorm.io/gorm" @@ -28,6 +29,7 @@ var ( func Init() { onlyOnce.Do(func() { + logrus.Info("Init Sponsor Manager") relayDBDsn := config.GetRelayDBDSN() relayDBVar, err := gorm.Open(postgres.Open(relayDBDsn), &gorm.Config{}) @@ -77,7 +79,7 @@ func LockUserBalance(userId string, userOpHash []byte, isTestNet bool, availableBalance := new(big.Float).Sub(balanceModel.AvailableBalance.Float, lockAmount) balanceModel.LockBalance = BigFloat{lockBalance} balanceModel.AvailableBalance = BigFloat{availableBalance} - err = utils.DBTransactional(relayDB, func() error { + err = utils.DBTransactional(relayDB, func(tx *gorm.DB) error { if updateErr := relayDB.Model(&UserSponsorBalanceDBModel{}). Where("pay_user_id = ?", balanceModel.PayUserId). Where("is_test_net = ?", isTestNet).Updates(balanceModel).Error; updateErr != nil { @@ -91,7 +93,7 @@ func LockUserBalance(userId string, userOpHash []byte, isTestNet bool, IsTestNet: isTestNet, UpdateType: global_const.UpdateTypeLock, } - if createErr := relayDB.Create(changeModel).Error; createErr != nil { + if createErr := tx.Create(changeModel).Error; createErr != nil { return err } return nil @@ -116,7 +118,7 @@ func ReleaseBalanceWithActualCost(userId string, userOpHash []byte, balanceModel.AvailableBalance = BigFloat{new(big.Float).Add(balanceModel.AvailableBalance.Float, refundBalance)} balanceModel.SponsoredBalance = BigFloat{new(big.Float).Add(balanceModel.SponsoredBalance.Float, actualGasCost)} - err = utils.DBTransactional(relayDB, func() error { + err = utils.DBTransactional(relayDB, func(tx *gorm.DB) error { if updateErr := relayDB.Model(&UserSponsorBalanceDBModel{}). Model(&UserSponsorBalanceDBModel{}). Where("pay_user_id = ?", balanceModel.PayUserId). @@ -160,7 +162,7 @@ func ReleaseUserOpHashLockWhenFail(userOpHash []byte, isTestNet bool) (*UserSpon lockBalance := changeModel.Amount balanceModel.LockBalance = BigFloat{new(big.Float).Sub(balanceModel.LockBalance.Float, lockBalance.Float)} balanceModel.AvailableBalance = BigFloat{new(big.Float).Add(balanceModel.AvailableBalance.Float, lockBalance.Float)} - err = utils.DBTransactional(relayDB, func() error { + err = utils.DBTransactional(relayDB, func(tx *gorm.DB) error { if updateErr := relayDB.Model(&UserSponsorBalanceDBModel{}). Where("pay_user_id = ?", balanceModel.PayUserId). Where("is_test_net = ?", isTestNet).Updates(balanceModel).Error; updateErr != nil { @@ -185,11 +187,11 @@ func ReleaseUserOpHashLockWhenFail(userOpHash []byte, isTestNet bool) (*UserSpon return balanceModel, nil } -func GetLogByTxHash(txHash string) (*UserSponsorBalanceUpdateLogDBModel, error) { +func GetLogByTxHash(txHash string, isTestNet bool) (*UserSponsorBalanceUpdateLogDBModel, error) { changeModel := &UserSponsorBalanceUpdateLogDBModel{} - err := relayDB.Where("tx_hash = ?", txHash).First(changeModel).Error + err := relayDB.Where("tx_hash = ?", txHash).Where("is_test_net = ?", isTestNet).First(changeModel).Error if err != nil { - return nil, err + return changeModel, err } return changeModel, nil } @@ -203,76 +205,69 @@ type DepositSponsorInput struct { IsTestNet bool `json:"is_test_net"` PayUserId string `json:"pay_user_id"` TxInfo map[string]string + Source string } func DepositSponsor(input *DepositSponsorInput) (*UserSponsorBalanceDBModel, error) { - - balanceModel, err := FindUserSponsorBalance(input.PayUserId, input.IsTestNet) - if err != nil { - return nil, err - } - - err = utils.DBTransactional(relayDB, func() error { - if errors.Is(err, gorm.ErrRecordNotFound) { + balanceModel, findBalanceError := FindUserSponsorBalance(input.PayUserId, input.IsTestNet) + txErr := utils.DBTransactional(relayDB, func(tx *gorm.DB) error { + if errors.Is(findBalanceError, gorm.ErrRecordNotFound) { //init Data balanceModel = &UserSponsorBalanceDBModel{} balanceModel.AvailableBalance = BigFloat{big.NewFloat(0)} balanceModel.PayUserId = input.PayUserId balanceModel.LockBalance = BigFloat{big.NewFloat(0)} + balanceModel.SponsoredBalance = BigFloat{big.NewFloat(0)} balanceModel.IsTestNet = input.IsTestNet - err = relayDB.Create(balanceModel).Error + balanceModel.Source = input.Source + balanceModel.SponsorAddress = input.From + err := tx.Create(balanceModel).Error if err != nil { - + logrus.Info("Create Balance ERROR ") return err } } - if err != nil { - - return err - } newAvailableBalance := BigFloat{new(big.Float).Add(balanceModel.AvailableBalance.Float, input.Amount)} balanceModel.AvailableBalance = newAvailableBalance - if updateErr := relayDB.Model(balanceModel). + if updateErr := tx.Model(balanceModel). Where("pay_user_id = ?", balanceModel.PayUserId). Where("is_test_net = ?", input.IsTestNet).Updates(balanceModel).Error; updateErr != nil { - return updateErr } - - txInfoJSon, _ := json.Marshal(input.TxInfo) changeModel := &UserSponsorBalanceUpdateLogDBModel{ PayUserId: input.PayUserId, Amount: BigFloat{input.Amount}, - Source: "Deposit", + Source: input.Source, IsTestNet: input.IsTestNet, UpdateType: global_const.UpdateTypeDeposit, TxHash: input.TxHash, - TxInfo: txInfoJSon, } - if createErr := relayDB.Create(changeModel).Error; createErr != nil { + if input.TxInfo != nil { + txInfo, _ := json.Marshal(input.TxInfo) + changeModel.TxInfo = txInfo + } + if createErr := tx.Create(changeModel).Error; createErr != nil { return createErr } return nil }) - if err != nil { - return nil, err - } - return balanceModel, nil + return balanceModel, txErr } func WithDrawSponsor(input *model.WithdrawSponsorRequest) (*UserSponsorBalanceDBModel, error) { + amount := big.NewFloat(input.Amount) balanceModel, err := FindUserSponsorBalance(input.PayUserId, input.IsTestNet) if err != nil { return nil, err } - if balanceModel.AvailableBalance.Cmp(input.Amount) < 0 { - return nil, xerrors.Errorf("Insufficient balance [%s] not Enough to Withdraw [%s]", balanceModel.AvailableBalance.String(), input.Amount.String()) + if balanceModel.AvailableBalance.Cmp(amount) < 0 { + return nil, xerrors.Errorf("Insufficient balance [%s] not Enough to Withdraw [%s]", balanceModel.AvailableBalance.String(), amount.String()) } - newAvailableBalance := new(big.Float).Sub(balanceModel.AvailableBalance.Float, input.Amount) + newAvailableBalance := new(big.Float).Sub(balanceModel.AvailableBalance.Float, amount) balanceModel.AvailableBalance = BigFloat{newAvailableBalance} - err = utils.DBTransactional(relayDB, func() error { + err = utils.DBTransactional(relayDB, func(tx *gorm.DB) error { if updateErr := relayDB.Model(&UserSponsorBalanceDBModel{}). Where("pay_user_id = ?", balanceModel.PayUserId). Where("is_test_net = ?", input.IsTestNet).Updates(balanceModel).Error; updateErr != nil { @@ -280,7 +275,7 @@ func WithDrawSponsor(input *model.WithdrawSponsorRequest) (*UserSponsorBalanceDB } changeModel := &UserSponsorBalanceUpdateLogDBModel{ PayUserId: input.PayUserId, - Amount: BigFloat{input.Amount}, + Amount: BigFloat{amount}, Source: "Withdraw", IsTestNet: input.IsTestNet, UpdateType: global_const.UpdateTypeWithdraw,