@@ -137,6 +137,58 @@ func TestSelfDestructAssociated(t *testing.T) {
137137 require .Equal (t , uint256 .NewInt (1 ), statedb .GetBalance (fc ))
138138}
139139
140+ // TestEIP6780WithPrefundedAddress verifies that EIP-6780 selfdestruct works correctly
141+ // when a contract is deployed to a prefunded address. This tests the fix for a bug where
142+ // contracts deployed to addresses with existing balance would not be destroyed by
143+ // SelfDestruct6780 because CreateAccount() was not called (since the account already existed).
144+ // The fix ensures CreateContract() marks the account as created for EIP-6780 purposes.
145+ func TestEIP6780WithPrefundedAddress (t * testing.T ) {
146+ k := & testkeeper .EVMTestApp .EvmKeeper
147+ ctx := testkeeper .EVMTestApp .GetContextForDeliverTx ([]byte {}).WithBlockTime (time .Now ())
148+ seiAddr , evmAddr := testkeeper .MockAddressPair ()
149+ k .SetAddressMapping (ctx , seiAddr , evmAddr )
150+
151+ statedb := state .NewDBImpl (ctx , k , false )
152+
153+ // Prefund the address with balance using statedb context
154+ amt := sdk .NewCoins (sdk .NewCoin (k .GetBaseDenom (ctx ), sdk .NewInt (1000000 )))
155+ k .BankKeeper ().MintCoins (statedb .Ctx (), types .ModuleName , amt )
156+ k .BankKeeper ().SendCoinsFromModuleToAccount (statedb .Ctx (), types .ModuleName , seiAddr , amt )
157+
158+ // Verify the account has balance but is not marked as "created" yet
159+ require .True (t , statedb .GetBalance (evmAddr ).CmpBig (big .NewInt (0 )) > 0 , "address should have balance" )
160+ require .False (t , statedb .Created (evmAddr ), "account should not be marked as created before CreateContract" )
161+
162+ // Simulate the EVM's contract creation flow for a prefunded address:
163+ // In go-ethereum's create(), if Exist() returns true (which it does for prefunded addresses),
164+ // CreateAccount() is NOT called. Instead, only CreateContract() is called.
165+ // This is the exact scenario that was broken before the fix.
166+ require .True (t , statedb .Exist (evmAddr ), "prefunded address should exist" )
167+
168+ // Only call CreateContract (not CreateAccount) - this simulates the real EVM behavior
169+ statedb .CreateContract (evmAddr )
170+
171+ // After CreateContract, the account should be marked as created for EIP-6780
172+ require .True (t , statedb .Created (evmAddr ), "account should be marked as created after CreateContract" )
173+
174+ // Set some contract state
175+ statedb .SetCode (evmAddr , []byte ("contract code" ))
176+ key := common .BytesToHash ([]byte ("storage_key" ))
177+ val := common .BytesToHash ([]byte ("storage_value" ))
178+ statedb .SetState (evmAddr , key , val )
179+
180+ // Now SelfDestruct6780 should work correctly - the key test is that destructed == true
181+ _ , destructed := statedb .SelfDestruct6780 (evmAddr )
182+ require .True (t , destructed , "SelfDestruct6780 should destruct the contract created in same tx" )
183+ require .True (t , statedb .HasSelfDestructed (evmAddr ), "account should be marked as self-destructed" )
184+
185+ // Finalize to clear the state
186+ statedb .Finalize ()
187+
188+ // After finalize, the contract's state should be cleared
189+ require .Equal (t , common.Hash {}, statedb .GetState (evmAddr , key ), "storage should be cleared after finalize" )
190+ }
191+
140192func TestSnapshot (t * testing.T ) {
141193 k := & testkeeper .EVMTestApp .EvmKeeper
142194 ctx := testkeeper .EVMTestApp .GetContextForDeliverTx ([]byte {}).WithBlockTime (time .Now ())
0 commit comments