From bfef94c99f6ccbc46543c4542f397bfa3fa242dd Mon Sep 17 00:00:00 2001 From: "aleksej.paschenko" Date: Thu, 15 Jun 2023 12:05:41 +0300 Subject: [PATCH] Add DepositStake and RecoverStake actions --- api/openapi.json | 42 ++++ api/openapi.yml | 32 +++ go.mod | 3 +- go.sum | 10 +- pkg/api/event_converters.go | 36 +++ pkg/bath/actions.go | 16 ++ pkg/bath/staking.go | 118 ++++++++++ pkg/bath/straws.go | 2 + pkg/blockchain/config/elector.go | 10 + pkg/i18n/translations/active.en.toml | 2 + pkg/i18n/translations/active.ru.toml | 6 + pkg/oas/oas_json_gen.go | 340 ++++++++++++++++++++++++++- pkg/oas/oas_schemas_gen.go | 168 +++++++++++++ pkg/oas/oas_validators_gen.go | 4 + 14 files changed, 774 insertions(+), 15 deletions(-) create mode 100644 pkg/bath/staking.go create mode 100644 pkg/blockchain/config/elector.go diff --git a/api/openapi.json b/api/openapi.json index d4cfe10f..4466e505 100644 --- a/api/openapi.json +++ b/api/openapi.json @@ -694,6 +694,9 @@ "ContractDeploy": { "$ref": "#/components/schemas/ContractDeployAction" }, + "DepositStake": { + "$ref": "#/components/schemas/DepositStakeAction" + }, "JettonTransfer": { "$ref": "#/components/schemas/JettonTransferAction" }, @@ -703,6 +706,9 @@ "NftPurchase": { "$ref": "#/components/schemas/NftPurchaseAction" }, + "RecoverStake": { + "$ref": "#/components/schemas/RecoverStakeAction" + }, "SmartContractExec": { "$ref": "#/components/schemas/SmartContractAction" }, @@ -737,6 +743,8 @@ "UnSubscribe", "AuctionBid", "NftPurchase", + "DepositStake", + "RecoverStake", "SmartContractExec", "Unknown" ], @@ -1189,6 +1197,23 @@ ], "type": "object" }, + "DepositStakeAction": { + "properties": { + "amount": { + "example": 1660050553, + "format": "int64", + "type": "integer" + }, + "staker": { + "$ref": "#/components/schemas/AccountAddress" + } + }, + "required": [ + "amount", + "staker" + ], + "type": "object" + }, "DnsExpiring": { "properties": { "items": { @@ -2202,6 +2227,23 @@ ], "type": "object" }, + "RecoverStakeAction": { + "properties": { + "amount": { + "example": 1660050553, + "format": "int64", + "type": "integer" + }, + "staker": { + "$ref": "#/components/schemas/AccountAddress" + } + }, + "required": [ + "amount", + "staker" + ], + "type": "object" + }, "Refund": { "properties": { "origin": { diff --git a/api/openapi.yml b/api/openapi.yml index 21e1627c..62e36f92 100644 --- a/api/openapi.yml +++ b/api/openapi.yml @@ -2601,6 +2601,8 @@ components: - UnSubscribe - AuctionBid - NftPurchase + - DepositStake + - RecoverStake - SmartContractExec - Unknown status: @@ -2626,6 +2628,10 @@ components: $ref: '#/components/schemas/AuctionBidAction' NftPurchase: $ref: '#/components/schemas/NftPurchaseAction' + DepositStake: + $ref: '#/components/schemas/DepositStakeAction' + RecoverStake: + $ref: '#/components/schemas/RecoverStakeAction' SmartContractExec: $ref: '#/components/schemas/SmartContractAction' simple_preview: @@ -2808,6 +2814,32 @@ components: bidder: $ref: '#/components/schemas/AccountAddress' + DepositStakeAction: + type: object + required: + - amount + - staker + properties: + amount: + type: integer + format: int64 + example: 1660050553 + staker: + $ref: '#/components/schemas/AccountAddress' + + RecoverStakeAction: + type: object + required: + - amount + - staker + properties: + amount: + type: integer + format: int64 + example: 1660050553 + staker: + $ref: '#/components/schemas/AccountAddress' + NftPurchaseAction: type: object required: diff --git a/go.mod b/go.mod index a91ca182..85bfba84 100644 --- a/go.mod +++ b/go.mod @@ -22,7 +22,7 @@ require ( github.com/sourcegraph/conc v0.3.0 github.com/stretchr/testify v1.8.1 github.com/tonkeeper/scam_backoffice_rules v0.0.0-20230413094040-a66ab71fb269 - github.com/tonkeeper/tongo v1.1.2-0.20230614170918-21867e935297 + github.com/tonkeeper/tongo v1.1.2-0.20230614212647-93fc48518802 go.opentelemetry.io/otel v1.11.1 go.opentelemetry.io/otel/metric v0.33.0 go.opentelemetry.io/otel/trace v1.11.1 @@ -61,7 +61,6 @@ require ( github.com/valyala/fasttemplate v1.2.2 // indirect go.uber.org/atomic v1.10.0 // indirect golang.org/x/crypto v0.0.0-20220321153916-2c7772ba3064 // indirect - golang.org/x/exp v0.0.0-20230116083435-1de6713980de // indirect golang.org/x/mod v0.8.0 // indirect golang.org/x/net v0.7.0 // indirect golang.org/x/sync v0.1.0 // indirect diff --git a/go.sum b/go.sum index e0fc74cf..c8ba51aa 100644 --- a/go.sum +++ b/go.sum @@ -268,10 +268,8 @@ github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKs github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/tonkeeper/scam_backoffice_rules v0.0.0-20230413094040-a66ab71fb269 h1:roJPVpmFnUZX6YCUqzoD5+0+Z2ruuuXmxWKS+IH3O2s= github.com/tonkeeper/scam_backoffice_rules v0.0.0-20230413094040-a66ab71fb269/go.mod h1:VGp8QednbWkKHcpQVlWyO0XSqAA0cR6d9wEdrDmHbbA= -github.com/tonkeeper/tongo v1.1.2-0.20230613142834-d288ff73f9f6 h1:+j84fDe+Gol48eBFcYI5IqKiKjLVfZSalpzWRGf3rus= -github.com/tonkeeper/tongo v1.1.2-0.20230613142834-d288ff73f9f6/go.mod h1:LdOBjpUz6vLp1EdX3E0XLNks9YI5XMSqaQahfOMrBEY= -github.com/tonkeeper/tongo v1.1.2-0.20230614170918-21867e935297 h1:dH9HmZUn/l+93SeDrLHxzEqod+OdX8313gp/NR+WECE= -github.com/tonkeeper/tongo v1.1.2-0.20230614170918-21867e935297/go.mod h1:LdOBjpUz6vLp1EdX3E0XLNks9YI5XMSqaQahfOMrBEY= +github.com/tonkeeper/tongo v1.1.2-0.20230614212647-93fc48518802 h1:XG9ic1xSrs6a5qmrEZWQXRZ97X7SofJ16EhX1fbJ0os= +github.com/tonkeeper/tongo v1.1.2-0.20230614212647-93fc48518802/go.mod h1:LdOBjpUz6vLp1EdX3E0XLNks9YI5XMSqaQahfOMrBEY= github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= github.com/valyala/fasttemplate v1.2.1/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ= @@ -318,12 +316,8 @@ golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u0 golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= -golang.org/x/exp v0.0.0-20221006183845-316c7553db56 h1:BrYbdKcCNjLyrN6aKqXy4hPw9qGI8IATkj4EWv9Q+kQ= -golang.org/x/exp v0.0.0-20221006183845-316c7553db56/go.mod h1:cyybsKvd6eL0RnXn6p/Grxp8F5bW7iYuBgsNCOHpMYE= golang.org/x/exp v0.0.0-20230116083435-1de6713980de h1:DBWn//IJw30uYCgERoxCg84hWtA97F4wMiKOIh00Uf0= golang.org/x/exp v0.0.0-20230116083435-1de6713980de/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc= -golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1 h1:k/i9J1pBpvlfR+9QsetwPyERsqu1GIbi967PQMq3Ivc= -golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1/go.mod h1:V1LtkGg67GoY2N1AnLN78QLrzxkLyJw7RJb1gzOOz9w= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= diff --git a/pkg/api/event_converters.go b/pkg/api/event_converters.go index 1c2ae2da..e681a780 100644 --- a/pkg/api/event_converters.go +++ b/pkg/api/event_converters.go @@ -28,6 +28,8 @@ const ( jettonTransferMessageID = "jettonTransferAction" smartContractMessageID = "smartContractExecAction" subscriptionMessageID = "subscriptionAction" + depositStakeMessageID = "depositStakeAction" + recoverStakeMessageID = "recoverStakeAction" ) func distinctAccounts(book addressBook, accounts ...*tongo.AccountID) []oas.AccountAddress { @@ -266,6 +268,40 @@ func (h Handler) convertAction(ctx context.Context, a bath.Action, acceptLanguag Seller: convertAccountAddress(a.NftPurchase.Seller, h.addressBook), Buyer: convertAccountAddress(a.NftPurchase.Buyer, h.addressBook), }) + case bath.DepositStake: + value := utils.HumanFriendlyCoinsRepr(a.DepositStake.Amount) + action.DepositStake.SetTo(oas.DepositStakeAction{ + Amount: a.DepositStake.Amount, + Staker: convertAccountAddress(a.DepositStake.Staker, h.addressBook), + }) + action.SimplePreview = oas.ActionSimplePreview{ + Name: "Deposit Stake", + Description: i18n.T(acceptLanguage.Value, i18n.C{ + MessageID: depositStakeMessageID, + TemplateData: map[string]interface{}{ + "Amount": value, + }, + }), + Value: oas.NewOptString(value), + Accounts: distinctAccounts(h.addressBook, &a.DepositStake.Elector, &a.DepositStake.Staker), + } + case bath.RecoverStake: + value := utils.HumanFriendlyCoinsRepr(a.RecoverStake.Amount) + action.RecoverStake.SetTo(oas.RecoverStakeAction{ + Amount: a.RecoverStake.Amount, + Staker: convertAccountAddress(a.RecoverStake.Staker, h.addressBook), + }) + action.SimplePreview = oas.ActionSimplePreview{ + Name: "Recover Stake", + Description: i18n.T(acceptLanguage.Value, i18n.C{ + MessageID: recoverStakeMessageID, + TemplateData: map[string]interface{}{ + "Amount": value, + }, + }), + Value: oas.NewOptString(value), + Accounts: distinctAccounts(h.addressBook, &a.RecoverStake.Elector, &a.RecoverStake.Staker), + } case bath.SmartContractExec: op := "Call" if a.SmartContractExec.Operation != "" { diff --git a/pkg/bath/actions.go b/pkg/bath/actions.go index 0fcbe45a..e4ecf2ab 100644 --- a/pkg/bath/actions.go +++ b/pkg/bath/actions.go @@ -22,6 +22,8 @@ const ( ContractDeploy ActionType = "ContractDeploy" Subscription ActionType = "Subscription" UnSubscription ActionType = "UnSubscribe" + DepositStake ActionType = "DepositStake" + RecoverStake ActionType = "RecoverStake" AuctionBid ActionType = "AuctionBid" AuctionTgInitBid ActionType = "AuctionTgInitBid" @@ -57,6 +59,8 @@ type ( Subscription *SubscriptionAction `json:",omitempty"` UnSubscription *UnSubscriptionAction `json:",omitempty"` AuctionBid *AuctionBidAction `json:",omitempty"` + DepositStake *DepositStakeAction `json:",omitempty"` + RecoverStake *RecoverStakeAction `json:",omitempty"` Success bool Type ActionType } @@ -91,6 +95,18 @@ type ( Price int64 } + DepositStakeAction struct { + Amount int64 + Elector tongo.AccountID + Staker tongo.AccountID + } + + RecoverStakeAction struct { + Amount int64 + Elector tongo.AccountID + Staker tongo.AccountID + } + JettonTransferAction struct { Comment *string Jetton tongo.AccountID diff --git a/pkg/bath/staking.go b/pkg/bath/staking.go new file mode 100644 index 00000000..8c867a1b --- /dev/null +++ b/pkg/bath/staking.go @@ -0,0 +1,118 @@ +package bath + +import ( + "github.com/tonkeeper/opentonapi/pkg/blockchain/config" + "github.com/tonkeeper/tongo" + "github.com/tonkeeper/tongo/abi" +) + +type BubbleDepositStake struct { + Staker tongo.AccountID + Amount int64 + Success bool +} + +func (ds BubbleDepositStake) ToAction() *Action { + return &Action{ + DepositStake: &DepositStakeAction{ + Amount: ds.Amount, + Elector: config.ElectorAddress(), + Staker: ds.Staker, + }, + Success: ds.Success, + Type: DepositStake, + } +} + +func FindDepositStake(bubble *Bubble) bool { + bubbleTx, ok := bubble.Info.(BubbleTx) + if !ok { + return false + } + if !bubbleTx.operation(abi.ElectorNewStakeMsgOp) { + return false + } + if bubbleTx.account.Address != config.ElectorAddress() { + return false + } + stake := BubbleDepositStake{ + Amount: bubbleTx.inputAmount, + Staker: bubbleTx.inputFrom.Address, + } + newBubble := Bubble{ + Accounts: bubble.Accounts, + ValueFlow: bubble.ValueFlow, + } + newBubble.Children = ProcessChildren(bubble.Children, + func(child *Bubble) *Merge { + confirmation, ok := child.Info.(BubbleTx) + if !ok { + return nil + } + if !confirmation.operation(abi.ElectorNewStakeConfirmationMsgOp) { + return nil + } + stake.Success = true + newBubble.ValueFlow.Merge(child.ValueFlow) + return &Merge{children: child.Children} + }) + newBubble.Info = stake + *bubble = newBubble + return true +} + +type BubbleRecoverStake struct { + Staker tongo.AccountID + Amount int64 + Success bool +} + +func (b BubbleRecoverStake) ToAction() *Action { + return &Action{ + RecoverStake: &RecoverStakeAction{ + Amount: b.Amount, + Elector: config.ElectorAddress(), + Staker: b.Staker, + }, + Success: b.Success, + Type: RecoverStake, + } +} + +func FindRecoverStake(bubble *Bubble) bool { + bubbleTx, ok := bubble.Info.(BubbleTx) + if !ok { + return false + } + if !bubbleTx.operation(abi.ElectorRecoverStakeRequestMsgOp) { + return false + } + if bubbleTx.account.Address != config.ElectorAddress() { + return false + } + recoverStake := BubbleRecoverStake{ + Amount: bubbleTx.inputAmount, + Staker: bubbleTx.inputFrom.Address, + } + newBubble := Bubble{ + Accounts: bubble.Accounts, + ValueFlow: bubble.ValueFlow, + } + newBubble.Children = ProcessChildren(bubble.Children, + func(child *Bubble) *Merge { + response, ok := child.Info.(BubbleTx) + if !ok { + return nil + } + if !response.operation(abi.ElectorRecoverStakeResponseMsgOp) { + return nil + } + recoverStake.Success = true + newBubble.ValueFlow.Merge(child.ValueFlow) + return &Merge{children: child.Children} + }) + newBubble.Info = recoverStake + *bubble = newBubble + return true + +} diff --git a/pkg/bath/straws.go b/pkg/bath/straws.go index 6a4c4432..0d3eacf2 100644 --- a/pkg/bath/straws.go +++ b/pkg/bath/straws.go @@ -21,6 +21,8 @@ var DefaultStraws = []Straw{ FindInitialSubscription, FindExtendedSubscription, FindNftPurchase, + FindDepositStake, + FindRecoverStake, } func FindNFTTransfer(bubble *Bubble) bool { diff --git a/pkg/blockchain/config/elector.go b/pkg/blockchain/config/elector.go new file mode 100644 index 00000000..39bab219 --- /dev/null +++ b/pkg/blockchain/config/elector.go @@ -0,0 +1,10 @@ +package config + +import ( + "github.com/tonkeeper/tongo" +) + +func ElectorAddress() tongo.AccountID { + // TODO: read from the blockchain config + return tongo.MustParseAccountID("Ef8zMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzM0vF") +} diff --git a/pkg/i18n/translations/active.en.toml b/pkg/i18n/translations/active.en.toml index eb733549..f2a5e19a 100644 --- a/pkg/i18n/translations/active.en.toml +++ b/pkg/i18n/translations/active.en.toml @@ -5,3 +5,5 @@ subscriptionAction = "Paying {{.Value}} for subscription" jettonTransferAction = "Transferring {{.Value}} {{.JettonName}}" nftTransferAction = "NFT Transfer" nftPurchaseAction = "Purchase NFT {{.Name}}" +depositStakeAction = "Staking {{.Amount}}" +recoverStakeAction = "Recover {{.Amount}} stake" diff --git a/pkg/i18n/translations/active.ru.toml b/pkg/i18n/translations/active.ru.toml index 27e4cfa9..102dbc60 100644 --- a/pkg/i18n/translations/active.ru.toml +++ b/pkg/i18n/translations/active.ru.toml @@ -16,3 +16,9 @@ other = "Перевод NFT" [nftPurchaseAction] other = "Покупка NFT {{.Name}}" + +[depositStakeAction] +other = "Стейкинг {{.Amount}}" + +[recoverStakeAction] +other = "Вывод {{.Amount}}" diff --git a/pkg/oas/oas_json_gen.go b/pkg/oas/oas_json_gen.go index 857b40b0..8bd32720 100644 --- a/pkg/oas/oas_json_gen.go +++ b/pkg/oas/oas_json_gen.go @@ -1634,6 +1634,18 @@ func (s Action) encodeFields(e *jx.Encoder) { s.NftPurchase.Encode(e) } } + { + if s.DepositStake.Set { + e.FieldStart("DepositStake") + s.DepositStake.Encode(e) + } + } + { + if s.RecoverStake.Set { + e.FieldStart("RecoverStake") + s.RecoverStake.Encode(e) + } + } { if s.SmartContractExec.Set { e.FieldStart("SmartContractExec") @@ -1647,7 +1659,7 @@ func (s Action) encodeFields(e *jx.Encoder) { } } -var jsonFieldsNameOfAction = [12]string{ +var jsonFieldsNameOfAction = [14]string{ 0: "type", 1: "status", 2: "TonTransfer", @@ -1658,8 +1670,10 @@ var jsonFieldsNameOfAction = [12]string{ 7: "UnSubscribe", 8: "AuctionBid", 9: "NftPurchase", - 10: "SmartContractExec", - 11: "simple_preview", + 10: "DepositStake", + 11: "RecoverStake", + 12: "SmartContractExec", + 13: "simple_preview", } // Decode decodes Action from json. @@ -1771,6 +1785,26 @@ func (s *Action) Decode(d *jx.Decoder) error { }(); err != nil { return errors.Wrap(err, "decode field \"NftPurchase\"") } + case "DepositStake": + if err := func() error { + s.DepositStake.Reset() + if err := s.DepositStake.Decode(d); err != nil { + return err + } + return nil + }(); err != nil { + return errors.Wrap(err, "decode field \"DepositStake\"") + } + case "RecoverStake": + if err := func() error { + s.RecoverStake.Reset() + if err := s.RecoverStake.Decode(d); err != nil { + return err + } + return nil + }(); err != nil { + return errors.Wrap(err, "decode field \"RecoverStake\"") + } case "SmartContractExec": if err := func() error { s.SmartContractExec.Reset() @@ -1782,7 +1816,7 @@ func (s *Action) Decode(d *jx.Decoder) error { return errors.Wrap(err, "decode field \"SmartContractExec\"") } case "simple_preview": - requiredBitSet[1] |= 1 << 3 + requiredBitSet[1] |= 1 << 5 if err := func() error { if err := s.SimplePreview.Decode(d); err != nil { return err @@ -1802,7 +1836,7 @@ func (s *Action) Decode(d *jx.Decoder) error { var failures []validate.FieldError for i, mask := range [2]uint8{ 0b00000011, - 0b00001000, + 0b00100000, } { if result := (requiredBitSet[i] & mask) ^ mask; result != 0 { // Mask only required fields and check equality to mask using XOR. @@ -2285,6 +2319,10 @@ func (s *ActionType) Decode(d *jx.Decoder) error { *s = ActionTypeAuctionBid case ActionTypeNftPurchase: *s = ActionTypeNftPurchase + case ActionTypeDepositStake: + *s = ActionTypeDepositStake + case ActionTypeRecoverStake: + *s = ActionTypeRecoverStake case ActionTypeSmartContractExec: *s = ActionTypeSmartContractExec case ActionTypeUnknown: @@ -4121,6 +4159,119 @@ func (s *CreditPhase) UnmarshalJSON(data []byte) error { return s.Decode(d) } +// Encode implements json.Marshaler. +func (s DepositStakeAction) Encode(e *jx.Encoder) { + e.ObjStart() + s.encodeFields(e) + e.ObjEnd() +} + +// encodeFields encodes fields. +func (s DepositStakeAction) encodeFields(e *jx.Encoder) { + { + + e.FieldStart("amount") + e.Int64(s.Amount) + } + { + + e.FieldStart("staker") + s.Staker.Encode(e) + } +} + +var jsonFieldsNameOfDepositStakeAction = [2]string{ + 0: "amount", + 1: "staker", +} + +// Decode decodes DepositStakeAction from json. +func (s *DepositStakeAction) Decode(d *jx.Decoder) error { + if s == nil { + return errors.New("invalid: unable to decode DepositStakeAction to nil") + } + var requiredBitSet [1]uint8 + + if err := d.ObjBytes(func(d *jx.Decoder, k []byte) error { + switch string(k) { + case "amount": + requiredBitSet[0] |= 1 << 0 + if err := func() error { + v, err := d.Int64() + s.Amount = int64(v) + if err != nil { + return err + } + return nil + }(); err != nil { + return errors.Wrap(err, "decode field \"amount\"") + } + case "staker": + requiredBitSet[0] |= 1 << 1 + if err := func() error { + if err := s.Staker.Decode(d); err != nil { + return err + } + return nil + }(); err != nil { + return errors.Wrap(err, "decode field \"staker\"") + } + default: + return d.Skip() + } + return nil + }); err != nil { + return errors.Wrap(err, "decode DepositStakeAction") + } + // Validate required fields. + var failures []validate.FieldError + for i, mask := range [1]uint8{ + 0b00000011, + } { + if result := (requiredBitSet[i] & mask) ^ mask; result != 0 { + // Mask only required fields and check equality to mask using XOR. + // + // If XOR result is not zero, result is not equal to expected, so some fields are missed. + // Bits of fields which would be set are actually bits of missed fields. + missed := bits.OnesCount8(result) + for bitN := 0; bitN < missed; bitN++ { + bitIdx := bits.TrailingZeros8(result) + fieldIdx := i*8 + bitIdx + var name string + if fieldIdx < len(jsonFieldsNameOfDepositStakeAction) { + name = jsonFieldsNameOfDepositStakeAction[fieldIdx] + } else { + name = strconv.Itoa(fieldIdx) + } + failures = append(failures, validate.FieldError{ + Name: name, + Error: validate.ErrFieldRequired, + }) + // Reset bit. + result &^= 1 << bitIdx + } + } + } + if len(failures) > 0 { + return &validate.Error{Fields: failures} + } + + return nil +} + +// MarshalJSON implements stdjson.Marshaler. +func (s DepositStakeAction) MarshalJSON() ([]byte, error) { + e := jx.Encoder{} + s.Encode(&e) + return e.Bytes(), nil +} + +// UnmarshalJSON implements stdjson.Unmarshaler. +func (s *DepositStakeAction) UnmarshalJSON(data []byte) error { + d := jx.DecodeBytes(data) + return s.Decode(d) +} + // Encode implements json.Marshaler. func (s DnsExpiring) Encode(e *jx.Encoder) { e.ObjStart() @@ -10696,6 +10847,39 @@ func (s *OptCreditPhase) UnmarshalJSON(data []byte) error { return s.Decode(d) } +// Encode encodes DepositStakeAction as json. +func (o OptDepositStakeAction) Encode(e *jx.Encoder) { + if !o.Set { + return + } + o.Value.Encode(e) +} + +// Decode decodes DepositStakeAction from json. +func (o *OptDepositStakeAction) Decode(d *jx.Decoder) error { + if o == nil { + return errors.New("invalid: unable to decode OptDepositStakeAction to nil") + } + o.Set = true + if err := o.Value.Decode(d); err != nil { + return err + } + return nil +} + +// MarshalJSON implements stdjson.Marshaler. +func (s OptDepositStakeAction) MarshalJSON() ([]byte, error) { + e := jx.Encoder{} + s.Encode(&e) + return e.Bytes(), nil +} + +// UnmarshalJSON implements stdjson.Unmarshaler. +func (s *OptDepositStakeAction) UnmarshalJSON(data []byte) error { + d := jx.DecodeBytes(data) + return s.Decode(d) +} + // Encode encodes GetAccountsReq as json. func (o OptGetAccountsReq) Encode(e *jx.Encoder) { if !o.Set { @@ -11133,6 +11317,39 @@ func (s *OptRawAccountExtraBalance) UnmarshalJSON(data []byte) error { return s.Decode(d) } +// Encode encodes RecoverStakeAction as json. +func (o OptRecoverStakeAction) Encode(e *jx.Encoder) { + if !o.Set { + return + } + o.Value.Encode(e) +} + +// Decode decodes RecoverStakeAction from json. +func (o *OptRecoverStakeAction) Decode(d *jx.Decoder) error { + if o == nil { + return errors.New("invalid: unable to decode OptRecoverStakeAction to nil") + } + o.Set = true + if err := o.Value.Decode(d); err != nil { + return err + } + return nil +} + +// MarshalJSON implements stdjson.Marshaler. +func (s OptRecoverStakeAction) MarshalJSON() ([]byte, error) { + e := jx.Encoder{} + s.Encode(&e) + return e.Bytes(), nil +} + +// UnmarshalJSON implements stdjson.Unmarshaler. +func (s *OptRecoverStakeAction) UnmarshalJSON(data []byte) error { + d := jx.DecodeBytes(data) + return s.Decode(d) +} + // Encode encodes Refund as json. func (o OptRefund) Encode(e *jx.Encoder) { if !o.Set { @@ -12357,6 +12574,119 @@ func (s *RawAccountExtraBalance) UnmarshalJSON(data []byte) error { return s.Decode(d) } +// Encode implements json.Marshaler. +func (s RecoverStakeAction) Encode(e *jx.Encoder) { + e.ObjStart() + s.encodeFields(e) + e.ObjEnd() +} + +// encodeFields encodes fields. +func (s RecoverStakeAction) encodeFields(e *jx.Encoder) { + { + + e.FieldStart("amount") + e.Int64(s.Amount) + } + { + + e.FieldStart("staker") + s.Staker.Encode(e) + } +} + +var jsonFieldsNameOfRecoverStakeAction = [2]string{ + 0: "amount", + 1: "staker", +} + +// Decode decodes RecoverStakeAction from json. +func (s *RecoverStakeAction) Decode(d *jx.Decoder) error { + if s == nil { + return errors.New("invalid: unable to decode RecoverStakeAction to nil") + } + var requiredBitSet [1]uint8 + + if err := d.ObjBytes(func(d *jx.Decoder, k []byte) error { + switch string(k) { + case "amount": + requiredBitSet[0] |= 1 << 0 + if err := func() error { + v, err := d.Int64() + s.Amount = int64(v) + if err != nil { + return err + } + return nil + }(); err != nil { + return errors.Wrap(err, "decode field \"amount\"") + } + case "staker": + requiredBitSet[0] |= 1 << 1 + if err := func() error { + if err := s.Staker.Decode(d); err != nil { + return err + } + return nil + }(); err != nil { + return errors.Wrap(err, "decode field \"staker\"") + } + default: + return d.Skip() + } + return nil + }); err != nil { + return errors.Wrap(err, "decode RecoverStakeAction") + } + // Validate required fields. + var failures []validate.FieldError + for i, mask := range [1]uint8{ + 0b00000011, + } { + if result := (requiredBitSet[i] & mask) ^ mask; result != 0 { + // Mask only required fields and check equality to mask using XOR. + // + // If XOR result is not zero, result is not equal to expected, so some fields are missed. + // Bits of fields which would be set are actually bits of missed fields. + missed := bits.OnesCount8(result) + for bitN := 0; bitN < missed; bitN++ { + bitIdx := bits.TrailingZeros8(result) + fieldIdx := i*8 + bitIdx + var name string + if fieldIdx < len(jsonFieldsNameOfRecoverStakeAction) { + name = jsonFieldsNameOfRecoverStakeAction[fieldIdx] + } else { + name = strconv.Itoa(fieldIdx) + } + failures = append(failures, validate.FieldError{ + Name: name, + Error: validate.ErrFieldRequired, + }) + // Reset bit. + result &^= 1 << bitIdx + } + } + } + if len(failures) > 0 { + return &validate.Error{Fields: failures} + } + + return nil +} + +// MarshalJSON implements stdjson.Marshaler. +func (s RecoverStakeAction) MarshalJSON() ([]byte, error) { + e := jx.Encoder{} + s.Encode(&e) + return e.Bytes(), nil +} + +// UnmarshalJSON implements stdjson.Unmarshaler. +func (s *RecoverStakeAction) UnmarshalJSON(data []byte) error { + d := jx.DecodeBytes(data) + return s.Decode(d) +} + // Encode implements json.Marshaler. func (s Refund) Encode(e *jx.Encoder) { e.ObjStart() diff --git a/pkg/oas/oas_schemas_gen.go b/pkg/oas/oas_schemas_gen.go index a2b38a3d..9e1bfd95 100644 --- a/pkg/oas/oas_schemas_gen.go +++ b/pkg/oas/oas_schemas_gen.go @@ -530,6 +530,8 @@ type Action struct { UnSubscribe OptUnSubscriptionAction `json:"UnSubscribe"` AuctionBid OptAuctionBidAction `json:"AuctionBid"` NftPurchase OptNftPurchaseAction `json:"NftPurchase"` + DepositStake OptDepositStakeAction `json:"DepositStake"` + RecoverStake OptRecoverStakeAction `json:"RecoverStake"` SmartContractExec OptSmartContractAction `json:"SmartContractExec"` SimplePreview ActionSimplePreview `json:"simple_preview"` } @@ -584,6 +586,16 @@ func (s Action) GetNftPurchase() OptNftPurchaseAction { return s.NftPurchase } +// GetDepositStake returns the value of DepositStake. +func (s Action) GetDepositStake() OptDepositStakeAction { + return s.DepositStake +} + +// GetRecoverStake returns the value of RecoverStake. +func (s Action) GetRecoverStake() OptRecoverStakeAction { + return s.RecoverStake +} + // GetSmartContractExec returns the value of SmartContractExec. func (s Action) GetSmartContractExec() OptSmartContractAction { return s.SmartContractExec @@ -644,6 +656,16 @@ func (s *Action) SetNftPurchase(val OptNftPurchaseAction) { s.NftPurchase = val } +// SetDepositStake sets the value of DepositStake. +func (s *Action) SetDepositStake(val OptDepositStakeAction) { + s.DepositStake = val +} + +// SetRecoverStake sets the value of RecoverStake. +func (s *Action) SetRecoverStake(val OptRecoverStakeAction) { + s.RecoverStake = val +} + // SetSmartContractExec sets the value of SmartContractExec. func (s *Action) SetSmartContractExec(val OptSmartContractAction) { s.SmartContractExec = val @@ -805,6 +827,8 @@ const ( ActionTypeUnSubscribe ActionType = "UnSubscribe" ActionTypeAuctionBid ActionType = "AuctionBid" ActionTypeNftPurchase ActionType = "NftPurchase" + ActionTypeDepositStake ActionType = "DepositStake" + ActionTypeRecoverStake ActionType = "RecoverStake" ActionTypeSmartContractExec ActionType = "SmartContractExec" ActionTypeUnknown ActionType = "Unknown" ) @@ -1508,6 +1532,32 @@ func (s *CreditPhase) SetCredit(val int64) { s.Credit = val } +// Ref: #/components/schemas/DepositStakeAction +type DepositStakeAction struct { + Amount int64 `json:"amount"` + Staker AccountAddress `json:"staker"` +} + +// GetAmount returns the value of Amount. +func (s DepositStakeAction) GetAmount() int64 { + return s.Amount +} + +// GetStaker returns the value of Staker. +func (s DepositStakeAction) GetStaker() AccountAddress { + return s.Staker +} + +// SetAmount sets the value of Amount. +func (s *DepositStakeAction) SetAmount(val int64) { + s.Amount = val +} + +// SetStaker sets the value of Staker. +func (s *DepositStakeAction) SetStaker(val AccountAddress) { + s.Staker = val +} + // Ref: #/components/schemas/DnsExpiring type DnsExpiring struct { Items []DnsExpiringItemsItem `json:"items"` @@ -3774,6 +3824,52 @@ func (o OptCreditPhase) Or(d CreditPhase) CreditPhase { return d } +// NewOptDepositStakeAction returns new OptDepositStakeAction with value set to v. +func NewOptDepositStakeAction(v DepositStakeAction) OptDepositStakeAction { + return OptDepositStakeAction{ + Value: v, + Set: true, + } +} + +// OptDepositStakeAction is optional DepositStakeAction. +type OptDepositStakeAction struct { + Value DepositStakeAction + Set bool +} + +// IsSet returns true if OptDepositStakeAction was set. +func (o OptDepositStakeAction) IsSet() bool { return o.Set } + +// Reset unsets value. +func (o *OptDepositStakeAction) Reset() { + var v DepositStakeAction + o.Value = v + o.Set = false +} + +// SetTo sets value to v. +func (o *OptDepositStakeAction) SetTo(v DepositStakeAction) { + o.Set = true + o.Value = v +} + +// Get returns value and boolean that denotes whether value was set. +func (o OptDepositStakeAction) Get() (v DepositStakeAction, ok bool) { + if !o.Set { + return v, false + } + return o.Value, true +} + +// Or returns value if set, or given parameter if does not. +func (o OptDepositStakeAction) Or(d DepositStakeAction) DepositStakeAction { + if v, ok := o.Get(); ok { + return v + } + return d +} + // NewOptGetAccountsReq returns new OptGetAccountsReq with value set to v. func NewOptGetAccountsReq(v GetAccountsReq) OptGetAccountsReq { return OptGetAccountsReq{ @@ -4372,6 +4468,52 @@ func (o OptRawAccountExtraBalance) Or(d RawAccountExtraBalance) RawAccountExtraB return d } +// NewOptRecoverStakeAction returns new OptRecoverStakeAction with value set to v. +func NewOptRecoverStakeAction(v RecoverStakeAction) OptRecoverStakeAction { + return OptRecoverStakeAction{ + Value: v, + Set: true, + } +} + +// OptRecoverStakeAction is optional RecoverStakeAction. +type OptRecoverStakeAction struct { + Value RecoverStakeAction + Set bool +} + +// IsSet returns true if OptRecoverStakeAction was set. +func (o OptRecoverStakeAction) IsSet() bool { return o.Set } + +// Reset unsets value. +func (o *OptRecoverStakeAction) Reset() { + var v RecoverStakeAction + o.Value = v + o.Set = false +} + +// SetTo sets value to v. +func (o *OptRecoverStakeAction) SetTo(v RecoverStakeAction) { + o.Set = true + o.Value = v +} + +// Get returns value and boolean that denotes whether value was set. +func (o OptRecoverStakeAction) Get() (v RecoverStakeAction, ok bool) { + if !o.Set { + return v, false + } + return o.Value, true +} + +// Or returns value if set, or given parameter if does not. +func (o OptRecoverStakeAction) Or(d RecoverStakeAction) RecoverStakeAction { + if v, ok := o.Get(); ok { + return v + } + return d +} + // NewOptRefund returns new OptRefund with value set to v. func NewOptRefund(v Refund) OptRefund { return OptRefund{ @@ -5197,6 +5339,32 @@ func (s *RawAccountExtraBalance) init() RawAccountExtraBalance { return m } +// Ref: #/components/schemas/RecoverStakeAction +type RecoverStakeAction struct { + Amount int64 `json:"amount"` + Staker AccountAddress `json:"staker"` +} + +// GetAmount returns the value of Amount. +func (s RecoverStakeAction) GetAmount() int64 { + return s.Amount +} + +// GetStaker returns the value of Staker. +func (s RecoverStakeAction) GetStaker() AccountAddress { + return s.Staker +} + +// SetAmount sets the value of Amount. +func (s *RecoverStakeAction) SetAmount(val int64) { + s.Amount = val +} + +// SetStaker sets the value of Staker. +func (s *RecoverStakeAction) SetStaker(val AccountAddress) { + s.Staker = val +} + // Ref: #/components/schemas/Refund type Refund struct { Type RefundType `json:"type"` diff --git a/pkg/oas/oas_validators_gen.go b/pkg/oas/oas_validators_gen.go index 73374ae7..2f0d8860 100644 --- a/pkg/oas/oas_validators_gen.go +++ b/pkg/oas/oas_validators_gen.go @@ -391,6 +391,10 @@ func (s ActionType) Validate() error { return nil case "NftPurchase": return nil + case "DepositStake": + return nil + case "RecoverStake": + return nil case "SmartContractExec": return nil case "Unknown":