diff --git a/api/openapi.json b/api/openapi.json index eb9685fb..5babee77 100644 --- a/api/openapi.json +++ b/api/openapi.json @@ -4310,6 +4310,9 @@ "format": "int64", "type": "integer" }, + "risk": { + "$ref": "#/components/schemas/Risk" + }, "sent_for_execution": { "example": false, "type": "boolean" @@ -4334,7 +4337,8 @@ "sent_for_execution", "signers", "approvals_num", - "expiration_date" + "expiration_date", + "risk" ], "type": "object" }, diff --git a/api/openapi.yml b/api/openapi.yml index 4ed85e4e..f6bd1a86 100644 --- a/api/openapi.yml +++ b/api/openapi.yml @@ -5482,6 +5482,7 @@ components: - signers - approvals_num - expiration_date + - risk properties: address: type: string @@ -5509,6 +5510,8 @@ components: expiration_date: type: integer format: int64 + risk: + $ref: '#/components/schemas/Risk' Refund: type: object required: diff --git a/go.sum b/go.sum index 416b42cf..583831df 100644 --- a/go.sum +++ b/go.sum @@ -272,8 +272,6 @@ github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsT github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/tonkeeper/scam_backoffice_rules v0.0.0-20240606040945-382d2b4edb98 h1:lpzXxMZktaBS5YouFNGIv6haEbsYtDA/gaCPAspWKLI= github.com/tonkeeper/scam_backoffice_rules v0.0.0-20240606040945-382d2b4edb98/go.mod h1:SqZXYO9vbID8ku+xnnaKXeNGmehxigODGrk5V1KqbRA= -github.com/tonkeeper/tongo v1.9.1-0.20240710061111-60ccf2c10f84 h1:tHmuFcQ0zUuGULQcpzBXHNW9hrLFiUJjio8o0XGUoN4= -github.com/tonkeeper/tongo v1.9.1-0.20240710061111-60ccf2c10f84/go.mod h1:MjgIgAytFarjCoVjMLjYEtpZNN1f2G/pnZhKjr28cWs= github.com/tonkeeper/tongo v1.9.1 h1:RaTHi7zvAhclv9EU9/9HLdGUZwq9iUc8EO9xtpuPwus= github.com/tonkeeper/tongo v1.9.1/go.mod h1:MjgIgAytFarjCoVjMLjYEtpZNN1f2G/pnZhKjr28cWs= github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= diff --git a/pkg/api/account_handlers.go b/pkg/api/account_handlers.go index 0a264818..d211d948 100644 --- a/pkg/api/account_handlers.go +++ b/pkg/api/account_handlers.go @@ -510,7 +510,11 @@ func (h *Handler) GetAccountMultisigs(ctx context.Context, params oas.GetAccount } var converted []oas.Multisig for _, multisig := range multisigs { - converted = append(converted, convertMultisig(multisig)) + oasMultisig, err := h.convertMultisig(ctx, multisig) + if err != nil { + return nil, toError(http.StatusInternalServerError, err) + } + converted = append(converted, *oasMultisig) } return &oas.Multisigs{Multisigs: converted}, nil } diff --git a/pkg/api/converters.go b/pkg/api/converters.go index adc3d5e5..0e2be0bf 100644 --- a/pkg/api/converters.go +++ b/pkg/api/converters.go @@ -1,6 +1,7 @@ package api import ( + "context" "encoding/json" "fmt" "math/big" @@ -11,6 +12,7 @@ import ( "github.com/tonkeeper/opentonapi/pkg/core" imgGenerator "github.com/tonkeeper/opentonapi/pkg/image" + walletPkg "github.com/tonkeeper/opentonapi/pkg/wallet" "github.com/tonkeeper/tongo/boc" "github.com/tonkeeper/tongo/tlb" @@ -210,7 +212,7 @@ func stringToTVMStackRecord(s string) (tlb.VmStackValue, error) { return tlb.VmStackValue{SumType: "VmStkCell", VmStkCell: tlb.Ref[boc.Cell]{Value: *c}}, nil } -func convertMultisig(item core.Multisig) oas.Multisig { +func (h *Handler) convertMultisig(ctx context.Context, item core.Multisig) (*oas.Multisig, error) { converted := oas.Multisig{ Address: item.AccountID.ToRaw(), Seqno: item.Seqno, @@ -227,6 +229,18 @@ func convertMultisig(item core.Multisig) oas.Multisig { for _, account := range order.Signers { signers = append(signers, account.ToRaw()) } + messages, err := convertMultisigActionsToRawMessages(order.Actions) + if err != nil { + return nil, err + } + risk, err := walletPkg.ExtractRiskFromRawMessages(messages) + if err != nil { + return nil, err + } + oasRisk, err := h.convertRisk(ctx, *risk, item.AccountID) + if err != nil { + return nil, err + } converted.Orders = append(converted.Orders, oas.MultisigOrder{ Address: order.AccountID.ToRaw(), OrderSeqno: order.OrderSeqno, @@ -235,7 +249,8 @@ func convertMultisig(item core.Multisig) oas.Multisig { Signers: signers, ApprovalsNum: order.ApprovalsNum, ExpirationDate: order.ExpirationDate, + Risk: oasRisk, }) } - return converted + return &converted, nil } diff --git a/pkg/api/multisig_handlers.go b/pkg/api/multisig_handlers.go index 7aba10fa..655a6c13 100644 --- a/pkg/api/multisig_handlers.go +++ b/pkg/api/multisig_handlers.go @@ -7,9 +7,31 @@ import ( "github.com/tonkeeper/opentonapi/pkg/core" "github.com/tonkeeper/opentonapi/pkg/oas" + "github.com/tonkeeper/tongo/abi" + "github.com/tonkeeper/tongo/boc" + "github.com/tonkeeper/tongo/tlb" "github.com/tonkeeper/tongo/ton" + tongoWallet "github.com/tonkeeper/tongo/wallet" ) +func convertMultisigActionsToRawMessages(actions []abi.MultisigSendMessageAction) ([]tongoWallet.RawMessage, error) { + var messages []tongoWallet.RawMessage + for _, action := range actions { + switch action.SumType { + case "SendMessage": + msg := boc.NewCell() + if err := tlb.Marshal(msg, action.SendMessage.Field0.Message); err != nil { + return nil, err + } + messages = append(messages, tongoWallet.RawMessage{ + Message: msg, + Mode: action.SendMessage.Field0.Mode, + }) + } + } + return messages, nil +} + func (h *Handler) GetMultisigAccount(ctx context.Context, params oas.GetMultisigAccountParams) (*oas.Multisig, error) { accountID, err := ton.ParseAccountID(params.AccountID) if err != nil { @@ -22,6 +44,9 @@ func (h *Handler) GetMultisigAccount(ctx context.Context, params oas.GetMultisig if err != nil { return nil, toError(http.StatusInternalServerError, err) } - converted := convertMultisig(*multisig) - return &converted, nil + converted, err := h.convertMultisig(ctx, *multisig) + if err != nil { + return nil, toError(http.StatusInternalServerError, err) + } + return converted, nil } diff --git a/pkg/core/multisig.go b/pkg/core/multisig.go index 636f98a6..16cb69e1 100644 --- a/pkg/core/multisig.go +++ b/pkg/core/multisig.go @@ -1,6 +1,7 @@ package core import ( + "github.com/tonkeeper/tongo/abi" "github.com/tonkeeper/tongo/ton" ) @@ -22,4 +23,5 @@ type MultisigOrder struct { ApprovalsMask []byte ApprovalsNum int32 ExpirationDate int64 + Actions []abi.MultisigSendMessageAction } diff --git a/pkg/oas/oas_json_gen.go b/pkg/oas/oas_json_gen.go index 19e4e8c0..6fdc842d 100644 --- a/pkg/oas/oas_json_gen.go +++ b/pkg/oas/oas_json_gen.go @@ -26317,9 +26317,13 @@ func (s *MultisigOrder) encodeFields(e *jx.Encoder) { e.FieldStart("expiration_date") e.Int64(s.ExpirationDate) } + { + e.FieldStart("risk") + s.Risk.Encode(e) + } } -var jsonFieldsNameOfMultisigOrder = [7]string{ +var jsonFieldsNameOfMultisigOrder = [8]string{ 0: "address", 1: "order_seqno", 2: "threshold", @@ -26327,6 +26331,7 @@ var jsonFieldsNameOfMultisigOrder = [7]string{ 4: "signers", 5: "approvals_num", 6: "expiration_date", + 7: "risk", } // Decode decodes MultisigOrder from json. @@ -26430,6 +26435,16 @@ func (s *MultisigOrder) Decode(d *jx.Decoder) error { }(); err != nil { return errors.Wrap(err, "decode field \"expiration_date\"") } + case "risk": + requiredBitSet[0] |= 1 << 7 + if err := func() error { + if err := s.Risk.Decode(d); err != nil { + return err + } + return nil + }(); err != nil { + return errors.Wrap(err, "decode field \"risk\"") + } default: return d.Skip() } @@ -26440,7 +26455,7 @@ func (s *MultisigOrder) Decode(d *jx.Decoder) error { // Validate required fields. var failures []validate.FieldError for i, mask := range [1]uint8{ - 0b01111111, + 0b11111111, } { if result := (requiredBitSet[i] & mask) ^ mask; result != 0 { // Mask only required fields and check equality to mask using XOR. diff --git a/pkg/oas/oas_schemas_gen.go b/pkg/oas/oas_schemas_gen.go index 73c19e0b..e68f6905 100644 --- a/pkg/oas/oas_schemas_gen.go +++ b/pkg/oas/oas_schemas_gen.go @@ -8958,6 +8958,7 @@ type MultisigOrder struct { Signers []string `json:"signers"` ApprovalsNum int32 `json:"approvals_num"` ExpirationDate int64 `json:"expiration_date"` + Risk Risk `json:"risk"` } // GetAddress returns the value of Address. @@ -8995,6 +8996,11 @@ func (s *MultisigOrder) GetExpirationDate() int64 { return s.ExpirationDate } +// GetRisk returns the value of Risk. +func (s *MultisigOrder) GetRisk() Risk { + return s.Risk +} + // SetAddress sets the value of Address. func (s *MultisigOrder) SetAddress(val string) { s.Address = val @@ -9030,6 +9036,11 @@ func (s *MultisigOrder) SetExpirationDate(val int64) { s.ExpirationDate = val } +// SetRisk sets the value of Risk. +func (s *MultisigOrder) SetRisk(val Risk) { + s.Risk = val +} + // Ref: #/components/schemas/Multisigs type Multisigs struct { Multisigs []Multisig `json:"multisigs"` diff --git a/pkg/oas/oas_validators_gen.go b/pkg/oas/oas_validators_gen.go index 41a7385f..77e21989 100644 --- a/pkg/oas/oas_validators_gen.go +++ b/pkg/oas/oas_validators_gen.go @@ -3649,6 +3649,17 @@ func (s *MultisigOrder) Validate() error { Error: err, }) } + if err := func() error { + if err := s.Risk.Validate(); err != nil { + return err + } + return nil + }(); err != nil { + failures = append(failures, validate.FieldError{ + Name: "risk", + Error: err, + }) + } if len(failures) > 0 { return &validate.Error{Fields: failures} } diff --git a/pkg/wallet/risk.go b/pkg/wallet/risk.go index 77921591..e3b00419 100644 --- a/pkg/wallet/risk.go +++ b/pkg/wallet/risk.go @@ -8,7 +8,7 @@ import ( "github.com/tonkeeper/tongo/boc" "github.com/tonkeeper/tongo/tlb" "github.com/tonkeeper/tongo/ton" - walletTongo "github.com/tonkeeper/tongo/wallet" + tongoWallet "github.com/tonkeeper/tongo/wallet" ) // Risk specifies assets that could be lost @@ -23,23 +23,28 @@ type Risk struct { Nfts []tongo.AccountID } -func ExtractRisk(version walletTongo.Version, msg *boc.Cell) (*Risk, error) { - rawMessages, err := walletTongo.ExtractRawMessages(version, msg) +func ExtractRisk(version tongoWallet.Version, msg *boc.Cell) (*Risk, error) { + rawMessages, err := tongoWallet.ExtractRawMessages(version, msg) if err != nil { return nil, err } + return ExtractRiskFromRawMessages(rawMessages) +} + +func ExtractRiskFromRawMessages(rawMessages []tongoWallet.RawMessage) (*Risk, error) { risk := Risk{ TransferAllRemainingBalance: false, Jettons: map[tongo.AccountID]big.Int{}, } for _, rawMsg := range rawMessages { - if walletTongo.IsMessageModeSet(int(rawMsg.Mode), walletTongo.AttachAllRemainingBalance) { + if tongoWallet.IsMessageModeSet(int(rawMsg.Mode), tongoWallet.AttachAllRemainingBalance) { risk.TransferAllRemainingBalance = true } var m tlb.Message if err := tlb.Unmarshal(rawMsg.Message, &m); err != nil { return nil, err } + var err error var tonValue uint64 var destination *tongo.AccountID if m.Info.IntMsgInfo != nil {