Onchain AI composability - AI Powered Wallet

In this example, we will demonstrate how to build a simple AI-powered wallet utilizing the LLAMA model deployed on the Base blockchain. This will be accomplished in a few easy steps.

Step 1: implement the suspiciousTransaction function

This function queries the on-chain LLAMA model to determine whether a transaction the wallet is about to make is suspicious. The prompt sent to the model is constructed using the wallet's transaction history and the details of the transfer. Providing this context allows the model to respond more accurately.

function suspiciousTransaction(
    address _receiver,
    uint256 _amount
) external {
    string memory prompt = string.concat(
        "Assess the following Ethereum transaction history for any suspicious patterns. Respond with 'yes' if there is ANY indication of unusual or potentially malicious activity, however slight. Respond with 'no' ONLY if the transaction history is completely clean and normal. Your answer must be one word only. ",
        Strings.toHexString(msg.sender),
        " transfer ",
        Strings.toString(_amount),
        " wei to ",
        Strings.toHexString(_receiver),
        ". ",
        context[msg.sender]
    );

    string memory request = buildRequest(prompt);

    uint256 inferenceId = AIKernel(kernel).infer(bytes(request));
    txInfo[inferenceId] = TxInfo(msg.sender, _receiver, _amount);

    emit SuspiciousTransaction(inferenceId, bytes(request));
}

Step 2: implement the send function

The send function takes the _inferenceId generated in the previous step as an argument. It retrieves the inference result provided by the LLAMA model's miners and uses it to determine whether the transaction is suspicious. If the transaction is deemed safe, its details are stored in the wallet's context for use in future transactions.

function send(uint256 _inferenceId) external payable {
        TxInfo memory info = txInfo[_inferenceId];

        require(info.sender == msg.sender, "AIPoweredWallet: Unauthorized");

        address receivedWallet = info.sender;
        require(
            receivedWallet != address(0),
            "AIPoweredWallet: Invalid wallet address"
        );
        require(
            info.amount == msg.value,
            "AIPoweredWallet: Invalid transaction amount"
        );

        bytes memory result = fetchInferenceResult(_inferenceId);

        require(
            keccak256(result) == keccak256(abi.encodePacked("No")),
            "AIPoweredWallet: Suspicious transaction"
        );

        payable(receivedWallet).transfer(msg.value);

        context[msg.sender] = string.concat(
            context[msg.sender],
            Strings.toHexString(msg.sender),
            " transfer ",
            Strings.toString(msg.value),
            " wei to ",
            Strings.toHexString(receivedWallet),
            ". "
        );
}

The complete example code is available at: https://github.com/eternalai-org/eternal-ai/tree/master/examples/AIPoweredWallet

You can run the code with the following command:

cp .env.example .env && npm install && npx hardhat compile && BASE_MAINNET_RPC_URL=https://base-mainnet.public.blastapi.io BASE_MAINNET_PRIVATE_KEY=<PRIVATE_KEY>  BASE_MAINNET_RECEIVER_ADDRESS=<RECEIVER_ADDRESS> BASE_MAINNET_TRANSFERRED_AMOUNT=<AMOUNT_IN_WEI> npm run suspiciousTransaction:base_mainnet

Note:

  • Replace <PRIVATE_KEY> with your actual wallet private key. Ensure that the wallet has sufficient ETH on the Base network to cover transaction fees and amounts.

  • Replace <RECEIVER_ADDRESS> with another wallet address. While the receiver address does not necessarily have to be the same for all transactions created by the wallet, it is exposed as an environment variable to simplify running the code.

Below is an example of three transactions (two safe and one suspicious) created using our wallet on the Base network:

  1. The wallet 0xAaAa26FbC6b28bf16929Ea216f4700dFCC11A159 attempted to send 0.01 ETH to 0xDEA1Bfc89102138cc90C32B4c9e0e2a970548B09

  2. The wallet 0xAaAa26FbC6b28bf16929Ea216f4700dFCC11A159 attempted to send 0.012 ETH to 0x529F45532C429F02Fb9FE1A5E43b11E80b720Fb0

  3. The wallet 0xAaAa26FbC6b28bf16929Ea216f4700dFCC11A159 attempted to send 0.000001 ETH to 0xEa7d4Bf0a8e4904f32045862eEDC91B261F53f99

In this example, the first and second transactions were evaluated as "safe" by the model. However, the third transaction was flagged as "suspicious" (and its Send transaction was rejected by Base's mempool) because its send amount was significantly smaller than the amounts in previous transactions.

Last updated