diff --git a/apps/README.md b/apps/README.md
index 20cc02072a153e156482705352901880a938f37d..e1874dad259d2e0b77d9a248284716d4dc8cd20c 100644
--- a/apps/README.md
+++ b/apps/README.md
@@ -89,7 +89,7 @@ Moved to stock caaa642c25d96a5d8f14cf031a898fed
 $ cd ../cement-cli
 $ node index.js bid
 ? Select asset 19e2f7a99288dfc9a2902e71bfc9dfe6 (Stock, type: 1002, status: stocked)
-? Choose an ammount of slag 34
+? Choose an amount of slag 34
 ? Provide the offered price 3
 Bid for slag stock 19e2f7a99288dfc9a2902e71bfc9dfe6
 
@@ -100,8 +100,29 @@ $ node index.js bid-accept
 0LWNvbXBhbnkxLmNvbSxPPWNlbWVudC1jb21wYW55MS5jb20sTD1SYWxlaWdoLFNUPU5vcnRoIENhcm9saW5hLEM9VVM= (quantity: 34, price: 3)
 Bid from cement-company1-com:eDUwOTo6Q049dXNlcixPVT1jbGllbnQrT1U9b3JnMStPVT1kZXBhcnRtZW50MTo6Q049Y2EuY2VtZW50LWNvbXBhbnkxLmNvbSxPPWNlbWVudC1jb21wYW55MS5jb20sTD1SYWxlaWdoLFNUPU5vcnRoIENhcm9saW5hLEM9VVM= accepted for asset 19e2f7a99288dfc9a2902e71bfc9dfe6
 
+$ node index.js discard-stock
+? Select asset 7bbed24d305800c2f2e61b7f14539249 (Stock, type: 1002, status: stocked)
+? Choose an amount of slag (max: 7297 kg): 729
+Discarded stock 15fb63d1d6071f9ee101bc41e5b4c75f (new stock e511a4dbb32669282e14838ec012e2e0)
+
 $ cd ../pubadmin-cli
 $ node index.js stats
+┌─────────────┬────────────┬─────────────────┬────────────────┬───────────────────────┐
+│             │ Total slag │          Reused │      Discarded │           Price (€/t) │
+│             │          t │           t [%] │          t [%] │        Avg [Min, Max] │
+├─────────────┼────────────┼─────────────────┼────────────────┼───────────────────────┤
+│ sidenor.com │     17.375 │ 3.763 [21.66 %] │ 1.302 [7.49 %] │ 18.13 [49.74, 522.61] │
+└─────────────┴────────────┴─────────────────┴────────────────┴───────────────────────┘
+
+┌─────────────────────┬────────────┬─────────────────────────┐
+│                     │ Total slag │             Price (€/t) │
+│                     │          t │          Avg [Min, Max] │
+├─────────────────────┼────────────┼─────────────────────────┤
+│ cement-company1.com │      0.667 │ 241.38 [121.79, 522.61] │
+├─────────────────────┼────────────┼─────────────────────────┤
+│ cement-company2.com │      3.096 │    49.74 [49.74, 49.74] │
+└─────────────────────┴────────────┴─────────────────────────┘
+
 
 # Or to generate/simulate a complete cycle:
 $ cd ../batch-sim
diff --git a/apps/batch-sim/index.js b/apps/batch-sim/index.js
index 714f3a283f815c8dd1fb57c5bf1f67ec07819bec..921fd57eeda9ee1701436b8164418fb892340a94 100644
--- a/apps/batch-sim/index.js
+++ b/apps/batch-sim/index.js
@@ -9,7 +9,8 @@ const {
   editComposition,
   sendToCone,
   sendToStock,
-  acceptBid
+  acceptBid,
+  discardStock
 } = require("@hypercog/sidenor-cli")
 
 const { bidAsset } = require("@hypercog/cement-cli")
@@ -42,23 +43,27 @@ const simulateCycle = async (arg1, cmd) => {
   //batchId = await createAssetAndSendToCone(apiClient, "simulated asset 2")
   //batchId = await createAssetAndSendToCone(apiClient, "simulated asset 3")
 
-  const selectedStock = await sendToStock(apiClient, { assetId: batchId })
+  const mergedStock = await sendToStock(apiClient, { assetId: batchId })
+  const selectedStockId = await discardStock(apiClient, {
+    assetId: mergedStock.id
+  })
+  const selectedStock = await apiClient.getAsset(selectedStockId)
 
   await signInAs(apiClient, otherArgs.cement1User, password)
   await bidAsset(apiClient, {
-    assetId: selectedStock.id,
+    assetId: selectedStockId,
     price: faker.datatype.number({ min: 50, max: 150 })
   })
 
   await signInAs(apiClient, otherArgs.cement2User, password)
   await bidAsset(apiClient, {
-    assetId: selectedStock.id,
+    assetId: selectedStockId,
     quantity: selectedStock.quantity - 500,
     price: faker.datatype.number({ min: 25, max: 200 })
   })
 
   await signInAs(apiClient, otherArgs.sidenorUser, password)
-  await acceptBid(apiClient, { assetId: selectedStock.id })
+  await acceptBid(apiClient, { assetId: selectedStockId })
 }
 
 const program = createCLIApp()
diff --git a/apps/cement-cli/lib.js b/apps/cement-cli/lib.js
index fdd44dc4c76d19d0a5417aefe043526ff88f116c..fc54b70c2aad9bb1d1dbb0fc7df8b60f9bef4ec8 100644
--- a/apps/cement-cli/lib.js
+++ b/apps/cement-cli/lib.js
@@ -19,7 +19,7 @@ const bidAsset = async (
       {
         type: "number",
         name: "inputQuantity",
-        message: `Choose an ammount of slag (max: ${assetToBid.quantity} ${assetToBid.units}):`,
+        message: `Choose an amount of slag to bid for (max: ${assetToBid.quantity} ${assetToBid.units}):`,
         default: Math.floor(assetToBid.quantity * 0.1) // Default: 10%
       }
     ])
diff --git a/apps/sidenor-cli/lib.js b/apps/sidenor-cli/lib.js
index a3e730baea4ddcc4bccc716f48ecf958f6cf7ad2..ea6eb6244a7966b047449f3622d0019e18de302d 100644
--- a/apps/sidenor-cli/lib.js
+++ b/apps/sidenor-cli/lib.js
@@ -234,37 +234,20 @@ const discardStock = async (apiClient, { assetId: paramAssetId, quantity }) => {
       {
         type: "number",
         name: "inputQuantity",
-        message: `Choose an ammount of slag (max: ${assetToDiscard.quantity} ${assetToDiscard.units}):`,
+        message: `Choose an amount of slag to discard (max: ${assetToDiscard.quantity} ${assetToDiscard.units}):`,
         default: Math.floor(assetToDiscard.quantity * 0.1) // Default: 10%
       }
     ])
     chosenQuantity = inputQuantity
   }
 
-  const newAssets = await apiClient.splitAsset(assetId, 2, {
-    archiveOld: true,
-    bidirectional: true,
-    base: {
-      type: assetToDiscard.type,
-      fields: assetToDiscard.fields
-    }
-  })
-
-  await apiClient.modifyAsset({
-    id: newAssets[0],
-    quantity: assetToDiscard.quantity - chosenQuantity,
-    units: assetToDiscard.units
-  })
-
-  await apiClient.modifyAsset({
-    id: newAssets[1],
-    quantity: chosenQuantity,
-    units: assetToDiscard.units
-  })
-
-  await apiClient.deleteAsset(newAssets[1])
+  const [newStock, discardedBatch] = await apiClient.deleteAsset(
+    assetId,
+    chosenQuantity
+  )
 
-  console.log(`Discarded stock ${newAssets[1]} (new stock ${newAssets[0]})`)
+  console.log(`Discarded stock ${discardedBatch} (new stock ${newStock})`)
+  return newStock
 }
 
 // To be reused as a library in @hypercog/batch-sim
diff --git a/apps/utils/client.js b/apps/utils/client.js
index c4fb3b83caefead13cf86638226958850165939e..6c93704307dd6f3df52092ec9c2c63ccecc0b4f0 100644
--- a/apps/utils/client.js
+++ b/apps/utils/client.js
@@ -38,6 +38,25 @@ class HypercogApiClient extends TraceblockApiClient {
       body: { id, bidder }
     })
   }
+
+  /**
+   * Archives an asset (overrides original definition).
+   *
+   * @param {string} id Asset identifier.
+   * @param {number} quantity Magnitude measured in the units specified in the associated asset definition.
+   */
+  async deleteAsset(id, quantity) {
+    const { payload } = await this._invoke("asset-archive", {
+      body: { id, quantity }
+    })
+    return payload
+  }
+
+  Bid(id, bidder) {
+    return this._invoke("asset-archive", {
+      body: { id, bidder }
+    })
+  }
 }
 
 module.exports = HypercogApiClient
diff --git a/chaincode/controller/discard/acl.go b/chaincode/controller/discard/acl.go
new file mode 100644
index 0000000000000000000000000000000000000000..1e9e4b470b6ba9b84acf9dd259372c3aed4286fd
--- /dev/null
+++ b/chaincode/controller/discard/acl.go
@@ -0,0 +1,38 @@
+/**
+ * acl.go
+ *
+ * COPYRIGHT: FUNDACIÓN TECNALIA RESEARCH & INNOVATION, 2022.
+ */
+
+package discard
+
+import (
+	"git.code.tecnalia.com/ledgerbuilder/sdk/core/api"
+	"git.code.tecnalia.com/ledgerbuilder/sdk/core/fabric/protos"
+	"git.code.tecnalia.com/ledgerbuilder/sdk/shared"
+
+	"git.code.tecnalia.com/traceblock/sdk/controller/utils"
+)
+
+func (c DiscardController) CheckACL(validations []utils.OwnershipACL, trigger shared.TriggerFunction) shared.TriggerFunction {
+	return func(stub shared.LedgerBuildrStubInterface, requestAsset shared.LedgerBuildrAsset) protos.Response {
+		const fnName = "ACL"
+
+		storedAsset, err := c.readAsset(stub, requestAsset)
+		if err != nil {
+			return api.NewApiResponsePtr(fnName, err, nil).SendResponse()
+		}
+
+		for _, validation := range validations {
+			if err := validation(storedAsset.Owner, stub); err != nil {
+				return api.NewApiResponsePtr(fnName, err, nil).SendResponse()
+			}
+		}
+
+		return trigger(stub, requestAsset)
+	}
+}
+
+func (c DiscardController) OnlySameOrgAndRole(trigger shared.TriggerFunction) shared.TriggerFunction {
+	return c.CheckACL([]utils.OwnershipACL{utils.OwnedBySameOrg, utils.OwnedBySameRoleOrAdmin}, trigger)
+}
\ No newline at end of file
diff --git a/chaincode/controller/discard/controller.go b/chaincode/controller/discard/controller.go
new file mode 100644
index 0000000000000000000000000000000000000000..d8e24d709fb639c37bbe7ceeca791196cc121c33
--- /dev/null
+++ b/chaincode/controller/discard/controller.go
@@ -0,0 +1,159 @@
+/**
+ * controller.go
+ *
+ * COPYRIGHT: FUNDACIÓN TECNALIA RESEARCH & INNOVATION, 2022.
+ */
+
+package discard
+
+import (
+	"errors"
+
+	"git.code.tecnalia.com/ledgerbuilder/sdk/core/api"
+	"git.code.tecnalia.com/ledgerbuilder/sdk/core/controller"
+	"git.code.tecnalia.com/ledgerbuilder/sdk/core/fabric/protos"
+	"git.code.tecnalia.com/ledgerbuilder/sdk/shared"
+
+	"git.code.tecnalia.com/blockchain/hypercog/controller/stats"
+
+	errs "git.code.tecnalia.com/traceblock/sdk/constants"
+	"git.code.tecnalia.com/traceblock/sdk/controller/base"
+	"git.code.tecnalia.com/traceblock/sdk/controller/split"
+	"git.code.tecnalia.com/traceblock/sdk/model"
+)
+
+type DiscardController struct {
+	base.TraceblockBaseController
+}
+
+var (
+	errInvalidInputData     = errors.New("failed to read model")
+	errInvalidDiscardQuantity = errors.New("quantity to discard is greater than the available quantity")
+)
+
+// constructor like function
+func NewDiscardController() *DiscardController {
+	ctl := new(DiscardController)
+	ctl.LowLevelController = controller.NewLowLevelController()
+	ctl.SetDataModelClosure(ctl.modelClosure)
+	return ctl
+}
+
+func (c DiscardController) modelClosure(stub shared.LedgerBuildrStubInterface) shared.LedgerBuildrAsset {
+	return NewDiscardParams()
+}
+
+func (c DiscardController) readTraceableAsset(stub shared.LedgerBuildrStubInterface, assetId string) (*model.TraceableAsset, error) {
+	readedModel, err := c.ReadAbstractAssetAndReturn(stub, assetId, model.NewTraceableAsset())
+	if err != nil {
+		return nil, err
+	}
+
+	// asset data successfully readed
+	asset, ok := readedModel.(*model.TraceableAsset)
+	if !ok {
+		return nil, errs.NotExistingAsset
+	}
+
+	return asset, nil
+}
+
+func (c DiscardController) readAsset(stub shared.LedgerBuildrStubInterface, requestAsset shared.LedgerBuildrAsset) (*model.TraceableAsset, error) {
+	return c.readTraceableAsset(stub, requestAsset.GetID())
+}
+
+
+// HyperCOG specific discard operation
+func  (c DiscardController) _discardAsset(stub shared.LedgerBuildrStubInterface, params *DiscardParams, discardableAsset *model.TraceableAsset) (*protos.Response, error) {
+	if discardableAsset.Quantity < params.Quantity {
+		return nil, errInvalidDiscardQuantity
+	}
+
+	var discardedStock *model.TraceableAsset
+	generatedIds := make([]string, 2)
+
+	if params.Quantity == discardableAsset.Quantity {
+		discardedStock = discardableAsset
+	} else {
+		// discardableAsset.Quantity > discardParams.Quantity
+		splitParams := new(split.SplitParams)
+		splitParams.SetID(discardableAsset.GetID())
+		splitParams.SplitConfig.ArchiveOld = true
+		splitParams.SplitConfig.Bidirectional = true
+		splitParams.SplitConfig.ChildCount = 2
+		splitParams.SplitConfig.BaseAsset.AssetType = discardableAsset.AssetType
+		splitParams.SplitConfig.BaseAsset.ArbitraryDataFields = discardableAsset.ArbitraryDataFields
+
+		subAssets, err := split.SplitAsset(c.TraceblockBaseController, stub, discardableAsset, *splitParams)
+		if err != nil {
+			return nil, err
+		}
+
+		for i, c := range subAssets {
+			generatedIds[i] = c.GetID()
+		}
+
+		newStock := subAssets[0]
+		newStock.Quantity = discardableAsset.Quantity - params.Quantity
+		newStock.Units = discardableAsset.Units
+
+		respNewStock:= c.SaveAbstractAsset(stub, &newStock)
+		if respNewStock.Status != shared.OK {
+			return &respNewStock, nil
+		}
+
+		discardedStock = &subAssets[1]
+
+		discardedStock.Quantity = params.Quantity
+		discardedStock.Units = discardableAsset.Units
+	}
+
+	discardedStock.ArbitraryDataFields["status"] = "discarded"
+
+	err := stats.RegisterDiscard(stub, discardedStock.Quantity, discardedStock.Units)
+	if err != nil {
+		return nil, err
+	}
+
+	respDiscarted := c.SaveAbstractAsset(stub, discardedStock)
+	if respDiscarted.Status != shared.OK {
+		return &respDiscarted, nil
+	}
+
+	ret := api.NewAPIGenericResponsePtr("DiscardController:Discard", nil, generatedIds).SendResponse()
+	return &ret, nil
+}
+
+func  (c DiscardController) _archiveAsset(stub shared.LedgerBuildrStubInterface, params shared.LedgerBuildrAsset) (*protos.Response, error) {
+	discardParams, ok := params.(*DiscardParams)
+	if discardParams == nil || !ok {
+		//failed when casting/fetching input data
+		return nil, errInvalidInputData
+	}
+
+	discardableAsset, err := c.readAsset(stub, discardParams)
+	if err != nil {
+		return nil, err
+	}
+
+	status, ok := discardableAsset.Get("status")
+	if status != "stocked" || status == "stocked" && discardParams.Quantity == 0 {
+		// Done in MarkAssetAsDeleted middleware in normal operation
+		discardableAsset.MarkModification(stub)
+		discardableAsset.MarkAsDeleted()
+
+		responseArchive := c.DeleteAbstractAsset(stub, discardableAsset)
+		return &responseArchive, nil
+	}
+
+	// HyperCOG specific discard operation
+	return c._discardAsset(stub, discardParams, discardableAsset)
+}
+
+func (c DiscardController) Discard(stub shared.LedgerBuildrStubInterface, params shared.LedgerBuildrAsset) protos.Response {
+	ret, err := c._archiveAsset(stub, params)
+	if err != nil {
+		return api.NewApiResponsePtr("DiscardController:Discard", err, nil).SendResponse()
+	}
+	return *ret
+}
\ No newline at end of file
diff --git a/chaincode/controller/discard/input.go b/chaincode/controller/discard/input.go
new file mode 100644
index 0000000000000000000000000000000000000000..4a03256bb3ed80aef64ca1aa6cc8ab2bdbc508fd
--- /dev/null
+++ b/chaincode/controller/discard/input.go
@@ -0,0 +1,68 @@
+/**
+ * input.go
+ *
+ * COPYRIGHT: FUNDACIÓN TECNALIA RESEARCH & INNOVATION, 2022.
+ */
+
+package discard
+
+import (
+	"git.code.tecnalia.com/ledgerbuilder/sdk/core/model/io"
+	"git.code.tecnalia.com/ledgerbuilder/sdk/shared"
+	errs "git.code.tecnalia.com/traceblock/sdk/constants"
+)
+
+type DiscardParams struct {
+	shared.LedgerBuildrAsset
+	AssetId     string `json:"id"`
+	Quantity    uint32 `json:"quantity,omitempty"`
+}
+
+func (p *DiscardParams) GetID() string {
+	return p.AssetId
+}
+
+func (p *DiscardParams) Get(key string) (interface{}, bool) {
+	return nil, false
+}
+
+func (p *DiscardParams) SetID(id string) {
+	p.AssetId = id
+}
+
+func (p *DiscardParams) StubBytes() []byte {
+	return []byte{}
+}
+
+func (p *DiscardParams) LedgerBytes() []byte {
+	return nil
+}
+
+func (p *DiscardParams) ReadValidation() bool {
+	return false
+}
+
+// set write validations to false to avoid ledger persistency
+func (p *DiscardParams) WriteValidation() bool {
+	return false
+}
+
+func (p *DiscardParams) StubReader(stub shared.LedgerBuildrStubInterface) (shared.LedgerBuildrAsset, error) {
+	if stub != nil {
+		parseErr := io.NewJSONSerializer().LoadFromByteArray(&p, stub.GetPayload())
+		return p, parseErr
+	}
+	return nil, errs.StubReader
+}
+
+func (p *DiscardParams) LedgerReader(data []byte) (shared.LedgerBuildrAsset, error) {
+	if data != nil {
+		parseErr := io.NewJSONSerializer().LoadFromByteArray(&p, data)
+		return p, parseErr
+	}
+	return nil, errs.LedgerReader
+}
+
+func NewDiscardParams() shared.LedgerBuildrAsset {
+	return new(DiscardParams)
+}
diff --git a/chaincode/controller/operations.go b/chaincode/controller/operations.go
index dd68be5bf7c02436c526ebf3a3cbbea0ca96a4eb..e270c4f3e168e90e2cd6d28fae58b908b7c38f01 100644
--- a/chaincode/controller/operations.go
+++ b/chaincode/controller/operations.go
@@ -21,6 +21,7 @@ import (
 	"git.code.tecnalia.com/traceblock/sdk/middleware"
 
 	"git.code.tecnalia.com/blockchain/hypercog/controller/bid"
+	"git.code.tecnalia.com/blockchain/hypercog/controller/discard"
 	"git.code.tecnalia.com/blockchain/hypercog/controller/stats"
 	m2 "git.code.tecnalia.com/blockchain/hypercog/middleware"
 )
@@ -40,24 +41,22 @@ var (
 	// bid controller
 	bidController			*bid.BidController
 	bidDecisionController	*bid.BidDecisionController
+	
+	discardController		*discard.DiscardController
 )
 
 func init() {
 	assetController = asset.NewTraceableAssetController()
-	// for debug/testing functions
-	testController = controller.NewHelperController()
-	// for ui related helper calls
-	uiController = controller.NewUIController()
-	// transfer controller
 	transferController = transfer.NewTransferAssetController()
-	// asset split controller
 	splitController = split.NewSplitController()
-	// asset join controller
 	joinController = join.NewJoinController()
-	// qr controller
 	qrController = qr.NewQRController()
-	// barcode controller
 	barcodeController = barcode.NewBarcodeController()
+	discardController = discard.NewDiscardController()
+	// for ui related helper calls
+	uiController = controller.NewUIController()
+	// for debug/testing functions
+	testController = controller.NewHelperController()
 	// bid controllers
 	bidController = bid.NewBidController()
 	bidDecisionController = bid.NewBidDecisionController()
@@ -113,14 +112,15 @@ func ContextOperations(m shared.AbstractChaincodeOperationManager) error {
 				nil,
 				assetController.OnlySameOrgAndRole(assetController.UpdateAsset),
 			).
-			AddOperation(
+			AddOperationWithoutDefaults(
 				"asset-archive",
 				shared.WRITE_OP,
-				[]shared.MiddlewareInterface{
-					middleware.MarkAssetAsDeleted,
-				},
 				nil,
-				assetController.OnlySameOrgAndRole(assetController.DeleteAbstractAsset),
+				discardController.StubReader,
+				discardController.LedgerReader,
+				nil,
+				nil,
+				discardController.OnlySameOrgAndRole(discardController.Discard),
 			).
 			AddOperationWithoutDefaults(
 				"asset-transfer",
diff --git a/chaincode/controller/stats/stub.go b/chaincode/controller/stats/stub.go
index 26359f5f61993d04129e6b97e6160bb1c660dfd6..66066ad42567f667501f4c701f93a2527b07e815 100644
--- a/chaincode/controller/stats/stub.go
+++ b/chaincode/controller/stats/stub.go
@@ -220,6 +220,23 @@ func RegisterSlag(stub shared.LedgerBuildrStubInterface, quantity uint32, units
 	return nil
 }
 
+
+func RegisterDiscard(stub shared.LedgerBuildrStubInterface, quantity uint32, units string) (error) {
+	orgStats, err := retrieveExistingStats(stub)
+	if err != nil {
+		return err
+	}
+
+	orgStats.RegisterDiscard(quantity, units)
+
+	err = upgradeSteelStats(stub, orgStats)
+	if err != nil {
+		return err
+	}
+
+	return nil
+}
+
 func RegisterSale(stub shared.LedgerBuildrStubInterface, acceptedBid *model.Bid, units string) (error) {
 	senderOrgStats, err := retrieveExistingStats(stub)
 	if err != nil {
diff --git a/chaincode/model/stats/steel.go b/chaincode/model/stats/steel.go
index 14020c08d2860ce5ad2a1a844b4959b0e54a816a..5293d659bed2e060039423ccb3a71d9a798509ec 100644
--- a/chaincode/model/stats/steel.go
+++ b/chaincode/model/stats/steel.go
@@ -28,6 +28,10 @@ func (raw *RawSteelOrgStats) RegisterSlag(quantity uint32, units string) {
 	raw.TotalSlag += toTons(quantity, units)
 }
 
+func (raw *RawSteelOrgStats) RegisterDiscard(quantity uint32, units string) {
+	raw.SlagDiscarded += toTons(quantity, units)
+}
+
 func (raw *RawSteelOrgStats) UpgradeSale(quantity uint32, price float32, units string) {
 	soldBatch := toTons(quantity, units)
 	raw.SlagReused += soldBatch