Commit 2e4b635d authored by pengjun's avatar pengjun

#627 remove collateralize close; add collateralize retrieve

parent 5523229c
......@@ -24,7 +24,7 @@ func CollateralizeCmd() *cobra.Command {
CollateralizeAppendRawTxCmd(),
CollateralizeRepayRawTxCmd(),
CollateralizePriceFeedRawTxCmd(),
CollateralizeCloseRawTxCmd(),
CollateralizeRetrieveRawTxCmd(),
CollateralizeManageRawTxCmd(),
CollateralizeQueryCmd(),
)
......@@ -233,22 +233,24 @@ func CollateralizePriceFeed(cmd *cobra.Command, args []string) {
}
// CollateralizeCloseRawTxCmd 生成开始交易命令行
func CollateralizeCloseRawTxCmd() *cobra.Command {
func CollateralizeRetrieveRawTxCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "close",
Short: "close a collateralize",
Run: CollateralizeClose,
Use: "retrieve",
Short: "retrieve balance",
Run: CollateralizeRetrieve,
}
addCollateralizeCloseFlags(cmd)
addCollateralizeRetrieveFlags(cmd)
return cmd
}
func addCollateralizeCloseFlags(cmd *cobra.Command) {
func addCollateralizeRetrieveFlags(cmd *cobra.Command) {
cmd.Flags().StringP("collateralizeID", "g", "", "collateralize ID")
cmd.MarkFlagRequired("collateralizeID")
cmd.Flags().StringP("balance", "b", "", "retrieve balance")
cmd.MarkFlagRequired("balance")
}
func CollateralizeClose(cmd *cobra.Command, args []string) {
func CollateralizeRetrieve(cmd *cobra.Command, args []string) {
title, _ := cmd.Flags().GetString("title")
cfg := types.GetCliSysParam(title)
if cfg == nil {
......@@ -257,11 +259,12 @@ func CollateralizeClose(cmd *cobra.Command, args []string) {
rpcLaddr, _ := cmd.Flags().GetString("rpc_laddr")
collateralizeID, _ := cmd.Flags().GetString("collateralizeID")
balance, _ := cmd.Flags().GetInt64("balance")
params := &rpctypes.CreateTxIn{
Execer: cfg.ExecName(pkt.CollateralizeX),
ActionName: "CollateralizeClose",
Payload: []byte(fmt.Sprintf("{\"collateralizeID\":\"%s\"}", collateralizeID)),
ActionName: "CollateralizeRetrieve",
Payload: []byte(fmt.Sprintf("{\"collateralizeID\":\"%s\", \"balance\": %d}", collateralizeID, balance)),
}
var res string
......
......@@ -528,11 +528,12 @@ func TestCollateralize(t *testing.T) {
assert.NotNil(t, res)
// collateralize close
p11 := &pkt.CollateralizeCloseTx{
// collateralize retrieve
p11 := &pkt.CollateralizeRetrieveTx{
CollateralizeID: common.ToHex(collateralizeID),
Balance:100,
}
createTx, err = pkt.CreateRawCollateralizeCloseTx(env.cfg, p11)
createTx, err = pkt.CreateRawCollateralizeRetrieveTx(env.cfg, p11)
if err != nil {
t.Error("RPC_Default_Process", "err", err)
}
......@@ -558,7 +559,7 @@ func TestCollateralize(t *testing.T) {
env.kvdb.Set(kv.Key, kv.Value)
}
// query collateralize by status
res, err = exec.Query("CollateralizeByStatus", types.Encode(&pkt.ReqCollateralizeByStatus{Status:2}))
res, err = exec.Query("CollateralizeByStatus", types.Encode(&pkt.ReqCollateralizeByStatus{Status:1}))
assert.Nil(t, err)
assert.NotNil(t, res)
}
......
......@@ -206,7 +206,7 @@ func (action *Action) GetFeedReceiptLog(collateralize *pty.Collateralize, record
// GetCloseReceiptLog generate logs for Collateralize close action
func (action *Action) GetCloseReceiptLog(collateralize *pty.Collateralize) *types.ReceiptLog {
log := &types.ReceiptLog{}
log.Ty = pty.TyLogCollateralizeClose
log.Ty = pty.TyLogCollateralizeRetrieve
c := &pty.ReceiptCollateralize{}
c.CollateralizeId = collateralize.CollateralizeId
......@@ -368,18 +368,16 @@ func (action *Action) CollateralizeCreate(create *pty.CollateralizeCreate) (*typ
return nil, pty.ErrPermissionDeny
}
collateralizeID := common.ToHex(action.txhash)
// 检查ccny余额
if !action.CheckExecTokenAccount(action.fromaddr, create.TotalBalance, false) {
clog.Error("CollateralizeCreate", "fromaddr", action.fromaddr, "balance", create.TotalBalance, "error", types.ErrInsufficientBalance)
return nil, types.ErrInsufficientBalance
}
// 查找ID是否重复
_, err := queryCollateralizeByID(action.db, collateralizeID)
// 根据地址查找ID
collateralizeIDs, err := queryCollateralizeByAddr(action.localDB, action.fromaddr, pty.CollateralizeStatusCreated, 0)
if err != types.ErrNotFound {
clog.Error("CollateralizeCreate", "CollateralizeCreate repeated", collateralizeID)
clog.Error("CollateralizeCreate.queryCollateralizeByAddr", "addr", action.fromaddr)
return nil, pty.ErrCollateralizeRepeatHash
}
......@@ -392,35 +390,46 @@ func (action *Action) CollateralizeCreate(create *pty.CollateralizeCreate) (*typ
logs = append(logs, receipt.Logs...)
kv = append(kv, receipt.KV...)
// 获取借贷配置
var collcfg *pty.CollateralizeManage
cfg, err := getCollateralizeConfig(action.db)
if cfg == nil {
collcfg = &pty.CollateralizeManage{
DebtCeiling:DefaultDebtCeiling,
LiquidationRatio:DefaultLiquidationRatio,
StabilityFeeRatio:DefaultStabilityFeeRation,
Period:DefaultPeriod,
CollTotalBalance:DefaultCollTotalBalance,
var collateralizeID string
coll := &CollateralizeDB{}
if collateralizeIDs == nil {
collateralizeID = common.ToHex(action.txhash)
// 获取借贷配置
var collcfg *pty.CollateralizeManage
cfg, _ := getCollateralizeConfig(action.db)
if cfg == nil {
collcfg = &pty.CollateralizeManage{
DebtCeiling:DefaultDebtCeiling,
LiquidationRatio:DefaultLiquidationRatio,
StabilityFeeRatio:DefaultStabilityFeeRation,
Period:DefaultPeriod,
CollTotalBalance:DefaultCollTotalBalance,
}
} else {
collcfg = cfg
}
// 构造coll结构
coll.CollateralizeId = collateralizeID
coll.LiquidationRatio = collcfg.LiquidationRatio
coll.TotalBalance = create.TotalBalance
coll.DebtCeiling = collcfg.DebtCeiling
coll.StabilityFeeRatio = collcfg.StabilityFeeRatio
coll.Period = collcfg.Period
coll.Balance = create.TotalBalance
coll.CreateAddr = action.fromaddr
coll.Status = pty.CollateralizeActionCreate
coll.Index = action.GetIndex()
coll.CollBalance = 0
} else {
collcfg = cfg
collateralize, err := queryCollateralizeByID(action.db, collateralizeIDs[0])
if err != nil {
clog.Error("CollateralizeCreate.queryCollateralizeByID", "addr", action.fromaddr, "execaddr", action.execaddr, "collId", collateralizeIDs[0])
return nil, err
}
coll.Collateralize = *collateralize
coll.TotalBalance += create.TotalBalance
}
// 构造coll结构
coll := &CollateralizeDB{}
coll.CollateralizeId = collateralizeID
coll.LiquidationRatio = collcfg.LiquidationRatio
coll.TotalBalance = create.TotalBalance
coll.DebtCeiling = collcfg.DebtCeiling
coll.StabilityFeeRatio = collcfg.StabilityFeeRatio
coll.Period = collcfg.Period
coll.Balance = create.TotalBalance
coll.CreateAddr = action.fromaddr
coll.Status = pty.CollateralizeActionCreate
coll.Index = action.GetIndex()
coll.CollBalance = 0
clog.Debug("CollateralizeCreate created", "CollateralizeID", collateralizeID, "TotalBalance", coll.TotalBalance)
// 保存
......@@ -1077,45 +1086,55 @@ func (action *Action) CollateralizeFeed(feed *pty.CollateralizeFeed) (*types.Rec
return receipt, nil
}
// CollateralizeClose 终止借
func (action *Action) CollateralizeClose(close *pty.CollateralizeClose) (*types.Receipt, error) {
// CollateralizeRetrieve 收回未放
func (action *Action) CollateralizeRetrieve(retrieve *pty.CollateralizeRetrieve) (*types.Receipt, error) {
var logs []*types.ReceiptLog
var kv []*types.KeyValue
var receipt *types.Receipt
collateralize, err := queryCollateralizeByID(action.db, close.CollateralizeId)
collateralize, err := queryCollateralizeByID(action.db, retrieve.CollateralizeId)
if err != nil {
clog.Error("CollateralizeClose", "CollateralizeId", close.CollateralizeId, "err", err)
clog.Error("CollateralizeRetrieve", "CollateralizeId", retrieve.CollateralizeId, "err", err)
return nil, err
}
if action.fromaddr != collateralize.CreateAddr {
clog.Error("CollateralizeClose", "CollateralizeId", close.CollateralizeId, "err", "account error", "create", collateralize.CreateAddr, "from", action.fromaddr)
clog.Error("CollateralizeRetrieve", "CollateralizeId", retrieve.CollateralizeId, "err", "account error", "create", collateralize.CreateAddr, "from", action.fromaddr)
return nil, pty.ErrPermissionDeny
}
for _, borrowRecord := range collateralize.BorrowRecords {
if borrowRecord.Status != pty.CollateralizeUserStatusClose {
clog.Error("CollateralizeClose", "CollateralizeId", close.CollateralizeId, "addr", action.fromaddr, "execaddr", action.execaddr, "err", pty.ErrCollateralizeRecordNotEmpty)
return nil, pty.ErrCollateralizeRecordNotEmpty
}
}
//for _, borrowRecord := range collateralize.BorrowRecords {
// if borrowRecord.Status != pty.CollateralizeUserStatusClose {
// clog.Error("CollateralizeRetrieve", "CollateralizeId", retrieve.CollateralizeId, "addr", action.fromaddr, "execaddr", action.execaddr, "err", pty.ErrCollateralizeRecordNotEmpty)
// return nil, pty.ErrCollateralizeRecordNotEmpty
// }
//}
// 收回金额不能大于待放出金额
if retrieve.Balance > collateralize.Balance {
clog.Error("CollateralizeRetrieve", "CollateralizeId", retrieve.CollateralizeId, "err", "balance error", "retrieve balance", retrieve.Balance, "available balance", collateralize.Balance)
return nil, pty.ErrPermissionDeny
}
// 解冻ccny
receipt, err = action.tokenAccount.ExecActive(action.fromaddr, action.execaddr, collateralize.Balance*Coin)
receipt, err = action.tokenAccount.ExecActive(action.fromaddr, action.execaddr, retrieve.Balance*Coin)
if err != nil {
clog.Error("IssuanceClose.ExecActive", "addr", action.fromaddr, "execaddr", action.execaddr, "amount", collateralize.TotalBalance)
clog.Error("IssuanceClose.ExecActive", "addr", action.fromaddr, "execaddr", action.execaddr, "balance", retrieve.Balance)
return nil, err
}
logs = append(logs, receipt.Logs...)
kv = append(kv, receipt.KV...)
clog.Debug("CollateralizeClose", "ID", close.CollateralizeId)
clog.Debug("CollateralizeRetrieve", "ID", retrieve.CollateralizeId, "balance", retrieve.Balance)
coll := &CollateralizeDB{*collateralize}
coll.Status = pty.CollateralizeStatusClose
coll.PreIndex = coll.Index
coll.Index = action.GetIndex()
coll.TotalBalance -= retrieve.Balance
coll.Balance -= retrieve.Balance
if coll.TotalBalance == 0 {
coll.PreIndex = coll.Index
coll.Index = action.GetIndex()
coll.Status = pty.CollateralizeStatusClose
}
coll.Save(action.db)
kv = append(kv, coll.GetKVSet()...)
......
......@@ -39,10 +39,10 @@ func (c *Collateralize) Exec_Feed(payload *pty.CollateralizeFeed, tx *types.Tran
return actiondb.CollateralizeFeed(payload)
}
// Exec_Close Action
func (c *Collateralize) Exec_Close(payload *pty.CollateralizeClose, tx *types.Transaction, index int) (*types.Receipt, error) {
// Exec_Retrieve Action
func (c *Collateralize) Exec_Retrieve(payload *pty.CollateralizeRetrieve, tx *types.Transaction, index int) (*types.Receipt, error) {
actiondb := NewCollateralizeAction(c, tx, index)
return actiondb.CollateralizeClose(payload)
return actiondb.CollateralizeRetrieve(payload)
}
// Exec_Close Action
......
......@@ -13,7 +13,7 @@ func (c *Collateralize) execDelLocal(tx *types.Transaction, receiptData *types.R
set := &types.LocalDBSet{}
for _, item := range receiptData.Logs {
if item.Ty == pty.TyLogCollateralizeCreate || item.Ty == pty.TyLogCollateralizeBorrow || item.Ty == pty.TyLogCollateralizeAppend ||
item.Ty == pty.TyLogCollateralizeRepay || item.Ty == pty.TyLogCollateralizeFeed || item.Ty == pty.TyLogCollateralizeClose {
item.Ty == pty.TyLogCollateralizeRepay || item.Ty == pty.TyLogCollateralizeFeed || item.Ty == pty.TyLogCollateralizeRetrieve {
var collateralizeLog pty.ReceiptCollateralize
err := types.Decode(item.Log, &collateralizeLog)
if err != nil {
......@@ -57,12 +57,14 @@ func (c *Collateralize) execDelLocal(tx *types.Transaction, receiptData *types.R
// set.KV = append(set.KV, c.deleteCollateralizeRecordAddr(collateralizeLog.AccountAddr, collateralizeLog.Index)...)
//}
break
case pty.TyLogCollateralizeClose:
set.KV = append(set.KV, c.deleteCollateralizeStatus(collateralizeLog.Status, collateralizeLog.Index)...)
set.KV = append(set.KV, c.addCollateralizeStatus(pty.CollateralizeStatusCreated, collateralizeLog.CollateralizeId,
collateralizeLog.PreIndex)...)
//set.KV = append(set.KV, c.addCollateralizeAddr(collateralizeLog.CreateAddr, collateralizeLog.CollateralizeId,
// collateralizeLog.PreStatus, collateralizeLog.PreIndex)...)
case pty.TyLogCollateralizeRetrieve:
if collateralizeLog.Status == pty.CollateralizeStatusClose {
set.KV = append(set.KV, c.deleteCollateralizeStatus(collateralizeLog.Status, collateralizeLog.Index)...)
set.KV = append(set.KV, c.addCollateralizeStatus(pty.CollateralizeStatusCreated, collateralizeLog.CollateralizeId,
collateralizeLog.PreIndex)...)
//set.KV = append(set.KV, c.addCollateralizeAddr(collateralizeLog.CreateAddr, collateralizeLog.CollateralizeId,
// collateralizeLog.PreStatus, collateralizeLog.PreIndex)...)
}
break
}
}
......@@ -96,8 +98,8 @@ func (c *Collateralize) ExecDelLocal_Feed(payload *pty.CollateralizeFeed, tx *ty
return c.execDelLocal(tx, receiptData)
}
// ExecDelLocal_Close Action
func (c *Collateralize) ExecDelLocal_Close(payload *pty.CollateralizeClose, tx *types.Transaction, receiptData *types.ReceiptData, index int) (*types.LocalDBSet, error) {
// ExecDelLocal_Retrieve Action
func (c *Collateralize) ExecDelLocal_Retrieve(payload *pty.CollateralizeRetrieve, tx *types.Transaction, receiptData *types.ReceiptData, index int) (*types.LocalDBSet, error) {
return c.execDelLocal(tx, receiptData)
}
......
......@@ -14,7 +14,7 @@ func (c *Collateralize) execLocal(tx *types.Transaction, receipt *types.ReceiptD
set := &types.LocalDBSet{}
for _, item := range receipt.Logs {
if item.Ty == pty.TyLogCollateralizeCreate || item.Ty == pty.TyLogCollateralizeBorrow || item.Ty == pty.TyLogCollateralizeAppend ||
item.Ty == pty.TyLogCollateralizeRepay || item.Ty == pty.TyLogCollateralizeFeed || item.Ty == pty.TyLogCollateralizeClose {
item.Ty == pty.TyLogCollateralizeRepay || item.Ty == pty.TyLogCollateralizeFeed || item.Ty == pty.TyLogCollateralizeRetrieve {
var collateralizeLog pty.ReceiptCollateralize
err := types.Decode(item.Log, &collateralizeLog)
if err != nil {
......@@ -59,10 +59,12 @@ func (c *Collateralize) execLocal(tx *types.Transaction, receipt *types.ReceiptD
// collateralizeLog.RecordId, collateralizeLog.Index)...)
//}
break
case pty.TyLogCollateralizeClose:
set.KV = append(set.KV, c.addCollateralizeStatus(collateralizeLog.Status, collateralizeLog.CollateralizeId, collateralizeLog.Index)...)
set.KV = append(set.KV, c.deleteCollateralizeStatus(collateralizeLog.PreStatus, collateralizeLog.PreIndex)...)
//set.KV = append(set.KV, c.deleteCollateralizeAddr(collateralizeLog.CreateAddr, collateralizeLog.PreIndex)...)
case pty.TyLogCollateralizeRetrieve:
if collateralizeLog.Status == pty.CollateralizeStatusClose {
set.KV = append(set.KV, c.addCollateralizeStatus(collateralizeLog.Status, collateralizeLog.CollateralizeId, collateralizeLog.Index)...)
set.KV = append(set.KV, c.deleteCollateralizeStatus(collateralizeLog.PreStatus, collateralizeLog.PreIndex)...)
//set.KV = append(set.KV, c.deleteCollateralizeAddr(collateralizeLog.CreateAddr, collateralizeLog.PreIndex)...)
}
break
}
}
......@@ -95,8 +97,8 @@ func (c *Collateralize) ExecLocal_Feed(payload *pty.CollateralizeFeed, tx *types
return c.execLocal(tx, receiptData)
}
// ExecLocal_Close Action
func (c *Collateralize) ExecLocal_Close(payload *pty.CollateralizeClose, tx *types.Transaction, receiptData *types.ReceiptData, index int) (*types.LocalDBSet, error) {
// ExecLocal_Retrieve Action
func (c *Collateralize) ExecLocal_Retrieve(payload *pty.CollateralizeRetrieve, tx *types.Transaction, receiptData *types.ReceiptData, index int) (*types.LocalDBSet, error) {
return c.execLocal(tx, receiptData)
}
......
......@@ -51,13 +51,13 @@ message AssetPriceRecord {
// action
message CollateralizeAction {
oneof value {
CollateralizeCreate create = 1; //创建一期借贷
CollateralizeBorrow borrow = 2; //借贷
CollateralizeRepay repay = 3; //清算
CollateralizeAppend append = 4; //追加
CollateralizeFeed feed = 5; //喂价
CollateralizeClose close = 6; //关闭
CollateralizeManage manage = 7; //全局配置
CollateralizeCreate create = 1; //创建一期借贷
CollateralizeBorrow borrow = 2; //借贷
CollateralizeRepay repay = 3; //清算
CollateralizeAppend append = 4; //追加
CollateralizeFeed feed = 5; //喂价
CollateralizeRetrieve retrieve = 6; //收回
CollateralizeManage manage = 7; //全局配置
}
int32 ty = 10;
}
......@@ -105,9 +105,10 @@ message CollateralizeFeed {
repeated int64 volume = 3; //成交量
}
// 放贷关闭
message CollateralizeClose {
// 收回
message CollateralizeRetrieve {
string collateralizeId = 1; //借贷期数ID
int64 balance = 2; //收回金额
}
// exec_local 放贷信息
......
......@@ -57,7 +57,7 @@ func (collateralize *CollateralizeType) GetLogMap() map[int64]*types.LogInfo {
TyLogCollateralizeRepay: {Ty: reflect.TypeOf(ReceiptCollateralize{}), Name: "LogCollateralizeRepay"},
TyLogCollateralizeAppend: {Ty: reflect.TypeOf(ReceiptCollateralize{}), Name: "LogCollateralizeAppend"},
TyLogCollateralizeFeed: {Ty: reflect.TypeOf(ReceiptCollateralize{}), Name: "LogCollateralizeFeed"},
TyLogCollateralizeClose: {Ty: reflect.TypeOf(ReceiptCollateralize{}), Name: "LogCollateralizeClose"},
TyLogCollateralizeRetrieve: {Ty: reflect.TypeOf(ReceiptCollateralize{}), Name: "LogCollateralizeRetrieve"},
}
}
......@@ -111,14 +111,14 @@ func (collateralize CollateralizeType) CreateTx(action string, message json.RawM
return nil, types.ErrInvalidParam
}
return CreateRawCollateralizeFeedTx(cfg, &param)
} else if action == "CollateralizeClose" {
var param CollateralizeCloseTx
} else if action == "CollateralizeRetrive" {
var param CollateralizeRetrieveTx
err := json.Unmarshal(message, &param)
if err != nil {
llog.Error("CreateTx", "Error", err)
return nil, types.ErrInvalidParam
}
return CreateRawCollateralizeCloseTx(cfg, &param)
return CreateRawCollateralizeRetrieveTx(cfg, &param)
} else if action == "CollateralizeManage" {
var param CollateralizeManageTx
err := json.Unmarshal(message, &param)
......@@ -135,13 +135,13 @@ func (collateralize CollateralizeType) CreateTx(action string, message json.RawM
// GetTypeMap method
func (collateralize CollateralizeType) GetTypeMap() map[string]int32 {
return map[string]int32{
"Create": CollateralizeActionCreate,
"Borrow": CollateralizeActionBorrow,
"Repay": CollateralizeActionRepay,
"Append": CollateralizeActionAppend,
"Feed": CollateralizeActionFeed,
"Close": CollateralizeActionClose,
"Manage": CollateralizeActionManage,
"Create": CollateralizeActionCreate,
"Borrow": CollateralizeActionBorrow,
"Repay": CollateralizeActionRepay,
"Append": CollateralizeActionAppend,
"Feed": CollateralizeActionFeed,
"Retrieve": CollateralizeActionRetrieve,
"Manage": CollateralizeActionManage,
}
}
......@@ -290,19 +290,20 @@ func CreateRawCollateralizeFeedTx(cfg *types.Chain33Config, parm *CollateralizeF
return tx, nil
}
// CreateRawCollateralizeCloseTx method
func CreateRawCollateralizeCloseTx(cfg *types.Chain33Config, parm *CollateralizeCloseTx) (*types.Transaction, error) {
// CreateRawCollateralizeRetrieveTx method
func CreateRawCollateralizeRetrieveTx(cfg *types.Chain33Config, parm *CollateralizeRetrieveTx) (*types.Transaction, error) {
if parm == nil {
llog.Error("CreateRawCollateralizeCloseTx", "parm", parm)
return nil, types.ErrInvalidParam
}
v := &CollateralizeClose{
v := &CollateralizeRetrieve{
CollateralizeId: parm.CollateralizeID,
Balance: parm.Balance,
}
close := &CollateralizeAction{
Ty: CollateralizeActionClose,
Value: &CollateralizeAction_Close{v},
Ty: CollateralizeActionRetrieve,
Value: &CollateralizeAction_Retrieve{v},
}
tx := &types.Transaction{
Execer: []byte(cfg.ExecName(CollateralizeX)),
......
......@@ -39,9 +39,10 @@ type CollateralizeFeedTx struct {
Fee int64 `json:"fee"`
}
// CollateralizeCloseTx for construction
type CollateralizeCloseTx struct {
// CollateralizeRetrieveTx for construction
type CollateralizeRetrieveTx struct {
CollateralizeID string `json:"collateralizeId"`
Balance int64 `json:"Balance"`
Fee int64 `json:"fee"`
}
......
......@@ -11,7 +11,7 @@ const (
CollateralizeActionRepay
CollateralizeActionAppend
CollateralizeActionFeed
CollateralizeActionClose
CollateralizeActionRetrieve
CollateralizeActionManage
//log for Collateralize
......@@ -20,7 +20,7 @@ const (
TyLogCollateralizeRepay = 733
TyLogCollateralizeAppend = 734
TyLogCollateralizeFeed = 735
TyLogCollateralizeClose = 736
TyLogCollateralizeRetrieve = 736
)
// Collateralize name
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment