Simple Summary
Agents are services involved in executing transactions. They can be commercial services such as exchanges and custodial wallet services. They could also be wallets, blockchain addresses, DeFi Protocols, bridges, and other services directly involved in a transaction.
Abstract
This specification defines how agents can represent themselves in a Transaction Authorization Protocol Flow, update details about themselves, and interact implemented using a small set of TAIP-2 Messages]TAIP-2 between each other.
Agents can be centralized services, software applications running on end-user devices, or decentralized protocols such as DEXes and Bridges.
Motivation
Traditional payment authorization protocols such as ISO-20022 or ISO-8583 only support centralized financial institutions as agents and must work better with self-hosted or decentralized participants.
For virtual asset transactions to truly become a core part of the world's financial infrastructure, all three types of agents can participate equally in the authorization flow of a transaction.
Specification
Representing Agents
Agents are identified using Decentralized Identifiers (DIDs). These identifiers have specific properties of being created by the Agent and support both authenticated and end-to-end encryption. DIDs can equally identify centralized and blockchain-native services such as wallets and DeFi protocols. Agents are represented in TAP in straightforward JSON-LD node syntax:
{
"@id": "did:web:vasp.com"
}
The following example shows its use in a TAIP-3 message:
{
"from": "did:web:originator.sample",
"type": "https://tap.rsvp/schema/1.0#Transfer",
"id": "...",
"to": ["did:pkh:eip155:1:0x1234a96D359eC26a11e2C2b3d8f8B8942d5Bfcdb"],
"body": {
"@context": "https://tap.rsvp/schema/1.0",
"@type": "https://tap.rsvp/schema/1.0#Transfer",
"asset": "eip155:1/slip44:60",
"originator": {
"@id": "did:web:originator.sample"
},
"amount": "1.23",
"agents": [
{
"@id": "did:web:originator.sample"
},
{
"@id": "did:pkh:eip155:1:0x1234a96D359eC26a11e2C2b3d8f8B8942d5Bfcdb",
"role": "SettlementAddress",
"for": "did:web:originator.sample"
}
]
}
}
The following are the attributes of an object in the agents
array:
@id
- REQUIRED the DID of the Agentrole
- OPTIONAL a string or an array of strings as specified for the particular kind of transaction. Eg.SettlementAddress
for TAIP-3for
- OPTIONAL a DID of another Agent or Party that this agent acts on behalf of in this transaction.policies
- OPTIONAL an array of TAIP-7 Policies
Future TAIPs are encouraged to extend the agent model with additional functionality.
Agent Interaction Types
There are three primary ways of interacting with agents:
- Centralized Agents, who can interact in real-time with TAIP-2 DIDComm Messages through a server endpoint defined in the DIDComm Transports
- End-user-controlled software, such as self-hosted wallets, can receive TAIP-2 DIDComm Messages in an interactive User Interface using DIDComm Out of Band
- Decentralized Protocol agents, such as DeFi protocols that can only communicate through blockchain transactions, possibly through an implementation of CAIP-74
Identifying Agents
DID Methods, implement different ways of creating and modifying Decentralized Identifiers. The recommendation is to use the following two DID Methods:
- WEB-DID For centralized services, allowing them to be identified by their domain name.
- PKH-DID For agent identified by a CAIP-10 blockchain address. For example, these could be both self-hosted and custodial wallets but also allow us to identify DeFi protocols.
Web DID for Centralized Services
Centralized Agents creating DIDs and implementing TAP SHOULD create a WEB-DID containing the following required sections in the DIDDoc:
- service containing a DID endpoint
- verificationMethod section containing public keys used for validating DIDComm message signatures
- keyAgreement section containing public keys used for encrypted DIDComm messages
PKH-DID's for Blockchain addresses
Since every wallet address has a blockchain account address, self-hosted wallets should be represented as a PKH DID using CAIP-10 identifiers.
For example, the Ethereum address can be represented as:
{
"@id": "did:pkh:eip155:1:0xab16a96D359eC26a11e2C2b3d8f8B8942d5Bfcdb"
}
Roles
Different agents can have specific roles specific to a particular transaction
type. For example settlementAddress
is a role in a TAIP-3 message indicating
how a transaction should be settled.
{
"@id": "did:pkh:eip155:1:0x1234a96D359eC26a11e2C2b3d8f8B8942d5Bfcdb",
"role": "settlementAddress"
}
Transaction Graphs
An essential aspect of managing risk in a transaction is to identify the various participants in a transaction. Agents typically act on behalf of another identity.
A transaction’s participants can be presented as the following graph of control, showing various missing vital pieces of information the Originating VASP’s risk department needs to discover, in particular, who is the beneficiary and who controls the Settlement Address:
graph TD
Transfer(Asset Transfer) --->|originator| Customer[did:eg:bob]
Transfer -->|beneficiary| Beneficiary[/???/]
Transfer -->|SourceAddress| CustodialWallet
OriginatingVASP[Originating VASP] -->|for| Customer
CustodialWallet -->|for| OriginatingVASP
Transfer -->|SettlementAddress| Wallet[Beneficiary Wallet]
Wallet -->|for| Unknown[/???/]
After discovering more about the Asset Transfer, we found it is a transaction to a third-party beneficiary at another exchange using a wallet API service. The graph looks like this, and we can manage risk better:
graph TD
Transfer(Asset Transfer) --->|originator| Customer[did:eg:bob]
Transfer -->|beneficiary| Beneficiary
Transfer -->|SourceAddress| CustodialWallet
OriginatingVASP[Originating VASP] -->|for| Customer
CustodialWallet -->|for| OriginatingVASP
Transfer -->|SettlementAddress| Wallet[Beneficiary Wallet]
Wallet -->|for| WalletAPI[MPC Wallet API]
WalletAPI -->|for| BeneficiaryVASP
BeneficiaryVASP[Beneficiary VASP] -->|for| Beneficiary
If we instead discovered that the transaction was a withdrawal to our customer's self-hosted wallet, the control graph would look like this:
graph TD
Transfer(Asset Transfer) --->|originator| Customer[did:eg:bob]
Transfer -->|beneficiary| Customer
Transfer -->|SettlementAddress| Wallet[Self-hosted Wallet]
Transfer -->|SourceAddress| CustodialWallet
OriginatingVASP[Originating VASP] -->|for| Customer
CustodialWallet -->|for| OriginatingVASP
Wallet -->|for| Customer
One of the primary jobs of TAP is to discover and identify the various controllers behind the parties and agents involved in a transaction to manage risk regarding them and ensure that the correct beneficiary receives a transaction.
Policies
Each agent can declare policies about different requirements that they need fulfilled to be able authorize a transaction. See TAIP-7 for more.
Agent meta data messages
In parallel with the Authorization Flow, agents can send TAIP-2 messages to other participants to provide or prove additional details about themselves or other participants. The messages allow agents to collaborate to fulfill each other's policies so they can successfully and swiftly authorize a transaction.
Please note that, like any TAIP-2 messages, these are just messages sent by an agent. For security purposes, a receiving Agent MUST determine if they can trust the sender for the information provided.
Any Agent can send one of the following messages:
AddAgents
- Adds one or more additional agents to the transactionReplaceAgent
- Replace an agent with another agentRemoveAgent
- Removes an agent from transaction
AddAgents
Any agent can add additional agents to a transaction by replying as a thread to
the initial message. The following shows the attributes of the body
object:
@context
- REQUIRED the JSON-LD contexthttps://tap.rsvp/schema/1.0
(provisional)@type
- REQUIRED the JSON-LD typehttps://tap.rsvp/schema/1.0#AddAgents
(provisional)agents
- REQUIRED an array of Agents to add to the transactions Agents list
If an existing transaction agent is included in the list of agents
, an Agent
SHOULD update their internal record for this Agent with any additional data
provided in this message.
Any new agents added should be included in the recipient list of the message.
ReplaceAgent
Any agent can replace themselves in a transaction by replying to the initial
message as a thread. The following shows the attributes of the body
object:
@context
- REQUIRED the JSON-LD contexthttps://tap.rsvp/schema/1.0
(provisional)@type
- REQUIRED the JSON-LD typehttps://tap.rsvp/schema/1.0#ReplaceAgent
(provisional)original
- REQUIRED the DID of the Agent to be replacedreplacement
- REQUIRED an Agent to add to the transactions Agents list
If a receiving Agent does not have a record for the Agent specified in the
original
, it SHOULD ignore this message.
The message's sender SHOULD include the Agent specified in the original
on the
recipient list so they can maintain a record that they are no longer part of
this transaction.
RemoveAgent
Any agent can propose removing another agent from the transaction by replying as
a thread to the initial message. The following shows the attributes of the
body
object:
@context
- REQUIRED the JSON-LD contexthttps://tap.rsvp/schema/1.0
(provisional)@type
- REQUIRED the JSON-LD typehttps://tap.rsvp/schema/1.0#RemoveAgent
(provisional)agent
- REQUIRED the DID of the Agent to be removed
If a receiving Agent does not have a record for the Agent specified in the agent
agent
attribute, it SHOULD ignore this message.
The message's sender SHOULD include the Agent specified in agent
on the
recipient list so they can maintain a record that they are no longer part of
this transaction.
Rationale
An end-user may request a transaction with fairly minimal information about its participants. The end-user's Agent must fill out the list of agents to manage risk on behalf of themselves and their customers.
The Agent structure provides an abstract method for multiple types of agents to collaborate to discover the required information to authorize a transaction using TAIP-4.
Test Cases
Provide here any test cases that will help implementers of the TAIP to validate their implementation.
DID Documents
The following is an example DID Document that could be created by a centralized service such as an exchange:
{
"did": "did:web:example.com",
"verificationMethod": [
{
"id": "did:web:example.com#key-1",
"type": "Ed25519VerificationKey2020",
"controller": "did:web:example.com",
"publicKeyMultibase": "zH3C2AVvLMv6gmMNam3uVAjZpfkcJCwDwnZn6z3wXmqPV"
}
],
"keyAgreement": [
{
"id": "did:example:example.com#key-x25519-1",
"type": "JsonWebKey2020",
"controller": "did:example:example.com",
"publicKeyJwk": {
"kty": "OKP",
"crv": "X25519",
"x": "avH0O2Y4tqLAq8y9zpianr8ajii5m4F_mICrzNlatXs"
}
}
],
"service": [
{
"id": "did:web:tap.rsvp#tap",
"type": "DIDCommMessaging",
"serviceEndpoint": {
"uri": "https://tap.rsvp/didcomm"
}
}
]
}
TAIP-3 Asset Transfers
Missing Nodes
See the following TAIP-3 message outlining a typical Asset Transfer where a customer is asking to transfer funds to a blockchain address:
{
"from": "did:web:originator.vasp",
"type": "https://tap.rsvp/schema/1.0#Transfer",
"id": "...",
"to": [
"did:web:beneficiary.vasp",
"did:pkh:eip155:1:0x1234a96D359eC26a11e2C2b3d8f8B8942d5Bfcdb"
],
"body": {
"@context": "https://tap.rsvp/schema/1.0",
"@type": "https://tap.rsvp/schema/1.0#Transfer",
"originator": {
"@id": "did:eg:bob"
},
"asset": "eip155:1/slip44:60",
"amount": "1.23",
"settlementId": "eip155:1:tx/0x3edb98c24d46d148eb926c714f4fbaa117c47b0c0821f38bfce9763604457c33",
"agents": [
{
"@id": "did:web:originator.vasp",
"for": "did:eg:bob"
},
{
"@id": "did:pkh:eip155:1:0x1234a96D359eC26a11e2C2b3d8f8B8942d5Bfcdb",
"role": "SettlementAddress"
}
]
}
}
Complete example showing VASP to VASP third party Asset Transfer
After completing the discovery aspects of TAP the Asset Transfer could look like this with a third party beneficiary and a VASP controlling the Settlement Address:
{
"from": "did:web:originator.vasp",
"type": "https://tap.rsvp/schema/1.0#Transfer",
"id": "...",
"to": [
"did:web:beneficiary.vasp",
"did:pkh:eip155:1:0x1234a96D359eC26a11e2C2b3d8f8B8942d5Bfcdb"
],
"body": {
"@context": "https://tap.rsvp/schema/1.0",
"@type": "https://tap.rsvp/schema/1.0#Transfer",
"originator": {
"@id": "did:eg:bob"
},
"beneficiary": {
"@id": "did:eg:alice"
},
"asset": "eip155:1/slip44:60",
"amount": "1.23",
"settlementId": "eip155:1:tx/0x3edb98c24d46d148eb926c714f4fbaa117c47b0c0821f38bfce9763604457c33",
"agents": [
{
"@id": "did:pkh:eip155:1:0xabcda96D359eC26a11e2C2b3d8f8B8942d5Bfcdb",
"for": "did:web:originator.vasp",
"role": "SourceAddress"
},
{
"@id": "did:web:originator.vasp",
"for": "did:eg:bob"
},
{
"@id": "did:web:beneficiary.vasp",
"for": "did:eg:alice"
},
{
"@id": "did:web:walletapi.sample",
"for": "did:web:beneficiary.vasp"
},
{
"@id": "did:pkh:eip155:1:0x1234a96D359eC26a11e2C2b3d8f8B8942d5Bfcdb",
"for": "did:web:walletapi.sample",
"role": "SettlementAddress"
}
]
}
}
Complete example showing VASP to first party self-hosted wallet Asset Transfer
After completing the discovery aspects of TAP we discover the Asset Transfer goes to the customer's own self-hosted wallet address:
{
"from": "did:web:originator.vasp",
"type": "https://tap.rsvp/schema/1.0#Transfer",
"id": "...",
"to": [
"did:web:beneficiary.vasp",
"did:pkh:eip155:1:0x1234a96D359eC26a11e2C2b3d8f8B8942d5Bfcdb"
],
"body": {
"@context": "https://tap.rsvp/schema/1.0",
"@type": "https://tap.rsvp/schema/1.0#Transfer",
"originator": {
"@id": "did:eg:bob"
},
"beneficiary": {
"@id": "did:eg:bob"
},
"asset": "eip155:1/slip44:60",
"amount": "1.23",
"settlementId": "eip155:1:tx/0x3edb98c24d46d148eb926c714f4fbaa117c47b0c0821f38bfce9763604457c33",
"agents": [
{
"@id": "did:pkh:eip155:1:0xabcda96D359eC26a11e2C2b3d8f8B8942d5Bfcdb",
"for": "did:web:originator.vasp",
"role": "SourceAddress"
},
{
"@id": "did:web:originator.vasp",
"for": "did:eg:bob"
},
{
"@id": "did:pkh:eip155:1:0x1234a96D359eC26a11e2C2b3d8f8B8942d5Bfcdb",
"for": "did:eg:bob",
"role": "SettlementAddress"
}
]
}
}
Agent Meta Data Messages
The following are example plaintext messages. See TAIP-2 for how to sign the messages.
AddAgents
{
"from": "did:web:beneficiary.vasp",
"type": "https://tap.rsvp/schema/1.0#AddAgents",
"thid": "ID of transfer request",
"to": ["did:web:originator.vasp"],
"body": {
"@context": "https://tap.rsvp/schema/1.0",
"@type": "https://tap.rsvp/schema/1.0#AddAgents",
"agents": [
{
"@id": "did:web:originator.vasp",
"for": "did:eg:bob"
},
{
"@id": "did:pkh:eip155:1:0x1234a96D359eC26a11e2C2b3d8f8B8942d5Bfcdb",
"for": "did:eg:bob",
"role": "SettlementAddress"
}
]
}
}
ReplaceAgent
{
"from": "did:web:beneficiary.vasp",
"type": "https://tap.rsvp/schema/1.0#ReplaceAgent",
"thid": "ID of transfer request",
"to": ["did:web:originator.vasp"],
"body": {
"@context": "https://tap.rsvp/schema/1.0",
"@type": "https://tap.rsvp/schema/1.0#ReplaceAgent",
"original": "did:web:originator.vasp",
"replacement": {
"@id": "did:pkh:eip155:1:0x1234a96D359eC26a11e2C2b3d8f8B8942d5Bfcdb",
"for": "did:eg:bob",
"role": "SettlementAddress"
}
}
}
RemoveAgent
{
"from": "did:web:beneficiary.vasp",
"type": "https://tap.rsvp/schema/1.0#RemoveAgent",
"thid": "ID of transfer request",
"to": ["did:web:originator.vasp"],
"body": {
"@context": "https://tap.rsvp/schema/1.0",
"@type": "https://tap.rsvp/schema/1.0#RemoveAgent",
"agent": "did:web:originator.vasp"
}
}
Security Considerations
As in any decentralized messaging protocol, it is paramount that the recipient of messages trust the senders in the context of a particular transaction.
TODO specify in more detail
Privacy Considerations
References
- TAIP-2 Defines the TAP Message structure
- TAIP-3 Asset Transfer Message
- TAIP-4 Transaction Authorization Protocol
- TAIP-6 Transaction Parties
- TAIP-7 Policies
- CAIP-10 Describes chainagnostic Account ID Specification
- CAIP-74 CACAO
- ISO-20022 ISO-20022 Universal Financial Industry message scheme
- ISO-8583 ISO-8683 Financial-transaction-card-originated messages
- DID W3C Decentralized Identifiers
- DIDComm DIDComm Messaging
- DIDCommTransports DIDComm Transports
- DIDCommOOB DIDComm Out-of-Band
- PKH-DID
did:pkh
specification - WEB-DID
did:web
specification
Copyright
Copyright and related rights waived via CC0.