<jupyter_start><jupyter_text>PETs/TETs – Hyperledger Aries – Manufacturer 2 (Holder) 🚛<jupyter_code>%%javascript
document.title ='🚛 Manufacturer2'<jupyter_output><empty_output><jupyter_text>PART 2: Issue a VC to the Manufacturer Agents**What:** Receive and store verifiable credential (VC) from the authority agent (i.e., the issuing authority)**Why:** To prove that the agent is a manufacturer to relying parties (e.g., the city agent)**How:** 1. [Initiate Manufacturer's AgentCommunicationManager (ACM)](1)2. [Connect with the Authority agent](2)3. [Request VC](3)**Accompanying Agents and Notebooks:** * Authority 🏛️: `02_issue_VC_manufacturers.ipynb` --- 0 - Setup 0.1 - Imports<jupyter_code>import os

from aries_cloudcontroller import AriesAgentController

import libs.helpers as helpers
from libs.agent_connection_manager import CredentialHolder<jupyter_output><empty_output><jupyter_text>0.2 – Variables<jupyter_code># Get relevant details from .env file
api_key = os.getenv("ACAPY_ADMIN_API_KEY")
admin_url = os.getenv("ADMIN_URL")
webhook_port = int(os.getenv("WEBHOOK_PORT"))
webhook_host = "0.0.0.0"<jupyter_output><empty_output><jupyter_text>---  1 – Initiate Manufacturer2 Agent 1.1 – Init ACA-PY agent controller<jupyter_code># Setup
agent_controller = AriesAgentController(admin_url,api_key)
print(f"Initialising a controller with admin api at {admin_url} and an api key of {api_key}")<jupyter_output>Initialising a controller with admin api at http://manufacturer2-agent:3021 and an api key of adminApiKey<jupyter_text>1.2 – Start Webhook Server to enable communication with other agents@todo: is communication with other agents, or with other docker containers?<jupyter_code># Listen on webhook server
await agent_controller.init_webhook_server(webhook_host, webhook_port)
print(f"Listening for webhooks from agent at http://{webhook_host}:{webhook_port}")<jupyter_output>Listening for webhooks from agent at http://0.0.0.0:3010<jupyter_text>1.3 – Init ACM issuing authority<jupyter_code># The CredentialHolder registers relevant webhook servers and event listeners
manufacturer2_agent = CredentialHolder(agent_controller)

# Verify if Manufacturer already has a VC 
# (if there are manufacturer credentials, there is no need to execute the notebook)
manufacturer2_agent.get_credentials()<jupyter_output>[1m[32mSuccessfully initiated AgentConnectionManager for a(n) Holder ACA-PY agent[0m<jupyter_text>--- 2 – Establish a connection with the Authority agentA connection with the credential issuer (i.e., the authority agent) must be established before a VC can be received. In this scenario, the Manufacturer2 requests a connection with the Authority to be certified as an official city agency. Thus, the Manufacturer2 agent sends an invitation to the Authority. In real life, the invitation can be shared via video call, phone call, or E-Mail. In this PoC, this is represented by copy and pasting the invitation into the manufacturers' notebooks. 2.1 Create invitation to Authority agentSeveral state changes of the connection between the Manufacturer agent, the inviter (A), and the authority agent, the invitee (B),  are required before successfully establishing a connection: | Step | State | Agent | Description | Function/Prompt/Variable || --- | --- | --- | --- | --- || 1 | invitation-sent | A | A sent an invitation to B | `create_connection_invitation()`| 2 | invitation-received | B | B receives the invitation of A | Prompt: Paste invitation from A || 3 | request-sent | B | B sends B connection request | Prompt: Accept invitation OR `auto_accept=True` || 4 | request-received | A | A receives the connection request from B | Prompt: Accept invitation request response OR `auto_accept=True` || 5 | response-sent | A | A sends B response to B | - || 6 | response-received | B | B receives the response from A | - || 7 | active (completed) | A | B pings A to finalize connection | Prompt: Trust ping OR `auto_ping=True` |<jupyter_code># Setup for connection with Authority agent
alias = None
auto_accept = True # Accept response of Authority agent right away
auto_ping = True
public = False # Do not use public DID
multi_use = False # Invitation is only for one invitee

connection_id = manufacturer2_agent.create_connection_invitation(alias=alias, auto_accept=auto_accept, public=public, multi_use=multi_use, auto_ping=auto_ping)<jupyter_output>[1m[35m
Copy & paste invitation and share with external agent(s):[0m
{
    '@id': '4d907424-5645-41bd-9f43-f80be3beffbb',
    '@type': 'did:sov:BzCbsNYhMrjHiqZDTUASHg;spec/connections/1.0/invitation',
    'label': 'AnonymousAgent2',
    'recipientKeys': ['<KEY>'],
    'serviceEndpoint': 'https://1241-91-182-140-7.ngrok.io',
}

---------------------------------------------------------------------
[1mConnection Webhook Event Received: Connections Handler[0m
Connection ID :  ecfdf28f-d324-4d49-86b0-0218c49abde7
State :  [34minvitation (invitation-sent)[0m
Routing State : none
Their Role :  invitee
---------------------------------------------------------------------

---------------------------------------------------------------------
[1mConnection Webhook Event Received: Connections Handler[0m
Connection ID :  ecfdf28f-d324-4d49-86b0-0218c49abde7
State :  [34mrequest (request-received)[0m
Routing State : none
Connection with :  Governanc[...]<jupyter_text>Break Point 5🚛 ➡️ 🏛Please switch to the Authority agent 🏛: Please paste the invitation in Step 4.1 when prompted. If auto_accept is set to False, enter "yes" when prompted before proceeding.---Proceed after Break Point 6 3 – Request VC from `Authority` agent 3.1 – Message `Authority` with request<jupyter_code># Get schema_id of manufacturer_schema to find the correct credential_exchange_id
identifiers = helpers.get_identifiers()
schema_id = identifiers["manufacturer_schema_identifiers"]["schema_id"]

# Variables
auto_request = True # Authomatically requests VC when offer is found
auto_store = True # Automatically stores VC if issued by Authority

# Request VC
manufacturer2_agent.request_vc(connection_id, schema_id, auto_request, auto_store)<jupyter_output>[34mGet stored identifiers dictionary to access schema information 💾[0m

---------------------------------------------------------------------
[1mHandle Issue Credential Webhook: Issue Credential Handler[0m
Connection ID : ecfdf28f-d324-4d49-86b0-0218c49abde7
Credential exchange ID : ad0c42df-9a0f-4ce6-8f3c-677cb24a5751
Agent Protocol Role :  holder
Protocol State :  [34mrequest_sent[0m
---------------------------------------------------------------------

---------------------------------------------------------------------
[1mHandle Issue Credential Webhook: Issue Credential Handler[0m
Connection ID : ecfdf28f-d324-4d49-86b0-0218c49abde7
Credential exchange ID : ad0c42df-9a0f-4ce6-8f3c-677cb24a5751
Agent Protocol Role :  holder
Protocol State :  [34mcredential_received[0m
---------------------------------------------------------------------
[31m
Credential ad0c42df-9a0f-4ce6-8f3c-677cb24a5751 is not stored in wallet.[0m
[1m[35m
Please provide a referent (like an ID) for[...]<jupyter_text>3.3 – Verify that VC was stored in wallet<jupyter_code>manufacturer2_agent.get_credentials()<jupyter_output><empty_output><jupyter_text>---  4 – Terminate ControllerWhenever you have finished with this notebook, be sure to terminate the controller. This is especially important if your business logic runs across multiple notebooks.<jupyter_code>await agent_controller.terminate()<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.15040381305441547, 'fraction_numerical': 0.03521779425393883, 'mean_word_length': 4.0092838196286475, 'pattern_counts': {'":': 0, '<': 37, '<?xml version=': 0, '>': 37, 'https://': 1, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 2, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '10', 'dir': 'jupyter-structured-clean-dedup', 'id': '526641', 'license': 'Apache-2.0', 'n_tokens_mistral': 2397, 'n_tokens_neox': 2208, 'n_words': 719, 'path': 'agents/manufacturer2/notebooks/02_get_manufacturer2_VC.ipynb', 'repo_name': 'kajaschmidt/aries-jupyter-playground', 'size': '7592'}