For local deployment, you will need a local instance of Kepler and the Witness worker.
If you want to use their production instances, you need to set the following environment variables:
export KEPLER_URL=https://kepler.tzprofiles.com
export WITNESS_URL=https://witness.tzprofiles.com
To run:
npm install
npm run build
For development purposes you can use
npm run dev
.
It is currently integrated with Cloudflare Pages. The HEAD
of main
is what
is available on tzprofiles.com -- and otherwise a specific deployment is
available for every commit of every branch.
Because the primary use-case of Tezos Profiles is the creation of a variety of claims, adding a new type of claim is easy and standardized:
- Add a new type
ClaimVCType
, this will be used as the final type in the produced Verifiable Credential, it is used by the UI to determine how to display / edit the VC's underlying data. Example:BasicProfile
,TwitterVerification
. - Add a new
ClaimType
, this will be used in many switch statements to determine per-claim type specialized behavior, generate default draft structures for the end user to fill out, and use the static copy universal to all claims of that type. Example:basic
,twitter
- Add an entry in
claimTypeFromVC
that translates fromClaimVCType
toClaimType
- Add a new type to
ClaimDraft
, this will represent thedraft
information of a Claim. This will be used to represent all claim specific information of a given claim, as opposed todisplay
which is all data that is the same between claims of the sameClaimType
. ExampleBasicDraft
,TwitterDraft
. - Add a new claim draft
interface
corresponding to theClaimDraft
added in the previous type. Example:
export interface BasicDraft {
alias: string,
description: string,
logo: string
website: string
}
export interface TwitterDraft {
handle: string
tweetUrl: string
}
At this point, the claims.ts
file should be complaining about the exhaustiveCheck
being hit by unaccounted for ClaimType
s. To fix that:
- Add a result to
newDisplay
for theClaimType
added in the second step, this will be an implementation of theClaimUIAssets
type. This is used to to contain all components and copy that is universal between all claims of the same type. This allows the UI to be autogenerated and copy changes to only take place in one place. Example:
case 'twitter':
return {
description: 'This process is used to link your Twitter account to your Tezos account by signing a message using your private key, entering your Twitter handle, and finally, tweeting that message.',
display: 'Twitter Account Verification',
icon: TwitterIcon,
route: '/twitter',
routeDescription: 'Twitter Account Information',
proof: 'Tweet',
title: 'Twitter Verification',
type: 'Social Media',
}
- Add a new result to
newDraft
which creates aClaimDraft
corresponding to theClaimType
added in the second step for when the user doesn't have a given claim. Example:
case 'basic':
return {
alias: '',
description: '',
logo: '',
website: ''
};
case 'twitter':
return {
handle: '',
tweetUrl: ''
};
-
Develop the verifiable credential that will be created / signed. There is not a consistent place to use this, but knowing what it will look like is important. Examples found in
worker
or theEthereum
route. -
Add a result corresponding to the
ClaimType
created in the second step tocontentToDraft
which takes aClaimType
and VC and returns an appropriate draft:
export const contentToDraft = (ct: ClaimType, content: any): ClaimDraft => {
switch (ct) {
case "basic": {
const {credentialSubject} = content;
const {alias, description, logo, website} = credentialSubject;
return {
alias,
description,
logo,
website
}
}
case "twitter": {
const {evidence, credentialSubject} = content;
const {sameAs} = credentialSubject;
const {tweetId} = evidence;
const handle = sameAs.replace('https://twitter.com/', '');
const tweetUrl = `https://twitter.com/${handle}/status/${tweetId}`;
return {
handle,
tweetUrl
}
}
}
exhaustiveCheck(ct);
}
- Add a result corresponding to the
ClaimType
created in the second step toclaimToOutlink
to be used in the Pubic View of the profile. Example:
let draft = contentToDraft(c.type, c.content);
switch (ct) {
case 'ethereum': {
draft = draft as EthereumDraft;
return `https://etherscan.io/address/${draft.address}`;
}
case 'twitter': {
draft = draft as TwitterDraft;
return `https://www.twitter.com/${draft.handle}`;
}
}
Claim generation basically falls into 2 categories, the simpler version is internal to the site such as with the basic
and ethereum
claims, the more complex requires the dapp
to reach out to a third party for some form of verification. The second category is referred to as socialMediaClaimType
. If the claim being added requires external interaction, then the following will be needed to generate the claim creation and signing programattically:
- Add an entry to the
socialMediaClaimType
, Exampletwitter
. This should be a subset ofClaimType
. - Add a result to
socialMediaTitle
corresponding to thesocialMediaClaimType
. - Add a result to
socialMediaHandle
corresponding to thesocialMediaClaimType
. - Add a result to
tzpHandle
corresponding to thesocialMediaClaimType
, this should be the handle of the Tezos Profile account associated with the platform.
- Add a display component to
src/components/claims/display
which will be used when a user looks at their claim's details from their own profile. Should show all elements of theclaim.draft
. - Add this component to the switch statement in
src/components/claims/display/ClaimsDisplay
. - Add a component to
src/routes
for the end user to interact with to create (and in the future, update) the claim. This should make use of theVerificationDescription
component (which because of the prior work, only needs to be passed theclaim.display
object to automatically render correctly) and theVerificationStep
components for each step. - If this is a
socialMediaClaimType
, usegetPreparedUnsignedMessage
to get the unsigned claim copy and following that, thegetFullSocialMediaClaim
to get the correctly formatted final post the user should make to the given platform. - Add the bespoke verification logic.
Now, all of the UI "just works"!