diff --git a/core/state_processor.go b/core/state_processor.go
index b4e864c2cb..328c392556 100644
--- a/core/state_processor.go
+++ b/core/state_processor.go
@@ -577,7 +577,7 @@ func (p *StateProcessor) Process(block *types.WorkObject, batch ethdb.Batch) (ty
 					value := etx.Value()
 					txGas := etx.Gas()
 					if txGas < params.TxGas {
-						continue
+						return nil, nil, nil, nil, 0, 0, 0, nil, nil, fmt.Errorf("etx gas is less than the minimum gas required")
 					}
 					txGas -= params.TxGas
 					if err := gp.SubGas(params.TxGas); err != nil {
@@ -587,15 +587,19 @@ func (p *StateProcessor) Process(block *types.WorkObject, batch ethdb.Batch) (ty
 					totalEtxGas += params.TxGas
 					denominations := misc.FindMinDenominations(value)
 					outputIndex := uint16(0)
+					total := big.NewInt(0)
+					success := true
 					// Iterate over the denominations in descending order
 					for denomination := types.MaxDenomination; denomination >= 0; denomination-- {
 						// If the denomination count is zero, skip it
 						if denominations[uint8(denomination)] == 0 {
 							continue
 						}
+
 						for j := uint64(0); j < denominations[uint8(denomination)]; j++ {
 							if txGas < params.CallValueTransferGas || outputIndex >= types.MaxOutputIndex {
 								// No more gas, the rest of the denominations are lost but the tx is still valid
+								success = false
 								break
 							}
 							txGas -= params.CallValueTransferGas
@@ -612,9 +616,29 @@ func (p *StateProcessor) Process(block *types.WorkObject, batch ethdb.Batch) (ty
 							utxosCreatedDeleted.UtxosCreatedHashes = append(utxosCreatedDeleted.UtxosCreatedHashes, types.UTXOHash(etx.Hash(), outputIndex, utxo))
 							utxosCreatedDeleted.UtxosCreatedKeys = append(utxosCreatedDeleted.UtxosCreatedKeys, rawdb.UtxoKeyWithDenomination(etx.Hash(), outputIndex, utxo.Denomination))
 							p.logger.Debugf("Converting Quai to Qi %032x with denomination %d index %d lock %d\n", tx.Hash(), denomination, outputIndex, lock)
+							total.Add(total, types.Denominations[uint8(denomination)])
 							outputIndex++
 						}
 					}
+					if success {
+						receipt = &types.Receipt{Type: tx.Type(), Status: types.ReceiptStatusSuccessful, GasUsed: etx.Gas() - txGas, TxHash: tx.Hash(),
+							Logs: []*types.Log{{
+								Address: *etx.To(),
+								Topics:  []common.Hash{types.QuaiToQiConversionTopic},
+								Data:    total.Bytes(),
+							}},
+						}
+					} else {
+						receipt = &types.Receipt{Type: tx.Type(), Status: types.ReceiptStatusFailed, GasUsed: etx.Gas(), TxHash: tx.Hash(),
+							Logs: []*types.Log{{
+								Address: *etx.To(),
+								Topics:  []common.Hash{types.QuaiToQiConversionTopic},
+								Data:    total.Bytes(),
+							}},
+						}
+					}
+					receipts = append(receipts, receipt)
+					allLogs = append(allLogs, receipt.Logs...)
 				} else if !types.IsCoinBaseTx(tx) && !etx.ETXSender().Location().Equal(*etx.To().Location()) && etx.To().IsInQiLedgerScope() { // Regular Qi ETX
 					utxo := types.NewUtxoEntry(types.NewTxOut(uint8(etx.Value().Uint64()), etx.To().Bytes(), big.NewInt(0)))
 					// There are no more checks to be made as the ETX is worked so add it to the set
diff --git a/core/types/transaction.go b/core/types/transaction.go
index a857889871..05c716c5af 100644
--- a/core/types/transaction.go
+++ b/core/types/transaction.go
@@ -1307,3 +1307,17 @@ func IsConversionTx(tx *Transaction) bool {
 	}
 	return tx.EtxType() == ConversionType
 }
+
+func IsQiToQuaiConversionTx(tx *Transaction) bool {
+	if tx.Type() == ExternalTxType && tx.EtxType() == ConversionType && tx.To().IsInQuaiLedgerScope() {
+		return true
+	}
+	return false
+}
+
+func IsQuaiToQiConversionTx(tx *Transaction) bool {
+	if tx.Type() == ExternalTxType && tx.EtxType() == ConversionType && tx.To().IsInQiLedgerScope() {
+		return true
+	}
+	return false
+}
diff --git a/core/types/utxo.go b/core/types/utxo.go
index aa8cc89272..c20d83a13c 100644
--- a/core/types/utxo.go
+++ b/core/types/utxo.go
@@ -20,7 +20,10 @@ const (
 	MaxTrimDenomination = 5
 )
 
-var MaxQi = new(big.Int).Mul(big.NewInt(math.MaxInt64), big.NewInt(params.Ether)) // This is just a default; determine correct value later
+var (
+	MaxQi                   = new(big.Int).Mul(big.NewInt(math.MaxInt64), big.NewInt(params.Ether)) // This is just a default; determine correct value later
+	QuaiToQiConversionTopic = crypto.Keccak256Hash([]byte("QuaiToQiConversion"))
+)
 
 // Denominations is a map of denomination to number of Qi
 var Denominations map[uint8]*big.Int
@@ -49,8 +52,8 @@ func init() {
 	TrimDepths = make(map[uint8]uint64)
 	TrimDepths[0] = params.GoldenAgeForkNumberV2 + 720  // 2 hours after fork starts from block 1
 	TrimDepths[1] = params.GoldenAgeForkNumberV2 + 720  // 2 hours
-	TrimDepths[2] = params.GoldenAgeForkNumberV2 + 1080  // 3 hours
-	TrimDepths[3] = params.GoldenAgeForkNumberV2 + 1080  // 3 hours
+	TrimDepths[2] = params.GoldenAgeForkNumberV2 + 1080 // 3 hours
+	TrimDepths[3] = params.GoldenAgeForkNumberV2 + 1080 // 3 hours
 	TrimDepths[4] = params.GoldenAgeForkNumberV2 + 2160 // 6 hours
 	TrimDepths[5] = params.GoldenAgeForkNumberV2 + 4320 // 12 hours
 }
diff --git a/core/types/wo.go b/core/types/wo.go
index db293955ca..e5bedf5023 100644
--- a/core/types/wo.go
+++ b/core/types/wo.go
@@ -449,7 +449,7 @@ func (wo *WorkObject) TransactionsWithReceipts() []*Transaction {
 			// ignore the coinbase tx
 			continue
 		}
-		if !IsConversionTx(t) && (t.Type() == QuaiTxType || (t.Type() == ExternalTxType && t.To().IsInQuaiLedgerScope())) {
+		if t.Type() == QuaiTxType || (t.Type() == ExternalTxType && t.Type() != ConversionType && t.To().IsInQuaiLedgerScope()) || IsQuaiToQiConversionTx(t) {
 			txs = append(txs, t)
 		}
 	}
diff --git a/core/vm/instructions.go b/core/vm/instructions.go
index 3e14591ca9..05aca55ad6 100644
--- a/core/vm/instructions.go
+++ b/core/vm/instructions.go
@@ -885,6 +885,7 @@ func opETX(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte
 	addr, value, etxGasLimit, gasTipCap, gasFeeCap, inOffset, inSize, accessListOffset, accessListSize := stack.pop(), stack.pop(), stack.pop(), stack.pop(), stack.pop(), stack.pop(), stack.pop(), stack.pop(), stack.pop()
 	toAddr := common.Bytes20ToAddress(addr.Bytes20(), interpreter.evm.chainConfig.Location)
 	// Verify address is not in context
+	// This means that a conversion cannot happen with opETX
 	if common.IsInChainScope(toAddr.Bytes(), interpreter.evm.chainConfig.Location) {
 		temp.Clear()
 		stack.push(&temp)
@@ -911,6 +912,21 @@ func opETX(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte
 		return nil, nil
 	}
 
+	if etxGasLimit.CmpUint64(math.MaxUint64) == 1 {
+		temp.Clear()
+		stack.push(&temp)
+		fmt.Printf("%x opETX error: gas limit %d is greater than maximum %d\n", scope.Contract.self.Address(), etxGasLimit, math.MaxInt64)
+		return nil, nil
+	}
+
+	// Overflow not a problem here as overflow guarantees a number larger than txgas
+	if etxGasLimit.Uint64() < params.TxGas {
+		temp.Clear()
+		stack.push(&temp)
+		fmt.Printf("%x opETX error: gas limit %d is less than minimum %d\n", scope.Contract.self.Address(), etxGasLimit, params.TxGas)
+		return nil, nil
+	}
+
 	interpreter.evm.StateDB.SubBalance(internalSender, total.ToBig())
 
 	// Get the arguments from the memory.
@@ -1004,6 +1020,14 @@ func opConvert(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]
 		return nil, nil
 	}
 
+	// Overflow not a problem here as overflow guarantees a number larger than txgas
+	if etxGasLimit.Uint64() < params.TxGas {
+		temp.Clear()
+		stack.push(&temp)
+		fmt.Printf("%x opETX error: gas limit %d is less than minimum %d\n", scope.Contract.self.Address(), etxGasLimit, params.TxGas)
+		return nil, nil
+	}
+
 	interpreter.evm.StateDB.SubBalance(internalSender, total.ToBig())
 
 	interpreter.evm.ETXCacheLock.RLock()
diff --git a/core/worker.go b/core/worker.go
index 8763982b42..9fa619b234 100644
--- a/core/worker.go
+++ b/core/worker.go
@@ -1241,8 +1241,7 @@ func (w *worker) commitTransaction(env *environment, parent *types.WorkObject, t
 				}
 			}
 			if txGas < params.TxGas {
-				// No gas, the result is a no-op but the tx is still valid
-				return nil, false, nil
+				return nil, false, fmt.Errorf("insufficient gas for Qi->Quai conversion")
 			}
 			txGas -= params.TxGas
 			if err := env.gasPool.SubGas(params.TxGas); err != nil {
@@ -1251,7 +1250,8 @@ func (w *worker) commitTransaction(env *environment, parent *types.WorkObject, t
 			gasUsed += params.TxGas
 			denominations := misc.FindMinDenominations(tx.Value())
 			outputIndex := uint16(0)
-
+			total := big.NewInt(0)
+			success := true
 			// Iterate over the denominations in descending order
 			for denomination := types.MaxDenomination; denomination >= 0; denomination-- {
 				// If the denomination count is zero, skip it
@@ -1261,6 +1261,7 @@ func (w *worker) commitTransaction(env *environment, parent *types.WorkObject, t
 				for j := uint64(0); j < denominations[uint8(denomination)]; j++ {
 					if txGas < params.CallValueTransferGas || outputIndex >= types.MaxOutputIndex {
 						// No more gas, the rest of the denominations are lost but the tx is still valid
+						success = false
 						break
 					}
 					txGas -= params.CallValueTransferGas
@@ -1271,9 +1272,32 @@ func (w *worker) commitTransaction(env *environment, parent *types.WorkObject, t
 					// the ETX hash is guaranteed to be unique
 					utxoHash := types.UTXOHash(tx.Hash(), outputIndex, types.NewUtxoEntry(types.NewTxOut(uint8(denomination), tx.To().Bytes(), lock)))
 					env.utxosCreate = append(env.utxosCreate, utxoHash)
+					total.Add(total, types.Denominations[uint8(denomination)])
 					outputIndex++
 				}
 			}
+			var receipt *types.Receipt
+			if success {
+				receipt = &types.Receipt{Type: tx.Type(), Status: types.ReceiptStatusSuccessful, GasUsed: tx.Gas() - txGas, TxHash: tx.Hash(),
+					Logs: []*types.Log{{
+						Address: *tx.To(),
+						Topics:  []common.Hash{types.QuaiToQiConversionTopic},
+						Data:    total.Bytes(),
+					}},
+				}
+			} else {
+				receipt = &types.Receipt{Type: tx.Type(), Status: types.ReceiptStatusFailed, GasUsed: tx.Gas(), TxHash: tx.Hash(),
+					Logs: []*types.Log{{
+						Address: *tx.To(),
+						Topics:  []common.Hash{types.QuaiToQiConversionTopic},
+						Data:    total.Bytes(),
+					}},
+				}
+			}
+			env.wo.Header().SetGasUsed(gasUsed)
+			env.txs = append(env.txs, tx)
+			env.gasUsedAfterTransaction = append(env.gasUsedAfterTransaction, gasUsed)
+			return receipt.Logs, true, nil
 		} else {
 			// This Qi ETX should cost more gas
 			if err := env.gasPool.SubGas(params.CallValueTransferGas); err != nil {
@@ -1282,11 +1306,13 @@ func (w *worker) commitTransaction(env *environment, parent *types.WorkObject, t
 			utxoHash := types.UTXOHash(tx.OriginatingTxHash(), tx.ETXIndex(), types.NewUtxoEntry(types.NewTxOut(uint8(tx.Value().Uint64()), tx.To().Bytes(), common.Big0)))
 			env.utxosCreate = append(env.utxosCreate, utxoHash)
 			gasUsed += params.CallValueTransferGas
+
+			env.wo.Header().SetGasUsed(gasUsed)
+			env.txs = append(env.txs, tx)
+			env.gasUsedAfterTransaction = append(env.gasUsedAfterTransaction, gasUsed)
+			return []*types.Log{}, false, nil
 		}
-		env.wo.Header().SetGasUsed(gasUsed)
-		env.txs = append(env.txs, tx)
-		env.gasUsedAfterTransaction = append(env.gasUsedAfterTransaction, gasUsed)
-		return []*types.Log{}, false, nil
+
 	} else if tx.Type() == types.ExternalTxType && types.IsConversionTx(tx) && tx.To().IsInQuaiLedgerScope() { // Qi->Quai Conversion
 		gasUsed := env.wo.GasUsed() + params.QiToQuaiConversionGas
 		env.wo.Header().SetGasUsed(gasUsed)