From 20e69210c340014d7b8cadb1b21566d8f55442cb Mon Sep 17 00:00:00 2001 From: Chen Chen <34592639+envestcc@users.noreply.github.com> Date: Mon, 22 May 2023 21:43:18 +0800 Subject: [PATCH] [IIP-13] contract staking struct definition (1/3 split by 3853) (#3861) * contractstaking bucket definition * address comments --- .../staking/contractstaking/bucket.go | 26 ++ .../staking/contractstaking/bucket_info.go | 70 +++++ .../staking/contractstaking/bucket_type.go | 58 ++++ .../contractstakingpb/contractstaking.pb.go | 293 ++++++++++++++++++ .../contractstakingpb/contractstaking.proto | 25 ++ 5 files changed, 472 insertions(+) create mode 100644 action/protocol/staking/contractstaking/bucket.go create mode 100644 action/protocol/staking/contractstaking/bucket_info.go create mode 100644 action/protocol/staking/contractstaking/bucket_type.go create mode 100644 action/protocol/staking/contractstaking/contractstakingpb/contractstaking.pb.go create mode 100644 action/protocol/staking/contractstaking/contractstakingpb/contractstaking.proto diff --git a/action/protocol/staking/contractstaking/bucket.go b/action/protocol/staking/contractstaking/bucket.go new file mode 100644 index 0000000000..ba7866d0da --- /dev/null +++ b/action/protocol/staking/contractstaking/bucket.go @@ -0,0 +1,26 @@ +// Copyright (c) 2023 IoTeX Foundation +// This source code is provided 'as is' and no warranties are given as to title or non-infringement, merchantability +// or fitness for purpose and, to the extent permitted by law, all liability for your use of the code is disclaimed. +// This source code is governed by Apache License 2.0 that can be found in the LICENSE file. + +package contractstaking + +import ( + "math/big" + + "github.com/iotexproject/iotex-address/address" +) + +// Bucket defines the bucket struct for contract staking +type Bucket struct { + Index uint64 + Candidate address.Address + Owner address.Address + StakedAmount *big.Int + StakedDurationBlockNumber uint64 + CreateBlockHeight uint64 + StakeStartBlockHeight uint64 + UnstakeStartBlockHeight uint64 + AutoStake bool + ContractAddress string // contract address for the bucket +} diff --git a/action/protocol/staking/contractstaking/bucket_info.go b/action/protocol/staking/contractstaking/bucket_info.go new file mode 100644 index 0000000000..8683a66880 --- /dev/null +++ b/action/protocol/staking/contractstaking/bucket_info.go @@ -0,0 +1,70 @@ +// Copyright (c) 2023 IoTeX Foundation +// This source code is provided 'as is' and no warranties are given as to title or non-infringement, merchantability +// or fitness for purpose and, to the extent permitted by law, all liability for your use of the code is disclaimed. +// This source code is governed by Apache License 2.0 that can be found in the LICENSE file. + +package contractstaking + +import ( + "github.com/iotexproject/iotex-address/address" + "google.golang.org/protobuf/proto" + + "github.com/iotexproject/iotex-core/action/protocol/staking/contractstaking/contractstakingpb" + "github.com/iotexproject/iotex-core/pkg/util/byteutil" +) + +type ( + // bucketInfo is the bucket information + bucketInfo struct { + TypeIndex uint64 + CreatedAt uint64 + UnlockedAt uint64 + UnstakedAt uint64 + Delegate address.Address // owner address of the delegate + Owner address.Address + } +) + +// Serialize serializes the bucket info +func (bi *bucketInfo) Serialize() []byte { + return byteutil.Must(proto.Marshal(bi.toProto())) +} + +// Deserialize deserializes the bucket info +func (bi *bucketInfo) Deserialize(b []byte) error { + m := contractstakingpb.BucketInfo{} + if err := proto.Unmarshal(b, &m); err != nil { + return err + } + return bi.loadProto(&m) +} + +func (bi *bucketInfo) toProto() *contractstakingpb.BucketInfo { + pb := &contractstakingpb.BucketInfo{ + TypeIndex: bi.TypeIndex, + Delegate: bi.Delegate.String(), + CreatedAt: bi.CreatedAt, + Owner: bi.Owner.String(), + UnlockedAt: bi.UnlockedAt, + UnstakedAt: bi.UnstakedAt, + } + return pb +} + +func (bi *bucketInfo) loadProto(p *contractstakingpb.BucketInfo) error { + delegate, err := address.FromString(p.Delegate) + if err != nil { + return err + } + owner, err := address.FromString(p.Owner) + if err != nil { + return err + } + bi.TypeIndex = p.TypeIndex + bi.CreatedAt = p.CreatedAt + bi.UnlockedAt = p.UnlockedAt + bi.UnstakedAt = p.UnstakedAt + bi.Delegate = delegate + bi.Owner = owner + return nil +} diff --git a/action/protocol/staking/contractstaking/bucket_type.go b/action/protocol/staking/contractstaking/bucket_type.go new file mode 100644 index 0000000000..98fca73346 --- /dev/null +++ b/action/protocol/staking/contractstaking/bucket_type.go @@ -0,0 +1,58 @@ +// Copyright (c) 2023 IoTeX Foundation +// This source code is provided 'as is' and no warranties are given as to title or non-infringement, merchantability +// or fitness for purpose and, to the extent permitted by law, all liability for your use of the code is disclaimed. +// This source code is governed by Apache License 2.0 that can be found in the LICENSE file. + +package contractstaking + +import ( + "math/big" + + "github.com/pkg/errors" + "google.golang.org/protobuf/proto" + + "github.com/iotexproject/iotex-core/action/protocol/staking/contractstaking/contractstakingpb" + "github.com/iotexproject/iotex-core/pkg/util/byteutil" +) + +type ( + // BucketType defines the type of contract staking bucket + BucketType struct { + Amount *big.Int + Duration uint64 // block numbers + ActivatedAt uint64 // block height + } +) + +// Serialize serializes the bucket type +func (bt *BucketType) Serialize() []byte { + return byteutil.Must(proto.Marshal(bt.toProto())) +} + +// Deserialize deserializes the bucket type +func (bt *BucketType) Deserialize(b []byte) error { + m := contractstakingpb.BucketType{} + if err := proto.Unmarshal(b, &m); err != nil { + return err + } + return bt.loadProto(&m) +} + +func (bt *BucketType) toProto() *contractstakingpb.BucketType { + return &contractstakingpb.BucketType{ + Amount: bt.Amount.String(), + Duration: bt.Duration, + ActivatedAt: bt.ActivatedAt, + } +} + +func (bt *BucketType) loadProto(p *contractstakingpb.BucketType) error { + amount, ok := big.NewInt(0).SetString(p.Amount, 10) + if !ok { + return errors.New("failed to parse amount") + } + bt.Amount = amount + bt.Duration = p.Duration + bt.ActivatedAt = p.ActivatedAt + return nil +} diff --git a/action/protocol/staking/contractstaking/contractstakingpb/contractstaking.pb.go b/action/protocol/staking/contractstaking/contractstakingpb/contractstaking.pb.go new file mode 100644 index 0000000000..506a53a29a --- /dev/null +++ b/action/protocol/staking/contractstaking/contractstakingpb/contractstaking.pb.go @@ -0,0 +1,293 @@ +// Copyright (c) 2019 IoTeX +// This source code is provided 'as is' and no warranties are given as to title or non-infringement, merchantability +// or fitness for purpose and, to the extent permitted by law, all liability for your use of the code is disclaimed. +// This source code is governed by Apache License 2.0 that can be found in the LICENSE file. + +// To compile the proto, run: +// protoc --go_out=plugins=grpc:. *.proto + +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.26.0 +// protoc v3.21.12 +// source: action/protocol/staking/contractstaking/contractstakingpb/contractstaking.proto + +package contractstakingpb + +import ( + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +type BucketType struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Amount string `protobuf:"bytes,1,opt,name=amount,proto3" json:"amount,omitempty"` + Duration uint64 `protobuf:"varint,2,opt,name=duration,proto3" json:"duration,omitempty"` + ActivatedAt uint64 `protobuf:"varint,3,opt,name=activatedAt,proto3" json:"activatedAt,omitempty"` +} + +func (x *BucketType) Reset() { + *x = BucketType{} + if protoimpl.UnsafeEnabled { + mi := &file_action_protocol_staking_contractstaking_contractstakingpb_contractstaking_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *BucketType) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*BucketType) ProtoMessage() {} + +func (x *BucketType) ProtoReflect() protoreflect.Message { + mi := &file_action_protocol_staking_contractstaking_contractstakingpb_contractstaking_proto_msgTypes[0] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use BucketType.ProtoReflect.Descriptor instead. +func (*BucketType) Descriptor() ([]byte, []int) { + return file_action_protocol_staking_contractstaking_contractstakingpb_contractstaking_proto_rawDescGZIP(), []int{0} +} + +func (x *BucketType) GetAmount() string { + if x != nil { + return x.Amount + } + return "" +} + +func (x *BucketType) GetDuration() uint64 { + if x != nil { + return x.Duration + } + return 0 +} + +func (x *BucketType) GetActivatedAt() uint64 { + if x != nil { + return x.ActivatedAt + } + return 0 +} + +type BucketInfo struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + TypeIndex uint64 `protobuf:"varint,1,opt,name=typeIndex,proto3" json:"typeIndex,omitempty"` + CreatedAt uint64 `protobuf:"varint,2,opt,name=createdAt,proto3" json:"createdAt,omitempty"` + UnlockedAt uint64 `protobuf:"varint,3,opt,name=unlockedAt,proto3" json:"unlockedAt,omitempty"` + UnstakedAt uint64 `protobuf:"varint,4,opt,name=unstakedAt,proto3" json:"unstakedAt,omitempty"` + Delegate string `protobuf:"bytes,5,opt,name=delegate,proto3" json:"delegate,omitempty"` + Owner string `protobuf:"bytes,6,opt,name=owner,proto3" json:"owner,omitempty"` +} + +func (x *BucketInfo) Reset() { + *x = BucketInfo{} + if protoimpl.UnsafeEnabled { + mi := &file_action_protocol_staking_contractstaking_contractstakingpb_contractstaking_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *BucketInfo) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*BucketInfo) ProtoMessage() {} + +func (x *BucketInfo) ProtoReflect() protoreflect.Message { + mi := &file_action_protocol_staking_contractstaking_contractstakingpb_contractstaking_proto_msgTypes[1] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use BucketInfo.ProtoReflect.Descriptor instead. +func (*BucketInfo) Descriptor() ([]byte, []int) { + return file_action_protocol_staking_contractstaking_contractstakingpb_contractstaking_proto_rawDescGZIP(), []int{1} +} + +func (x *BucketInfo) GetTypeIndex() uint64 { + if x != nil { + return x.TypeIndex + } + return 0 +} + +func (x *BucketInfo) GetCreatedAt() uint64 { + if x != nil { + return x.CreatedAt + } + return 0 +} + +func (x *BucketInfo) GetUnlockedAt() uint64 { + if x != nil { + return x.UnlockedAt + } + return 0 +} + +func (x *BucketInfo) GetUnstakedAt() uint64 { + if x != nil { + return x.UnstakedAt + } + return 0 +} + +func (x *BucketInfo) GetDelegate() string { + if x != nil { + return x.Delegate + } + return "" +} + +func (x *BucketInfo) GetOwner() string { + if x != nil { + return x.Owner + } + return "" +} + +var File_action_protocol_staking_contractstaking_contractstakingpb_contractstaking_proto protoreflect.FileDescriptor + +var file_action_protocol_staking_contractstaking_contractstakingpb_contractstaking_proto_rawDesc = []byte{ + 0x0a, 0x4f, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, + 0x6c, 0x2f, 0x73, 0x74, 0x61, 0x6b, 0x69, 0x6e, 0x67, 0x2f, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x61, + 0x63, 0x74, 0x73, 0x74, 0x61, 0x6b, 0x69, 0x6e, 0x67, 0x2f, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x61, + 0x63, 0x74, 0x73, 0x74, 0x61, 0x6b, 0x69, 0x6e, 0x67, 0x70, 0x62, 0x2f, 0x63, 0x6f, 0x6e, 0x74, + 0x72, 0x61, 0x63, 0x74, 0x73, 0x74, 0x61, 0x6b, 0x69, 0x6e, 0x67, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x12, 0x11, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x61, 0x63, 0x74, 0x73, 0x74, 0x61, 0x6b, 0x69, + 0x6e, 0x67, 0x70, 0x62, 0x22, 0x62, 0x0a, 0x0a, 0x42, 0x75, 0x63, 0x6b, 0x65, 0x74, 0x54, 0x79, + 0x70, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x64, 0x75, + 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x08, 0x64, 0x75, + 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x20, 0x0a, 0x0b, 0x61, 0x63, 0x74, 0x69, 0x76, 0x61, + 0x74, 0x65, 0x64, 0x41, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0b, 0x61, 0x63, 0x74, + 0x69, 0x76, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x22, 0xba, 0x01, 0x0a, 0x0a, 0x42, 0x75, 0x63, + 0x6b, 0x65, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x79, 0x70, 0x65, 0x49, + 0x6e, 0x64, 0x65, 0x78, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x74, 0x79, 0x70, 0x65, + 0x49, 0x6e, 0x64, 0x65, 0x78, 0x12, 0x1c, 0x0a, 0x09, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, + 0x41, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, + 0x64, 0x41, 0x74, 0x12, 0x1e, 0x0a, 0x0a, 0x75, 0x6e, 0x6c, 0x6f, 0x63, 0x6b, 0x65, 0x64, 0x41, + 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0a, 0x75, 0x6e, 0x6c, 0x6f, 0x63, 0x6b, 0x65, + 0x64, 0x41, 0x74, 0x12, 0x1e, 0x0a, 0x0a, 0x75, 0x6e, 0x73, 0x74, 0x61, 0x6b, 0x65, 0x64, 0x41, + 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0a, 0x75, 0x6e, 0x73, 0x74, 0x61, 0x6b, 0x65, + 0x64, 0x41, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x64, 0x65, 0x6c, 0x65, 0x67, 0x61, 0x74, 0x65, 0x18, + 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x64, 0x65, 0x6c, 0x65, 0x67, 0x61, 0x74, 0x65, 0x12, + 0x14, 0x0a, 0x05, 0x6f, 0x77, 0x6e, 0x65, 0x72, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, + 0x6f, 0x77, 0x6e, 0x65, 0x72, 0x42, 0x5e, 0x5a, 0x5c, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, + 0x63, 0x6f, 0x6d, 0x2f, 0x69, 0x6f, 0x74, 0x65, 0x78, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, + 0x2f, 0x69, 0x6f, 0x74, 0x65, 0x78, 0x2d, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x61, 0x63, 0x74, 0x69, + 0x6f, 0x6e, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2f, 0x73, 0x74, 0x61, 0x6b, + 0x69, 0x6e, 0x67, 0x2f, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x61, 0x63, 0x74, 0x73, 0x74, 0x61, 0x6b, + 0x69, 0x6e, 0x67, 0x2f, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x61, 0x63, 0x74, 0x73, 0x74, 0x61, 0x6b, + 0x69, 0x6e, 0x67, 0x70, 0x62, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, +} + +var ( + file_action_protocol_staking_contractstaking_contractstakingpb_contractstaking_proto_rawDescOnce sync.Once + file_action_protocol_staking_contractstaking_contractstakingpb_contractstaking_proto_rawDescData = file_action_protocol_staking_contractstaking_contractstakingpb_contractstaking_proto_rawDesc +) + +func file_action_protocol_staking_contractstaking_contractstakingpb_contractstaking_proto_rawDescGZIP() []byte { + file_action_protocol_staking_contractstaking_contractstakingpb_contractstaking_proto_rawDescOnce.Do(func() { + file_action_protocol_staking_contractstaking_contractstakingpb_contractstaking_proto_rawDescData = protoimpl.X.CompressGZIP(file_action_protocol_staking_contractstaking_contractstakingpb_contractstaking_proto_rawDescData) + }) + return file_action_protocol_staking_contractstaking_contractstakingpb_contractstaking_proto_rawDescData +} + +var file_action_protocol_staking_contractstaking_contractstakingpb_contractstaking_proto_msgTypes = make([]protoimpl.MessageInfo, 2) +var file_action_protocol_staking_contractstaking_contractstakingpb_contractstaking_proto_goTypes = []interface{}{ + (*BucketType)(nil), // 0: contractstakingpb.BucketType + (*BucketInfo)(nil), // 1: contractstakingpb.BucketInfo +} +var file_action_protocol_staking_contractstaking_contractstakingpb_contractstaking_proto_depIdxs = []int32{ + 0, // [0:0] is the sub-list for method output_type + 0, // [0:0] is the sub-list for method input_type + 0, // [0:0] is the sub-list for extension type_name + 0, // [0:0] is the sub-list for extension extendee + 0, // [0:0] is the sub-list for field type_name +} + +func init() { + file_action_protocol_staking_contractstaking_contractstakingpb_contractstaking_proto_init() +} +func file_action_protocol_staking_contractstaking_contractstakingpb_contractstaking_proto_init() { + if File_action_protocol_staking_contractstaking_contractstakingpb_contractstaking_proto != nil { + return + } + if !protoimpl.UnsafeEnabled { + file_action_protocol_staking_contractstaking_contractstakingpb_contractstaking_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*BucketType); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_action_protocol_staking_contractstaking_contractstakingpb_contractstaking_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*BucketInfo); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_action_protocol_staking_contractstaking_contractstakingpb_contractstaking_proto_rawDesc, + NumEnums: 0, + NumMessages: 2, + NumExtensions: 0, + NumServices: 0, + }, + GoTypes: file_action_protocol_staking_contractstaking_contractstakingpb_contractstaking_proto_goTypes, + DependencyIndexes: file_action_protocol_staking_contractstaking_contractstakingpb_contractstaking_proto_depIdxs, + MessageInfos: file_action_protocol_staking_contractstaking_contractstakingpb_contractstaking_proto_msgTypes, + }.Build() + File_action_protocol_staking_contractstaking_contractstakingpb_contractstaking_proto = out.File + file_action_protocol_staking_contractstaking_contractstakingpb_contractstaking_proto_rawDesc = nil + file_action_protocol_staking_contractstaking_contractstakingpb_contractstaking_proto_goTypes = nil + file_action_protocol_staking_contractstaking_contractstakingpb_contractstaking_proto_depIdxs = nil +} diff --git a/action/protocol/staking/contractstaking/contractstakingpb/contractstaking.proto b/action/protocol/staking/contractstaking/contractstakingpb/contractstaking.proto new file mode 100644 index 0000000000..fa29ea5609 --- /dev/null +++ b/action/protocol/staking/contractstaking/contractstakingpb/contractstaking.proto @@ -0,0 +1,25 @@ +// Copyright (c) 2019 IoTeX +// This source code is provided 'as is' and no warranties are given as to title or non-infringement, merchantability +// or fitness for purpose and, to the extent permitted by law, all liability for your use of the code is disclaimed. +// This source code is governed by Apache License 2.0 that can be found in the LICENSE file. + +// To compile the proto, run: +// protoc --go_out=plugins=grpc:. *.proto +syntax = "proto3"; +package contractstakingpb; +option go_package = "github.com/iotexproject/iotex-core/action/protocol/staking/contractstaking/contractstakingpb"; + +message BucketType { + string amount = 1; + uint64 duration = 2; + uint64 activatedAt = 3; +} + +message BucketInfo { + uint64 typeIndex = 1; + uint64 createdAt = 2; + uint64 unlockedAt = 3; + uint64 unstakedAt = 4; + string delegate = 5; + string owner = 6; +} \ No newline at end of file