SafeConnect Widget V1
SafeConnect Version 2 is out now! Check out the new devx page here.
SafeConnect is a Javascript SDK that enables VASPs to easily collect information from your customer about the virtual assets' recipient without making significant changes to your front-end. It is usually rendered at point of transaction by passing it the destination wallet address, the amount, and the asset type a user wish to transfer
If the fiat value of the virtual assets being sent is above the threshold for travel rule, the Widget will help collect all the information about the recipient that is required in your jurisdiction:
If your customer is sending virtual assets to themselves (by selecting the "Yes, I own this account"-checkbox), it will not collect the recipient's name or other details as that should already be known to you and available in the KYC database.
Likewise, if the destination wallet address is already known, it will not ask the customer to select where the wallet is hosted.
JavaScript SDK Readme
You can find the readme here.
Implementation examples
Below are a few examples you can use to test the Widget locally, make sure to customize:
{{URL}}
- Testing URL: https://beta-widget.notabene.dev
- Production URL: https://beta-widget.notabene.id
{{originatorVASPdid}}
the vaspDID{{TOKEN}}
the customerToken
Html - standard implementation
Html - custom fields and validation
NextJS - implementation example
React Native - implementation example
Html - post deposit widget example
Environment URLs
Production URL: https://beta-widget.notabene.id
Testing URL: https://beta-widget.notabene.dev
Using widget payload in txCreate
When the Widget returns isValid=**true**
the "notabene.tx" object contains all the necessary data to create a transaction apart from the originator data.
To correctly structure the body of the txCreate request, you have to extract the beneficiary data from the IVMS object, the transaction data is available in the notabene.tx object, and only the originator data has to be added retrieving it from you internal records.
Take a look at the example below to see how to orchestrate the data for a successful txCreate request:
const tx = {
originator: {} // HERE you need to fill the originator info
beneficiary: returnedTransaction.ivms.beneficiary,
};
const payload: TransactionCreateRequest = {
...returnedTransaction,
...tx,
};
Following is a pseudo code of how we transform the tx returned by the widget and call txCreate in our internal testing application that implements the widget.
/ buildPerson is a helper that builds the ivms object
const tx = {
transactionBlockchainInfo: {
origin: originatorAddress,
destination: address,
},
originator: {
...buildPerson("originator", {
name: originatorName,
country: originatorCountry,
nationalId: originatorId,
blockchainAddress: originatorAddress,
dateOfBirth: originatorDate,
}),
},
beneficiary: widgetPayload?.originatorEqualsBeneficiary
? buildPerson("beneficiary", {
name: originatorName,
country: originatorCountry,
nationalId: originatorId,
blockchainAddress: address,
dateOfBirth: originatorDate,
})
: widgetPayload?.ivms.beneficiary,
};
const txCreatePayload = {
...widgetPayload,
...tx,
};
Developer options
It is possible to customize the logic of the Widget by setting the following parameters:
Custom style
Here you can pass configuration which will customize the styles of the Widget to meet your brand needs, all values are optional:
{
primaryColor: '#fff',
secondaryColor: '#fff',
primaryFontColor: '#fff',
secondaryFontColor: '#fff',
backgroundColor: '#fff',
fontFamily: Arial,
logo: {LOGO_URL},
mode: 'dark', // default: 'light'
// If you are using the Signature flow, here is the full list of custom theme that can be applied to the WalletConnect Modal.
'--w3m-font-family',
'--w3m-font-feature-settings',
'--w3m-overlay-background-color',
'--w3m-overlay-backdrop-filter',
'--w3m-z-index',
'--w3m-accent-color',
'--w3m-accent-fill-color',
'--w3m-background-color',
'--w3m-background-image-url',
'--w3m-logo-image-url',
'--w3m-background-border-radius',
'--w3m-container-border-radius',
'--w3m-wallet-icon-border-radius',
'--w3m-wallet-icon-large-border-radius',
'--w3m-wallet-icon-small-border-radius',
'--w3m-input-border-radius',
'--w3m-notification-border-radius',
'--w3m-button-border-radius',
'--w3m-secondary-button-border-radius',
'--w3m-icon-button-border-radius',
'--w3m-button-hover-highlight-border-radius',
}
To get a list of supported fonts, visit https://fonts.google.com/
To get more details about the WalletConnect theme variables, visit General style variables.
Custom dictionary
Pass a dictionary
object mapping in text in the Widget to your own language, for example; to replace Recipient's physical address
with a different text:
authToken: '..Bz6_qCOyQ7tomzGjzxMpTifylRYxPm1x1gwYQfecD6-CGGawmZ4u2bIvu2wxh55xehqanCrk_aP6pXB6ZXMTPgA',
dictionary: {
"Recipient's physical address": "Recipient's street, city, postal, country",
},
Here is a list of all the text you can change:
Withdrawal / deposit lables = {
WITHDRAWAL: {
address: "Recipient's physical address",
checkingInfo: "Checking recipient information...",
collectInfo:
"Due to regulations, we're required to collect additional information about the recipient.",
confirmPartyAddress:
"I confirm the beneficiary's address belongs to the beneficiary person.",
name: "Recipient's full name",
partyInfo: "Recipient Information",
selectDestination: "Where is recipient's wallet hosted?",
selectPartyVasp: "Select recipient's VASP",
selectParty: "Select recipient entity",
transferFromOwnAccount: "Transferring to an account you own?",
},
POST_DEPOSIT: {
address: "Sender's physical address",
checkingInfo: "Checking sender information...",
collectInfo:
"Due to regulations, we're required to collect additional information about the person who has sent you virtual assets before we can deposit them to your account.",
confirmPartyAddress:
"I confirm the sender's address belongs to the sender person.",
name: "Sender's full name",
partyInfo: "Sender Information",
selectDestination: "Where is sender's wallet hosted?",
selectPartyVasp: "Select sender's VASP",
selectParty: "Select sender entity",
transferFromOwnAccount: "Was this transferred from an account you own?",
}
},
commonLabels = {
additionalInfo: "Additional Information Required",
agreeTerms: "I agree to the terms below",
agreeShareInfo:
"By sending this transfer you agree to share your personal information (full name, physical address, national identification information) with the receiving exchange.",
cancel: "Cancel",
countryOfIssue: "Country of Issue",
confirmAddress: "I confirm this is my address",
connectWallet: "CONNECT WALLET",
continue: "Continue",
destination: "Destination",
enterRegistrationAuthority: "Enter authority name",
enterIdNumber: "Enter ID number",
enterPlaceOfBirth: "Enter place of birth",
error: "An error occurred",
errorSorry: "Sorry for the inconvenience.",
dateOfBirth: "Date of Birth",
dateOfBirthFormat: "mm/dd/yyyy",
enterName: "Enter name",
enterAddress: "Enter physical address",
legalPerson: "Legal Person",
loading: "Loading...",
messageSigned: "Message successfully signed",
nationalIdType: "National Identification Type",
nationalIdNumber: "National Identification Number",
naturalPerson: "Natural Person",
nonCustodialWallet: "Non-custodial wallet (Argent, Metamask, Rainbow, etc.)",
noOptions: "No options",
placeOfBirth: "Place of Birth",
readyToSend: "Ready to Send",
registrationAuthority: "Registration Authority",
ownAccount: "Yes, I own this account",
selectCountryOfIssue: "Select country of issue",
selectIdType: "Select ID type",
type: "Type",
verifyWallet:
"Please verify your non-custodial wallet by following the steps below.",
reconnect: "RE-CONNECT",
signMessage: "SIGN MESSAGE",
signYourWallet: "Please sign on your wallet",
selectWallet: "Select a wallet to connect and sign the message with.",
transferDetails: "Transfer Details",
tryAgain: "Try again",
walletVerification: "Wallet verification",
};
Field props
By default, the Widget will ask users to provide the missing information based on what is required in the originatorVASPs jurisdiction.
You can request the user to provide additional information using forceDisplay
, and it is also possible to make a specific field optional by using optional
:
field name | forceDisplay | optional | description |
---|---|---|---|
counterparty | -- | ☑️ | Counterparty VASP or Wallet (destination or originator) |
dateAndPlaceOfBirth | ☑️ | -- | Recipient (or Sender) Date and Place of Birth |
geographicAddress | ☑️ | ☑️ | Recipient (or Sender) Address |
name | ☑️ | -- | Recipient (or Sender) Name |
nationalIdentification | ☑️ | --️ | Recipient (or Sender) National Identification |
country | ☑️ | ☑️ | Recipient (or Sender) Country of Residence |
Example setup for fields:
fieldsProps: {
geographicAddress: {
forceDisplay: true,
optional: true
},
counterparty: {
optional: true
}
}
Transaction type allowed
transactionTypeAllowed can be used to limit the type of destinations a user can withdraw to:
ALL
- Transaction to other VASPs and unhosted wallets are allowed. (default)VASP_2_VASP_ONLY
- Only transaction destinations that are VASPs are allowed.SELF_TRANSACTION_ONLY
- Only transaction destinations that the originator owns are allowed.NON_CUSTODIAL_ONLY
- Only transactions to unhosted wallets are allowed.
Non-custodial declaration type
Our self-hosted wallet verification tool, SafeConnect, enables customers to verify self-hosted wallet ownership on more than 200 Ethereum-based wallets + the most popular Bitcoin wallets.
nonCustodialDeclarationType sets which ownership proof you want to use:
- SIGNATURE - The ownership proof will be cryptographically signed message by the originator using a wallet. (default)
Below is a video of an off-chain signature for a BTC address using a Ledger hardware wallet:
Below is a video of a off-chain signature for a BTC address using Electrum software wallet:
Below is a video of an off-chain signature for a ETH address using Metamask software wallet:
Re-using proofs
Signature proofs can be re-used for later transfers to the same destination as demonstrated in this video; note that the customerRef used to get a customerToken has to be consistent and unique for every customer on your platform.
- DECLARATION - The ownership proof will be declared by the originator using a checkbox.
Fallbacks
WALLET_NOT_SUPPORTED - If a wallet does not support signing a message to produce a cryptographic signature, these are the fall-back methods available:
DECLARATION
- Falls back to the self declaration flow
REJECT
- Rejects the transaction and throws an error
const notabene = new Notabene({
widget: '<https://beta-widget.notabene.id'>,
container: '#container',
authToken: '{CUSTOMER_TOKEN}'
theme: {THEME},
dictionary: {DICTIONARY},
fallbacks: [{flow: "WALLET_NOT_SUPPORTED", action: "DECLARATION"}]
});
Allow free-text input
counterpartyManualEntry
: TRUE | FALSE (default)
Use this option if you want to allow your customers to provide free-text type in a VASP name in the counterparty field.
Opt-in features
REUSE_ADDRESS_OWNERSHIP_PROOF: For a given unique customer (identified by the customerRef from the customer token used) + unique wallet address, the widget would not ask for data collection if the customer previously verified the address ownership in a previous first party self-hosted transfer.
const notabene = new Notabene({
widget: 'https://beta-widget.notabene.id',
container: '#container',
authToken: '{CUSTOMER_TOKEN}'
theme: {THEME},
dictionary: {DICTIONARY},
optInFeatures: ['REUSE_ADDRESS_OWNERSHIP_PROOF']
});
Type of Widget
It's possible to load two forms depending on the use case, the WITHDRAWAL and the POST_DEPOSIT form.
notabene.renderWidget();
ornotabene.renderWidget('WITHDRAWAL');
will render the form used to collect beneficiary data pre-transaction;notabene.renderWidget('POST_DEPOSIT');
will render a form that is used to collect missing data about the originator in a transaction created using txNotify;
Using the widget only for unhosted wallet verification
If you wish to use the Widget only for a self-hosted wallet flow, use one following customization options:
The setting below will only allow first-party transactions, and all non-custodial transactions will require a signature proof:
transactionTypeAllowed: 'NON_CUSTODIAL_ONLY',
nonCustodialDeclarationType: 'SIGNATURE',
The setting below will allow first, and third-party transactions only, first-party non-custodial transactions will require a signature proof, and third-party non-custodial transactions will require a self-declaration.
transactionTypeAllowed: 'NON_CUSTODIAL_ONLY',
nonCustodialDeclarationType: 'DECLARATION',
You also need to consider which fallback you allow for WALLET_NOT_SUPPORTED
.
Validating unhosted wallet proof
After a user has signed a message which certifies that they control the wallet address:
The widget payload will contain the message details inside "beneficiaryProof":
beneficiaryAccountNumber: "0xeC96782057A6ddEa4D0E1ed74A152E8c4f5fb6D3"
beneficiaryDid: "did:ethr:0xbcd807f27af34172641d481c873e9902f6917b65"
beneficiaryProof:
address: "0xeC96782057A6ddEa4D0E1ed74A152E8c4f5fb6D3"
attestation: "I certify that\n\nETH account 0xeC96782057A6ddEa4D0E1ed74A152E8c4f5fb6D3\n\nbelonged to did:ethr:0xbcd807f27af34172641d481c873e9902f6917b65\n\non Wed, 02 Nov 2022 02:58:11 GMT"
proof: "0xd5dd487ec1ee1620b5cb810841682dde049cc6dfad06394296f37788174f5c4c7df789c4b987a1a140f56e3438e15c70cc0f76c22b655d97b0b5e09ae53d6e2b1b"
type: "eip-191"
isNonCustodial: true
isValid: true
originatorDid: "did:ethr:0xbcd807f27af34172641d481c873e9902f6917b65"
originatorEqualsBeneficiary: true
originatorVASPdid: "did:ethr:0x940a4b2a0932733b842e4aa906761bb3d3bd8148"
transactionAmount: "15000000000"
transactionAsset: "ETH"
transactionBlockchainInfo:
{destination: '0xeC96782057A6ddEa4D0E1ed74A152E8c4f5fb6D3'}
This means that the signature ("proof") can be validated using the ethers or viem. Here is an example using ethers:
const { verifyMessage } = require("ethers");
const verify = async ({ message, address, signature }) => {
try {
const signerAddr = await verifyMessage(message, signature);
const result = signerAddr.toLowerCase() === address.toLowerCase();
return { result, signerAddr };
} catch (err) {
console.log(err);
return { error: err.message };
}
};
const signature =
"0xd5dd487ec1ee1620b5cb810841682dde049cc6dfad06394296f37788174f5c4c7df789c4b987a1a140f56e3438e15c70cc0f76c22b655d97b0b5e09ae53d6e2b1b";
const message =
"I certify that\n\nETH account 0xeC96782057A6ddEa4D0E1ed74A152E8c4f5fb6D3\n\nbelonged to did:ethr:0xbcd807f27af34172641d481c873e9902f6917b65\n\non Wed, 02 Nov 2022 02:58:11 GMT";
const address = "0xeC96782057A6ddEa4D0E1ed74A152E8c4f5fb6D3";
verify({ message, address, signature }).then(
({ result, signerAddr, error }) => {
if (result) {
console.log(
"Signature is valid. Signer Address:",
signerAddr,
"=",
address
);
} else {
console.log(
"Signature is not valid. Signer Address:",
signerAddr,
"!=",
address
);
}
if (error) {
console.log("Error: " + error);
}
}
);
//This returns:
//Signature is valid. Signer Address: 0xeC96782057A6ddEa4D0E1ed74A152E8c4f5fb6D3 = 0xeC96782057A6ddEa4D0E1ed74A152E8c4f5fb6D3
Blacklist
[
"wallet",
"ledger",
"trust wallet",
"uniswap",
"uni swap",
"rainbow",
"Trustwallet",
"trust wall",
"trezor",
"rainbow wallet",
"pp",
"phantom",
"pay",
"other",
"not sure",
"NonCustodian",
"Non-custodial wallet (Argent, Metamask, Rainbow, etc.)",
"Non-Custodial Wallet",
"non custodial wallet",
"no",
"no idea",
"Nano s ledger",
"nanotrade (Non Custodial)",
"Nano x",
"nano",
"na",
"my binance",
"my Binance eth",
"my Binance usdt",
"mohammad",
"mm",
"metamask",
"metamasks",
"MetaMask.io",
"metamask.com",
"meneme",
"exodus",
"blockchain",
"block chain wallet",
"1inch",
"1 inch",
"Atomic",
"DeFi Wallet",
"deposit",
"electrum",
"Electrum (Non custodial wallet)",
"exodus market",
"Fantom",
"me",
"pp",
"solana",
"sp",
"etherscan",
"cake wallet"
]
Widget payload examples
Unhosted 1st party w/cryptographic proof
{
"transactionAsset": "ETH",
"transactionAmount": "4000000000000000000",
"beneficiaryAccountNumber": "0x4920a60fc6464D584B1725f3c450a7b006b440C7",
"transactionBlockchainInfo": {
"origin": "0xF09c6Fd938E55DACa9BB42d91F9b4e9690aBc425",
"destination": "0x4920a60fc6464D584B1725f3c450a7b006b440C7"
},
"originatorVASPdid": "did:ethr:0x7c546f3df830a3e0a63de13d4ae32d64f26e74b2",
"ivms": {
"beneficiary": {
"beneficiaryPersons": [],
"accountNumber": [
"0x4920a60fc6464D584B1725f3c450a7b006b440C7"
]
}
},
"originatorDid": "did:ethr:0x010484208e7267a00ad5ebb23517abf5c14d97e3",
"beneficiaryProof": {
"proof": "0x881cacfa7bce1da6491f9e9a25c99a1cd759eb01097558c5eb1cff3d56a8a55a2c22e7656859e496a49053a7eeb783a51daa60786a4c9a0c2fa5bbdb3a670aae1b",
"attestation": "I certify that ETH account 0x4920a60fc6464D584B1725f3c450a7b006b440C7 belonged to did:ethr:0x010484208e7267a00ad5ebb23517abf5c14d97e3 on Tue, 17 Sep 2024 04:35:43 GMT",
"address": "0x4920a60fc6464D584B1725f3c450a7b006b440C7",
"type": "eip-191",
"wallet_provider": "injected"
},
"isNonCustodial": true,
"originatorEqualsBeneficiary": true,
"beneficiaryDid": "did:ethr:0x010484208e7267a00ad5ebb23517abf5c14d97e3",
"isValid": true,
"originator": {
"originatorPersons": [
{
"naturalPerson": {
"name": [
{
"nameIdentifier": [
{
"primaryIdentifier": "Smith",
"secondaryIdentifier": "John",
"nameIdentifierType": "LEGL"
}
]
}
],
"geographicAddress": [
{
"addressLine": [
"1st Street"
],
"country": "VA"
}
],
"countryOfResidence": "VA",
"nationalIdentification": {
"nationalIdentifier": "1345123421",
"countryOfIssue": "VA",
"nationalIdentifierType": "MISC"
},
"dateAndPlaceOfBirth": {
"dateOfBirth": "2023-12-06",
"placeOfBirth": "VA"
}
}
}
],
"accountNumber": [
"0xF09c6Fd938E55DACa9BB42d91F9b4e9690aBc425"
]
},
"beneficiary": {
"beneficiaryPersons": [
{
"naturalPerson": {
"name": [
{
"nameIdentifier": [
{
"primaryIdentifier": "Smith",
"secondaryIdentifier": "John",
"nameIdentifierType": "LEGL"
}
]
}
],
"geographicAddress": [
{
"addressLine": [
"1st Street"
],
"country": "VA"
}
],
"countryOfResidence": "VA",
"nationalIdentification": {
"nationalIdentifier": "1345123421",
"countryOfIssue": "VA",
"nationalIdentifierType": "MISC"
},
"dateAndPlaceOfBirth": {
"dateOfBirth": "2023-12-06",
"placeOfBirth": "VA"
}
}
}
],
"accountNumber": [
"0x4920a60fc6464D584B1725f3c450a7b006b440C7"
]
}
}
Unhosted 3rd party w/checkbox proof
{
"transactionAsset": "ETH",
"transactionAmount": "1000000000000000000",
"beneficiaryAccountNumber": "0x7a250d5630b4cf519739df2c5dacb4c659f2448d",
"transactionBlockchainInfo": {
"origin": "0xF09c6Fd938E55DACa9BB42d91F9b4e9690aBc425",
"destination": "0x7a250d5630b4cf519739df2c5dacb4c659f2448d"
},
"originatorVASPdid": "did:ethr:0x7c546f3df830a3e0a63de13d4ae32d64f26e74b2",
"ivms": {
"beneficiary": {
"beneficiaryPersons": [
{
"naturalPerson": {
"name": [
{
"nameIdentifier": [
{
"primaryIdentifier": "Smith",
"secondaryIdentifier": "Alice",
"nameIdentifierType": "LEGL"
}
]
}
],
"nationalIdentification": {
"nationalIdentifier": "SG23423432432",
"nationalIdentifierType": "ARNU",
"countryOfIssue": "SG"
}
}
}
],
"accountNumber": [
"0x7a250d5630b4cf519739df2c5dacb4c659f2448d"
]
}
},
"originatorDid": "did:ethr:0x010484208e7267a00ad5ebb23517abf5c14d97e3",
"isNonCustodial": true,
"originatorEqualsBeneficiary": false,
"beneficiaryName": "Alice Smith",
"beneficiaryPersonType": "NATURAL",
"beneficiaryNationalIdentification": {
"nationalIdentifierType": "ARNU",
"nationalIdentifier": "SG23423432432",
"countryOfIssue": "SG",
"registrationAuthority": null
},
"beneficiaryProof": {
"type": "checkbox",
"proof": "checked"
},
"isValid": true,
"originator": {
"originatorPersons": [
{
"naturalPerson": {
"name": [
{
"nameIdentifier": [
{
"primaryIdentifier": "Christo",
"nameIdentifierType": "LEGL"
}
]
}
],
"geographicAddress": [
{
"addressLine": [
"1st Street"
],
"country": "VA"
}
],
"countryOfResidence": "VA",
"nationalIdentification": {
"nationalIdentifier": "1345123421",
"countryOfIssue": "VA",
"nationalIdentifierType": "MISC"
},
"dateAndPlaceOfBirth": {
"dateOfBirth": "2023-12-06",
"placeOfBirth": "VA"
}
}
}
],
"accountNumber": [
"0xF09c6Fd938E55DACa9BB42d91F9b4e9690aBc425"
]
},
"beneficiary": {
"beneficiaryPersons": [
{
"naturalPerson": {
"name": [
{
"nameIdentifier": [
{
"primaryIdentifier": "Smith",
"secondaryIdentifier": "Alice",
"nameIdentifierType": "LEGL"
}
]
}
],
"nationalIdentification": {
"nationalIdentifier": "SG23423432432",
"nationalIdentifierType": "ARNU",
"countryOfIssue": "SG"
}
}
}
],
"accountNumber": [
"0x7a250d5630b4cf519739df2c5dacb4c659f2448d"
]
}
}
Hosted
{
"transactionAsset": "ETH",
"transactionAmount": "6000000000000000000",
"beneficiaryAccountNumber": "0x7a250d5630t4cf539739df2c5dacb4c659f2488d",
"transactionBlockchainInfo": {
"origin": "0xF09c6Fd938E55DACa9BB42d91F9b4e9690aBc425",
"destination": "0x7a250d5630t4cf539739df2c5dacb4c659f2488d"
},
"originatorVASPdid": "did:ethr:0x7c546f3df830a3e0a63de13d4ae32d64f26e74b2",
"isValid": true,
"ivms": {
"beneficiary": {
"beneficiaryPersons": [
{
"naturalPerson": {
"name": [
{
"nameIdentifier": [
{
"primaryIdentifier": "Smith",
"secondaryIdentifier": "Dave",
"nameIdentifierType": "LEGL"
}
]
}
],
"nationalIdentification": {
"nationalIdentifier": "321321321321",
"nationalIdentifierType": "CCPT",
"countryOfIssue": "PA"
}
}
}
],
"accountNumber": [
"0x7a250d5630t4cf539739df2c5dacb4c659f2488d"
]
}
},
"originatorDid": "did:ethr:0x010484208e7267a00ad5ebb23517abf5c14d97e3",
"isNonCustodial": false,
"originatorEqualsBeneficiary": false,
"beneficiaryVASPname": "Crypto.com",
"beneficiaryVASPdid": "did:ethr:0x893519504a7ee8d949454625cd5b4163b4ec232e",
"beneficiaryName": "Dave Smith",
"beneficiaryPersonType": "NATURAL",
"beneficiaryNationalIdentification": {
"nationalIdentifierType": "CCPT",
"nationalIdentifier": "321321321321",
"countryOfIssue": "PA",
"registrationAuthority": null
},
"originator": {
"originatorPersons": [
{
"naturalPerson": {
"name": [
{
"nameIdentifier": [
{
"primaryIdentifier": "Christo",
"nameIdentifierType": "LEGL"
}
]
}
],
"geographicAddress": [
{
"addressLine": [
"1st Street"
],
"country": "VA"
}
],
"countryOfResidence": "VA",
"nationalIdentification": {
"nationalIdentifier": "1345123421",
"countryOfIssue": "VA",
"nationalIdentifierType": "MISC"
},
"dateAndPlaceOfBirth": {
"dateOfBirth": "2023-12-06",
"placeOfBirth": "VA"
}
}
}
],
"accountNumber": [
"0xF09c6Fd938E55DACa9BB42d91F9b4e9690aBc425"
]
},
"beneficiary": {
"beneficiaryPersons": [
{
"naturalPerson": {
"name": [
{
"nameIdentifier": [
{
"primaryIdentifier": "Smith",
"secondaryIdentifier": "Dave",
"nameIdentifierType": "LEGL"
}
]
}
],
"nationalIdentification": {
"nationalIdentifier": "321321321321",
"nationalIdentifierType": "CCPT",
"countryOfIssue": "PA"
}
}
}
],
"accountNumber": [
"0x7a250d5630t4cf539739df2c5dacb4c659f2488d"
]
}
}
Updated about 1 month ago