From 4b7f55ce8f0f3849f40cbd0b330f57359926fe8d Mon Sep 17 00:00:00 2001 From: Alexey Kostenko Date: Mon, 9 Dec 2024 22:15:23 +0300 Subject: [PATCH 1/5] extra balances --- api/openapi.json | 34 +++++ api/openapi.yml | 25 ++++ pkg/api/account_converters.go | 21 +++ pkg/api/account_handlers.go | 6 + pkg/api/wallet_handlers.go | 3 + pkg/oas/oas_json_gen.go | 211 ++++++++++++++++++++++++++++--- pkg/oas/oas_schemas_gen.go | 63 ++++++++- pkg/references/extra_currency.go | 13 ++ 8 files changed, 356 insertions(+), 20 deletions(-) create mode 100644 pkg/references/extra_currency.go diff --git a/api/openapi.json b/api/openapi.json index 03069717..bd3202da 100644 --- a/api/openapi.json +++ b/api/openapi.json @@ -735,6 +735,12 @@ "example": {}, "type": "object" }, + "extra_balance": { + "items": { + "$ref": "#/components/schemas/ExtraCurrency" + }, + "type": "array" + }, "get_methods": { "example": [ "get_item_data" @@ -3229,6 +3235,34 @@ ], "type": "object" }, + "ExtraCurrency": { + "properties": { + "amount": { + "example": "1000000000", + "type": "string", + "x-js-format": "bigint" + }, + "decimals": { + "example": 5, + "type": "integer" + }, + "id": { + "example": 239, + "format": "int32", + "type": "integer" + }, + "name": { + "example": "FMS", + "type": "string" + } + }, + "required": [ + "id", + "amount", + "decimals" + ], + "type": "object" + }, "FoundAccounts": { "properties": { "addresses": { diff --git a/api/openapi.yml b/api/openapi.yml index d7f79500..4b44d770 100644 --- a/api/openapi.yml +++ b/api/openapi.yml @@ -4600,6 +4600,10 @@ components: format: int64 example: 123456789 x-js-format: bigint + extra_balance: + type: array + items: + $ref: '#/components/schemas/ExtraCurrency' currencies_balance: description: "{'USD': 1, 'IDR': 1000}" type: object @@ -7389,6 +7393,27 @@ components: type: integer format: int64 example: 1668436763 + ExtraCurrency: + type: object + required: + - id + - amount + - decimals + properties: + id: + type: integer + example: 239 + format: int32 + amount: + type: string + x-js-format: bigint + example: "1000000000" + name: + type: string + example: FMS + decimals: + type: integer + example: 5 responses: Error: diff --git a/pkg/api/account_converters.go b/pkg/api/account_converters.go index ecf8da84..195f1550 100644 --- a/pkg/api/account_converters.go +++ b/pkg/api/account_converters.go @@ -2,7 +2,9 @@ package api import ( "fmt" + "github.com/shopspring/decimal" imgGenerator "github.com/tonkeeper/opentonapi/pkg/image" + "github.com/tonkeeper/opentonapi/pkg/references" "sort" "github.com/tonkeeper/tongo/abi" @@ -57,6 +59,7 @@ func convertToRawAccount(account *core.Account) (oas.BlockchainRawAccount, error } } if account.ExtraBalances != nil { + // TODO: use int instead of uint? balances := make(map[string]string, len(account.ExtraBalances)) for key, value := range account.ExtraBalances { balances[fmt.Sprintf("%v", key)] = fmt.Sprintf("%v", value) @@ -72,6 +75,24 @@ func convertToRawAccount(account *core.Account) (oas.BlockchainRawAccount, error return rawAccount, nil } +func convertExtraCurrencies(extraBalances map[uint32]decimal.Decimal) []oas.ExtraCurrency { + res := make([]oas.ExtraCurrency, 0, len(extraBalances)) + for k, v := range extraBalances { + cur := oas.ExtraCurrency{ + ID: int32(k), + Amount: v.String(), + Decimals: 9, // TODO: or replace with default const + } + meta, ok := references.ExtraCurrencies[int32(k)] + if ok { + cur.Name.SetTo(meta.Name) + cur.Decimals = meta.Decimals + } + res = append(res, cur) + } + return res +} + func convertToAccount(account *core.Account, ab *addressbook.KnownAddress, state chainState) oas.Account { acc := oas.Account{ Address: account.AccountAddress.ToRaw(), diff --git a/pkg/api/account_handlers.go b/pkg/api/account_handlers.go index bfc1f164..bce4ac8d 100644 --- a/pkg/api/account_handlers.go +++ b/pkg/api/account_handlers.go @@ -72,6 +72,9 @@ func (h *Handler) GetAccount(ctx context.Context, params oas.GetAccountParams) ( } else { res = convertToAccount(rawAccount, nil, h.state) } + if rawAccount.ExtraBalances != nil { + res.ExtraBalance = convertExtraCurrencies(rawAccount.ExtraBalances) + } return &res, nil } @@ -114,6 +117,9 @@ func (h *Handler) GetAccounts(ctx context.Context, request oas.OptGetAccountsReq } else { res = convertToAccount(account, nil, h.state) } + if account.ExtraBalances != nil { + res.ExtraBalance = convertExtraCurrencies(account.ExtraBalances) + } results[account.AccountAddress] = res } // if we don't find an account, we return it with "nonexist" status diff --git a/pkg/api/wallet_handlers.go b/pkg/api/wallet_handlers.go index 77215979..96e085f1 100644 --- a/pkg/api/wallet_handlers.go +++ b/pkg/api/wallet_handlers.go @@ -38,6 +38,9 @@ func (h *Handler) GetWalletsByPublicKey(ctx context.Context, params oas.GetWalle } else { res = convertToAccount(account, nil, h.state) } + if account.ExtraBalances != nil { + res.ExtraBalance = convertExtraCurrencies(account.ExtraBalances) + } results = append(results, res) } return &oas.Accounts{Accounts: results}, nil diff --git a/pkg/oas/oas_json_gen.go b/pkg/oas/oas_json_gen.go index d9780778..a77cd846 100644 --- a/pkg/oas/oas_json_gen.go +++ b/pkg/oas/oas_json_gen.go @@ -71,6 +71,16 @@ func (s *Account) encodeFields(e *jx.Encoder) { e.FieldStart("balance") e.Int64(s.Balance) } + { + if s.ExtraBalance != nil { + e.FieldStart("extra_balance") + e.ArrStart() + for _, elem := range s.ExtraBalance { + elem.Encode(e) + } + e.ArrEnd() + } + } { if s.CurrenciesBalance.Set { e.FieldStart("currencies_balance") @@ -139,20 +149,21 @@ func (s *Account) encodeFields(e *jx.Encoder) { } } -var jsonFieldsNameOfAccount = [13]string{ +var jsonFieldsNameOfAccount = [14]string{ 0: "address", 1: "balance", - 2: "currencies_balance", - 3: "last_activity", - 4: "status", - 5: "interfaces", - 6: "name", - 7: "is_scam", - 8: "icon", - 9: "memo_required", - 10: "get_methods", - 11: "is_suspended", - 12: "is_wallet", + 2: "extra_balance", + 3: "currencies_balance", + 4: "last_activity", + 5: "status", + 6: "interfaces", + 7: "name", + 8: "is_scam", + 9: "icon", + 10: "memo_required", + 11: "get_methods", + 12: "is_suspended", + 13: "is_wallet", } // Decode decodes Account from json. @@ -188,6 +199,23 @@ func (s *Account) Decode(d *jx.Decoder) error { }(); err != nil { return errors.Wrap(err, "decode field \"balance\"") } + case "extra_balance": + if err := func() error { + s.ExtraBalance = make([]ExtraCurrency, 0) + if err := d.Arr(func(d *jx.Decoder) error { + var elem ExtraCurrency + if err := elem.Decode(d); err != nil { + return err + } + s.ExtraBalance = append(s.ExtraBalance, elem) + return nil + }); err != nil { + return err + } + return nil + }(); err != nil { + return errors.Wrap(err, "decode field \"extra_balance\"") + } case "currencies_balance": if err := func() error { s.CurrenciesBalance.Reset() @@ -199,7 +227,7 @@ func (s *Account) Decode(d *jx.Decoder) error { return errors.Wrap(err, "decode field \"currencies_balance\"") } case "last_activity": - requiredBitSet[0] |= 1 << 3 + requiredBitSet[0] |= 1 << 4 if err := func() error { v, err := d.Int64() s.LastActivity = int64(v) @@ -211,7 +239,7 @@ func (s *Account) Decode(d *jx.Decoder) error { return errors.Wrap(err, "decode field \"last_activity\"") } case "status": - requiredBitSet[0] |= 1 << 4 + requiredBitSet[0] |= 1 << 5 if err := func() error { if err := s.Status.Decode(d); err != nil { return err @@ -280,7 +308,7 @@ func (s *Account) Decode(d *jx.Decoder) error { return errors.Wrap(err, "decode field \"memo_required\"") } case "get_methods": - requiredBitSet[1] |= 1 << 2 + requiredBitSet[1] |= 1 << 3 if err := func() error { s.GetMethods = make([]string, 0) if err := d.Arr(func(d *jx.Decoder) error { @@ -310,7 +338,7 @@ func (s *Account) Decode(d *jx.Decoder) error { return errors.Wrap(err, "decode field \"is_suspended\"") } case "is_wallet": - requiredBitSet[1] |= 1 << 4 + requiredBitSet[1] |= 1 << 5 if err := func() error { v, err := d.Bool() s.IsWallet = bool(v) @@ -331,8 +359,8 @@ func (s *Account) Decode(d *jx.Decoder) error { // Validate required fields. var failures []validate.FieldError for i, mask := range [2]uint8{ - 0b00011011, - 0b00010100, + 0b00110011, + 0b00101000, } { if result := (requiredBitSet[i] & mask) ^ mask; result != 0 { // Mask only required fields and check equality to mask using XOR. @@ -15589,6 +15617,153 @@ func (s *Event) UnmarshalJSON(data []byte) error { return s.Decode(d) } +// Encode implements json.Marshaler. +func (s *ExtraCurrency) Encode(e *jx.Encoder) { + e.ObjStart() + s.encodeFields(e) + e.ObjEnd() +} + +// encodeFields encodes fields. +func (s *ExtraCurrency) encodeFields(e *jx.Encoder) { + { + e.FieldStart("id") + e.Int32(s.ID) + } + { + e.FieldStart("amount") + e.Str(s.Amount) + } + { + if s.Name.Set { + e.FieldStart("name") + s.Name.Encode(e) + } + } + { + e.FieldStart("decimals") + e.Int(s.Decimals) + } +} + +var jsonFieldsNameOfExtraCurrency = [4]string{ + 0: "id", + 1: "amount", + 2: "name", + 3: "decimals", +} + +// Decode decodes ExtraCurrency from json. +func (s *ExtraCurrency) Decode(d *jx.Decoder) error { + if s == nil { + return errors.New("invalid: unable to decode ExtraCurrency to nil") + } + var requiredBitSet [1]uint8 + + if err := d.ObjBytes(func(d *jx.Decoder, k []byte) error { + switch string(k) { + case "id": + requiredBitSet[0] |= 1 << 0 + if err := func() error { + v, err := d.Int32() + s.ID = int32(v) + if err != nil { + return err + } + return nil + }(); err != nil { + return errors.Wrap(err, "decode field \"id\"") + } + case "amount": + requiredBitSet[0] |= 1 << 1 + if err := func() error { + v, err := d.Str() + s.Amount = string(v) + if err != nil { + return err + } + return nil + }(); err != nil { + return errors.Wrap(err, "decode field \"amount\"") + } + case "name": + if err := func() error { + s.Name.Reset() + if err := s.Name.Decode(d); err != nil { + return err + } + return nil + }(); err != nil { + return errors.Wrap(err, "decode field \"name\"") + } + case "decimals": + requiredBitSet[0] |= 1 << 3 + if err := func() error { + v, err := d.Int() + s.Decimals = int(v) + if err != nil { + return err + } + return nil + }(); err != nil { + return errors.Wrap(err, "decode field \"decimals\"") + } + default: + return d.Skip() + } + return nil + }); err != nil { + return errors.Wrap(err, "decode ExtraCurrency") + } + // Validate required fields. + var failures []validate.FieldError + for i, mask := range [1]uint8{ + 0b00001011, + } { + 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(jsonFieldsNameOfExtraCurrency) { + name = jsonFieldsNameOfExtraCurrency[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 *ExtraCurrency) MarshalJSON() ([]byte, error) { + e := jx.Encoder{} + s.Encode(&e) + return e.Bytes(), nil +} + +// UnmarshalJSON implements stdjson.Unmarshaler. +func (s *ExtraCurrency) UnmarshalJSON(data []byte) error { + d := jx.DecodeBytes(data) + return s.Decode(d) +} + // Encode implements json.Marshaler. func (s *FoundAccounts) Encode(e *jx.Encoder) { e.ObjStart() diff --git a/pkg/oas/oas_schemas_gen.go b/pkg/oas/oas_schemas_gen.go index 24656402..69932473 100644 --- a/pkg/oas/oas_schemas_gen.go +++ b/pkg/oas/oas_schemas_gen.go @@ -64,8 +64,9 @@ func (s *AccStatusChange) UnmarshalText(data []byte) error { // Ref: #/components/schemas/Account type Account struct { - Address string `json:"address"` - Balance int64 `json:"balance"` + Address string `json:"address"` + Balance int64 `json:"balance"` + ExtraBalance []ExtraCurrency `json:"extra_balance"` // {'USD': 1, 'IDR': 1000}. CurrenciesBalance OptAccountCurrenciesBalance `json:"currencies_balance"` // Unix timestamp. @@ -91,6 +92,11 @@ func (s *Account) GetBalance() int64 { return s.Balance } +// GetExtraBalance returns the value of ExtraBalance. +func (s *Account) GetExtraBalance() []ExtraCurrency { + return s.ExtraBalance +} + // GetCurrenciesBalance returns the value of CurrenciesBalance. func (s *Account) GetCurrenciesBalance() OptAccountCurrenciesBalance { return s.CurrenciesBalance @@ -156,6 +162,11 @@ func (s *Account) SetBalance(val int64) { s.Balance = val } +// SetExtraBalance sets the value of ExtraBalance. +func (s *Account) SetExtraBalance(val []ExtraCurrency) { + s.ExtraBalance = val +} + // SetCurrenciesBalance sets the value of CurrenciesBalance. func (s *Account) SetCurrenciesBalance(val OptAccountCurrenciesBalance) { s.CurrenciesBalance = val @@ -5398,6 +5409,54 @@ func (s *Event) SetInProgress(val bool) { s.InProgress = val } +// Ref: #/components/schemas/ExtraCurrency +type ExtraCurrency struct { + ID int32 `json:"id"` + Amount string `json:"amount"` + Name OptString `json:"name"` + Decimals int `json:"decimals"` +} + +// GetID returns the value of ID. +func (s *ExtraCurrency) GetID() int32 { + return s.ID +} + +// GetAmount returns the value of Amount. +func (s *ExtraCurrency) GetAmount() string { + return s.Amount +} + +// GetName returns the value of Name. +func (s *ExtraCurrency) GetName() OptString { + return s.Name +} + +// GetDecimals returns the value of Decimals. +func (s *ExtraCurrency) GetDecimals() int { + return s.Decimals +} + +// SetID sets the value of ID. +func (s *ExtraCurrency) SetID(val int32) { + s.ID = val +} + +// SetAmount sets the value of Amount. +func (s *ExtraCurrency) SetAmount(val string) { + s.Amount = val +} + +// SetName sets the value of Name. +func (s *ExtraCurrency) SetName(val OptString) { + s.Name = val +} + +// SetDecimals sets the value of Decimals. +func (s *ExtraCurrency) SetDecimals(val int) { + s.Decimals = val +} + // Ref: #/components/schemas/FoundAccounts type FoundAccounts struct { Addresses []FoundAccountsAddressesItem `json:"addresses"` diff --git a/pkg/references/extra_currency.go b/pkg/references/extra_currency.go new file mode 100644 index 00000000..5aea713e --- /dev/null +++ b/pkg/references/extra_currency.go @@ -0,0 +1,13 @@ +package references + +type ExtraCurrencyMeta struct { + Name string + Decimals int +} + +var ExtraCurrencies = map[int32]ExtraCurrencyMeta{ + 239: { + Name: "FMS", + Decimals: 5, + }, +} From 9782db5037dd5e397184fae5b8ad872fb5c9f99a Mon Sep 17 00:00:00 2001 From: Alexey Kostenko Date: Mon, 9 Dec 2024 23:23:13 +0300 Subject: [PATCH 2/5] extra value for messages --- api/openapi.json | 6 +++ api/openapi.yml | 4 ++ pkg/api/account_converters.go | 3 +- pkg/api/blockchain_converters.go | 3 ++ pkg/core/account.go | 3 +- pkg/core/converters.go | 25 +++++++----- pkg/core/extra_currencies.go | 5 +++ pkg/core/transactions.go | 1 + pkg/oas/oas_json_gen.go | 68 ++++++++++++++++++++++---------- pkg/oas/oas_schemas_gen.go | 11 ++++++ 10 files changed, 96 insertions(+), 33 deletions(-) create mode 100644 pkg/core/extra_currencies.go diff --git a/api/openapi.json b/api/openapi.json index bd3202da..2303873e 100644 --- a/api/openapi.json +++ b/api/openapi.json @@ -4211,6 +4211,12 @@ "format": "int64", "type": "integer", "x-js-format": "bigint" + }, + "value_extra": { + "items": { + "$ref": "#/components/schemas/ExtraCurrency" + }, + "type": "array" } }, "required": [ diff --git a/api/openapi.yml b/api/openapi.yml index 4b44d770..2664866b 100644 --- a/api/openapi.yml +++ b/api/openapi.yml @@ -3723,6 +3723,10 @@ components: format: int64 x-js-format: bigint example: 60000000 + value_extra: + type: array + items: + $ref: '#/components/schemas/ExtraCurrency' fwd_fee: type: integer format: int64 diff --git a/pkg/api/account_converters.go b/pkg/api/account_converters.go index 195f1550..629da136 100644 --- a/pkg/api/account_converters.go +++ b/pkg/api/account_converters.go @@ -2,7 +2,6 @@ package api import ( "fmt" - "github.com/shopspring/decimal" imgGenerator "github.com/tonkeeper/opentonapi/pkg/image" "github.com/tonkeeper/opentonapi/pkg/references" "sort" @@ -75,7 +74,7 @@ func convertToRawAccount(account *core.Account) (oas.BlockchainRawAccount, error return rawAccount, nil } -func convertExtraCurrencies(extraBalances map[uint32]decimal.Decimal) []oas.ExtraCurrency { +func convertExtraCurrencies(extraBalances core.ExtraCurrencies) []oas.ExtraCurrency { res := make([]oas.ExtraCurrency, 0, len(extraBalances)) for k, v := range extraBalances { cur := oas.ExtraCurrency{ diff --git a/pkg/api/blockchain_converters.go b/pkg/api/blockchain_converters.go index a3920d18..8e79d6f1 100644 --- a/pkg/api/blockchain_converters.go +++ b/pkg/api/blockchain_converters.go @@ -269,6 +269,9 @@ func convertMessage(m core.Message, book addressBook) oas.Message { value, _ := json.Marshal(m.DecodedBody.Value) msg.DecodedBody = g.ChangeJsonKeys(value, g.CamelToSnake) } + if m.ValueExtra != nil { + msg.ValueExtra = convertExtraCurrencies(m.ValueExtra) + } return msg } diff --git a/pkg/core/account.go b/pkg/core/account.go index 2d5942ef..645e8b4c 100644 --- a/pkg/core/account.go +++ b/pkg/core/account.go @@ -6,7 +6,6 @@ import ( "github.com/tonkeeper/tongo/abi" "github.com/tonkeeper/tongo/ton" - "github.com/shopspring/decimal" "github.com/tonkeeper/tongo/tlb" ) @@ -15,7 +14,7 @@ type Account struct { AccountAddress ton.AccountID Status tlb.AccountStatus TonBalance int64 - ExtraBalances map[uint32]decimal.Decimal + ExtraBalances ExtraCurrencies LastTransactionLt uint64 LastTransactionHash ton.Bits256 Code []byte diff --git a/pkg/core/converters.go b/pkg/core/converters.go index 08e8a03e..94ac61ce 100644 --- a/pkg/core/converters.go +++ b/pkg/core/converters.go @@ -313,6 +313,7 @@ func ConvertMessage(message tlb.Message, txLT uint64, cd *abi.ContractDescriptio if err != nil { return Message{}, err } + return Message{ MessageID: MessageID{ CreatedLt: info.CreatedLt, @@ -324,6 +325,7 @@ func ConvertMessage(message tlb.Message, txLT uint64, cd *abi.ContractDescriptio Bounce: info.Bounce, Bounced: info.Bounced, Value: int64(info.Value.Grams), + ValueExtra: extractExtraCurrencies(info.Value.Other), FwdFee: int64(info.FwdFee), IhrFee: int64(info.IhrFee), ImportFee: 0, @@ -434,15 +436,7 @@ func ConvertToAccount(accountId tongo.AccountID, shardAccount tlb.ShardAccount) } balance := acc.Account.Storage.Balance res.TonBalance = int64(balance.Grams) - items := balance.Other.Dict.Items() - if len(items) > 0 { - otherBalances := make(map[uint32]decimal.Decimal, len(items)) - for _, item := range items { - value := big.Int(item.Value) - otherBalances[uint32(item.Key)] = decimal.NewFromBigInt(&value, 0) - } - res.ExtraBalances = otherBalances - } + res.ExtraBalances = extractExtraCurrencies(balance.Other) res.LastTransactionLt = shardAccount.LastTransLt res.LastTransactionHash = tongo.Bits256(shardAccount.LastTransHash) if acc.Account.Storage.State.SumType == "AccountUninit" { @@ -481,6 +475,19 @@ func ConvertToAccount(accountId tongo.AccountID, shardAccount tlb.ShardAccount) return res, nil } +func extractExtraCurrencies(extraCurrencyCollection tlb.ExtraCurrencyCollection) ExtraCurrencies { + items := extraCurrencyCollection.Dict.Items() + if len(items) > 0 { + res := make(map[uint32]decimal.Decimal, len(items)) + for _, item := range items { + value := big.Int(item.Value) + res[uint32(item.Key)] = decimal.NewFromBigInt(&value, 0) + } + return res + } + return nil // TODO: or return empty map +} + func ExtractTransactions(id tongo.BlockIDExt, block *tlb.Block) ([]*Transaction, error) { rawTransactions := block.AllTransactions() transactions := make([]*Transaction, 0, len(rawTransactions)) diff --git a/pkg/core/extra_currencies.go b/pkg/core/extra_currencies.go new file mode 100644 index 00000000..9101a526 --- /dev/null +++ b/pkg/core/extra_currencies.go @@ -0,0 +1,5 @@ +package core + +import "github.com/shopspring/decimal" + +type ExtraCurrencies map[uint32]decimal.Decimal diff --git a/pkg/core/transactions.go b/pkg/core/transactions.go index 77f70930..fe056c6f 100644 --- a/pkg/core/transactions.go +++ b/pkg/core/transactions.go @@ -163,6 +163,7 @@ type Message struct { Bounce bool Bounced bool Value int64 + ValueExtra ExtraCurrencies FwdFee int64 IhrFee int64 ImportFee int64 diff --git a/pkg/oas/oas_json_gen.go b/pkg/oas/oas_json_gen.go index a77cd846..cd5c6f80 100644 --- a/pkg/oas/oas_json_gen.go +++ b/pkg/oas/oas_json_gen.go @@ -25751,6 +25751,16 @@ func (s *Message) encodeFields(e *jx.Encoder) { e.FieldStart("value") e.Int64(s.Value) } + { + if s.ValueExtra != nil { + e.FieldStart("value_extra") + e.ArrStart() + for _, elem := range s.ValueExtra { + elem.Encode(e) + } + e.ArrEnd() + } + } { e.FieldStart("fwd_fee") e.Int64(s.FwdFee) @@ -25815,25 +25825,26 @@ func (s *Message) encodeFields(e *jx.Encoder) { } } -var jsonFieldsNameOfMessage = [18]string{ +var jsonFieldsNameOfMessage = [19]string{ 0: "msg_type", 1: "created_lt", 2: "ihr_disabled", 3: "bounce", 4: "bounced", 5: "value", - 6: "fwd_fee", - 7: "ihr_fee", - 8: "destination", - 9: "source", - 10: "import_fee", - 11: "created_at", - 12: "op_code", - 13: "init", - 14: "hash", - 15: "raw_body", - 16: "decoded_op_name", - 17: "decoded_body", + 6: "value_extra", + 7: "fwd_fee", + 8: "ihr_fee", + 9: "destination", + 10: "source", + 11: "import_fee", + 12: "created_at", + 13: "op_code", + 14: "init", + 15: "hash", + 16: "raw_body", + 17: "decoded_op_name", + 18: "decoded_body", } // Decode decodes Message from json. @@ -25915,8 +25926,25 @@ func (s *Message) Decode(d *jx.Decoder) error { }(); err != nil { return errors.Wrap(err, "decode field \"value\"") } + case "value_extra": + if err := func() error { + s.ValueExtra = make([]ExtraCurrency, 0) + if err := d.Arr(func(d *jx.Decoder) error { + var elem ExtraCurrency + if err := elem.Decode(d); err != nil { + return err + } + s.ValueExtra = append(s.ValueExtra, elem) + return nil + }); err != nil { + return err + } + return nil + }(); err != nil { + return errors.Wrap(err, "decode field \"value_extra\"") + } case "fwd_fee": - requiredBitSet[0] |= 1 << 6 + requiredBitSet[0] |= 1 << 7 if err := func() error { v, err := d.Int64() s.FwdFee = int64(v) @@ -25928,7 +25956,7 @@ func (s *Message) Decode(d *jx.Decoder) error { return errors.Wrap(err, "decode field \"fwd_fee\"") } case "ihr_fee": - requiredBitSet[0] |= 1 << 7 + requiredBitSet[1] |= 1 << 0 if err := func() error { v, err := d.Int64() s.IhrFee = int64(v) @@ -25960,7 +25988,7 @@ func (s *Message) Decode(d *jx.Decoder) error { return errors.Wrap(err, "decode field \"source\"") } case "import_fee": - requiredBitSet[1] |= 1 << 2 + requiredBitSet[1] |= 1 << 3 if err := func() error { v, err := d.Int64() s.ImportFee = int64(v) @@ -25972,7 +26000,7 @@ func (s *Message) Decode(d *jx.Decoder) error { return errors.Wrap(err, "decode field \"import_fee\"") } case "created_at": - requiredBitSet[1] |= 1 << 3 + requiredBitSet[1] |= 1 << 4 if err := func() error { v, err := d.Int64() s.CreatedAt = int64(v) @@ -26004,7 +26032,7 @@ func (s *Message) Decode(d *jx.Decoder) error { return errors.Wrap(err, "decode field \"init\"") } case "hash": - requiredBitSet[1] |= 1 << 6 + requiredBitSet[1] |= 1 << 7 if err := func() error { v, err := d.Str() s.Hash = string(v) @@ -26056,8 +26084,8 @@ func (s *Message) Decode(d *jx.Decoder) error { // Validate required fields. var failures []validate.FieldError for i, mask := range [3]uint8{ - 0b11111111, - 0b01001100, + 0b10111111, + 0b10011001, 0b00000000, } { if result := (requiredBitSet[i] & mask) ^ mask; result != 0 { diff --git a/pkg/oas/oas_schemas_gen.go b/pkg/oas/oas_schemas_gen.go index 69932473..87118f3b 100644 --- a/pkg/oas/oas_schemas_gen.go +++ b/pkg/oas/oas_schemas_gen.go @@ -8588,6 +8588,7 @@ type Message struct { Bounce bool `json:"bounce"` Bounced bool `json:"bounced"` Value int64 `json:"value"` + ValueExtra []ExtraCurrency `json:"value_extra"` FwdFee int64 `json:"fwd_fee"` IhrFee int64 `json:"ihr_fee"` Destination OptAccountAddress `json:"destination"` @@ -8633,6 +8634,11 @@ func (s *Message) GetValue() int64 { return s.Value } +// GetValueExtra returns the value of ValueExtra. +func (s *Message) GetValueExtra() []ExtraCurrency { + return s.ValueExtra +} + // GetFwdFee returns the value of FwdFee. func (s *Message) GetFwdFee() int64 { return s.FwdFee @@ -8723,6 +8729,11 @@ func (s *Message) SetValue(val int64) { s.Value = val } +// SetValueExtra sets the value of ValueExtra. +func (s *Message) SetValueExtra(val []ExtraCurrency) { + s.ValueExtra = val +} + // SetFwdFee sets the value of FwdFee. func (s *Message) SetFwdFee(val int64) { s.FwdFee = val From 30eb0a1f208b7a2501a5bb3beaf475fce29719d8 Mon Sep 17 00:00:00 2001 From: Alexey Kostenko Date: Tue, 10 Dec 2024 13:32:41 +0300 Subject: [PATCH 3/5] int32 instead of uint32 for currency_id --- pkg/api/account_converters.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/pkg/api/account_converters.go b/pkg/api/account_converters.go index 629da136..7ea08294 100644 --- a/pkg/api/account_converters.go +++ b/pkg/api/account_converters.go @@ -58,10 +58,9 @@ func convertToRawAccount(account *core.Account) (oas.BlockchainRawAccount, error } } if account.ExtraBalances != nil { - // TODO: use int instead of uint? balances := make(map[string]string, len(account.ExtraBalances)) for key, value := range account.ExtraBalances { - balances[fmt.Sprintf("%v", key)] = fmt.Sprintf("%v", value) + balances[fmt.Sprintf("%v", int32(key))] = fmt.Sprintf("%v", value) } rawAccount.ExtraBalance = oas.NewOptBlockchainRawAccountExtraBalance(balances) } From 4a2d6c8801e305176a8ea7c380a2816355c0e576 Mon Sep 17 00:00:00 2001 From: Alexey Kostenko Date: Tue, 10 Dec 2024 22:34:05 +0300 Subject: [PATCH 4/5] extra currency transfer action --- api/openapi.json | 67 +++++ api/openapi.yml | 49 ++++ pkg/api/account_converters.go | 16 +- pkg/api/event_converters.go | 34 +++ pkg/bath/actions.go | 11 + pkg/bath/bubble.go | 2 + pkg/bath/bubble_tx.go | 73 +++-- pkg/core/converters.go | 8 +- pkg/core/extra_currencies.go | 6 +- pkg/oas/oas_json_gen.go | 446 +++++++++++++++++++++++++++++-- pkg/oas/oas_schemas_gen.go | 194 ++++++++++++++ pkg/oas/oas_validators_gen.go | 50 ++++ pkg/references/extra_currency.go | 18 +- 13 files changed, 907 insertions(+), 67 deletions(-) diff --git a/api/openapi.json b/api/openapi.json index 2303873e..8bd64cc6 100644 --- a/api/openapi.json +++ b/api/openapi.json @@ -1063,6 +1063,9 @@ "ElectionsRecoverStake": { "$ref": "#/components/schemas/ElectionsRecoverStakeAction" }, + "ExtraCurrencyTransfer": { + "$ref": "#/components/schemas/ExtraCurrencyTransferAction" + }, "InscriptionMint": { "$ref": "#/components/schemas/InscriptionMintAction" }, @@ -1127,6 +1130,7 @@ "type": { "enum": [ "TonTransfer", + "ExtraCurrencyTransfer", "JettonTransfer", "JettonBurn", "JettonMint", @@ -3119,6 +3123,33 @@ ], "type": "object" }, + "EcPreview": { + "properties": { + "decimals": { + "example": 5, + "type": "integer" + }, + "image": { + "example": "https://cache.tonapi.io/images/extra.jpg", + "type": "string" + }, + "name": { + "example": "FMS", + "type": "string" + }, + "symbol": { + "example": "FMS", + "type": "string" + } + }, + "required": [ + "name", + "symbol", + "decimals", + "image" + ], + "type": "object" + }, "ElectionsDepositStakeAction": { "properties": { "amount": { @@ -3263,6 +3294,42 @@ ], "type": "object" }, + "ExtraCurrencyTransferAction": { + "properties": { + "amount": { + "description": "amount in quanta of tokens", + "example": "1000000000", + "type": "string", + "x-js-format": "bigint" + }, + "comment": { + "example": "Hi! This is your salary. \nFrom accounting with love.", + "type": "string" + }, + "currency": { + "$ref": "#/components/schemas/EcPreview" + }, + "encrypted_comment": { + "$ref": "#/components/schemas/EncryptedComment" + }, + "recipient": { + "$ref": "#/components/schemas/AccountAddress" + }, + "refund": { + "$ref": "#/components/schemas/Refund" + }, + "sender": { + "$ref": "#/components/schemas/AccountAddress" + } + }, + "required": [ + "sender", + "recipient", + "amount", + "currency" + ], + "type": "object" + }, "FoundAccounts": { "properties": { "addresses": { diff --git a/api/openapi.yml b/api/openapi.yml index 2664866b..b78bd48a 100644 --- a/api/openapi.yml +++ b/api/openapi.yml @@ -5744,6 +5744,7 @@ components: example: "TonTransfer" enum: - TonTransfer + - ExtraCurrencyTransfer - JettonTransfer - JettonBurn - JettonMint @@ -5772,6 +5773,8 @@ components: - failed TonTransfer: $ref: '#/components/schemas/TonTransferAction' + ExtraCurrencyTransfer: + $ref: '#/components/schemas/ExtraCurrencyTransferAction' ContractDeploy: $ref: '#/components/schemas/ContractDeployAction' JettonTransfer: @@ -5842,6 +5845,52 @@ components: $ref: '#/components/schemas/EncryptedComment' refund: $ref: '#/components/schemas/Refund' + EcPreview: + type: object + required: + - name + - symbol + - decimals + - image + properties: + name: + type: string + example: FMS + symbol: + type: string + example: FMS + decimals: + type: integer + example: 5 + image: + type: string + example: https://cache.tonapi.io/images/extra.jpg + ExtraCurrencyTransferAction: + type: object + required: + - sender + - recipient + - amount + - currency + properties: + sender: + $ref: '#/components/schemas/AccountAddress' + recipient: + $ref: '#/components/schemas/AccountAddress' + amount: + type: string + x-js-format: bigint + example: "1000000000" + description: amount in quanta of tokens + comment: + type: string + example: "Hi! This is your salary. \nFrom accounting with love." + encrypted_comment: + $ref: '#/components/schemas/EncryptedComment' + refund: + $ref: '#/components/schemas/Refund' + currency: + $ref: '#/components/schemas/EcPreview' SmartContractAction: type: object required: diff --git a/pkg/api/account_converters.go b/pkg/api/account_converters.go index 7ea08294..656c2883 100644 --- a/pkg/api/account_converters.go +++ b/pkg/api/account_converters.go @@ -4,6 +4,7 @@ import ( "fmt" imgGenerator "github.com/tonkeeper/opentonapi/pkg/image" "github.com/tonkeeper/opentonapi/pkg/references" + "math/big" "sort" "github.com/tonkeeper/tongo/abi" @@ -60,7 +61,8 @@ func convertToRawAccount(account *core.Account) (oas.BlockchainRawAccount, error if account.ExtraBalances != nil { balances := make(map[string]string, len(account.ExtraBalances)) for key, value := range account.ExtraBalances { - balances[fmt.Sprintf("%v", int32(key))] = fmt.Sprintf("%v", value) + v := big.Int(value) + balances[fmt.Sprintf("%v", key)] = fmt.Sprintf("%v", v.String()) } rawAccount.ExtraBalance = oas.NewOptBlockchainRawAccountExtraBalance(balances) } @@ -76,15 +78,15 @@ func convertToRawAccount(account *core.Account) (oas.BlockchainRawAccount, error func convertExtraCurrencies(extraBalances core.ExtraCurrencies) []oas.ExtraCurrency { res := make([]oas.ExtraCurrency, 0, len(extraBalances)) for k, v := range extraBalances { + amount := big.Int(v) + meta := references.GetExtraCurrencyMeta(k) cur := oas.ExtraCurrency{ - ID: int32(k), - Amount: v.String(), - Decimals: 9, // TODO: or replace with default const + ID: k, + Amount: amount.String(), + Decimals: meta.Decimals, } - meta, ok := references.ExtraCurrencies[int32(k)] - if ok { + if meta.Name != "" { cur.Name.SetTo(meta.Name) - cur.Decimals = meta.Decimals } res = append(res, cur) } diff --git a/pkg/api/event_converters.go b/pkg/api/event_converters.go index e265a5c8..7f3dc857 100644 --- a/pkg/api/event_converters.go +++ b/pkg/api/event_converters.go @@ -151,6 +151,38 @@ func (h *Handler) convertActionTonTransfer(t *bath.TonTransferAction, acceptLang return action, simplePreview } +func (h *Handler) convertActionExtraCurrencyTransfer(t *bath.ExtraCurrencyTransferAction, acceptLanguage string, viewer *tongo.AccountID) (oas.OptExtraCurrencyTransferAction, oas.ActionSimplePreview) { + var action oas.OptExtraCurrencyTransferAction + amount := big.Int(t.Amount) + meta := references.GetExtraCurrencyMeta(t.CurrencyID) + action.SetTo(oas.ExtraCurrencyTransferAction{ + Amount: amount.String(), + Comment: g.Opt(t.Comment), + Recipient: convertAccountAddress(t.Recipient, h.addressBook), + Sender: convertAccountAddress(t.Sender, h.addressBook), + EncryptedComment: convertEncryptedComment(t.EncryptedComment), + Currency: oas.EcPreview{ + Name: meta.Name, + Symbol: meta.Symbol, + Decimals: meta.Decimals, + Image: meta.Image, + }, + }) + if t.Refund != nil { + action.Value.Refund.SetTo(oas.Refund{ + Type: oas.RefundType(t.Refund.Type), + Origin: t.Refund.Origin, + }) + } + simplePreview := oas.ActionSimplePreview{ + Name: "Extra Currency Transfer", + Description: "", // TODO: add description + Accounts: distinctAccounts(viewer, h.addressBook, &t.Sender, &t.Recipient), + // TODO: add value + } + return action, simplePreview +} + func (h *Handler) convertActionNftTransfer(t *bath.NftTransferAction, acceptLanguage string, viewer *tongo.AccountID) (oas.OptNftItemTransferAction, oas.ActionSimplePreview) { var action oas.OptNftItemTransferAction action.SetTo(oas.NftItemTransferAction{ @@ -428,6 +460,8 @@ func (h *Handler) convertAction(ctx context.Context, viewer *tongo.AccountID, a switch a.Type { case bath.TonTransfer: action.TonTransfer, action.SimplePreview = h.convertActionTonTransfer(a.TonTransfer, acceptLanguage.Value, viewer) + case bath.ExtraCurrencyTransfer: + action.ExtraCurrencyTransfer, action.SimplePreview = h.convertActionExtraCurrencyTransfer(a.ExtraCurrencyTransfer, acceptLanguage.Value, viewer) case bath.NftItemTransfer: action.NftItemTransfer, action.SimplePreview = h.convertActionNftTransfer(a.NftItemTransfer, acceptLanguage.Value, viewer) case bath.JettonTransfer: diff --git a/pkg/bath/actions.go b/pkg/bath/actions.go index 0b1dee5d..68d53890 100644 --- a/pkg/bath/actions.go +++ b/pkg/bath/actions.go @@ -19,6 +19,7 @@ import ( const ( TonTransfer ActionType = "TonTransfer" + ExtraCurrencyTransfer ActionType = "ExtraCurrencyTransfer" SmartContractExec ActionType = "SmartContractExec" NftItemTransfer ActionType = "NftItemTransfer" NftPurchase ActionType = "NftPurchase" @@ -69,6 +70,7 @@ type ( Action struct { TonTransfer *TonTransferAction `json:",omitempty"` + ExtraCurrencyTransfer *ExtraCurrencyTransferAction `json:",omitempty"` SmartContractExec *SmartContractAction `json:",omitempty"` NftItemTransfer *NftTransferAction `json:",omitempty"` NftPurchase *NftPurchaseAction `json:",omitempty"` @@ -101,6 +103,15 @@ type ( Sender tongo.AccountID Refund *Refund } + ExtraCurrencyTransferAction struct { + CurrencyID int32 + Amount tlb.VarUInteger32 + Comment *string + EncryptedComment *EncryptedComment + Recipient tongo.AccountID + Sender tongo.AccountID + Refund *Refund + } SmartContractAction struct { TonAttached int64 Executor tongo.AccountID diff --git a/pkg/bath/bubble.go b/pkg/bath/bubble.go index 9adae96c..6a274fee 100644 --- a/pkg/bath/bubble.go +++ b/pkg/bath/bubble.go @@ -78,6 +78,7 @@ func fromTrace(trace *core.Trace) *Bubble { btx.bounced = msg.Bounced btx.inputAmount += msg.Value btx.inputAmount += msg.IhrFee + btx.inputExtraAmount = msg.ValueExtra btx.opCode = msg.OpCode btx.decodedBody = msg.DecodedBody btx.inputFrom = source @@ -95,6 +96,7 @@ func fromTrace(trace *core.Trace) *Bubble { Children: make([]*Bubble, len(trace.Children)), ValueFlow: &ValueFlow{ Accounts: map[tongo.AccountID]*AccountValueFlow{ + // TODO: add extra currency trace.Account: { Ton: inputAmount, }, diff --git a/pkg/bath/bubble_tx.go b/pkg/bath/bubble_tx.go index 7f60e231..6ee55fb1 100644 --- a/pkg/bath/bubble_tx.go +++ b/pkg/bath/bubble_tx.go @@ -2,24 +2,24 @@ package bath import ( "fmt" - "github.com/ghodss/yaml" "github.com/tonkeeper/opentonapi/pkg/core" "github.com/tonkeeper/tongo/abi" ) type BubbleTx struct { - success bool - transactionType core.TransactionType - inputAmount int64 - inputFrom *Account - bounce bool - bounced bool - external bool - account Account - opCode *uint32 - decodedBody *core.DecodedMessageBody - init []byte + success bool + transactionType core.TransactionType + inputAmount int64 + inputExtraAmount core.ExtraCurrencies + inputFrom *Account + bounce bool + bounced bool + external bool + account Account + opCode *uint32 + decodedBody *core.DecodedMessageBody + init []byte additionalInfo *core.TraceAdditionalInfo accountWasActiveAtComputingTime bool @@ -52,7 +52,7 @@ func (b BubbleTx) ToAction() *Action { } return nil } - if b.opCode != nil && (*b.opCode != 0 && !b.operation(abi.EncryptedTextCommentMsgOp)) && b.accountWasActiveAtComputingTime && !b.account.Is(abi.Wallet) { + if b.opCode != nil && (*b.opCode != 0 && !b.operation(abi.EncryptedTextCommentMsgOp)) && b.accountWasActiveAtComputingTime && !b.account.Is(abi.Wallet) && len(b.inputExtraAmount) == 0 { operation := fmt.Sprintf("0x%08x", *b.opCode) payload := "" if b.decodedBody != nil { @@ -71,25 +71,48 @@ func (b BubbleTx) ToAction() *Action { Type: SmartContractExec, } } - a := &Action{ - TonTransfer: &TonTransferAction{ - Amount: b.inputAmount, - Recipient: b.account.Address, - Sender: b.inputFrom.Address, //can't be null because we check IsExternal - }, - Success: true, - Type: TonTransfer, - } + var ( + comment *string + encryptedComment *EncryptedComment + ) if b.decodedBody != nil { switch s := b.decodedBody.Value.(type) { case abi.TextCommentMsgBody: converted := string(s.Text) - a.TonTransfer.Comment = &converted + comment = &converted case abi.EncryptedTextCommentMsgBody: - a.TonTransfer.EncryptedComment = &EncryptedComment{EncryptionType: "simple", CipherText: s.CipherText} + encryptedComment = &EncryptedComment{EncryptionType: "simple", CipherText: s.CipherText} } } - return a + if len(b.inputExtraAmount) > 0 { + action := Action{ + ExtraCurrencyTransfer: &ExtraCurrencyTransferAction{ + Recipient: b.account.Address, + Sender: b.inputFrom.Address, //can't be null because we check IsExternal + Comment: comment, + EncryptedComment: encryptedComment, + }, + Success: true, + Type: ExtraCurrencyTransfer, + } + for id, amount := range b.inputExtraAmount { + action.ExtraCurrencyTransfer.CurrencyID = id + action.ExtraCurrencyTransfer.Amount = amount + break // TODO: extract more than one currency + } + return &action + } + return &Action{ + TonTransfer: &TonTransferAction{ + Amount: b.inputAmount, + Recipient: b.account.Address, + Sender: b.inputFrom.Address, //can't be null because we check IsExternal + Comment: comment, + EncryptedComment: encryptedComment, + }, + Success: true, + Type: TonTransfer, + } } func (b BubbleTx) operation(name string) bool { diff --git a/pkg/core/converters.go b/pkg/core/converters.go index 94ac61ce..c9184801 100644 --- a/pkg/core/converters.go +++ b/pkg/core/converters.go @@ -5,7 +5,6 @@ import ( "math/big" "sort" - "github.com/shopspring/decimal" "github.com/tonkeeper/tongo" "github.com/tonkeeper/tongo/abi" "github.com/tonkeeper/tongo/boc" @@ -478,14 +477,13 @@ func ConvertToAccount(accountId tongo.AccountID, shardAccount tlb.ShardAccount) func extractExtraCurrencies(extraCurrencyCollection tlb.ExtraCurrencyCollection) ExtraCurrencies { items := extraCurrencyCollection.Dict.Items() if len(items) > 0 { - res := make(map[uint32]decimal.Decimal, len(items)) + res := make(map[int32]tlb.VarUInteger32, len(items)) for _, item := range items { - value := big.Int(item.Value) - res[uint32(item.Key)] = decimal.NewFromBigInt(&value, 0) + res[int32(item.Key)] = item.Value } return res } - return nil // TODO: or return empty map + return nil } func ExtractTransactions(id tongo.BlockIDExt, block *tlb.Block) ([]*Transaction, error) { diff --git a/pkg/core/extra_currencies.go b/pkg/core/extra_currencies.go index 9101a526..dc9a8fa2 100644 --- a/pkg/core/extra_currencies.go +++ b/pkg/core/extra_currencies.go @@ -1,5 +1,7 @@ package core -import "github.com/shopspring/decimal" +import ( + "github.com/tonkeeper/tongo/tlb" +) -type ExtraCurrencies map[uint32]decimal.Decimal +type ExtraCurrencies map[int32]tlb.VarUInteger32 diff --git a/pkg/oas/oas_json_gen.go b/pkg/oas/oas_json_gen.go index cd5c6f80..97071c2a 100644 --- a/pkg/oas/oas_json_gen.go +++ b/pkg/oas/oas_json_gen.go @@ -1694,6 +1694,12 @@ func (s *Action) encodeFields(e *jx.Encoder) { s.TonTransfer.Encode(e) } } + { + if s.ExtraCurrencyTransfer.Set { + e.FieldStart("ExtraCurrencyTransfer") + s.ExtraCurrencyTransfer.Encode(e) + } + } { if s.ContractDeploy.Set { e.FieldStart("ContractDeploy") @@ -1822,31 +1828,32 @@ func (s *Action) encodeFields(e *jx.Encoder) { } } -var jsonFieldsNameOfAction = [24]string{ +var jsonFieldsNameOfAction = [25]string{ 0: "type", 1: "status", 2: "TonTransfer", - 3: "ContractDeploy", - 4: "JettonTransfer", - 5: "JettonBurn", - 6: "JettonMint", - 7: "NftItemTransfer", - 8: "Subscribe", - 9: "UnSubscribe", - 10: "AuctionBid", - 11: "NftPurchase", - 12: "DepositStake", - 13: "WithdrawStake", - 14: "WithdrawStakeRequest", - 15: "ElectionsDepositStake", - 16: "ElectionsRecoverStake", - 17: "JettonSwap", - 18: "SmartContractExec", - 19: "DomainRenew", - 20: "InscriptionTransfer", - 21: "InscriptionMint", - 22: "simple_preview", - 23: "base_transactions", + 3: "ExtraCurrencyTransfer", + 4: "ContractDeploy", + 5: "JettonTransfer", + 6: "JettonBurn", + 7: "JettonMint", + 8: "NftItemTransfer", + 9: "Subscribe", + 10: "UnSubscribe", + 11: "AuctionBid", + 12: "NftPurchase", + 13: "DepositStake", + 14: "WithdrawStake", + 15: "WithdrawStakeRequest", + 16: "ElectionsDepositStake", + 17: "ElectionsRecoverStake", + 18: "JettonSwap", + 19: "SmartContractExec", + 20: "DomainRenew", + 21: "InscriptionTransfer", + 22: "InscriptionMint", + 23: "simple_preview", + 24: "base_transactions", } // Decode decodes Action from json. @@ -1854,7 +1861,7 @@ func (s *Action) Decode(d *jx.Decoder) error { if s == nil { return errors.New("invalid: unable to decode Action to nil") } - var requiredBitSet [3]uint8 + var requiredBitSet [4]uint8 if err := d.ObjBytes(func(d *jx.Decoder, k []byte) error { switch string(k) { @@ -1888,6 +1895,16 @@ func (s *Action) Decode(d *jx.Decoder) error { }(); err != nil { return errors.Wrap(err, "decode field \"TonTransfer\"") } + case "ExtraCurrencyTransfer": + if err := func() error { + s.ExtraCurrencyTransfer.Reset() + if err := s.ExtraCurrencyTransfer.Decode(d); err != nil { + return err + } + return nil + }(); err != nil { + return errors.Wrap(err, "decode field \"ExtraCurrencyTransfer\"") + } case "ContractDeploy": if err := func() error { s.ContractDeploy.Reset() @@ -2079,7 +2096,7 @@ func (s *Action) Decode(d *jx.Decoder) error { return errors.Wrap(err, "decode field \"InscriptionMint\"") } case "simple_preview": - requiredBitSet[2] |= 1 << 6 + requiredBitSet[2] |= 1 << 7 if err := func() error { if err := s.SimplePreview.Decode(d); err != nil { return err @@ -2089,7 +2106,7 @@ func (s *Action) Decode(d *jx.Decoder) error { return errors.Wrap(err, "decode field \"simple_preview\"") } case "base_transactions": - requiredBitSet[2] |= 1 << 7 + requiredBitSet[3] |= 1 << 0 if err := func() error { s.BaseTransactions = make([]string, 0) if err := d.Arr(func(d *jx.Decoder) error { @@ -2117,10 +2134,11 @@ func (s *Action) Decode(d *jx.Decoder) error { } // Validate required fields. var failures []validate.FieldError - for i, mask := range [3]uint8{ + for i, mask := range [4]uint8{ 0b00000011, 0b00000000, - 0b11000000, + 0b10000000, + 0b00000001, } { if result := (requiredBitSet[i] & mask) ^ mask; result != 0 { // Mask only required fields and check equality to mask using XOR. @@ -2613,6 +2631,8 @@ func (s *ActionType) Decode(d *jx.Decoder) error { switch ActionType(v) { case ActionTypeTonTransfer: *s = ActionTypeTonTransfer + case ActionTypeExtraCurrencyTransfer: + *s = ActionTypeExtraCurrencyTransfer case ActionTypeJettonTransfer: *s = ActionTypeJettonTransfer case ActionTypeJettonBurn: @@ -14426,6 +14446,153 @@ func (s *DomainRenewAction) UnmarshalJSON(data []byte) error { return s.Decode(d) } +// Encode implements json.Marshaler. +func (s *EcPreview) Encode(e *jx.Encoder) { + e.ObjStart() + s.encodeFields(e) + e.ObjEnd() +} + +// encodeFields encodes fields. +func (s *EcPreview) encodeFields(e *jx.Encoder) { + { + e.FieldStart("name") + e.Str(s.Name) + } + { + e.FieldStart("symbol") + e.Str(s.Symbol) + } + { + e.FieldStart("decimals") + e.Int(s.Decimals) + } + { + e.FieldStart("image") + e.Str(s.Image) + } +} + +var jsonFieldsNameOfEcPreview = [4]string{ + 0: "name", + 1: "symbol", + 2: "decimals", + 3: "image", +} + +// Decode decodes EcPreview from json. +func (s *EcPreview) Decode(d *jx.Decoder) error { + if s == nil { + return errors.New("invalid: unable to decode EcPreview to nil") + } + var requiredBitSet [1]uint8 + + if err := d.ObjBytes(func(d *jx.Decoder, k []byte) error { + switch string(k) { + case "name": + requiredBitSet[0] |= 1 << 0 + if err := func() error { + v, err := d.Str() + s.Name = string(v) + if err != nil { + return err + } + return nil + }(); err != nil { + return errors.Wrap(err, "decode field \"name\"") + } + case "symbol": + requiredBitSet[0] |= 1 << 1 + if err := func() error { + v, err := d.Str() + s.Symbol = string(v) + if err != nil { + return err + } + return nil + }(); err != nil { + return errors.Wrap(err, "decode field \"symbol\"") + } + case "decimals": + requiredBitSet[0] |= 1 << 2 + if err := func() error { + v, err := d.Int() + s.Decimals = int(v) + if err != nil { + return err + } + return nil + }(); err != nil { + return errors.Wrap(err, "decode field \"decimals\"") + } + case "image": + requiredBitSet[0] |= 1 << 3 + if err := func() error { + v, err := d.Str() + s.Image = string(v) + if err != nil { + return err + } + return nil + }(); err != nil { + return errors.Wrap(err, "decode field \"image\"") + } + default: + return d.Skip() + } + return nil + }); err != nil { + return errors.Wrap(err, "decode EcPreview") + } + // Validate required fields. + var failures []validate.FieldError + for i, mask := range [1]uint8{ + 0b00001111, + } { + 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(jsonFieldsNameOfEcPreview) { + name = jsonFieldsNameOfEcPreview[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 *EcPreview) MarshalJSON() ([]byte, error) { + e := jx.Encoder{} + s.Encode(&e) + return e.Bytes(), nil +} + +// UnmarshalJSON implements stdjson.Unmarshaler. +func (s *EcPreview) UnmarshalJSON(data []byte) error { + d := jx.DecodeBytes(data) + return s.Decode(d) +} + // Encode implements json.Marshaler. func (s *ElectionsDepositStakeAction) Encode(e *jx.Encoder) { e.ObjStart() @@ -15764,6 +15931,198 @@ func (s *ExtraCurrency) UnmarshalJSON(data []byte) error { return s.Decode(d) } +// Encode implements json.Marshaler. +func (s *ExtraCurrencyTransferAction) Encode(e *jx.Encoder) { + e.ObjStart() + s.encodeFields(e) + e.ObjEnd() +} + +// encodeFields encodes fields. +func (s *ExtraCurrencyTransferAction) encodeFields(e *jx.Encoder) { + { + e.FieldStart("sender") + s.Sender.Encode(e) + } + { + e.FieldStart("recipient") + s.Recipient.Encode(e) + } + { + e.FieldStart("amount") + e.Str(s.Amount) + } + { + if s.Comment.Set { + e.FieldStart("comment") + s.Comment.Encode(e) + } + } + { + if s.EncryptedComment.Set { + e.FieldStart("encrypted_comment") + s.EncryptedComment.Encode(e) + } + } + { + if s.Refund.Set { + e.FieldStart("refund") + s.Refund.Encode(e) + } + } + { + e.FieldStart("currency") + s.Currency.Encode(e) + } +} + +var jsonFieldsNameOfExtraCurrencyTransferAction = [7]string{ + 0: "sender", + 1: "recipient", + 2: "amount", + 3: "comment", + 4: "encrypted_comment", + 5: "refund", + 6: "currency", +} + +// Decode decodes ExtraCurrencyTransferAction from json. +func (s *ExtraCurrencyTransferAction) Decode(d *jx.Decoder) error { + if s == nil { + return errors.New("invalid: unable to decode ExtraCurrencyTransferAction to nil") + } + var requiredBitSet [1]uint8 + + if err := d.ObjBytes(func(d *jx.Decoder, k []byte) error { + switch string(k) { + case "sender": + requiredBitSet[0] |= 1 << 0 + if err := func() error { + if err := s.Sender.Decode(d); err != nil { + return err + } + return nil + }(); err != nil { + return errors.Wrap(err, "decode field \"sender\"") + } + case "recipient": + requiredBitSet[0] |= 1 << 1 + if err := func() error { + if err := s.Recipient.Decode(d); err != nil { + return err + } + return nil + }(); err != nil { + return errors.Wrap(err, "decode field \"recipient\"") + } + case "amount": + requiredBitSet[0] |= 1 << 2 + if err := func() error { + v, err := d.Str() + s.Amount = string(v) + if err != nil { + return err + } + return nil + }(); err != nil { + return errors.Wrap(err, "decode field \"amount\"") + } + case "comment": + if err := func() error { + s.Comment.Reset() + if err := s.Comment.Decode(d); err != nil { + return err + } + return nil + }(); err != nil { + return errors.Wrap(err, "decode field \"comment\"") + } + case "encrypted_comment": + if err := func() error { + s.EncryptedComment.Reset() + if err := s.EncryptedComment.Decode(d); err != nil { + return err + } + return nil + }(); err != nil { + return errors.Wrap(err, "decode field \"encrypted_comment\"") + } + case "refund": + if err := func() error { + s.Refund.Reset() + if err := s.Refund.Decode(d); err != nil { + return err + } + return nil + }(); err != nil { + return errors.Wrap(err, "decode field \"refund\"") + } + case "currency": + requiredBitSet[0] |= 1 << 6 + if err := func() error { + if err := s.Currency.Decode(d); err != nil { + return err + } + return nil + }(); err != nil { + return errors.Wrap(err, "decode field \"currency\"") + } + default: + return d.Skip() + } + return nil + }); err != nil { + return errors.Wrap(err, "decode ExtraCurrencyTransferAction") + } + // Validate required fields. + var failures []validate.FieldError + for i, mask := range [1]uint8{ + 0b01000111, + } { + 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(jsonFieldsNameOfExtraCurrencyTransferAction) { + name = jsonFieldsNameOfExtraCurrencyTransferAction[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 *ExtraCurrencyTransferAction) MarshalJSON() ([]byte, error) { + e := jx.Encoder{} + s.Encode(&e) + return e.Bytes(), nil +} + +// UnmarshalJSON implements stdjson.Unmarshaler. +func (s *ExtraCurrencyTransferAction) UnmarshalJSON(data []byte) error { + d := jx.DecodeBytes(data) + return s.Decode(d) +} + // Encode implements json.Marshaler. func (s *FoundAccounts) Encode(e *jx.Encoder) { e.ObjStart() @@ -30756,6 +31115,39 @@ func (s *OptEncryptedComment) UnmarshalJSON(data []byte) error { return s.Decode(d) } +// Encode encodes ExtraCurrencyTransferAction as json. +func (o OptExtraCurrencyTransferAction) Encode(e *jx.Encoder) { + if !o.Set { + return + } + o.Value.Encode(e) +} + +// Decode decodes ExtraCurrencyTransferAction from json. +func (o *OptExtraCurrencyTransferAction) Decode(d *jx.Decoder) error { + if o == nil { + return errors.New("invalid: unable to decode OptExtraCurrencyTransferAction to nil") + } + o.Set = true + if err := o.Value.Decode(d); err != nil { + return err + } + return nil +} + +// MarshalJSON implements stdjson.Marshaler. +func (s OptExtraCurrencyTransferAction) MarshalJSON() ([]byte, error) { + e := jx.Encoder{} + s.Encode(&e) + return e.Bytes(), nil +} + +// UnmarshalJSON implements stdjson.Unmarshaler. +func (s *OptExtraCurrencyTransferAction) 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 { diff --git a/pkg/oas/oas_schemas_gen.go b/pkg/oas/oas_schemas_gen.go index 87118f3b..5b7e2c69 100644 --- a/pkg/oas/oas_schemas_gen.go +++ b/pkg/oas/oas_schemas_gen.go @@ -658,6 +658,7 @@ type Action struct { Type ActionType `json:"type"` Status ActionStatus `json:"status"` TonTransfer OptTonTransferAction `json:"TonTransfer"` + ExtraCurrencyTransfer OptExtraCurrencyTransferAction `json:"ExtraCurrencyTransfer"` ContractDeploy OptContractDeployAction `json:"ContractDeploy"` JettonTransfer OptJettonTransferAction `json:"JettonTransfer"` JettonBurn OptJettonBurnAction `json:"JettonBurn"` @@ -696,6 +697,11 @@ func (s *Action) GetTonTransfer() OptTonTransferAction { return s.TonTransfer } +// GetExtraCurrencyTransfer returns the value of ExtraCurrencyTransfer. +func (s *Action) GetExtraCurrencyTransfer() OptExtraCurrencyTransferAction { + return s.ExtraCurrencyTransfer +} + // GetContractDeploy returns the value of ContractDeploy. func (s *Action) GetContractDeploy() OptContractDeployAction { return s.ContractDeploy @@ -816,6 +822,11 @@ func (s *Action) SetTonTransfer(val OptTonTransferAction) { s.TonTransfer = val } +// SetExtraCurrencyTransfer sets the value of ExtraCurrencyTransfer. +func (s *Action) SetExtraCurrencyTransfer(val OptExtraCurrencyTransferAction) { + s.ExtraCurrencyTransfer = val +} + // SetContractDeploy sets the value of ContractDeploy. func (s *Action) SetContractDeploy(val OptContractDeployAction) { s.ContractDeploy = val @@ -1120,6 +1131,7 @@ type ActionType string const ( ActionTypeTonTransfer ActionType = "TonTransfer" + ActionTypeExtraCurrencyTransfer ActionType = "ExtraCurrencyTransfer" ActionTypeJettonTransfer ActionType = "JettonTransfer" ActionTypeJettonBurn ActionType = "JettonBurn" ActionTypeJettonMint ActionType = "JettonMint" @@ -1146,6 +1158,7 @@ const ( func (ActionType) AllValues() []ActionType { return []ActionType{ ActionTypeTonTransfer, + ActionTypeExtraCurrencyTransfer, ActionTypeJettonTransfer, ActionTypeJettonBurn, ActionTypeJettonMint, @@ -1174,6 +1187,8 @@ func (s ActionType) MarshalText() ([]byte, error) { switch s { case ActionTypeTonTransfer: return []byte(s), nil + case ActionTypeExtraCurrencyTransfer: + return []byte(s), nil case ActionTypeJettonTransfer: return []byte(s), nil case ActionTypeJettonBurn: @@ -1225,6 +1240,9 @@ func (s *ActionType) UnmarshalText(data []byte) error { case ActionTypeTonTransfer: *s = ActionTypeTonTransfer return nil + case ActionTypeExtraCurrencyTransfer: + *s = ActionTypeExtraCurrencyTransfer + return nil case ActionTypeJettonTransfer: *s = ActionTypeJettonTransfer return nil @@ -5104,6 +5122,54 @@ func (s *DomainRenewAction) SetRenewer(val AccountAddress) { s.Renewer = val } +// Ref: #/components/schemas/EcPreview +type EcPreview struct { + Name string `json:"name"` + Symbol string `json:"symbol"` + Decimals int `json:"decimals"` + Image string `json:"image"` +} + +// GetName returns the value of Name. +func (s *EcPreview) GetName() string { + return s.Name +} + +// GetSymbol returns the value of Symbol. +func (s *EcPreview) GetSymbol() string { + return s.Symbol +} + +// GetDecimals returns the value of Decimals. +func (s *EcPreview) GetDecimals() int { + return s.Decimals +} + +// GetImage returns the value of Image. +func (s *EcPreview) GetImage() string { + return s.Image +} + +// SetName sets the value of Name. +func (s *EcPreview) SetName(val string) { + s.Name = val +} + +// SetSymbol sets the value of Symbol. +func (s *EcPreview) SetSymbol(val string) { + s.Symbol = val +} + +// SetDecimals sets the value of Decimals. +func (s *EcPreview) SetDecimals(val int) { + s.Decimals = val +} + +// SetImage sets the value of Image. +func (s *EcPreview) SetImage(val string) { + s.Image = val +} + // Ref: #/components/schemas/ElectionsDepositStakeAction type ElectionsDepositStakeAction struct { Amount int64 `json:"amount"` @@ -5457,6 +5523,88 @@ func (s *ExtraCurrency) SetDecimals(val int) { s.Decimals = val } +// Ref: #/components/schemas/ExtraCurrencyTransferAction +type ExtraCurrencyTransferAction struct { + Sender AccountAddress `json:"sender"` + Recipient AccountAddress `json:"recipient"` + // Amount in quanta of tokens. + Amount string `json:"amount"` + Comment OptString `json:"comment"` + EncryptedComment OptEncryptedComment `json:"encrypted_comment"` + Refund OptRefund `json:"refund"` + Currency EcPreview `json:"currency"` +} + +// GetSender returns the value of Sender. +func (s *ExtraCurrencyTransferAction) GetSender() AccountAddress { + return s.Sender +} + +// GetRecipient returns the value of Recipient. +func (s *ExtraCurrencyTransferAction) GetRecipient() AccountAddress { + return s.Recipient +} + +// GetAmount returns the value of Amount. +func (s *ExtraCurrencyTransferAction) GetAmount() string { + return s.Amount +} + +// GetComment returns the value of Comment. +func (s *ExtraCurrencyTransferAction) GetComment() OptString { + return s.Comment +} + +// GetEncryptedComment returns the value of EncryptedComment. +func (s *ExtraCurrencyTransferAction) GetEncryptedComment() OptEncryptedComment { + return s.EncryptedComment +} + +// GetRefund returns the value of Refund. +func (s *ExtraCurrencyTransferAction) GetRefund() OptRefund { + return s.Refund +} + +// GetCurrency returns the value of Currency. +func (s *ExtraCurrencyTransferAction) GetCurrency() EcPreview { + return s.Currency +} + +// SetSender sets the value of Sender. +func (s *ExtraCurrencyTransferAction) SetSender(val AccountAddress) { + s.Sender = val +} + +// SetRecipient sets the value of Recipient. +func (s *ExtraCurrencyTransferAction) SetRecipient(val AccountAddress) { + s.Recipient = val +} + +// SetAmount sets the value of Amount. +func (s *ExtraCurrencyTransferAction) SetAmount(val string) { + s.Amount = val +} + +// SetComment sets the value of Comment. +func (s *ExtraCurrencyTransferAction) SetComment(val OptString) { + s.Comment = val +} + +// SetEncryptedComment sets the value of EncryptedComment. +func (s *ExtraCurrencyTransferAction) SetEncryptedComment(val OptEncryptedComment) { + s.EncryptedComment = val +} + +// SetRefund sets the value of Refund. +func (s *ExtraCurrencyTransferAction) SetRefund(val OptRefund) { + s.Refund = val +} + +// SetCurrency sets the value of Currency. +func (s *ExtraCurrencyTransferAction) SetCurrency(val EcPreview) { + s.Currency = val +} + // Ref: #/components/schemas/FoundAccounts type FoundAccounts struct { Addresses []FoundAccountsAddressesItem `json:"addresses"` @@ -12398,6 +12546,52 @@ func (o OptEncryptedComment) Or(d EncryptedComment) EncryptedComment { return d } +// NewOptExtraCurrencyTransferAction returns new OptExtraCurrencyTransferAction with value set to v. +func NewOptExtraCurrencyTransferAction(v ExtraCurrencyTransferAction) OptExtraCurrencyTransferAction { + return OptExtraCurrencyTransferAction{ + Value: v, + Set: true, + } +} + +// OptExtraCurrencyTransferAction is optional ExtraCurrencyTransferAction. +type OptExtraCurrencyTransferAction struct { + Value ExtraCurrencyTransferAction + Set bool +} + +// IsSet returns true if OptExtraCurrencyTransferAction was set. +func (o OptExtraCurrencyTransferAction) IsSet() bool { return o.Set } + +// Reset unsets value. +func (o *OptExtraCurrencyTransferAction) Reset() { + var v ExtraCurrencyTransferAction + o.Value = v + o.Set = false +} + +// SetTo sets value to v. +func (o *OptExtraCurrencyTransferAction) SetTo(v ExtraCurrencyTransferAction) { + o.Set = true + o.Value = v +} + +// Get returns value and boolean that denotes whether value was set. +func (o OptExtraCurrencyTransferAction) Get() (v ExtraCurrencyTransferAction, 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 OptExtraCurrencyTransferAction) Or(d ExtraCurrencyTransferAction) ExtraCurrencyTransferAction { + 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{ diff --git a/pkg/oas/oas_validators_gen.go b/pkg/oas/oas_validators_gen.go index fb1c9670..0e5f49f4 100644 --- a/pkg/oas/oas_validators_gen.go +++ b/pkg/oas/oas_validators_gen.go @@ -261,6 +261,24 @@ func (s *Action) Validate() error { Error: err, }) } + if err := func() error { + if value, ok := s.ExtraCurrencyTransfer.Get(); ok { + if err := func() error { + if err := value.Validate(); err != nil { + return err + } + return nil + }(); err != nil { + return err + } + } + return nil + }(); err != nil { + failures = append(failures, validate.FieldError{ + Name: "ExtraCurrencyTransfer", + Error: err, + }) + } if err := func() error { if value, ok := s.ContractDeploy.Get(); ok { if err := func() error { @@ -579,6 +597,8 @@ func (s ActionType) Validate() error { switch s { case "TonTransfer": return nil + case "ExtraCurrencyTransfer": + return nil case "JettonTransfer": return nil case "JettonBurn": @@ -2361,6 +2381,36 @@ func (s *Event) Validate() error { return nil } +func (s *ExtraCurrencyTransferAction) Validate() error { + if s == nil { + return validate.ErrNilPointer + } + + var failures []validate.FieldError + if err := func() error { + if value, ok := s.Refund.Get(); ok { + if err := func() error { + if err := value.Validate(); err != nil { + return err + } + return nil + }(); err != nil { + return err + } + } + return nil + }(); err != nil { + failures = append(failures, validate.FieldError{ + Name: "refund", + Error: err, + }) + } + if len(failures) > 0 { + return &validate.Error{Fields: failures} + } + return nil +} + func (s *FoundAccounts) Validate() error { if s == nil { return validate.ErrNilPointer diff --git a/pkg/references/extra_currency.go b/pkg/references/extra_currency.go index 5aea713e..b79f3b99 100644 --- a/pkg/references/extra_currency.go +++ b/pkg/references/extra_currency.go @@ -1,13 +1,29 @@ package references +const DefaultExtraCurrencyDecimals = 9 + type ExtraCurrencyMeta struct { Name string + Symbol string + Image string Decimals int } -var ExtraCurrencies = map[int32]ExtraCurrencyMeta{ +var extraCurrencies = map[int32]ExtraCurrencyMeta{ 239: { Name: "FMS", Decimals: 5, + Symbol: "FMS", }, } + +func GetExtraCurrencyMeta(id int32) ExtraCurrencyMeta { + meta, ok := extraCurrencies[id] + if ok { + return meta + } + return ExtraCurrencyMeta{ + Decimals: DefaultExtraCurrencyDecimals, + // TODO: add default placeholders + } +} From 8d0139b12faae5dc65aad356af8dc3ad1a409403 Mon Sep 17 00:00:00 2001 From: Alexey Kostenko Date: Wed, 11 Dec 2024 01:24:47 +0300 Subject: [PATCH 5/5] fix --- api/openapi.json | 8 ----- api/openapi.yml | 6 ---- pkg/api/event_converters.go | 7 ----- pkg/bath/actions.go | 7 +++-- pkg/oas/oas_json_gen.go | 58 ++++++++--------------------------- pkg/oas/oas_schemas_gen.go | 22 ------------- pkg/oas/oas_validators_gen.go | 48 ----------------------------- 7 files changed, 17 insertions(+), 139 deletions(-) diff --git a/api/openapi.json b/api/openapi.json index 8bd64cc6..684c7828 100644 --- a/api/openapi.json +++ b/api/openapi.json @@ -3133,17 +3133,12 @@ "example": "https://cache.tonapi.io/images/extra.jpg", "type": "string" }, - "name": { - "example": "FMS", - "type": "string" - }, "symbol": { "example": "FMS", "type": "string" } }, "required": [ - "name", "symbol", "decimals", "image" @@ -3315,9 +3310,6 @@ "recipient": { "$ref": "#/components/schemas/AccountAddress" }, - "refund": { - "$ref": "#/components/schemas/Refund" - }, "sender": { "$ref": "#/components/schemas/AccountAddress" } diff --git a/api/openapi.yml b/api/openapi.yml index b78bd48a..ca858fd9 100644 --- a/api/openapi.yml +++ b/api/openapi.yml @@ -5848,14 +5848,10 @@ components: EcPreview: type: object required: - - name - symbol - decimals - image properties: - name: - type: string - example: FMS symbol: type: string example: FMS @@ -5887,8 +5883,6 @@ components: example: "Hi! This is your salary. \nFrom accounting with love." encrypted_comment: $ref: '#/components/schemas/EncryptedComment' - refund: - $ref: '#/components/schemas/Refund' currency: $ref: '#/components/schemas/EcPreview' SmartContractAction: diff --git a/pkg/api/event_converters.go b/pkg/api/event_converters.go index 7f3dc857..2db1ac19 100644 --- a/pkg/api/event_converters.go +++ b/pkg/api/event_converters.go @@ -162,18 +162,11 @@ func (h *Handler) convertActionExtraCurrencyTransfer(t *bath.ExtraCurrencyTransf Sender: convertAccountAddress(t.Sender, h.addressBook), EncryptedComment: convertEncryptedComment(t.EncryptedComment), Currency: oas.EcPreview{ - Name: meta.Name, Symbol: meta.Symbol, Decimals: meta.Decimals, Image: meta.Image, }, }) - if t.Refund != nil { - action.Value.Refund.SetTo(oas.Refund{ - Type: oas.RefundType(t.Refund.Type), - Origin: t.Refund.Origin, - }) - } simplePreview := oas.ActionSimplePreview{ Name: "Extra Currency Transfer", Description: "", // TODO: add description diff --git a/pkg/bath/actions.go b/pkg/bath/actions.go index 68d53890..771d8881 100644 --- a/pkg/bath/actions.go +++ b/pkg/bath/actions.go @@ -110,7 +110,6 @@ type ( EncryptedComment *EncryptedComment Recipient tongo.AccountID Sender tongo.AccountID - Refund *Refund } SmartContractAction struct { TonAttached int64 @@ -274,7 +273,7 @@ func (a Action) ContributeToExtra(account tongo.AccountID) int64 { return 0 } switch a.Type { - case NftItemTransfer, ContractDeploy, UnSubscription, JettonMint, JettonBurn, WithdrawStakeRequest, DomainRenew, InscriptionMint, InscriptionTransfer: // actions without extra + case NftItemTransfer, ContractDeploy, UnSubscription, JettonMint, JettonBurn, WithdrawStakeRequest, DomainRenew, InscriptionMint, InscriptionTransfer, ExtraCurrencyTransfer: // actions without extra return 0 case TonTransfer: return detectDirection(account, a.TonTransfer.Sender, a.TonTransfer.Recipient, a.TonTransfer.Amount) @@ -351,6 +350,10 @@ func (a *TonTransferAction) SubjectAccounts() []tongo.AccountID { return []tongo.AccountID{a.Sender, a.Recipient} } +func (a *ExtraCurrencyTransferAction) SubjectAccounts() []tongo.AccountID { + return []tongo.AccountID{a.Sender, a.Recipient} +} + func (a *SmartContractAction) SubjectAccounts() []tongo.AccountID { return []tongo.AccountID{a.Contract, a.Executor} } diff --git a/pkg/oas/oas_json_gen.go b/pkg/oas/oas_json_gen.go index 97071c2a..afe93451 100644 --- a/pkg/oas/oas_json_gen.go +++ b/pkg/oas/oas_json_gen.go @@ -14455,10 +14455,6 @@ func (s *EcPreview) Encode(e *jx.Encoder) { // encodeFields encodes fields. func (s *EcPreview) encodeFields(e *jx.Encoder) { - { - e.FieldStart("name") - e.Str(s.Name) - } { e.FieldStart("symbol") e.Str(s.Symbol) @@ -14473,11 +14469,10 @@ func (s *EcPreview) encodeFields(e *jx.Encoder) { } } -var jsonFieldsNameOfEcPreview = [4]string{ - 0: "name", - 1: "symbol", - 2: "decimals", - 3: "image", +var jsonFieldsNameOfEcPreview = [3]string{ + 0: "symbol", + 1: "decimals", + 2: "image", } // Decode decodes EcPreview from json. @@ -14489,20 +14484,8 @@ func (s *EcPreview) Decode(d *jx.Decoder) error { if err := d.ObjBytes(func(d *jx.Decoder, k []byte) error { switch string(k) { - case "name": - requiredBitSet[0] |= 1 << 0 - if err := func() error { - v, err := d.Str() - s.Name = string(v) - if err != nil { - return err - } - return nil - }(); err != nil { - return errors.Wrap(err, "decode field \"name\"") - } case "symbol": - requiredBitSet[0] |= 1 << 1 + requiredBitSet[0] |= 1 << 0 if err := func() error { v, err := d.Str() s.Symbol = string(v) @@ -14514,7 +14497,7 @@ func (s *EcPreview) Decode(d *jx.Decoder) error { return errors.Wrap(err, "decode field \"symbol\"") } case "decimals": - requiredBitSet[0] |= 1 << 2 + requiredBitSet[0] |= 1 << 1 if err := func() error { v, err := d.Int() s.Decimals = int(v) @@ -14526,7 +14509,7 @@ func (s *EcPreview) Decode(d *jx.Decoder) error { return errors.Wrap(err, "decode field \"decimals\"") } case "image": - requiredBitSet[0] |= 1 << 3 + requiredBitSet[0] |= 1 << 2 if err := func() error { v, err := d.Str() s.Image = string(v) @@ -14547,7 +14530,7 @@ func (s *EcPreview) Decode(d *jx.Decoder) error { // Validate required fields. var failures []validate.FieldError for i, mask := range [1]uint8{ - 0b00001111, + 0b00000111, } { if result := (requiredBitSet[i] & mask) ^ mask; result != 0 { // Mask only required fields and check equality to mask using XOR. @@ -15964,26 +15947,19 @@ func (s *ExtraCurrencyTransferAction) encodeFields(e *jx.Encoder) { s.EncryptedComment.Encode(e) } } - { - if s.Refund.Set { - e.FieldStart("refund") - s.Refund.Encode(e) - } - } { e.FieldStart("currency") s.Currency.Encode(e) } } -var jsonFieldsNameOfExtraCurrencyTransferAction = [7]string{ +var jsonFieldsNameOfExtraCurrencyTransferAction = [6]string{ 0: "sender", 1: "recipient", 2: "amount", 3: "comment", 4: "encrypted_comment", - 5: "refund", - 6: "currency", + 5: "currency", } // Decode decodes ExtraCurrencyTransferAction from json. @@ -16047,18 +16023,8 @@ func (s *ExtraCurrencyTransferAction) Decode(d *jx.Decoder) error { }(); err != nil { return errors.Wrap(err, "decode field \"encrypted_comment\"") } - case "refund": - if err := func() error { - s.Refund.Reset() - if err := s.Refund.Decode(d); err != nil { - return err - } - return nil - }(); err != nil { - return errors.Wrap(err, "decode field \"refund\"") - } case "currency": - requiredBitSet[0] |= 1 << 6 + requiredBitSet[0] |= 1 << 5 if err := func() error { if err := s.Currency.Decode(d); err != nil { return err @@ -16077,7 +16043,7 @@ func (s *ExtraCurrencyTransferAction) Decode(d *jx.Decoder) error { // Validate required fields. var failures []validate.FieldError for i, mask := range [1]uint8{ - 0b01000111, + 0b00100111, } { 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 5b7e2c69..588e9844 100644 --- a/pkg/oas/oas_schemas_gen.go +++ b/pkg/oas/oas_schemas_gen.go @@ -5124,17 +5124,11 @@ func (s *DomainRenewAction) SetRenewer(val AccountAddress) { // Ref: #/components/schemas/EcPreview type EcPreview struct { - Name string `json:"name"` Symbol string `json:"symbol"` Decimals int `json:"decimals"` Image string `json:"image"` } -// GetName returns the value of Name. -func (s *EcPreview) GetName() string { - return s.Name -} - // GetSymbol returns the value of Symbol. func (s *EcPreview) GetSymbol() string { return s.Symbol @@ -5150,11 +5144,6 @@ func (s *EcPreview) GetImage() string { return s.Image } -// SetName sets the value of Name. -func (s *EcPreview) SetName(val string) { - s.Name = val -} - // SetSymbol sets the value of Symbol. func (s *EcPreview) SetSymbol(val string) { s.Symbol = val @@ -5531,7 +5520,6 @@ type ExtraCurrencyTransferAction struct { Amount string `json:"amount"` Comment OptString `json:"comment"` EncryptedComment OptEncryptedComment `json:"encrypted_comment"` - Refund OptRefund `json:"refund"` Currency EcPreview `json:"currency"` } @@ -5560,11 +5548,6 @@ func (s *ExtraCurrencyTransferAction) GetEncryptedComment() OptEncryptedComment return s.EncryptedComment } -// GetRefund returns the value of Refund. -func (s *ExtraCurrencyTransferAction) GetRefund() OptRefund { - return s.Refund -} - // GetCurrency returns the value of Currency. func (s *ExtraCurrencyTransferAction) GetCurrency() EcPreview { return s.Currency @@ -5595,11 +5578,6 @@ func (s *ExtraCurrencyTransferAction) SetEncryptedComment(val OptEncryptedCommen s.EncryptedComment = val } -// SetRefund sets the value of Refund. -func (s *ExtraCurrencyTransferAction) SetRefund(val OptRefund) { - s.Refund = val -} - // SetCurrency sets the value of Currency. func (s *ExtraCurrencyTransferAction) SetCurrency(val EcPreview) { s.Currency = val diff --git a/pkg/oas/oas_validators_gen.go b/pkg/oas/oas_validators_gen.go index 0e5f49f4..0ad09224 100644 --- a/pkg/oas/oas_validators_gen.go +++ b/pkg/oas/oas_validators_gen.go @@ -261,24 +261,6 @@ func (s *Action) Validate() error { Error: err, }) } - if err := func() error { - if value, ok := s.ExtraCurrencyTransfer.Get(); ok { - if err := func() error { - if err := value.Validate(); err != nil { - return err - } - return nil - }(); err != nil { - return err - } - } - return nil - }(); err != nil { - failures = append(failures, validate.FieldError{ - Name: "ExtraCurrencyTransfer", - Error: err, - }) - } if err := func() error { if value, ok := s.ContractDeploy.Get(); ok { if err := func() error { @@ -2381,36 +2363,6 @@ func (s *Event) Validate() error { return nil } -func (s *ExtraCurrencyTransferAction) Validate() error { - if s == nil { - return validate.ErrNilPointer - } - - var failures []validate.FieldError - if err := func() error { - if value, ok := s.Refund.Get(); ok { - if err := func() error { - if err := value.Validate(); err != nil { - return err - } - return nil - }(); err != nil { - return err - } - } - return nil - }(); err != nil { - failures = append(failures, validate.FieldError{ - Name: "refund", - Error: err, - }) - } - if len(failures) > 0 { - return &validate.Error{Fields: failures} - } - return nil -} - func (s *FoundAccounts) Validate() error { if s == nil { return validate.ErrNilPointer