Skip to content

Add EVM function to reclaim ERC20 tokens from attacker's EOA addresses#8293

Merged
j1010001 merged 1 commit intov0.44from
mpeter/reclaim-fraudulent-erc20-tokens
Jan 6, 2026
Merged

Add EVM function to reclaim ERC20 tokens from attacker's EOA addresses#8293
j1010001 merged 1 commit intov0.44from
mpeter/reclaim-fraudulent-erc20-tokens

Conversation

@m-Peter
Copy link
Copy Markdown
Collaborator

@m-Peter m-Peter commented Jan 5, 2026

Depends on: onflow/flow-core-contracts#573

Necessary change to reclaim ERC20 tokens from the attacker's EOA addresses:

After we perform this last reclamation process, we can revert all changes to EVM & FlowServiceAccount contracts.

@m-Peter m-Peter self-assigned this Jan 5, 2026
@m-Peter m-Peter requested a review from a team as a code owner January 5, 2026 10:25
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Jan 5, 2026

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@m-Peter
Copy link
Copy Markdown
Collaborator Author

m-Peter commented Jan 5, 2026

Tx to reclaim USDF:

import EVM from 0xe467b9dd11fa00df
import FlowServiceAccount from 0xe467b9dd11fa00df

transaction(from: String, to: String, amount: UInt256) {
    let flowServiceAccountAdmin: &FlowServiceAccount.Administrator

    prepare(signer: auth(BorrowValue) &Account) {
        self.flowServiceAccountAdmin = signer.storage.borrow<&FlowServiceAccount.Administrator>(
            from: /storage/flowServiceAdmin
        ) ?? panic("Unable to borrow reference to administrator resource")
    }

    execute {
        let usdfContractAddress: String = "0x2aaBea2058b5aC2D339b163C6Ab6f2b6d53aabED"
        let toAddress: EVM.EVMAddress = EVM.addressFromString(to)
        let transferCallData: [UInt8] = EVM.encodeABIWithSignature(
            "transfer(address,uint256)",
            [toAddress, amount]
        )
        let txResult = self.flowServiceAccountAdmin.reclaimERC20FromAttackerEOAs(
            from: from,
            to: usdfContractAddress,
            data: transferCallData
        )

        assert(
            txResult.status == EVM.Status.successful,
            message: "evm_error=\(txResult.errorMessage);evm_error_code=\(txResult.errorCode)"
        )
    }
}

Tx to reclaim TRUMP:

import EVM from 0xe467b9dd11fa00df
import FlowServiceAccount from 0xe467b9dd11fa00df

transaction(from: String, to: String, amount: UInt256) {
    let flowServiceAccountAdmin: &FlowServiceAccount.Administrator

    prepare(signer: auth(BorrowValue) &Account) {
        self.flowServiceAccountAdmin = signer.storage.borrow<&FlowServiceAccount.Administrator>(
            from: /storage/flowServiceAdmin
        ) ?? panic("Unable to borrow reference to administrator resource")
    }

    execute {
        let trumpContractAddress: String = "0xD3378b419feae4e3A4Bb4f3349DBa43a1B511760"
        let toAddress: EVM.EVMAddress = EVM.addressFromString(to)
        let approveCallData: [UInt8] = EVM.encodeABIWithSignature(
            "approve(address,uint256)",
            [toAddress, amount]
        )
        var txResult = self.flowServiceAccountAdmin.reclaimERC20FromAttackerEOAs(
            from: from,
            to: trumpContractAddress,
            data: approveCallData
        )

        assert(
            txResult.status == EVM.Status.successful,
            message: "evm_error=\(txResult.errorMessage);evm_error_code=\(txResult.errorCode)"
        )

        let transferCallData: [UInt8] = EVM.encodeABIWithSignature(
            "transfer(address,uint256)",
            [toAddress, amount]
        )
        txResult = self.flowServiceAccountAdmin.reclaimERC20FromAttackerEOAs(
            from: from,
            to: trumpContractAddress,
            data: transferCallData
        )

        assert(
            txResult.status == EVM.Status.successful,
            message: "evm_error=\(txResult.errorMessage);evm_error_code=\(txResult.errorCode)"
        )
	}
}

@codecov-commenter
Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

@j1010001 j1010001 merged commit 0dadbee into v0.44 Jan 6, 2026
56 of 57 checks passed
@j1010001 j1010001 deleted the mpeter/reclaim-fraudulent-erc20-tokens branch January 6, 2026 18:52
@j1010001 j1010001 mentioned this pull request Jan 6, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants