---
title: Proof of Event
status: Draft
authors: Abhishek Jain <abhishek.jain@trili.tech>, Andreas Gassmann <a.gassmann@papers.ch>
type: LA
created: 2023-04-09
date: 2023-04-23
version: 1
---
## Table of Contents
- [Summary](#summary)
- [Motivation](#motivation)
- [Specification](#specification)
- [Definitions](#definitions)
- [Receiving Tez](#receiving-tez)
- [Wallet to dApp Interaction](#wallet-to-dapp-interaction)
- [Proof of Event](#proof-of-event)
- [Considerations for dApps](#considerations-for-dapps)
- [Supported Required from dApps](#supported-required-from-dapps)
- [Sequence Diagram](#sequence-diagram)
- [User Flow](#user-flow)
- [Contract Specification](#contract-specification)
- [Copyright](#copyright)
## Summary
This proposal presents a standard for Abstracted Accounts to interface with dApps. A standardised approach is needed to facilitate a more adoptable and user friendly interaction between wallets and dApps. Primary attention has been given to interactions with wallets when it comes to proving ownership, which is currently done through message signing for implicit accounts. In absence of a key pair, for originated accounts, a new concept of Proof of Event is proposed.
## Motivation
Abstracted accounts provide a few advantages for security minded users and DAOs. A level of indirection between individual user accounts and the abstracted wallet allows for easier account management functionality (for example, key ownership rotation without requiring to transfer tokens between accounts). DAOs may want a bespoke wallet action and ownership permissions which isn’t possible with a user wallet. Other benefits can include multi-signature support and spending limits.
Interacting with dApps is an important use case for users. For user wallets, ownership is proven with a signing message request transmitted to the user’s wallet application through the transport channel; being Beacon (or WalletConnect 2.0). However, unlike implicit wallets, abstracted accounts are not borne out of a private key and do not possess signing capability. They would require a different approach to prove identity. This document proposes a new standard and scheme for smart contracts signing messages.
## Specification
The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in [RFC 2119][1].
An Abstracted Account, being a smart contract, needs a mechanism to interface with the caller (user), through which it is instructed to take action. This can be done with customised code at the discretion of the smart contract developer. This is well understood and adopted, and also sits outside the scope of this proposal.
An important requirement to be a wallet is how it presents itself to the rest of the chain, how it solves for dApp interaction, signing requests and identity verification. More on this later.
### Definitions
- **Session**: A user session is a time and/or purpose bound freedom of operation awarded to the user operating the dApp on behalf of the wallet which has authenticated the user.
- **Transport Channel**: For the purpose of this document, it refers to the channel facilitating the communication between the dApp and the wallet application. This being Beacon or WalletConnect 2.0.
- **Wallet Application**: To avoid confusion, Wallet Application specifically refers to the software for users to operate their Tezos accounts, and what would represent the user/wallet when communicating with dApps over the transport channel.
### Receiving Tez
Given that transacting tokens is the most essential use case for a wallet, calling the default entrypoint should be reserved for receiving tez. Note: It is not required for a contract to be able to receive transfers, but if it wishes to do so, it should do so via this entrypoint.
### Wallet to dApp Interaction
Wallet Applications can communicate to the dApp that it is connecting using an abstracted account smart contract wallet. It **MUST** do so by modifying existing responses in the following way:
For Beacon, introduce three new fields ‘“address”, “type” and "verification_type" in the PermissionResponse interface,
```typescript
export interface PermissionResponse extends BeaconBaseMessage {
...
address: string;
type: string;
verification_type: string;
...
}
```
- `address`: the wallet address (optional for backwards compatibility, in absence of address field, use public key to derive the address)
- `type`: can be ‘implicit’ | ‘abstracted_account’,
- `verification_type`: if type is "abstracted_account" then supply ‘proof_of_event’ (optional for backwards compatibility, in absence of 'address' field, assumed to be an implicit type and ignore this field)
For Wallet Connect 2.0, the “algo” field is repurposed to indicate "abstracted_account" type.
```typescript
// Result
{
...
"result": [
{
"algo": "<string>",
"verification_type": "<string>"
...
}
]
}
```
- `algo`: supply the curve for an implicit account and “abstracted_account” for abstracted accounts
### Proof of Event
Abstracted Account wallets are not tied to a public key, instead they would emit contract events to prove account ownership. Events are supported by the protocol and are a way for contracts to deliver information to external applications. This mechanism is designed to allow off-chain applications to react to Tezos smart contracts execution.
dApps **MAY** challenge the wallet to emit a specific event message that can be verified later. This mechanism essentially is a substitute for signing a message. If an abstract account contract emitted an event, of the dApps choosing, would hold equal value as message signing. We shall call a contract’s event emission (for purposes of verifying identity to dApps) as a ==Proof of Event==.
In such cases, the request **REQUIRES** a string payload (decided by the dApp) to be emitted by the abstracted account wallet in the form of Proof of Event.
For Beacon, introduce a new request object for proof of event challenges,
```typescript
export interface ProofOfEventChallengeRequest extends BeaconBaseMessage {
type: BeaconMessageType.ProofOfEventChallengeRequest;
payload: string;
contractAddress: string;
dAppChallengeId: string;
}
```
For Wallet Connect 2.0, a new request format as follows,
```typescript
// Request
{
...
"method": "tezos_proofOfEventChallenge",
"params": {
"payload": "<string>",
"dAppChallengeId": "<string>",
"contractAddress": "<string>",
}
}
```
- `payload`: payload for Proof of Event
- `dAppChallengeId`: dApp decided challenge identifier
- `contractAddress`: the contract address of the abstracted account
Wallet application **MUST** explicitly accept or reject the challenge request for it to be recorded. dApps **SHOULD** persist this challenge securely so it can be referenced at a later point for verifying the Proof of event.
For Beacon, introduce a new response object for proof of event challenge response,
```typescript
export interface ProofOfEventChallengeResponse extends BeaconBaseMessage {
type: BeaconMessageType.ProofOfEventChallengeResponse;
dAppChallengeId: string;
isAccepted: boolean;
}
```
For Wallet Connect 2.0, a new response format as follows,
```typescript
// Result
{
...
"result": {
"dAppChallengeId": "<string>",
"isAccepted": "<boolean>",
}
}
```
- `isAccepted`: indicating whether the challenge is accepted
The dApp will be **REQUIRED** to explicitly provide an acknowledgment to recording the Proof of Event challenge as explained below.
For Beacon, introduce a new object for proof of event recorded response,
```typescript
export interface ProofOfEventChallengeRecorded extends BeaconBaseMessage {
type: BeaconMessageType.ProofOfEventChallengeRecorded;
dAppChallengeId: string;
success: boolean;
errorMessage: string;
}
```
For Wallet Connect 2.0, a new response format as follows,
```typescript
// Request
{
...
"method": "tezos_proofOfEventChallengeRecorded",
"param": {
"dAppChallengeId": "<string>",
"success": "<boolean>",
"errorMessage": "<string>",
}
}
```
- `success`: indicating whether the challenge is recorded successfully
- `errorMessage`: optional, error message incase of failure
dApps would require services and API support to verify Proof of Events. An indexer (such as tzkt) **MAY** be extended to support a read lookup for a specific contract and whether an event was emitted. This would greatly aid adoption among dApps. See spec below:
```typescript
// Request
https://api.tzkt.io/.../events/{address}/
https://api.tzkt.io/.../events/{address}/<hash-of-emit-payload>
// Response
[
{
“payload_hash” : {
“operation_hash” : “string” // Hash of the operation that triggered the event
“emitted” : “boolean” // True, false if the event has been emitted
“timestamp” : “string <date-time>” // Optional, Timestamp of the block at which the event was emitted
“level” : “integer <int32>” // Height of the block at which the account balance was calculated
}
}
]
```
### Considerations for dApps
Abstracted Accounts will break a long held assumption and paradigm that all wallets are implicit accounts. Keep in mind the following:
- Not all addresses begin with TZ{1..4}, a smart contract wallet would follow the KT prefix scheme. dApps need to adjust to allow for such pairing, and signing.
- Transport channels should not assume that all accounts that are shared have a public key (which is used to generate the TZ{1..4} addresses).
- Proof of Event verifications are indirect and temporal, a user may lose ability the ability to verify ownership in the future. dApps are suggested to use Proof of Event verification for specific actions and avoid verifying for long sessions.
### Supported Required from dApps
- Proof of Events may require multiple individuals to perform on-chain operations, leading to an undefined period of time for - - Proof of Event to be emitted. dApps would need to persist the Proof of Event challenges on the backend that are pending verification. dApps would need to support and manage user sessions so they are able to recognise the user when they attempt to login after the Proof of Event has been emitted successfully.
- dApps are recommended to store the following fields together on their backend; challenge id, user session id, abstracted wallet address, and payload.
## Sequence Diagram

## User Flow
Below User flow demonstrates the connection between the dApp and an abstracted account supporting wallet application, and emit challenge to verification.

## Contract Specification
### `Proof_of_event_challenge` entrypoint
```
(pair %proof_of_event_challenge
(bytes %challenge_id)
(bytes %payload)
)
```
Proposing with a Proof of Event challenge object is specified with a pair `challenge_id` and `payload`. This proposal doesn't specify the internal mechanics of how this Event is managed internally within the contract.
### ```proof of event``` event format
```
EMIT %proof_of_event (pair (bytes %challenge_id) (bytes %payload))
```
The proof of event is emitted with `%proof_of_event` tag along with the pair
object containing the challenge_id and payload.
## Copyright
Copyright and related rights waived via [CC0][2].
[1]: https://www.ietf.org/rfc/rfc2119.txt
[2]: https://www.ietf.org/rfc/rfc2413.txt