Try   HackMD

Background

Sometimes, you don't want a transaction to be sent right away. For example, there might be an NFT mint that starts tomorrow at 7AM, but you don't want to wake up at 7AM to mint the NFT. With fun.xyz's automated actions, you can schedule a transaction at 7AM, pre-sign it, and make sure it only executes when the NFT mint opens.

This document explains the design decisions and the architecture of Automated Actions. This includes smart contract design, sdk changes, server changes, storage changes(dynamoDB), and a new service that simulates transactions and sends them to bundler.

Tenets

Availability: When an automated action is scheduled, it should be executed as soon as the validation condition is true
Scalability: We want to minimize the costs are are paying to aws, dynamoDB, our api server, and the cost of rpcs for simulation

Customer Experience

Creating an Automated Action

Each automated action is based off of a module, which is a smart contract that plugs into funwallet.sol. Each automated action module has two functions validate(bytes calldata data) and execute(bytes calldata data)

contract AutomatedAction {
    function validate(bytes calldata data) public returns(bool){
    
    }
    
    function execute(bytes calldata data) external {}
}

The validate function will repeatedly be called, and the execute will be called as soon as validate returns true for that specific data.

Sending an Automated Action

Automated Actions are sent from the SDK. When sending a transaction, a user can specify automatedAction=true in {Insert correct function from sdk here} and the transaction will be sent to the automated actions database instead of to the bundler

The Automated Action being executed

The automated action userOp will sit in the database and the corresponding validate() function will be called. When validate returns true, the userOp will be sent to the bundler.

Architecture

Api Server Changes

/createAutomatedAction

Parameters:

  • chainId: number
  • actionType: ActionType
  • userOp: UserOperation
  • moduleAddress: string
  • data: BytesLike
  • walletAddress: string

Creates an entry in the FunWalletAction DynamoDB

  • status: Enum {Pending, Cancelled, Success, Failed}
    returns actionId

/deleteAutomatedAction

  • actionId: string
  • chainId: string

Deletes an entry in the FunWalletAction DynamoDB
We could also just use the existing delete method

/executeAutomatedAction

  • actionId: string
  • chainId: string
  • entryPointAddress: string

Database Schema

We are using the same database FunWalletAction as the one being used in M of N transactions.

@table(FUN_WALLET_ACTION_TABLE_NAME)
export class FunWalletAction {
    @hashKey()
    actionId: string

    @rangeKey()
    chainId: string

    @versionAttribute()
    version: number

    @attribute()
    actionType: ActionType

    @attribute()
    authType: AuthType

    @attribute()
    groupId: string

    @attribute()
    message: string

    @attribute()
    walletAddr: string

    @attribute()
    nonce: string

    @attribute()
    userOp: UserOperation

    @attribute()
    status: FunWalletActionStatus

    @attribute()
    proposer: string

    @attribute()
    proposedTime: number

    @attribute()
    executedBy: string

    @attribute()
    executedTime: number

    @attribute()
    relatedActionIds: string[]

    @attribute()
    signatures: Signature[]

    @attribute()
    lastUpdatedTime: number
    
    ## These are new fields
    @attribute()
    data: string
    
    @attribute()
    moduleAddress: string
}

Might need to add a some key that lets us only query the actions that are relevant to automatedActions

Cron Job

Tbh not sure what aws service to use here, but essentially we would:

  1. Fetch all Actions from dynamoDB
  2. For each action, check moduleAddress.validate(data) which is an onchain call. If this returns true, then send the userOp to the bundler. If this returns false, do nothing

SDK

First class action vs sendTxLater

Implementation Plan

  • Write Demo smart contracts for automated actions(done)
  • Create api server changes
  • Create SDK changes
  • Create Cron Job server

Do we every verify nonces in useroperations? If so, do we just check that the nonce has not been used in the past? If we check that the nonce > previous nonce + 1, automated actions will only be able to work in the order that you create automated actions in. If not, this might be a security issue, but not for automated actions

Is the dynamoDB live?

What do we use sendTxLater for? if that is true, can we just send the automated action to the database?