---
title: "Account abstraction parte 4: assinaturas agregadas"
description: "Explore o avanço do ERC-4337 com assinaturas agregadas. Simplifique a validação de múltiplas user ops usando uma única assinatura criptográfica, melhorando a eficiência das transações."
---

## Aggregate signatures

Nossa implementação atual valida cada user op do bundle separadamente. Essa é uma forma bem direta de pensar a validação, mas potencialmente custosa. Verificar assinaturas pode acabar ficando caro em termos de gas, porque isso exige bastante aritmética criptográfica.

**Não seria bom se pudéssemos validar vários ops ao mesmo tempo com apenas uma assinatura em vez de várias?**

Fazer isso depende de um conceito da criptografia, **assinaturas agregadas**.

Um esquema de assinatura que suporta agregação oferece uma forma, dadas várias mensagens assinadas com chaves diferentes, de gerar uma única assinatura combinada tal que verificar a assinatura combinada implica que todas as assinaturas que a compõem também são válidas.

Um exemplo comum de esquema de assinatura que suporta agregação é [BLS](https://en.wikipedia.org/wiki/BLS_digital_signature).

Essa otimização é particularmente útil para implementar rollups, já que o objetivo principal de um rollup é a compressão de dados, e a agregação de assinaturas nos permite comprimir a parte referente às assinaturas.

Para saber mais sobre a economia de espaço obtida com a agregação de assinaturas, veja [o tweet do Vitalik sobre o assunto](https://twitter.com/VitalikButerin/status/1554983955182809088).

### Apresentando os aggregators

De imediato, percebemos que nem todos os user ops de um bundle podem ter suas assinaturas agregadas juntas. Lembre-se de que uma wallet tem permissão para usar qualquer lógica arbitrária que quiser para validar a assinatura que recebe, então pode haver vários esquemas de assinatura presentes no mesmo bundle.

Como provavelmente não podemos agregar assinaturas de esquemas diferentes, nosso bundle acabará com grupos de ops, cada grupo usando um esquema de agregação distinto ou nenhum esquema de agregação.

Como precisamos ter vários esquemas de agregação representados on chain, cada um com sua própria lógica, cada esquema de agregação será representado por um contrato que chamaremos de **aggregator**.

Um esquema de agregação é definido por como ele combina várias assinaturas em uma só e por como ele valida a assinatura combinada, então um aggregator expõe essas duas funções como métodos:

<ImageBlock
  src="https://media.alchemy.com/1704793497-aggregator-contract-combining-user-ops-to-single-signature.jpeg"
  alt="Um contrato agregador combina ops de múltiplos usuários em um grupo com uma única assinatura."
  width={960}
  height={540}
  caption="Um contrato agregador combina ops de múltiplos usuários em um grupo com uma única assinatura."
/>

Como cada wallet define seu próprio esquema de assinatura, cabe a cada wallet decidir com qual aggregator ela é compatível, se houver algum.

**Se uma wallet quiser participar da agregação, ela expõe um método para escolher seu aggregator:**

Usando esse novo método `getAggregator`, o bundler pode agrupar ops que têm o mesmo aggregator e usar o método `aggregateSignatures` desse aggregator para calcular uma assinatura combinada para eles.

**Um grupo poderia se parecer com isto:**

<CalloutBlock>

💡 Se um bundler tiver conhecimento off-chain sobre um aggregator em particular, ele pode otimizar codificando de forma nativa uma versão do algoritmo de agregação de assinaturas, em vez de executar `aggregateSignatures` como código EVM.

</CalloutBlock>

Em seguida, precisamos atualizar o contrato entry point para usar os novos aggregators.

Lembre-se de que o entry point tem um método `handleOps` que recebe uma lista de ops.

**Vamos dar a ele um novo método,** `handleAggregatedOps`**, que faz a mesma coisa, mas recebe os ops agrupados por aggregator:**

O novo método, `handleAggregatedOps`, funciona basicamente da mesma forma que `handleOps`. A única diferença está na etapa de validação.

Enquanto `handleOps` realiza a validação chamando o método `validateOp` de cada wallet, `handleAggregatedOps` vai, em vez disso, chamar o método `validateSignatures` do aggregator sobre a assinatura combinada de cada grupo, usando o aggregator daquele grupo.

<ImageBlock
  src="https://media.alchemy.com/1703863779-account-abstraction-key-concepts.jpeg"
  alt="Diagrama: o executor agrupa user ops com o agregador antes de enviá-las ao entry point para validação em lote"
  width={960}
  height={540}
  caption="O executor usa o agregador para agrupar ops antes de enviá-las ao entry point, para que todas possam ser validadas ao mesmo tempo."
/>

Estamos quase terminando!

Mas há um problema aqui que já deve ser bem familiar a essa altura.

O bundler quer simular a validação e verificar que o aggregator vai validar um grupo de ops antes de incluí-los no bundle, porque, se a validação falhar, o bundler é obrigado a pagar pelo gas. Mas um aggregator com lógica arbitrária pode facilmente ter sucesso durante a simulação e falhar durante a execução.

Vamos resolver isso exatamente da mesma forma que fizemos para paymasters e factories: restringimos a quais [storage](https://www.alchemy.com/docs/smart-contract-storage-layout) o aggregator pode acessar e quais opcodes ele pode usar, e exigimos que ele faça stake de ETH no entry point, a menos que não acesse storage.

E é isso para assinaturas agregadas!

### Encerramento

O que criamos aqui é mais ou menos a [arquitetura completa do ERC-4337](https://eips.ethereum.org/EIPS/eip-4337)! Existem algumas diferenças nos detalhes, como os nomes e argumentos de alguns dos métodos, mas não sobra nada que eu consideraria uma diferença arquitetural. Se eu fiz um bom trabalho, você agora deve conseguir ler o ERC-4337 de verdade e entender o que está acontecendo.

Se você chegou até aqui, muito obrigado por ler minha explicação! Espero que ela tenha te ajudado tanto quanto me ajudou escrevê-la.

## Adendo: diferenças em relação ao ERC-4337

Embora já tenhamos a arquitetura geral da account abstraction definida, as pessoas inteligentes por trás do ERC-4337 pensaram em algumas coisas ligeiramente diferentes do que descrevemos acima.

Vamos ver algumas delas!

### 1. Intervalos de tempo de validação

Acima, fui bem vago sobre o tipo de retorno do `validateOp` da wallet e do `validatePaymasterOp` do paymaster. O ERC-4337 encontra uma boa forma de aproveitar isso.

Algo que uma wallet gostaria muito de fazer é permitir que um user op seja válido apenas por um certo período de tempo. Caso contrário, um bundler mal-intencionado poderia segurar essa operação por muito tempo e depois incluí-la em um bundle bem mais tarde, num momento vantajoso para o bundler.

A wallet poderia querer se proteger disso verificando o `TIMESTAMP` durante a validação, para garantir que ele não esteja muito distante no futuro, mas não pode, porque proibimos o `TIMESTAMP` durante a validação para evitar que as simulações fiquem imprecisas. Isso significa que a wallet precisa de outra forma de indicar em quais momentos a operação é válida.

**Assim, o ERC-4337 dá a** `validateOp`** um valor de retorno que a wallet pode usar para escolher um intervalo de tempo:**

Esse valor de retorno representa o intervalo de tempo em que a operação é válida como dois inteiros de 8 bytes, um após o outro.

Outra observação do ERC-4337: as wallets devem retornar um valor sentinela do validateOp em vez de reverter em caso de falha na validação, o que ajuda na estimativa de gas, já que o [eth_estimateGas](https://www.alchemy.com/docs/chains/ethereum/ethereum-api-endpoints/eth-estimate-gas) não informa quanto gas foi usado em uma transação que reverte.

### 2. Call data arbitrário para wallets e factories

Dissemos que a interface da nossa wallet era:

No ERC-4337, as wallets não têm de fato um método chamado `executeOp`.

**Em vez disso, a user operation tem um campo** `callData`**:**

Isso é passado para a wallet como call data.

Para um contrato inteligente típico, os quatro primeiros bytes desses dados serão interpretados como um function selector e o restante como argumentos da função.

Isso significa que, além do método `validateOp` obrigatório, as wallets podem definir sua própria interface, e as user operations podem ser usadas para chamar métodos arbitrários na wallet.

Na mesma linha, no ERC-4337 os contratos factory não têm de fato um método `deployContract`. Eles também recebem call data arbitrário, nesse caso a partir do campo `initCode` do op.

### 3. Dados compactos para paymasters e factories

Acima, dissemos que a user operation continha campos para especificar um paymaster, assim como quais dados passar para ele:

**No ERC-4337, esses campos são combinados em um só como uma otimização, em que os primeiros 20 bytes do campo são o endereço do paymaster e o restante são os dados:**

O mesmo vale para as factories e os dados enviados a elas: enquanto usamos dois campos, `factory` e `factoryData`, o ERC-4337 combina esses em um único campo, `initCode`.

Pronto, você conseguiu!

Esperamos que você tenha aprendido bastante sobre Account Abstraction.

### Você poderia ter inventado a account abstraction

Perdeu o início dessa série de 4 partes? Volte e leia desde o começo!

1. [Account Abstraction Parte 1: Protegendo Nossos Ativos](https://www.alchemy.com/overviews/what-is-account-abstraction)
1. [Account Abstraction Parte 2: Patrocinando Transações com Paymasters](https://www.alchemy.com/overviews/what-is-account-abstraction-paymasters)
1. [Account Abstraction Parte 3: Criação de Wallets](https://www.alchemy.com/overviews/what-is-account-abstraction-wallet-creation)
