Saltearse al contenido

Tu Primera Multisig de Aptos (SDK de Python)

En este tutorial, aprenderás cómo crear y gestionar una cuenta multisig que requiere 2 de 3 titulares de claves para aprobar cualquier transacción. Aprenderás cómo:

  1. Configurar un entorno de desarrollo para Aptos
  2. Crear múltiples cuentas para actuar como titulares de claves
  3. Configurar una cuenta multisig que requiere 2-de-3 firmas
  4. Financiar cuentas y verificar balances
  5. Crear y ejecutar transacciones multisig

Conceptualmente, una cuenta multisig (multi-firma) funciona como una bóveda bancaria que requiere múltiples titulares de claves para autorizar el acceso. En Aptos, esto se implementa con firmas digitales en lugar de claves físicas, con cada firmante autorizado proporcionando su aprobación criptográfica.

Primero, vamos a preparar nuestro entorno de desarrollo. Crearemos un espacio de trabajo aislado e instalaremos todas las dependencias necesarias.

  1. Abrir una terminal

    Abre una nueva ventana de terminal.

  2. Verificar instalación de Python

    Ejecuta este comando para verificar tu versión de Python:

    Ventana de terminal
    python3 --version

    Deberías ver algo como “Python 3.7” o superior.

  3. Crear directorio del proyecto

    Crea una nueva carpeta para nuestro proyecto:

    Ventana de terminal
    mkdir my-first-multisig
  4. Navegar al directorio del proyecto

    Muévete a esta nueva carpeta:

    Ventana de terminal
    cd my-first-multisig
  5. Crear entorno virtual

    Configura un entorno de Python aislado:

    Ventana de terminal
    python3 -m venv venv

    Este comando:

    • Crea un entorno de Python aislado
    • Instala una instancia fresca de Python
    • Mantiene las dependencias del proyecto separadas de tu Python del sistema
    • Crea una carpeta venv (¡puedes ver pero no modificar su contenido!)
  6. Activar entorno virtual

    Ventana de terminal
    source venv/bin/activate

    Este comando:

    • Modifica las variables de entorno de tu terminal
    • Hace que tu terminal use el Python de venv en lugar del tuyo
    • Verás (venv) al inicio de tu línea de terminal
    • Para desactivarlo más tarde, simplemente escribe deactivate
  7. Instalar SDK de Aptos

    Instala el SDK requerido:

    Ventana de terminal
    pip install aptos-sdk

    Este comando:

    • Descarga el paquete SDK de Aptos desde PyPI (Índice de Paquetes de Python)
    • Lo instala dentro de tu carpeta venv
    • Crea archivos en venv/lib/python3.x/site-packages/aptos_sdk
    • Puedes ver estos archivos navegando a esa carpeta

Vamos a empezar a construir nuestra implementación multisig. Primero, configuraremos nuestros imports, bucle principal y configuración base.

  1. Crear script de Python

    Crea un archivo de script de Python vacío:

    Ventana de terminal
    touch multisig.py
  2. Añadir código base

    Abre multisig.py en tu IDE (recomendamos VSCode o JetBrains) y añade el siguiente código:

    Apache-2.0
    # Copyright © Aptos Foundation
    import asyncio
    import subprocess
    import time
    from aptos_sdk.account import Account, RotationProofChallenge
    from aptos_sdk.account_address import AccountAddress
    from aptos_sdk.async_client import FaucetClient, RestClient
    from aptos_sdk.authenticator import Authenticator, MultiEd25519Authenticator
    from aptos_sdk.bcs import Serializer
    from aptos_sdk.ed25519 import MultiPublicKey, MultiSignature
    from aptos_sdk.transactions import (
    EntryFunction,
    RawTransaction,
    Script,
    ScriptArgument,
    SignedTransaction,
    TransactionArgument,
    TransactionPayload,
    )
    from aptos_sdk.type_tag import StructTag, TypeTag
    # Configuración de red - usando devnet para pruebas. Comprueba las URLs actuales en:
    # https://github.com/aptos-labs/aptos-python-sdk/blob/main/examples/common.py
    NODE_URL = "https://fullnode.devnet.aptoslabs.com/v1"
    FAUCET_URL = "https://faucet.devnet.aptoslabs.com"
    should_wait = True
    # "wait" se usa para hacer que el terminal sea más interactivo, por lo que es más fácil seguir lo que está sucediendo.
    def wait():
    """Espera a que el usuario presione Enter antes de continuar con la siguiente sección."""
    if should_wait:
    input("\nPresiona Enter para continuar...")
    # Ahora definimos nuestra función principal que llama a todo lo demás.
    # Añadiremos todas las adiciones futuras dentro de esta función.
    async def main(should_wait_input=True):
    # Esto solo se usa para este tutorial.
    global should_wait
    should_wait = should_wait_input
    # Inicializamos los clientes de blockchain
    rest_client = RestClient(NODE_URL)
    faucet_client = FaucetClient(FAUCET_URL, rest_client)
    ############# Añadir código adicional aquí ###############
    ######################################################
    if __name__ == "__main__":
    asyncio.run(main())

    Este código importa todos los módulos necesarios del SDK de Aptos. El módulo aptos_sdk.account proporciona la funcionalidad esencial para gestionar cuentas y firmas, mientras que aptos_sdk.transactions nos da las herramientas para crear y enviar transacciones de blockchain.

Al igual que una bóveda bancaria necesita titulares de claves designados, nuestra multisig necesita firmantes autorizados. Vamos a crear las cuentas de nuestros titulares de claves.

  1. Crear cuentas de titulares de claves

    Añade el siguiente código después de ############# Añadir código adicional aquí ###############:

    # Crear tres cuentas para actuar como nuestros titulares de claves
    alice = Account.generate()
    bob = Account.generate()
    chad = Account.generate()

    La función Account.generate() crea una nueva cuenta de Aptos con un nuevo par de claves. Cada cuenta tendrá su propia clave privada (para firmar) y clave pública (para verificar). En nuestra configuración multisig, estas cuentas representan los titulares de claves que tendrán autorización para firmar transacciones, similar a como cada titular de clave de bóveda física tendría su propia clave física única.

  2. Añadir información de la cuenta

    Añade este código debajo de chad = Account.generate():

    print("\n=== Direcciones de cuenta ===")
    print(f"Alice: {alice.address()}")
    print(f"Bob: {bob.address()}")
    print(f"Chad: {chad.address()}")
    print("\n=== Claves de autenticación ===")
    print(f"Alice: {alice.auth_key()}")
    print(f"Bob: {bob.auth_key()}")
    print(f"Chad: {chad.auth_key()}")
    print("\n=== Claves públicas ===")
    print(f"Alice: {alice.public_key()}")
    print(f"Bob: {bob.public_key()}")
    print(f"Chad: {chad.public_key()}")
    wait()
    # Añadir código adicional debajo de este wait()
  3. Ejecutar el script

    Ejecuta nuestro multisig.py desde tu terminal:

    Ventana de terminal
    python3 multisig.py

    Deberías ver una salida mostrando las direcciones, claves de autenticación y claves públicas de cada cuenta. Por ejemplo:

    Ventana de terminal
    === Direcciones de cuenta ===
    Alice: 0x5323a06f21b04af53fc57367b50d3bbb5675c655bc9bc62f33b5e083d5d06b8b
    Bob: 0x9f3e94fc92e0076336c122a576304c0b9fa8def13a98c469dce05e0836b9fe5b
    Chad: 0x1d0e7b790493dcf7bc7ce60bf4ccdcca1d38ce0d7f8dd26d2791a6d3ff6da708
    === Claves de autenticación ===
    Alice: 0x5323a06f21b04af53fc57367b50d3bbb5675c655bc9bc62f33b5e083d5d06b8b
    Bob: 0x9f3e94fc92e0076336c122a576304c0b9fa8def13a98c469dce05e0836b9fe5b
    Chad: 0x1d0e7b790493dcf7bc7ce60bf4ccdcca1d38ce0d7f8dd26d2791a6d3ff6da708
    === Claves públicas ===
    Alice: 0x730264a36d4ec90af2e28e1cf9c4d686440598317123469a7c827d4fcdf74715
    Bob: 0xcf21e85337a313bdac33d068960a3e52d22ce0e6190e9acc03a1c9930e1eaf3e
    Chad: 0xa1a2aef8525eb20655387d3ed50b9a3ea1531ef6117f579d0da4bcf5a2e1f76d

Ahora que tenemos nuestros titulares de claves (Alice, Bob y Chad), vamos a configurar nuestra configuración multisig.

  1. Configurar cuenta multisig

    Añade el código para configurar una cuenta multisig de 2-de-3:

    # Configurar una cuenta multisig de 2-de-3
    threshold = 2
    multisig_public_key = MultiPublicKey(
    [alice.public_key(), bob.public_key(), chad.public_key()],
    threshold
    )
    multisig_address = AccountAddress.from_key(multisig_public_key)

    El threshold = 2 establece nuestro requisito de dos firmas de tres posibles firmantes. La MultiPublicKey combina todas las claves públicas en una sola configuración multisig.

  2. Mostrar información de la cuenta multisig

    Imprime la información de la cuenta multisig añadiendo este código debajo de nuestro nuevo multisig_address:

    print("\n=== Cuenta multisig de 2-de-3 ===")
    print(f"Clave pública de la cuenta: {multisig_public_key}")
    print(f"Dirección de la cuenta: {multisig_address}")
    wait()
    # Añadir código adicional aquí
  3. Ejecutar el script

    Verifica la salida:

    Ventana de terminal
    python3 multisig.py

    Deberías ver una salida mostrando la clave pública de tipo de tu cuenta multisig y su dirección única en la blockchain de Aptos. Por ejemplo:

    Ventana de terminal
    === Cuenta multisig de 2-de-3 ===
    Clave pública de la cuenta: 2-de-3 Multi-Ed25519 clave pública
    Dirección de la cuenta: 0x08cac3b7b7ce4fbc5b18bc039279d7854e4c898cbf82518ac2650b565ad4d364

Al igual que las cuentas bancarias nuevas necesitan depósitos iniciales, nuestras cuentas de blockchain necesitan fondos para operar.

  1. Añadir código de financiación

    Añade el código para financiar todas las cuentas:

    print("\n=== Financiamiento de cuentas ===")
    alice_start = 10_000_000
    bob_start = 20_000_000
    chad_start = 30_000_000
    multisig_start = 40_000_000
    # Financiar todas las cuentas simultáneamente
    alice_fund = faucet_client.fund_account(alice.address(), alice_start)
    bob_fund = faucet_client.fund_account(bob.address(), bob_start)
    chad_fund = faucet_client.fund_account(chad.address(), chad_start)
    multisig_fund = faucet_client.fund_account(multisig_address, multisig_start)
    await asyncio.gather(*[alice_fund, bob_fund, chad_fund, multisig_fund])

    La función fund_account() solicita tokens de prueba del faucet de Aptos para que podamos experimentar sin usar APT real. Financiamos todas las cuentas simultáneamente en lugar de una a la vez inicializándolas como [nombre]_fund y luego llamando a la función asíncrona que las recolecta: asyncio.gather().

  2. Comprobar balances

    Añade el código para comprobar todos los balances y imprimirlos:

    # Comprobar todos los balances
    alice_balance = rest_client.account_balance(alice.address())
    bob_balance = rest_client.account_balance(bob.address())
    chad_balance = rest_client.account_balance(chad.address())
    multisig_balance = rest_client.account_balance(multisig_address)
    [alice_balance, bob_balance, chad_balance, multisig_balance] = await asyncio.gather(
    *[alice_balance, bob_balance, chad_balance, multisig_balance]
    )
    print(f"Balance de Alice: {alice_balance}")
    print(f"Balance de Bob: {bob_balance}")
    print(f"Balance de Chad: {chad_balance}")
    print(f"Balance de Multisig: {multisig_balance}")
    wait()

    La función account_balance() consulta la blockchain para cada cuenta por su saldo actual. Nuevamente, usamos asyncio.gather() para hacer todas estas consultas eficientemente en paralelo.

  3. Ejecutar el script

    Verifica el éxito del financiamiento ejecutando:

    Ventana de terminal
    python3 multisig.py

    La salida debería mostrar cada cuenta con su saldo respectivo. Por ejemplo:

    Ventana de terminal
    === Financiamiento de cuentas ===
    Balance de Alice: 10000000
    Balance de Bob: 20000000
    Balance de Chad: 30000000
    Balance de Multisig: 40000000

Creando Nuestra Primera Transacción Multisig

Sección titulada «Creando Nuestra Primera Transacción Multisig»

Ahora vamos a crear una transacción que requiere múltiples firmas. Transferiremos 100 octas de la cuenta multisig a Chad, similar a como una transferencia bancaria requeriría la aprobación de dos gerentes para un retiro grande.

  1. Crear transacción de transferencia

    Crea la transacción de transferencia definiendo sus parámetros:

    # Crear la transacción de transferencia
    entry_function = EntryFunction.natural(
    module="0x1::coin",
    function="transfer",
    ty_args=[TypeTag(StructTag.from_str("0x1::aptos_coin::AptosCoin"))],
    args=[
    TransactionArgument(chad.address(), Serializer.struct),
    TransactionArgument(100, Serializer.u64),
    ],
    )
    # Construir la transacción bruta
    chain_id = await rest_client.chain_id()
    raw_transaction = RawTransaction(
    sender=multisig_address,
    sequence_number=0,
    payload=TransactionPayload(entry_function),
    max_gas_amount=2000,
    gas_unit_price=100,
    expiration_timestamps_secs=int(time.time()) + 600,
    chain_id=chain_id,
    )

    El código anterior:

    • Usa EntryFunction.natural() para crear una transferencia de 100 octas (la unidad más pequeña de APT) a la dirección de Chad
    • Configura los parámetros de la transacción como límites de gas y tiempo de expiración
    • Crea una transacción bruta que aún necesita firmas antes de poder ser enviada
  2. Obtener firmas

    Obtén firmas de Alice y Bob:

    alice_signature = alice.sign(raw_transaction.keyed())
    bob_signature = bob.sign(raw_transaction.keyed())
    print("\n=== Firmas individuales ===")
    print(f"Alice: {alice_signature}")
    print(f"Bob: {bob_signature}")
    wait()

    El código anterior:

    • Tiene a Alice que firma la transacción con su clave privada
    • Tiene a Bob que firma la misma transacción con su clave privada
    • Imprime las firmas para verificar que se crearon correctamente
  3. Ejecutar el script

    Después de añadir el código para crear la transacción y obtener las firmas, ejecuta el script:

    Ventana de terminal
    python3 multisig.py

    Deberías ver algo como:

    Ventana de terminal
    === Firmas individuales ===
    Alice: 0x360e66c75b1ba787ec7b05998cbc14276d7fc0c006fb10c33d5cc3c4cc2ec4f53a8c0996b8e746fd6d86b09b4f8bb128cbf62d8b375f5b974faae040e889ac0d
    Bob: 0xdcfd1965e531deb79de9d8daf7f28f46023107ce4f11612ce76da33e808486a0a368b34563d4f89d6179a3957a266c1e8809691fddabba3c2a3d8be14d6f2f0c

    Esto muestra que tanto Alice como Bob han firmado la transacción. Cada firma es un hash único que prueba que autorizaron la transacción con sus claves privadas.

Ahora vamos a combinar las firmas y enviar la transacción. Esto es similar a reunir todos los papeles firmados de los gerentes de banco y enviarlos para procesar una gran transferencia.

  1. Combinar firmas

    Combina las firmas en un autenticador multisig:

    # Combinar las firmas (mapa de índice de clave pública del firmante a firma)
    sig_map = [(0, alice_signature), (1, bob_signature)]
    multisig_signature = MultiSignature(sig_map)
    # Crear el autenticador con nuestra configuración multisig
    authenticator = Authenticator(
    MultiEd25519Authenticator(multisig_public_key, multisig_signature)
    )

    El sig_map vincula cada clave pública del firmante a su firma, probando que tanto Alice como Bob han aprobado esta transacción. Los objetos MultiSignature y Authenticator empaquetan estas firmas en un formato que la blockchain puede verificar.

  2. Enviar transacción

    Crea y envía la transacción firmada:

    # Crear y enviar la transacción firmada
    signed_transaction = SignedTransaction(raw_transaction, authenticator)
    print("\n=== Enviando transacción de transferencia ===")
    tx_hash = await rest_client.submit_bcs_transaction(signed_transaction)
    await rest_client.wait_for_transaction(tx_hash)
    print(f"Hash de la transacción: {tx_hash}")

    La SignedTransaction combina los datos originales de la transacción con el autenticador que prueba que ambas firmas requeridas están presentes. Luego, las enviamos a la blockchain usando submit_bcs_transaction() y esperamos la confirmación.

  3. Comprobar nuevos balances

    Comprueba los nuevos balances de las cuentas después de la transacción:

    print("\n=== Nuevos balances de cuenta ===")
    [alice_balance, bob_balance, chad_balance, multisig_balance] = await asyncio.gather(
    *[
    rest_client.account_balance(alice.address()),
    rest_client.account_balance(bob.address()),
    rest_client.account_balance(chad.address()),
    rest_client.account_balance(multisig_address),
    ]
    )
    print(f"Balance de Alice: {alice_balance}")
    print(f"Balance de Bob: {bob_balance}")
    print(f"Balance de Chad: {chad_balance}")
    print(f"Balance de Multisig: {multisig_balance}")
  4. Ejecutar el script

    Para ver los resultados de la transacción, ejecuta:

    Ventana de terminal
    python3 multisig.py

    Deberías ver algo como:

    Ventana de terminal
    === Enviando transacción de transferencia ===
    Hash de la transacción: 0x2f0b7fc8e69213f0c7e720e660f789b6e3d3564729a298f2b4f6794245833f2d
    === Nuevos balances de cuenta ===
    Balance de Alice: 10000000
    Balance de Bob: 20000000
    Balance de Chad: 30000100 # Aumentado en 100 octas
    Balance de Multisig: 39999200 # Disminuido en 100 octas más tarifas de gas

    Nota cómo:

    • El saldo de Chad aumentó exactamente en 100 octas, pero los saldos de Alice y Bob no cambiaron ya que solo firmaron
    • La cuenta multisig pagó tanto el monto de la transferencia como las tarifas de gas

Has completado los conceptos básicos de la multisig de Aptos - creando una “bóveda” (cuenta multisig), añadiendo “titulares de claves” (firmantes) y haciendo una transferencia simple que requiere múltiples aprobaciones. Pero al igual que el banco moderno, hay mucho más que podemos hacer:

Al igual que tener un número de cuenta bancaria personalizado, Aptos te permite crear “direcciones vanas” que comienzan con caracteres específicos. Imagina poder elegir un número de cuenta memorable como “0xdd…” para tu empresa “Digital Dynamics”!

Los bancos te permiten actualizar tus credenciales de seguridad sin cambiar tu número de cuenta. De manera similar, las cuentas multisig de Aptos pueden “rotar” sus claves de autenticación mientras mantienen la misma dirección - perfecto para actualizar la seguridad sin interrumpir las configuraciones de pago existentes.

Al igual que los bancos tienen sistemas de aprobación complejos para cuentas corporativas grandes, la multisig de Aptos puede interactuar con contratos inteligentes y sistemas de gobierno. Imagina configurar reglas automatizadas como:

  • Aprobaciones requeridas basadas en el tamaño de la transacción
  • Transacciones bloqueadas por tiempo
  • Integración con sistemas de votación DAO
  1. Revisa el ejemplo de código completo que incluye todas las características avanzadas (ver arriba).
  2. Aprende sobre gobierno multisig en este tutorial.
  3. Explora abstracción de cuenta en Aptos.
  4. Únete al Aptos Discord para soporte de desarrolladores.