Skip to main content
Los Intents son el corazon de Pan API. Representan objetivos financieros de alto nivel en lugar de transacciones especificas. En lugar de decirle a Pan exactamente que transacciones ejecutar, expresas lo que quieres lograr y Pan determina la mejor manera de hacerlo.

¿Qué es un Intent?

Un intent es una declaracion de un objetivo financiero. Cuando creas un intent, le dices a Pan que quieres lograr, no como lograrlo.

Enfoque Tradicional

// Especificas COMO hacerlo
await bridge(500, 'arbitrum', 'base');
await approve(usdc, aavePool);
await aavePool.supply(usdc, 500);

Enfoque Intent

// Especificas QUE quieres
await pan.lend({
  walletId: 'wallet_123',
  amount: 500,
  asset: 'USDC'
});
El sistema de Pan automaticamente:
  1. Analiza el estado actual del wallet
  2. Evalua protocolos DeFi y oportunidades disponibles
  3. Genera un plan de ejecucion optimizado
  4. Ejecuta el plan de forma segura
1

Tu App envia request

POST /intents con action: lend, amount: 1000 USDC
2

Planificacion

Pan consulta balances (500 ARB, 500 Base) y APYs (Base 8.5%, ARB 7.2%)
3

Generacion de plan

Plan optimo: bridge ARB a Base + deposit en Aave
4

Ejecucion

Pan ejecuta bridge y deposit, retornando txHashes
5

Resultado

Intent completado con resultados y costos de gas

Tipos de Intent

Lend (Prestar)

Deposita fondos en un protocolo de lending para ganar intereses:
const intent = await pan.lend({
  walletId: 'pan_wallet_abc123',
  amount: 1000,
  asset: 'USDC'
  // chain es opcional - Pan encuentra el mejor APY
});
Que hace Pan:
  • Consulta APYs en todas las chains soportadas
  • Identifica donde estan los fondos del wallet
  • Si es necesario, hace bridge a la chain con mejor APY
  • Deposita en el protocolo (Aave) automaticamente

Withdraw (Retirar)

Retira fondos de un protocolo de lending:
const intent = await pan.withdraw({
  walletId: 'pan_wallet_abc123',
  amount: 500,
  asset: 'USDC',
  chain: 'base' // requerido para withdraw
});

Bridge

Mueve fondos entre chains:
const intent = await pan.bridge({
  walletId: 'pan_wallet_abc123',
  amount: 500,
  asset: 'USDC',
  fromChain: 'ethereum',
  toChain: 'arbitrum'
});

Parametros de Intent

Comunes a todos los intents

ParametroTipoRequeridoDescripcion
walletIdstringSiID de la wallet Pan
actionstringSilend, withdraw, o bridge
amountnumberSiCantidad en unidades del token
assetstringNoToken a usar (default: USDC)

Especificos por accion

Lend:
ParametroTipoRequeridoDescripcion
chainstringNoChain destino. Si no se especifica, Pan elige la mejor
Withdraw:
ParametroTipoRequeridoDescripcion
chainstringSiChain de donde retirar
Bridge:
ParametroTipoRequeridoDescripcion
fromChainstringSiChain origen
toChainstringSiChain destino

Ciclo de Vida de un Intent

Los intents pasan por estados bien definidos:
EstadoDescripcionSiguiente
pendingIntent creado y validadoplanning
planningAnalizando balances, consultando yields, generando planexecuting o failed
executingEjecutando pasos: bridges, depositscompleted o failed
completedTodas las transacciones confirmadasFinal
failedError registrado, fondos segurosFinal
1

Pending

El intent ha sido creado y registrado en el sistema. Este estado es muy breve.
{ "status": "pending" }
2

Planning

Pan esta analizando el wallet, evaluando protocolos, y generando el plan de ejecucion optimo.
{
  "status": "planning",
  "executionPlan": null  // Aun no disponible
}
Que ocurre internamente:
  • Consulta balances del wallet en todas las chains
  • Obtiene APYs actuales de protocolos
  • Calcula rutas de bridge optimas
  • Estima costos de gas
  • Genera plan de ejecucion
3

Executing

Pan esta ejecutando las transacciones en blockchain.
{
  "status": "executing",
  "executionPlan": {
    "strategy": "single-bridge",
    "steps": [
      { "type": "bridge", "status": "completed" },
      { "type": "deposit", "status": "executing" }
    ]
  },
  "results": {
    "completedSteps": 1,
    "transactions": [
      { "type": "bridge", "txHash": "0x123..." }
    ]
  }
}
4

Completed

Todas las operaciones completaron exitosamente.
{
  "status": "completed",
  "results": {
    "completedSteps": 2,
    "totalGasUsed": "350000",
    "totalGasCostUsd": 2.30,
    "finalAmount": "998.50",
    "apy": 8.52
  },
  "completedAt": "2024-01-15T10:45:30Z"
}
5

Failed

Algo salio mal durante la ejecucion.
{
  "status": "failed",
  "error": {
    "code": "INSUFFICIENT_FUNDS",
    "message": "Wallet does not have sufficient USDC",
    "details": {
      "required": "1000 USDC",
      "available": "750 USDC"
    }
  },
  "results": {
    "completedSteps": 1,
    "failedStep": 2
  }
}

Monitorear Intents

La ejecucion de intents es asincrona. Debes hacer polling para seguir el progreso:
async function esperarIntent(intentId) {
  const maxIntentos = 60; // 5 minutos
  let intentos = 0;

  while (intentos < maxIntentos) {
    const intent = await pan.getIntent(intentId);

    console.log(`Estado: ${intent.status}`);

    // Mostrar progreso si esta ejecutando
    if (intent.status === 'executing' && intent.executionPlan) {
      const pasos = intent.executionPlan.steps;
      const completados = intent.results?.completedSteps || 0;
      console.log(`  Progreso: ${completados}/${pasos.length}`);

      // Mostrar transacciones completadas
      intent.results?.transactions?.forEach(tx => {
        console.log(`  ${tx.type}: ${tx.txHash}`);
      });
    }

    // Verificar estados finales
    if (intent.status === 'completed') {
      console.log('Intent completado!');
      console.log(`Gas total: $${intent.results.totalGasCostUsd}`);
      return intent;
    }

    if (intent.status === 'failed') {
      console.error('Intent fallido:', intent.error.message);
      throw new Error(intent.error.message);
    }

    // Esperar 5 segundos
    await new Promise(r => setTimeout(r, 5000));
    intentos++;
  }

  throw new Error('Timeout esperando intent');
}
Intervalo de polling recomendado: 5-10 segundos. Mas frecuente desperdicia recursos, menos frecuente reduce responsividad.

Estrategias de Ejecucion

Pan determina automaticamente la mejor estrategia basandose en el estado del wallet:
SituacionEstrategiaPasos
Fondos ya en mejor chainno-bridgeDeposito directo
Fondos en una chain diferentesingle-bridge1 bridge + deposit
Fondos en multiples chainsmulti-bridgeN bridges + deposit
Sin fondos suficientesinsufficientError: fondos insuficientes

no-bridge

Los fondos ya estan en la chain destino. Deposito directo.
{
  "strategy": "no-bridge",
  "steps": [
    { "type": "deposit", "chain": "base", "amount": "1000" }
  ]
}

single-bridge

Los fondos estan en una sola chain diferente. Un bridge + deposito.
{
  "strategy": "single-bridge",
  "steps": [
    { "type": "bridge", "from": "arbitrum", "to": "base", "amount": "1000" },
    { "type": "deposit", "chain": "base", "amount": "1000" }
  ]
}

multi-bridge

Los fondos estan distribuidos en multiples chains. Varios bridges + deposito.
{
  "strategy": "multi-bridge",
  "steps": [
    { "type": "bridge", "from": "ethereum", "to": "base", "amount": "200" },
    { "type": "bridge", "from": "arbitrum", "to": "base", "amount": "500" },
    { "type": "deposit", "chain": "base", "amount": "1000" }
  ]
}

insufficient

No hay fondos suficientes. El intent falla en planning.
{
  "status": "failed",
  "error": {
    "code": "INSUFFICIENT_FUNDS",
    "message": "Not enough USDC across all chains",
    "details": {
      "required": "1000",
      "available": "750"
    }
  }
}

Manejo de Errores

Errores Comunes

CodigoDescripcionSolucion
INSUFFICIENT_FUNDSNo hay fondos suficientesDepositar mas fondos
WALLET_NOT_FOUNDWallet no existeVerificar walletId
INVALID_CHAINChain no soportadaUsar chain valida
BRIDGE_FAILEDFallo en bridgeReintentar intent
DEPOSIT_FAILEDFallo en depositoVerificar protocolo

Estructura de Error

{
  "error": {
    "code": "ERROR_CODE",
    "message": "Mensaje legible para humanos",
    "details": {
      "campo1": "valor1",
      "campo2": "valor2"
    }
  }
}

Reintentar Intents Fallidos

async function ejecutarConReintento(params, maxReintentos = 3) {
  let ultimoError;

  for (let i = 0; i < maxReintentos; i++) {
    try {
      const intent = await pan.lend(params);
      return await esperarIntent(intent.id);
    } catch (error) {
      ultimoError = error;

      // Solo reintentar errores transitorios
      const reintentables = ['BRIDGE_FAILED', 'NETWORK_ERROR', 'TIMEOUT'];
      if (!reintentables.includes(error.code)) {
        throw error;
      }

      console.log(`Reintento ${i + 1}/${maxReintentos}...`);
      await new Promise(r => setTimeout(r, 5000 * (i + 1))); // Backoff
    }
  }

  throw ultimoError;
}

Ejemplos Avanzados

Lending con Verificacion de APY

async function lendSiApy(walletId, amount, minApy) {
  // Obtener yields actuales
  const { rates, best } = await pan.yields.getAll();

  // Verificar APY minimo
  if (best.apy < minApy) {
    console.log(`APY actual (${best.apy}%) menor a minimo (${minApy}%)`);
    return null;
  }

  // Crear intent
  const intent = await pan.lend({
    walletId,
    amount,
    asset: 'USDC'
  });

  console.log(`Lending a ${best.chain} con ${best.apy}% APY`);
  return intent;
}

// Uso: solo prestar si APY > 7%
await lendSiApy('wallet_123', 1000, 7.0);

Rebalanceo Automatico

async function rebalancearAMejorYield(walletId) {
  // 1. Obtener balances actuales
  const balancesResponse = await pan.wallet.getBalances(walletId);

  // 2. Calcular total disponible
  let totalUsdc = 0;
  for (const chainData of balancesResponse.chains) {
    const usdc = chainData.tokens.find(t => t.asset === 'USDC');
    if (usdc) totalUsdc += parseFloat(usdc.balanceFormatted);
  }

  if (totalUsdc === 0) {
    console.log('No hay USDC disponible');
    return;
  }

  // 3. Obtener mejor yield
  const { best } = await pan.yields.getAll();
  console.log(`Mejor yield: ${best.apy}% en ${best.chain}`);

  // 4. Crear intent de lending
  // Pan automaticamente consolidara fondos de todas las chains
  const intent = await pan.lend({
    walletId,
    amount: totalUsdc,
    asset: 'USDC'
  });

  return intent;
}

Notificaciones de Progreso

async function ejecutarConNotificaciones(walletId, amount, onProgress) {
  const intent = await pan.lend({ walletId, amount, asset: 'USDC' });

  let ultimoEstado = null;
  let ultimosPasos = 0;

  while (true) {
    const actual = await pan.getIntent(intent.id);

    // Notificar cambio de estado
    if (actual.status !== ultimoEstado) {
      onProgress({
        type: 'status',
        status: actual.status,
        message: getStatusMessage(actual.status)
      });
      ultimoEstado = actual.status;
    }

    // Notificar pasos completados
    const pasosCompletados = actual.results?.completedSteps || 0;
    if (pasosCompletados > ultimosPasos) {
      const paso = actual.executionPlan.steps[pasosCompletados - 1];
      onProgress({
        type: 'step',
        step: paso,
        completed: pasosCompletados,
        total: actual.executionPlan.steps.length
      });
      ultimosPasos = pasosCompletados;
    }

    // Estado final
    if (actual.status === 'completed' || actual.status === 'failed') {
      return actual;
    }

    await new Promise(r => setTimeout(r, 5000));
  }
}

function getStatusMessage(status) {
  return {
    pending: 'Iniciando...',
    planning: 'Calculando mejor estrategia...',
    executing: 'Ejecutando transacciones...',
    completed: 'Completado!',
    failed: 'Error en ejecucion'
  }[status];
}

// Uso
await ejecutarConNotificaciones('wallet_123', 1000, (progress) => {
  console.log(progress);
  // Enviar a UI, webhook, etc.
});

Proximos Pasos