Message Authorization

This example demonstrates how to use message authorization in xplajs, allowing one account (grantee) to execute transactions on behalf of another account (granter) within specified limits.

import { EthSecp256k1HDWallet } from "@xpla/xpla"
import { HDPath } from "@interchainjs/types"
import { DirectSigner } from "@interchainjs/cosmos"
import { createCosmosQueryClient } from "@interchainjs/cosmos"
import { DEFAULT_COSMOS_EVM_SIGNER_CONFIG } from "@xpla/xpla/signers/config";
import { Any, Coin } from "@xpla/xplajs";
import { grant, Grant, SendAuthorization, exec, MsgSend } from "@xpla/xplajs";
import { MessageComposer } from "@xpla/xplajs/cosmos/bank/v1beta1/tx.registry";


// Granter mnemonic
const granterMnemonic = "notice oak worry limit wrap speak medal online prefer cluster roof addict wrist behave treat actual wasp year salad speed social layer crew genius"

// Grantee mnemonic  
const granteeMnemonic = "quality vacuum heart guard buzz spike sight swarm shove special gym robust assume sudden deposit grid alcohol choice devote leader tilt noodle tide penalty"

async function grantAuthorization(
  granterSigner: DirectSigner,
  granteeAddress: string,
  spendLimit: Coin,
  duration: Date
) {
const granterAddress = (await granterSigner.getAddresses())[0]
  const sendAuth = SendAuthorization.fromPartial({
    spendLimit: [spendLimit]
  })

  const authAny = Any.fromPartial({
    typeUrl: "/cosmos.bank.v1beta1.SendAuthorization",
    value: SendAuthorization.encode(sendAuth).finish()
  })

const tx = await grant(
    granterSigner,
    granterAddress,
    {
        granter: granterAddress,
        grantee: granteeAddress,
        grant: Grant.fromPartial({
            authorization: authAny,
            expiration: duration
            }),
        },
        {
        amount: [{denom: "axpla", amount: "56000000000000000"}],
        gas: "200000",
        },
        ""
)
  
  return tx
}

async function sendAuthorized(
  granteeSigner: DirectSigner,
  granterAddress: string,
  toAddress: string,
  amount: Coin
) {
    const granteeAddress = (await granteeSigner.getAddresses())[0]
  const msgSend = MsgSend.fromPartial({
    fromAddress: granterAddress,
    toAddress: toAddress,
    amount: [amount]
  })

  const sendMsgAny = Any.fromPartial({
    typeUrl: "/cosmos.bank.v1beta1.MsgSend",
    value: MsgSend.encode(msgSend).finish()
  })

  const tx = await exec(
    granteeSigner,
    granteeAddress,
    {
        grantee: granteeAddress,
        msgs: [sendMsgAny]
      },
      {
        amount: [{denom: "axpla", amount: "56000000000000000"}],
        gas: "200000",
      },
      ""
  )

  return tx
}

async function main() {
    const prefix = "xpla"
    const queryClient = await createCosmosQueryClient("https://cube-rpc.xpla.io");
    const baseSignConfig = {
        queryClient: queryClient,
        chainId: "cube_47-5",
        addressPrefix: prefix,
    }
    const signerConfig = {
        ...DEFAULT_COSMOS_EVM_SIGNER_CONFIG,
        ...baseSignConfig
    }

  // Create granter signer (xpla16wx7ye3ce060tjvmmpu8lm0ak5xr7gm2dp0kpt)
  const granterWallet = await EthSecp256k1HDWallet.fromMnemonic(granterMnemonic, {
    derivations: [{
      prefix,
      hdPath: HDPath.eth().toString()
    }]
  })
  const granterSigner = new DirectSigner(granterWallet, signerConfig)
  const granterAddress = (await granterSigner.getAddresses())[0]

  // Create grantee signer (xpla1pe9mc2q72u94sn2gg52ramrt26x5efw6hr5gt4)
  const granteeWallet = await EthSecp256k1HDWallet.fromMnemonic(granteeMnemonic, {
    derivations: [{
      prefix,
      hdPath: HDPath.eth().toString()
    }]
  })
  const granteeSigner = new DirectSigner(granteeWallet, signerConfig)
  const granteeAddress = (await granteeSigner.getAddresses())[0]

  try {
    // Grant authorization
    console.log("Granting authorization...")
    const grantTx = await grantAuthorization(
      granterSigner,
      granteeAddress,
      Coin.fromPartial({denom: "axpla", amount: "1000000000000000000"}),
      new Date(Date.now() + 24 * 60 * 60 * 1000) // 24 hours from now
    )
    console.log("Authorization granted:", grantTx)

    // Wait for transaction to be processed 
    console.log("Waiting for transaction to be included in block...")
    await new Promise(resolve => setTimeout(resolve, 10000))

    // Execute authorized send
    console.log("Executing authorized send...")
    const execTx = await sendAuthorized(
      granteeSigner,
      granterAddress,
      granterAddress, // Send back to granter for testing
      Coin.fromPartial({denom: "axpla", amount: "1000000000000000000"}) // 1 XPLA
    )
    console.log("Authorized send executed:", execTx)

  } catch (error) {
    console.error("Error:", error)
  }
}

main().catch(console.error)