Welcome to blockchain-core’s documentation!¶
Getting Started¶
The blockchain core is a helper library, that offers helpers for interacting with the evan.network blockchain. It is written in TypeScript and offers several (up to a certain degree) stand-alone modules, that can be used for
- creating and updating contracts
- managing user profiles
- en- and decryption
- distributed filesystem file handling
- key exchange and key handling
- ENS domain handling
- sending and receiving bmails
Adding blockchain core¶
First you need to get blockchain core and its dependencies into your project. This can be done using the following methods:
- npm:
npm install @evan.network/api-blockchain-core web3@1.0.0-beta.55
After that you need to create a blockchain core runtime with a predefined configuration.
Node.js version >= 10 is supported. The framework has been tested with Node.js 10, 11 and 12.
Configuring and initializing blockchain core¶
// require blockchain-core dependencies
const Web3 = require('web3');
// require blockchain-core
const { Ipfs, createDefaultRuntime } = require('@evan.network/api-blockchain-core');
const runtimeConfig = {
// account map to blockchain accounts with their private key
accountMap: {
'ACCOUNTID':
'PRIVATE KEY',
},
// key configuration for private data handling
keyConfig: {
'ACCOUNTID': 'PASSWORD',
},
// ipfs configuration for evan.network storage
ipfs: {host: 'ipfs.test.evan.network', port: '443', protocol: 'https'},
// web3 provider config (currently evan.network testcore)
web3Provider: 'wss://testcore.evan.network/ws',
};
async function init() {
// initialize dependencies
const provider = new Web3.providers.WebsocketProvider(
runtimeConfig.web3Provider,
{ clientConfig: { keepalive: true, keepaliveInterval: 5000 } });
const web3 = new Web3(provider, null, { transactionConfirmationBlocks: 1 });
const dfs = new Ipfs({ dfsConfig: runtimeConfig.ipfs });
// create runtime
const runtime = await createDefaultRuntime(web3, dfs, { accountMap: runtimeConfig.accountMap, keyConfig: runtimeConfig.keyConfig });
console.dir(runtime);
}
init();
or you can initialize the api-blockchain-core runtime with your mnemonic and your password previously created on evan.network
// require blockchain-core dependencies
const Web3 = require('web3');
// require blockchain-core
const { Ipfs, createDefaultRuntime } = require('@evan.network/api-blockchain-core');
// ipfs configuration for evan.network testnet storage
const ipfsConfig = {host: 'ipfs.test.evan.network', port: '443', protocol: 'https'};
// web3 provider config (currently evan.network testcore)
const web3Provider = 'wss://testcore.evan.network/ws'
async function init() {
// initialize dependencies
const provider = new Web3.providers.WebsocketProvider(
web3Provider,
{ clientConfig: { keepalive: true, keepaliveInterval: 5000 } });
const web3 = new Web3(provider, null, { transactionConfirmationBlocks: 1 });
const dfs = new Ipfs({ dfsConfig: ipfsConfig });
// create runtime
const runtime = await createDefaultRuntime(
web3,
dfs,
{
mnemonic: 'YOUR_MNEMNONIC',
password: 'YOUR_PASSWORD'
}
);
console.dir(runtime);
}
init();
That’s it! Now you can use the runtime
object and interact with the evan.network blockchain.
The blockchain-core api is a set of modules which can be plugged in individually. So the above runtime
is a full blown entry point to the api. You can also plug your own runtime with needed modules together.
Create a new profile on evan.network via API¶
When you want to create profiles programatically via our API, you can use the “Onboarding” class on the api-blockchain-core with the function createNewProfile
. You can also generate your custom mnemonic from the Onboarding class as well. The only thing that should be defined is a password for the profile
// require blockchain-core
const { Onboarding } = require('@evan.network/api-blockchain-core');
async function createProfile() {
// generate a new random mnemnoic
const mnemonic = Onboarding.createMnemonic();
// create a profile for a mnemonic and a given password
const profile = await Onboarding.createNewProfile(mnemonic, 'CUSTOM_PASSWORD');
console.dir(profile);
}
createProfile();
Blockchain¶
Executor¶
Class Name | Executor |
---|---|
Extends | Logger |
Source | executor.ts |
Examples | executor.spec.ts |
The executor is used for
- making contract calls
- executing contract transactions
- creating contracts
- send EVEs to another account or contract
The signer requires you to have a contract instance, either by
- loading the contract via Description helper (if the contract has an abi at its description)
- loading the contract via ContractLoader helper (if the contract has not abi at its description)
- directly via web3.js.
constructor¶
new Executor(options);
Creates a new Executor instance.
The Executor allows to pass the defaultOptions
property to its constructor. This property contains options for transactions and calls, that will be used if no other properties are provided in calls/transactions. Explicitly passed options always overwrite default options.
Parameters¶
options
-ExecutorOptions
: options for ServiceContract constructor.config
-any
: configuration object for the executor instancedefaultOptions
-any
(optional): default options for web3 transactions/callseventHub
-EventHub
:EventHub
instancesigner
-SignerInterface
:SignerInterface
instanceweb3
-Web3
:Web3
instancelog
-Function
(optional): function to use for logging:(message, level) => {...}
logLevel
-LogLevel
(optional): messages with this level will be logged withlog
logLog
-LogLogInterface
(optional): container for collecting log messageslogLogLevel
-LogLevel
(optional): messages with this level will be pushed tologLog
Returns¶
Executor
instance
init¶
executor.init(name);
initialize executor
Parameters¶
options
-any
: object with the property “eventHub” (of the type EventHub)eventHub
-EventHub
: The initialized EventHub Module.
Returns¶
void
.
executeContractCall¶
executor.executeContractCall(contract, functionName, ...args);
run the given call from contract
Parameters¶
contract
-any
: the target contractfunctionName
-string
: name of the contract function to call...args
-any[]
: optional array of arguments for contract call. if last arguments is {Object}, it is used as the options parameter
Returns¶
Promise
resolves to any
: contract calls result.
Example¶
const greetingMessage = await runtime.executor.executeContractCall(
contract, // web3.js contract instance
'greet' // function name
);
executeContractTransaction¶
executor.executeContractTransaction(contract, functionName, inputOptions, ...functionArguments);
execute a transaction against the blockchain, handle gas exceeded and return values from contract function
Parameters¶
contract
-any
: contract instancefunctionName
-string
: name of the contract function to callinputOptions
-any
: options objectfrom
-string
(optional): The address the call “transaction” should be made from.gas
-number
(optional): The amount of gas provided with the transaction.event
-any
(optional): object with two propertiestarget
(contract name) andeventName
getEventResult
-function
(optional): callback function which will be called when the event is triggered. First argument is the full event info, second argument is an options with the event arguments.eventTimeout
-number
(optional): timeout (in ms) to wait for a event result before the transaction is marked as errorestimate
-boolean
(optional): Should the amount of gas be estimated for the transaction (overwritesgas
parameter)force
-string
(optional): Forces the transaction to be executed. Ignores estimation errorsautoGas
-number
(optional): enables autoGas 1.1 ==> adds 10% to estimated gas costs. value capped to current block.value
-number
(optional): Allows to specify the amount of funds for transfer
...functionArguments
-any[]
: optional arguments to pass to contract transaction
Returns¶
Promise
resolves to: no result
(if no event to watch was given), the event
(if event but no getEventResult was given), the
value returned by getEventResult(eventObject, arguments).
Because an estimation is performed, even if a fixed gas cost has been set, failing transactions are rejected before being executed. This protects users from executing transactions, that consume all provided gas and fail, which is usually not intended, especially if a large amount of gas has been provided. To prevent this behavior for any reason, add a force: true
to the options, though it is not advised to do so.
To allow to retrieve the result of a transaction, events can be used to receive values from a transaction. If an event is provided, the transaction will only be fulfilled, if the event is triggered. To use this option, the executor needs to have the eventHub
property has to be set. Transactions, that contain event related options and are passed to an executor without an eventHub
will be rejected immediately.
Example¶
const accountId = '0x...';
const greetingMessage = await runtime.executor.executeContractTransaction(
contract, // web3.js contract instance
'setData', // function name
{ from: accountId, }, // perform transaction with this account
123, // arguments after the options are passed to the contract
);
Provided gas is estimated automatically with a fault tolerance of 10% and then used as gas limit in the transaction. For a different behavior, set autoGas in the transaction options:
const greetingMessage = await runtime.executor.executeContractTransaction(
contract, // web3.js contract instance
'setData', // function name
{ from: accountId, autoGas: 1.05, }, // 5% fault tolerance
123, // arguments after the options are passed to the contract
);
or set a fixed gas limit:
const greetingMessage = await runtime.executor.executeContractTransaction(
contract, // web3.js contract instance
'setData', // function name
{ from: accountId, gas: 100000, }, // fixed gas limit
123, // arguments after the options are passed to the contract
);
Using events for getting return values:
const contractId = await runtime.executor.executeContractTransaction(
factory,
'createContract', {
from: accountId,
autoGas: 1.1,
event: { target: 'FactoryInterface', eventName: 'ContractCreated', },
getEventResult: (event, args) => args.newAddress,
},
);
executeSend¶
executor.executeSend(options);
send EVEs to target account
Parameters¶
options
-any
: the target contractfrom
-string
: The address the call “transaction” should be made from.to
-string
: The address where the eve’s should be send to.value
-number
: Amount to send in Wei
Returns¶
Promise
resolves to void
: resolved when done.
Example¶
await runtime.executor.executeSend({
from: '0x...', // send from this account
to: '0x...', // receiving account
value: web3.utils.toWei('1'), // amount to send in Wei
});
createContract¶
executor.createContract(contractName, functionArguments, options);
creates a contract by contstructing creation transaction and signing it with private key of options.from
Parameters¶
contractName
-string
: contract name (must be available withing contract loader module)functionArguments
-any[]
: arguments for contract creation, pass empty Array if no argumentsoptions
-any
: options objectfrom
-string
: The address the call “transaction” should be made from.gas
-number
: Provided gas amout for contract creation.
Returns¶
Promise
resolves to any
: new contract.
Example¶
const newContractAddress = await runtime.executor.createContract(
'Greeter', // contract name
['I am a demo greeter! :3'], // constructor arguments
{ from: '0x...', gas: 100000, }, // gas has to be provided with a fixed value
);
ExecutorAgent¶
Class Name | ExecutorAgent |
---|---|
Extends | Executor |
Source | executor-agent.ts |
Examples | executor-agent.spec.ts |
The ExecutorAgent
module is designed to cover basically the same tasks as the Executor module. While the last one performs the transactions directly with an account, that is given as inputOptions, the ExecutorAgent
module wraps those transactions by submitting them to a smart agent.
The smart agent receives those transactions and performs them with its own account, if a valid tokens has been passed to it alongside the transaction data. Tokens for transactions can be issued at the smart agent as well (a password is required for this).
Using the ExecutorAgent
allows to delegate transactions to users that do not have their own blockchain accounts. Delegating those transactions requires that smart agent user to be invited into the contract instead of the users, that will interact with the contract.
Users without accounts are then interacting with the front-end the same way as regular users, but do not submit their transactions themselves, they make a REST request against a smart agent server. To prevent spamming and scamming, the users use tokens for their transactions. Tokens are basically like prepaid telephone card and allows to perform a limited set of functions for a limited amount of times. Tokens can only be created with a valid password.
Let’s say, we have created a DataContract, that contains three questions, that should be answered by someone without an own blockchain account (think of a customer survey or something similar).
To allow that, first invite the corresponding smart agent account into the contract. Smart agent accounts for this should be known to the party, that wants to delegate transactions and their funds are maintained by this party, we’ll use an example address for this here.
For abbreviation we assume, we have the following values:
let dataContractInstance; // our data contract with the survey questions
let contractOwner; // 'we' - the contract creator and owner
let businessCenterDomain = 'testbc.evan'; // contracts business center
let smartAgentId; // account id of our smart agent
let password; // password, for token generation
So let’s invite the smart agent to our contract:
await dataContract.inviteToContract(
businessCenterDomain,
dataContractInstance.options.address,
contractOwner,
smartAgentId,
);
Now with the smart agent being able to perform transactions, create a token for transaction delegation. We want the user to be able to:
- accept the invitation
- write three answers
- mark their state as “done”
const txToken = await executor.generateToken(
password, [
{ contract: dataContractInstance, functionName: 'changeConsumerState', count: 2, },
{ contract: dataContractInstance, functionName: 'addListEntry', count: 3, },
]);
Allowing addListEntry
three time is to allow them to write three answers. One of the changeConsumerState
times is for accepting the contract, which is done by setting the own state to Active
. The other one is for marking editing as done (setting the own state to Terminated
).
The resulting token txToken
is a string, that can be handed over to our users without an account. This is usually done by sending them an email with a link, that contains the token and skips the login step for them and routes them directly to the contract, they should respond to.
Let’s switch sides. The next steps are performed in the front-end by a user without a blockchain account, that has received the token.
To make transaction via a smart agent, create an instance of the ExecutorWallet
and assign the token from before as token
.
const executor = new ExecutorAgent({
agentUrl
config,
eventHub,
signer,
web3
});
executor.token = txToken;
To use the ExecutorWallet
instance created this way in your other modules, hand it over to their contstructor like instead of a normal Executor
instance. Then use your modules, that have the ExeutorWallet
instance like you would use them for making transactions with your own account.
const surveyAnswer = {
foo: 'sample',
bar: 123,
};
await dataContract.addListEntries(dataContractInstance, ['surveyAnswers'], [sampleValue], smartAgentId);
Note, that the last sample uses the smartAgentId as the performing account. Because transactions are estimated before being executed and in some cases the underlying modules require an “active” account, that is used as the users identity, this has to match the smart agents account id. The smart agent account id is passed alongside the token via the link in the email for users wihtout blockchain accounts. References, that would point to a users account have to be replaced with this smart agent account id.

transaction flow in agent based transactions
constructor¶
new ExecutorAgent(options);
Creates a new ExecutorAgent instance.
The ExecutorAgent allows to pass the defaultOptions
property to its constructor. This property contains options for transactions and calls, that will be used if no other properties are provided in calls/transactions. Explicitly passed options always overwrite default options.
Parameters¶
options
-ExecutorAgentOptions
: options for ServiceContract constructor.config
-any
: configuration object for the executor instancedefaultOptions
-any
(optional): default options for web3 transactions/callseventHub
-EventHub
:EventHub
instancesigner
-SignerInterface
:SignerInterface
instanceweb3
-Web3
:Web3
instanceagentUrl
-string
(optional): agent url, including protocol, host and port, defaults to'http://localhost:8080'
log
-Function
(optional): function to use for logging:(message, level) => {...}
logLevel
-LogLevel
(optional): messages with this level will be logged withlog
logLog
-LogLogInterface
(optional): container for collecting log messageslogLogLevel
-LogLevel
(optional): messages with this level will be pushed tologLog
Returns¶
ExecutorAgent
instance
init¶
executor.init(name);
initialize executor
Parameters¶
options
-any
: object with the property “eventHub” (of the type EventHub)eventHub
-EventHub
: The initialized EventHub Module.
Returns¶
void
.
executeContractCall¶
executor.executeContractCall(contract, functionName, ...args);
run the given call from contract
this is done as a rest call against the smart agent
a token is not required for performing calls
Parameters¶
contract
-any
: the target contractfunctionName
-string
: name of the contract function to call...args
-any[]
: optional array of arguments for contract call. if last arguments is {Object}, it is used as the options parameter
Returns¶
Promise
resolves to any
: contract calls result.
Example¶
const greetingMessage = await runtime.executor.executeContractCall(
contract, // web3.js contract instance
'greet' // function name
);
executeContractTransaction¶
executor.executeContractTransaction(contract, functionName, inputOptions, ...functionArguments);
execute a transaction against the blockchain, handle gas exceeded and return values from contract function
this is done as a rest call against the smart agent
transactions, that transfer EVEs to a target account, will be rejected
this requires a valid token issued with generateToken
beforehand, tokens can be set at the executor with:
executor.token = someToken;
Parameters¶
contract
-any
: contract instancefunctionName
-string
: name of the contract function to callinputOptions
-any
: options objectfrom
-string
(optional): The address the call “transaction” should be made from.gas
-number
(optional): The amount of gas provided with the transaction.event
-string
(optional): The event to wait for a result of the transaction,getEventResult
-function
(optional): callback function which will be called when the event is triggered.eventTimeout
-number
(optional): timeout (in ms) to wait for a event result before the transaction is marked as errorestimate
-boolean
(optional): Should the amount of gas be estimated for the transaction (overwritesgas
parameter)force
-string
(optional): Forces the transaction to be executed. Ignores estimation errorsautoGas
-number
(optional): enables autoGas 1.1 ==> adds 10% to estimated gas costs. value capped to current block.
...functionArguments
-any[]
: optional arguments to pass to contract transaction
Returns¶
Promise
resolves to: no result
(if no event to watch was given), the event
(if event but no getEventResult was given), the
value returned by getEventResult(eventObject).
Because an estimation is performed, even if a fixed gas cost has been set, failing transactions are rejected before being executed. This protects users from executing transactions, that consume all provided gas and fail, which is usually not intended, especially if a large amount of gas has been provided. To prevent this behavior for any reason, add a force: true
to the options, though it is not advised to do so.
To allow to retrieve the result of a transaction, events can be used to receive values from a transaction. If an event is provided, the transaction will only be fulfilled, if the event is triggered. To use this option, the executor needs to have the eventHub
property has to be set. Transactions, that contain event related options and are passed to an executor without an eventHub
will be rejected immediately.
Example¶
const accountId = '0x...';
const greetingMessage = await runtime.executor.executeContractTransaction(
contract, // web3.js contract instance
'setData', // function name
{ from: accountId, }, // perform transaction with this account
123, // arguments after the options are passed to the contract
);
Provided gas is estimated automatically with a fault tolerance of 10% and then used as gas limit in the transaction. For a different behavior, set autoGas in the transaction options:
const greetingMessage = await runtime.executor.executeContractTransaction(
contract, // web3.js contract instance
'setData', // function name
{ from: accountId, autoGas: 1.05, }, // 5% fault tolerance
123, // arguments after the options are passed to the contract
);
or set a fixed gas limit:
const greetingMessage = await runtime.executor.executeContractTransaction(
contract, // web3.js contract instance
'setData', // function name
{ from: accountId, gas: 100000, }, // fixed gas limit
123, // arguments after the options are passed to the contract
);
Using events for getting return values:
const contractId = await runtime.executor.executeContractTransaction(
factory,
'createContract', {
from: accountId,
autoGas: 1.1,
event: { target: 'FactoryInterface', eventName: 'ContractCreated', },
getEventResult: (event, args) => args.newAddress,
},
);
executeSend¶
executor.executeSend(options);
creating contracts directly is not supported by the walled based executor, use a regular Executor for such tasks
createContract¶
executor.createContract(contractName, functionArguments, options);
creates a contract by contstructing creation transaction and signing it with private key of options.from
this is done as a rest call against the smart agent
transactions, that transfer EVEs to a target account, will be rejected
this requires a valid token issued with generateToken
beforehand, tokens can be set at the executor with:
executor.token = someToken;
Parameters¶
contractName
-string
: contract name (must be available withing contract loader module)functionArguments
-any[]
: arguments for contract creation, pass empty Array if no argumentsoptions
-any
: options objectfrom
-string
: The address the call “transaction” should be made from.gas
-number
: Provided gas amout for contract creation.
Returns¶
Promise
resolves to any
: new contract.
Example¶
const newContractAddress = await runtime.executor.createContract(
'Greeter', // contract name
['I am a demo greeter! :3'], // constructor arguments
{ from: '0x...', gas: 100000, }, // gas has to be provided with a fixed value
);
generateToken¶
executor.generateToken(password, functions);
generate a new token for transactions (or contract creations)
this generates a new token for the given functions, this token can be used for each requested function (either only once or multiple times, if a count > 1 has been requested)
Parameters¶
password
-string
: password for token creationfunctions
-any[]
: array of function signatures as abi objects
Returns¶
Promise
returns string
: token for given transactions
Example¶
Tokens can be created for transactions by passing the contract and the function name to it:
const txToken = await executor.generateToken(
password, [{ contract: contract, functionName: 'addListEntry', }]);
When the token should be able to perform those transactions multiple times, pass a count alongside:
const txToken = await executor.generateToken(
password, [{ contract: contract, functionName: 'addListEntry', count: 3, }]);
When wanting to perform a contract creation without a factory contract, this contract has to be known to the smart agent. Then the contract name can be passed as ‘signature’:
cosnt ccToken = await executor.generateToken(
password, [{ signature: 'Owned', }]);
ExecutorWallet¶
Class Name | ExecutorWallet |
---|---|
Extends | Executor |
Source | executor-wallet.ts |
Examples | executor-wallet.spec.ts |
The ExecutorWallet
module is designed to cover basically the same tasks as the Executor
module. While the last one performs the transactions directly with an account, that is given as inputOptions, the ExecutorWallet
module wraps those transactions by submitting them to a configured wallet contract.

transaction flow in wallet based transactions
The wallet is a smart contract and the account, that performs the transactions against the target contracts on the blockchain. Transactions are wrapped by using the Wallet
module, see details on how to transactions are performed internally at the documentation page of the Wallet
module.
Because transactions are performed via the Wallet
module, they have the same limitations in regards to en- and decryption as described in the introduction section of the Wallet
.
constructor¶
new ExecutorWallet(options);
Creates a new ExecutorWallet
instance.
The ExecutorWallet allows to pass the defaultOptions
property to its constructor. This property contains options for transactions and calls, that will be used if no other properties are provided in calls/transactions. Explicitly passed options always overwrite default options.
Parameters¶
options
-ExecutorWalletOptions
: options for ServiceContract constructor.accountId
-string
: account, that is used for making transactions against wallet contractconfig
-any
: configuration object for the executor instanceeventHub
-EventHub
:EventHub
instancesigner
-SignerInterface
:SignerInterface
instancewallet
-Wallet
:Wallet
instance with a loaded wallet contractweb3
-Web3
:Web3
instancedefaultOptions
-any
(optional): default options for web3 transactions/callslog
-Function
(optional): function to use for logging:(message, level) => {...}
logLevel
-LogLevel
(optional): messages with this level will be logged withlog
logLog
-LogLogInterface
(optional): container for collecting log messageslogLogLevel
-LogLevel
(optional): messages with this level will be pushed tologLog
Returns¶
ExecutorWallet
instance
Example¶
const executor = new ExecutorWallet({
accountId,
config,
eventHub,
signer,
wallet,
web3
});
init¶
executor.init(name);
initialize executor
Parameters¶
options
-any
: object with the property “eventHub” (of the type EventHub)eventHub
-EventHub
: The initialized EventHub Module.
Returns¶
void
.
executeContractCall¶
executor.executeContractCall(contract, functionName, ...args);
run the given call from contract
note, that if a from is used, this from is replaced with the wallets address
Parameters¶
contract
-any
: the target contractfunctionName
-string
: name of the contract function to call...args
-any[]
: optional array of arguments for contract call. if last arguments is {Object}, it is used as the options parameter
Returns¶
Promise
resolves to any
: contract calls result.
Example¶
const greetingMessage = await runtime.executor.executeContractCall(
contract, // web3.js contract instance
'greet' // function name
);
executeContractTransaction¶
executor.executeContractTransaction(contract, functionName, inputOptions, ...functionArguments);
execute a transaction against the blockchain, handle gas exceeded and return values from contract function,
note, that a from passed to this function will be replaced with the wallets address and that transactions, that transfer EVEs to a target account, will be rejected
Parameters¶
contract
-any
: contract instancefunctionName
-string
: name of the contract function to callinputOptions
-any
: options objectfrom
-string
(optional): The address the call “transaction” should be made from.gas
-number
(optional): The amount of gas provided with the transaction.event
-string
(optional): The event to wait for a result of the transaction,getEventResult
-function
(optional): callback function which will be called when the event is triggered.eventTimeout
-number
(optional): timeout (in ms) to wait for a event result before the transaction is marked as errorestimate
-boolean
(optional): Should the amount of gas be estimated for the transaction (overwritesgas
parameter)force
-string
(optional): Forces the transaction to be executed. Ignores estimation errorsautoGas
-number
(optional): enables autoGas 1.1 ==> adds 10% to estimated gas costs. value capped to current block.
...functionArguments
-any[]
: optional arguments to pass to contract transaction
Returns¶
Promise
resolves to: no result
(if no event to watch was given), the event
(if event but no getEventResult was given), the
value returned by getEventResult(eventObject).
Because an estimation is performed, even if a fixed gas cost has been set, failing transactions are rejected before being executed. This protects users from executing transactions, that consume all provided gas and fail, which is usually not intended, especially if a large amount of gas has been provided. To prevent this behavior for any reason, add a force: true
to the options, though it is not advised to do so.
To allow to retrieve the result of a transaction, events can be used to receive values from a transaction. If an event is provided, the transaction will only be fulfilled, if the event is triggered. To use this option, the executor needs to have the eventHub
property has to be set. Transactions, that contain event related options and are passed to an executor without an eventHub
will be rejected immediately.
Example¶
const accountId = '0x...';
const greetingMessage = await runtime.executor.executeContractTransaction(
contract, // web3.js contract instance
'setData', // function name
{ from: accountId, }, // perform transaction with this account
123, // arguments after the options are passed to the contract
);
Provided gas is estimated automatically with a fault tolerance of 10% and then used as gas limit in the transaction. For a different behavior, set autoGas in the transaction options:
const greetingMessage = await runtime.executor.executeContractTransaction(
contract, // web3.js contract instance
'setData', // function name
{ from: accountId, autoGas: 1.05, }, // 5% fault tolerance
123, // arguments after the options are passed to the contract
);
or set a fixed gas limit:
const greetingMessage = await runtime.executor.executeContractTransaction(
contract, // web3.js contract instance
'setData', // function name
{ from: accountId, gas: 100000, }, // fixed gas limit
123, // arguments after the options are passed to the contract
);
Using events for getting return values:
const contractId = await runtime.executor.executeContractTransaction(
factory,
'createContract', {
from: accountId,
autoGas: 1.1,
event: { target: 'FactoryInterface', eventName: 'ContractCreated', },
getEventResult: (event, args) => args.newAddress,
},
);
executeSend¶
executor.executeSend(options);
sending funds is not supported by the walled based executor, use a regular Executor for such tasks
createContract¶
executor.createContract(contractName, functionArguments, options);
creating contracts directly is not supported by the walled based executor, use a regular Executor for such tasks
Signer Identity¶
Class Name | SignerIdentity |
---|---|
Implements | SignerInterface |
Extends | Logger |
Source | signer-idenitity.ts |
The signers are used to create contract transactions and are used internally by the Executor. The default runtime uses the SignerInternal helper to sign transaction.
In most cases, you won’t have to use the Signer objects directly yourself, as the Executor is your entry point for performing contract transactions. SignerIdentity may be an exception to this rule, as it can be used to check currently used identity and account.
Note, that this signer supports using accounts and identities. If the .from property in the options is given as configured activeIdentity, transaction will be made via this identity, which requires the underlyingAccount to be in control of this identity. If .from is given as underlyingAcccount, transactions will be made directly from this account. Also keep in mind, that in both cases underlyingAccount needs to have enough funds to pay for the transactions, as this account is used to pay for them.
Public Properties¶
activeIdentity
-string
: identity used for transactions, usually controlled by underlyingAccountunderlyingAccount
-string
: account, that pays for transactions used for transactions, usually controlling activeIdentity
constructor¶
new SignerIdentity(options, config);
Creates a new SignerInternal instance. config can be set up later on with updateConfig, if required (e.g. when initializing a circular structure).
Parameters¶
options
-SignerIdentityOptions
: options for SignerIdentity constructor (runtime like object)contractLoader
-ContractLoader
:ContractLoader
instanceverifications
-Verifications
:Verifications
instanceweb3
-Web3
:Web3
instancelog
-Function
(optional): function to use for logging:(message, level) => {...}
logLevel
-LogLevel
(optional): messages with this level will be logged withlog
logLog
-LogLogInterface
(optional): container for collecting log messageslogLogLevel
-LogLevel
(optional): messages with this level will be pushed tologLog
config
-SignerIdentityConfig
(optional): custom config for SignerIdentity instanceactiveIdentity
-string
: identity used for transactions, usually controlled by underlyingAccountunderlyingAccount
-string
: account, that pays for transactions used for transactions, usually controlled by underlyingAccountunderlyingSigner
-SignerInterface
: an instance of aSignerInterface
implementation; usually aSignerInternal
instance
Returns¶
SignerIdentity
instance
Example¶
const signer = new SignerIdentity(
{
contractLoader,
verifications,
web3,
},
{
activeIdentity: await verifications.getIdentityForAccount(accounts[0], true),
underlyingAccount: accounts[0],
underlyingSigner,
},
);
signAndExecuteSend¶
signer.signAndExecuteSend(options, handleTxResult);
Performs a value transfer transaction. This will send specified funds to identity, which will send it to target. Funds are returned if transaction fails.
Parameters¶
options
-any
:from
-string
: The address the call “transaction” should be made from.to
-string
: The address where the eve’s should be send to.value
-number
: Amount to send in Wei
handleTxResult
-function(error, receipt)
: callback when transaction receipt is available or error
Example¶
const patchedInput = runtime.signer.signAndExecuteSend({
from: '0x...', // send from this identity/account
to: '0x...', // receiving account
value: web3.utils.toWei('1'), // amount to send in Wei
}, (err, receipt) => {
console.dir(arguments);
});
signAndExecuteTransaction¶
signer.signAndExecuteTransaction(contract, functionName, functionArguments, options, handleTxResult);
Create, sign and submit a contract transaction.
Parameters¶
contract
-any
: contract instance from api.eth.loadContract(…)functionName
-string
: function namefunctionArguments
-any[]
: arguments for contract creation, pass empty Array if no argumentsoptions
-any
:from
-string
: The address (identity/account) the call “transaction” should be made from.gas
-number
: Amount of gas to attach to the transactionto
-string
(optional): The address where the eve’s should be send to.value
-number
(optional): Amount to send in Wei
handleTxResult
-function(error, receipt)
: callback when transaction receipt is available or error
createContract¶
signer.createContract(contractName, functionArguments, options);
Creates a smart contract.
Parameters¶
contractName
-any
: contractName from contractLoaderfunctionArguments
-any[]
: arguments for contract creation, pass empty Array if no argumentsoptions
-any
:from
-string
: The address the call “transaction” should be made from.gas
-number
: Amount of gas to attach to the transaction
signMessage¶
signer.signMessage(accountId, message);
Sign given message with accounts private key, does not work for identity.
Parameters¶
accountId
-string
: accountId to sign with, cannot be done with activeIdentitymessage
-string
: message to sign
Returns¶
Promise
resolves to string
: signature
updateConfig¶
signer.updateConfig(partialOptions, config);
Update config of SignerIdentity can also be used to setup verifications and accounts after initial setup and linking with other modules.
Parameters¶
partialOptions
-{ verifications: Verifications }
: object with verifications property, e.g. a runtimeconfig
-SignerIdentityConfig
: custom config for SignerIdentity instanceactiveIdentity
-string
: identity used for transactions, usually controlled by underlyingAccountunderlyingAccount
-string
: account, that pays for transactions used for transactions, usually controlled by underlyingAccountunderlyingSigner
-SignerInterface
: an instance of aSignerInterface
implementation; usually aSignerInternal
instance
Returns¶
Promise
returns void
: resolved when done
Example¶
// create new instance
const signer = new SignerIdentity(
{
contractLoader,
verifications,
web3,
},
);
// use instance, e.g. reference it in other components like `verifications`
// ...
// now set verfications instance and account in signer
signer.updateConfig(
{ verifications },
{
activeIdentity,
underlyingAccount,
underlyingSigner: signerInternal,
},
);
Account Store¶
Class Name | AccountStore |
---|---|
Implements | KeyStoreInterface |
Extends | Logger |
Source | account-store.ts |
The AccountStore implements the KeyStoreInterface and is a wrapper for a storage, where evan.network account ids are stored. The default AccountStore takes an account –> private key mapping as a pojo as its arguments and uses this to perform lookups, when the getPrivateKey function is called. This lookup needs to be done, when transactions are signed by the InternalSigner (see Signer).
Note that the return value of the getPrivateKey function is a promise. This may not be required in the default AccountStore, but this allows you to implement own implementations of the KeyStoreInterface, which may enforce a more strict security behavior or are able to access other sources for private keys.
constructor¶
new AccountStore(options);
Creates a new AccountStore instance.
Parameters¶
options
-AccountStoreOptions
: options for AccountStore constructor.accounts
-any
: object with accountid/privatekey mappinglog
-Function
(optional): function to use for logging:(message, level) => {...}
logLevel
-LogLevel
(optional): messages with this level will be logged withlog
logLog
-LogLogInterface
(optional): container for collecting log messageslogLogLevel
-LogLevel
(optional): messages with this level will be pushed tologLog
Returns¶
AccountStore
instance
getPrivateKey¶
accountStore.getPrivateKey(accountId);
get private key for given account
Parameters¶
accountId
-string
: eth accountId
Returns¶
Promise resolves to string
: private key for this account
Example¶
const privateKey = await runtime.accountStore.getPrivateKey('0x0000000000000000000000000000000000000002');
Event Hub¶
Class Name | EventHub |
---|---|
Extends | Logger |
Source | event-hub.ts |
The EventHub helper is wrapper for using contract events. These include - contract events (e.g. contract factory may trigger an event, announcing the address of the new contract) - global events (some contracts in the evan.network economy, like the MailBox use such global events)
constructor¶
new EventHub(options);
Creates a new EventHub instance.
Parameters¶
options
-EventHubOptions
: options for EventHub constructor.config
-any
: configuration object for the eventhub modulenameResolver
-NameResolver
:NameResolver
instancecontractLoader
-ContractLoader
:ContractLoader
instanceeventWeb3
-Web3
(optional):Web3
instance used for event handling (metamask web3 can’t handle events correct)log
-Function
(optional): function to use for logging:(message, level) => {...}
logLevel
-LogLevel
(optional): messages with this level will be logged withlog
logLog
-LogLogInterface
(optional): container for collecting log messageslogLogLevel
-LogLevel
(optional): messages with this level will be pushed tologLog
Returns¶
EventHub
instance
subscribe¶
eventHub.subscribe(contractName, contractAddress, eventName, filterFunction, onEvent, fromBlock);
subscribe to a contract event or a global EventHub event
Parameters¶
contractName
-string
: target contract name (must be available withinContractLoader
)contractAddress
-string
: target contract addresseventName
-string
: name of the event to subscribe tofilterFunction
-function
: a function that returns true or a Promise that resolves to true if onEvent function should be appliedonEvent
-function
: executed when event was fired and the filter matches, gets the event as its parameterfromBlock
-string
(optional): get all events from this block, defaults tolatest
Returns¶
Promise
resolves to string
: event subscription.
Example¶
// subscribe to the 'ContractEvent' at the EventHub located at '00000000000000000000000000000000deadbeef'
runtime.eventHub
.subscribe(
'EventHub',
'00000000000000000000000000000000deadbeef',
'ContractEvent',
(event) => true,
(event) => {
console.dir(event)
}
)
.then((result) => { subscription = result; })
once¶
eventHub.once(contractName, contractAddress, eventName, filterFunction, onEvent, fromBlock);
subscribe to a contract event or a global EventHub event, remove subscription when filterFunction matched
Parameters¶
toRemove
-any
:contractAddress
-string
: target contract addresseventName
-string
: name of the event to subscribe tofilterFunction
-function
: a function that returns true or a Promise that resolves to true if onEvent function should be appliedonEvent
-function
: executed when event was fired and the filter matches, gets the event as its parameterfromBlock
-string
(optional): get all events from this block, defaults tolatest
Returns¶
Promise
resolves to string
: event subscription.
Example¶
// subscribe to the 'ContractEvent' at the EventHub located at '00000000000000000000000000000000deadbeef'
runtime.eventHub
.once(
'EventHub',
'00000000000000000000000000000000deadbeef',
'ContractEvent',
(event) => true,
(event) => {
console.dir(event)
}
)
.then((result) => { subscription = result; })
unsubscribe¶
eventHub.unsubscribe(toRemove);
unsubscribe an event subscription
Parameters¶
contractName
-string
: target contract name (must be available withinContractLoader
)subscription
-string
: target guid for the subscription that should be removedcontractId
-string
: target contractId where all subscriptions should be removed (can be ‘all’)
Returns¶
Promise
resolves to void
: resolved when done.
Example¶
// subscribe to the 'ContractEvent' at the EventHub located at '00000000000000000000000000000000deadbeef'
runtime.eventHub
.unsubscribe({
subscription: 'f0315d39-5e03-4e82-b765-df1c03037b3a'
})
Name Resolver¶
Class Name | NameResolver |
---|---|
Extends | Logger |
Source | name-resolver.ts |
Examples | name-resolver.spec.ts |
The NameResolver is a collection of helper functions, that can be used for ENS interaction. These include:
- setting and getting ENS addresses
- setting and getting ENS content flags, which is used when setting data in distributed file system, especially in case of setting a description for an ENS address
constructor¶
new NameResolver(options);
Creates a new NameResolver instance.
Parameters¶
options
-NameResolverOptions
: options for NameResolver constructor.config
-any
: configuration object for the NameResolver instanceexecutor
-Executor
:Executor
instancecontractLoader
-ContractLoader
:ContractLoader
instanceweb3
-Web3
:Web3
instancelog
-Function
(optional): function to use for logging:(message, level) => {...}
logLevel
-LogLevel
(optional): messages with this level will be logged withlog
logLog
-LogLogInterface
(optional): container for collecting log messageslogLogLevel
-LogLevel
(optional): messages with this level will be pushed tologLog
Returns¶
NameResolver
instance
Example¶
const nameResolver = new NameResolver({
cryptoProvider,
dfs,
executor,
keyProvider,
nameResolver,
contractLoader,
web3,
});
getAddressOrContent¶
nameResolver.getAddressOrContent(name, type);
get address or content of an ens entry
Parameters¶
name
-string
: ens domain name (plain text)type
-string
: content type to get (address or content)
Returns¶
Promise
resolves to string
: address, returns null if not available
Example¶
const testEvanAddress = await runtime.nameResolver.getAddressOrContent('test.evan', 'address');
// returns 0x9c0Aaa728Daa085Dfe85D3C72eE1c1AdF425be49
getAddress¶
nameResolver.getAddress(name);
get address of an ens entry
Parameters¶
name
-string
: ens domain name (plain text)
Returns¶
Promise
resolves to string
: address, returns null if not available
Example¶
const testEvanAddress = await runtime.nameResolver.getAddress('test.evan');
// returns 0x9c0Aaa728Daa085Dfe85D3C72eE1c1AdF425be49
getContent¶
nameResolver.getContent(name);
get content of an ens entry
Parameters¶
name
-string
: ens domain name (plain text)
Returns¶
Promise
resolves to string
: content, returns null if not available
Example¶
const testEvanAddress = await runtime.nameResolver.getContent('test.evan');
// returns (encoded ipfs hash) 0x9c0Aaa728Daa085Dfe85D3C72eE1c1AdF425be49
setAddressOrContent¶
nameResolver.setAddressOrContent(name, value, accountId, domainOwnerId, type);
set ens name. this can be a root level domain domain.test or a subdomain sub.domain.test
Parameters¶
name
-string
: ens domain name (plain text)value
-string
: ethereum addressaccountId
-string
: owner of the parent domaindomainOwnerId
-string
: owner of the address to settype
-string
: content type to set
Returns¶
Promise
resolves to void
: resolves when done
Example¶
const testEvanAddress = await runtime.nameResolver
.setAddressOrContent(
'test.evan',
'0x9c0Aaa728Daa085Dfe85D3C72eE1c1AdF425be49',
'0x000000000000000000000000000000000000beef',
'0x000000000000000000000000000000000000beef',
'address'
);
// returns (encoded ipfs hash) 0x9c0Aaa728Daa085Dfe85D3C72eE1c1AdF425be49
setAddress¶
nameResolver.setAddress(name, address, accountId, domainOwnerId);
set address for ens name. this can be a root level domain domain.test or a subdomain sub.domain.test
Parameters¶
name
-string
: ens domain name (plain text)address
-string
: ethereum addressaccountId
-string
: owner of the parent domaindomainOwnerId
-string
: owner of the address to set
Returns¶
Promise
resolves to void
: resolves when done
Example¶
const testEvanAddress = await runtime.nameResolver
.setAddress(
'test.evan',
'0x9c0Aaa728Daa085Dfe85D3C72eE1c1AdF425be49',
'0x000000000000000000000000000000000000beef',
'0x000000000000000000000000000000000000beef'
);
setContent¶
nameResolver.setContent(name, content, accountId, domainOwnerId);
set content for ens name. this can be a root level domain domain.test or a subdomain sub.domain.test
Parameters¶
name
-string
: ens domain name (plain text)content
-string
: ethereum addressaccountId
-string
: owner of the parent domaindomainOwnerId
-string
: owner of the address to set
Returns¶
Promise
resolves to void
: resolves when done
Example¶
const testEvanAddress = await runtime.nameResolver
.setContent(
'test.evan',
'0x9c0Aaa728Daa085Dfe85D3C72eE1c1AdF425be49',
'0x000000000000000000000000000000000000beef',
'0x000000000000000000000000000000000000beef'
);
claimAddress¶
nameResolver.claimAddress(name, accountId[, domainOwnerId, price]);
Tries to claim node ownership from parent nodes owner, this assumes, that the parent node owner is a registar, that supports claiming address from it (FIFS registrar or PayableRegistrar).
Parameters¶
name
-string
: domain name to set (plain text)accountId
-string
: account, that executes the transactiondomainOwnerId
-string
(optional): owner of the new domain, defaults toaccountId
value
-string|number
(optional): value to send (if registrar is payable)
Returns¶
Promise
returns void
: resolved when done
Example¶
// claim '123test.fifs.registrar.test.evan' with account[0] for account[1] from FIFS registrar
const domain = '123test.fifs.registrar.test.evan';
await nameResolver.claimAddress(domain, accounts[0], accounts[1]);
// claim '123test.payable.registrar.test.evan' with account[0] for account[1] from payable registrar
const domain = '123test.fifs.registrar.test.evan';
const price = await nameResolver.getPrice(domain);
await nameResolver.claimAddress(domain, accounts[0], accounts[1], price);
claimPermanentAddress¶
nameResolver.claimPermanentAddress(name, accountId[, domainOwnerId]);
Registers a permanent domain via registrar, can only be done by registrar owner.
Parameters¶
name
-string
: domain name to set (plain text)accountId
-string
: account, that executes the transaction, has to be registrar ownerdomainOwnerId
-string
(optional): owner of the new domain, defaults toaccountId
Returns¶
Promise
returns void
: resolved when done
Example¶
// claim '123sample.evan' with account[0] for account[1] from registrar
const domain = '123sample.evan';
await nameResolver.claimPermanentAddress(domain, accounts[0], accounts[1]);
setPrice¶
nameResolver.setPrice(name, accountId, newPrice);
Set price for a registrar at a domain.
Parameters¶
name
-string
: ENS address of a domain owned by a registrar (e.g. ‘sample.payable.test.evan’)accountId
-string
: account that performs the action (needs proper permisions for registrar)newPrice
-number|string
(optional): new price in Wei
Returns¶
Promise
returns void
: resolved when done
Example¶
await nameResolver.setPrice(
'payable.registrar.test.evan',
'0x1111111111111111111111111111111111111111',
web3.utils.toWei('5', 'ether'),
);
getPrice¶
nameResolver.getPrice(name);
Get price for domain (if domain is payable).
Parameters¶
name
-string
: a domain to check price for (e.g. ‘sample.payable.test.evan’)
Returns¶
Promise
returns string
: price in Wei
Example¶
console.log(await nameResolver.getPrice('payable.registrar.test.evan'));
// Output:
// 5000000000000000000
setValidUntil¶
nameResolver.setValidUntil(name, accountId, newPrice);
Set duration, that an address is valid; resolval stops after this, depending on configuration of the ENS an extra period, where owner is still available, can be granted; notice that this can only be done by parent owner of given domain.
Parameters¶
name
-string
: ENS address of a domain owned by a registrar (e.g. ‘sample.payable.test.evan’)accountId
-string
: account that performs the action; must be parent owner of given domainvalidUntil
-number|string
: js timestamp, when name resolution stops
Returns¶
Promise
returns void
: resolved when done
Example¶
await nameResolver.setValidUntil(
'payable.registrar.test.evan',
'0x1111111111111111111111111111111111111111',
Date.now() + 60000,
);
getValidUntil¶
nameResolver.getValidUntil(name);
Get timestamp, when domain will stop resolval.
Parameters¶
name
-string
: domain to get valid until for
Returns¶
Promise
returns string
: js timestamp, when resolver lookup will expire
Example¶
console.log(await nameResolver.getValidUntil('payable.registrar.test.evan'));
// Output:
// 1544630375417
claimFunds¶
namerResolver.claimFunds(name, accountId);
Verification funds for domain.
Parameters¶
name
-string
: ENS address of a domain owned by a registrar (e.g. ‘sample.payable.test.evan’)accountId
-string
: account that performs the action (needs proper permisions for registrar)
Returns¶
Promise
returns void
: resolved when done
Example¶
await nameResolver.claimFunds(
'payable.registrar.test.evan',
'0x1111111111111111111111111111111111111111',
);
getFactory¶
nameResolver.getFactory(contractName);
helper function for retrieving a factory address (e.g. ‘tasks.factory.evan’)
Parameters¶
contractName
-string
: name of the contract that is created by the factory
Returns¶
string
: address of the contract factory
Example¶
const taskFactory = await runtime.nameResolver.getFactory('tasks');
// returns '0x9c0Aaa728Daa085Dfe85D3C72eE1c1AdF425be49';
getDomainName¶
nameResolver.getDomainName(domainConfig, ...subLabels);
builds full domain name based on the provided domain config a module initalization.
Parameters¶
domainConfig
-string[] | string
: The domain configuration...subLabels
-string[]
: array of domain elements to be looked up and added at the lefthand
Returns¶
string
: the domain name
Example¶
const domain = runtime.nameResolver.getDomainName(['factory', 'root'], 'task');
// returns 'task.factory.evan';
getArrayFromIndexContract¶
nameResolver.getArrayFromIndexContract(indexContract, listHash, retrievers, chain, triesLeft);
retrieve an array with all values of a list from an index contract.
Parameters¶
indexContract
-any
: Ethereum contract address (DataStoreIndex)listHash
-string
: bytes32 namehash like api.nameResolver.sha3(‘ServiceContract’)retrievers
-any
(optional): overwrites for index or index like contract property retrievals defaults to:
{
listEntryGet: 'listEntryGet',
listLastModified: 'listLastModified',
listLength: 'listLength',
}
chain
-Promise
: Promise, for chaining multiple requests (should be omitted when called ‘from outside’, defaults to Promise.resolve())triesLeft
-number
: tries left before quitting defaults to10
getArrayFromListContract¶
nameResolver.getArrayFromListContract(indexContract, count, offset, reverse, chain, triesLeft);
retrieve an array with all values of a list from an index contract.
Parameters¶
indexContract
-any
: Ethereum contract address (DataStoreIndex)count
-number
(optional): how many items should be returned, defaults to10
offset
-number
(optional): how many items should be skipped, defaults to0
reverse
-boolean
(optional): should the list be iterated reverse, defaults tofalse
chain
-Promise
(optional): Promise, for chaining multiple requests (should be omitted when called ‘from outside’, defaults to Promise.resolve())triesLeft
-number
(optional): tries left before quitting defaults to10
getArrayFromUintMapping¶
nameResolver.getArrayFromUintMapping(contract, countRetriever, elementRetriever[, count, offset, reverse]);
retrieve elements from a contract using a count and element retriever function.
Parameters¶
contract
-any
: Ethereum contract address (DataStoreIndex)countRetriever
-Function
: function which returns the count of the retrieved elementselementRetriever
-Function
: function which returns the element of the retrieved elementscount
-number
(optional): number of elements to retrieve, defaults to10
offset
-number
(optional): skip this many items when retrieving, defaults to0
reverse
-boolean
(optional): retrieve items in reverse order, defaults tofalse
sha3¶
nameResolver.sha3(input);
sha3 hashes an input, substitutes web3.utils.sha3 from geth console
Parameters¶
input
-string | buffer
: input text or buffer to hash
soliditySha3¶
nameResolver.soliditySha3(...args);
Will calculate the sha3 of given input parameters in the same way solidity would. This means arguments will be ABI converted and tightly packed before being hashed.
Parameters¶
args
-string | buffer
: arguments for hashing
Description¶
Class Name | Description |
---|---|
Extends | Description |
Source | description.ts |
Examples | description.spec.ts |
The Description module is the main entry point for interacting with contract descriptions. It allows you to:
- get and set descriptions
- work with contracts and ENS descriptions
- create web3.js contract instances directly from an Ethereum address and its description
- The main use cases for interacting with a contracts description in your application will most probably be reading a contracts description and loading contracts via their description.
The examples folder folder contains some samples for getting started. With consuming or setting contract descriptions.
When setting descriptions to contracts, these contracts have to support the Executor
interface.
A simple flow for working with description may look like following:
We already have smart contract, that supports the zz interface and set a description to it.
const address = '0x...'; // or 'test.evan' as ens name
const accountId = '0x...';
const description = {
"public": {
"name": "DBCP sample contract",
"description": "DBCP sample contract description",
"author": "dbcp test",
"tags": [
"example",
"greeter"
],
"version": "0.1.0",
"dbcpVersion": 2
}
};
await runtime.description.setDescription(address, description, accountId);
Now we have made some updates to our contract and we want to update its version to 0.2.0
.
// get description const retrieved = await runtime.description.getDescription(address, accountId);
// update version const accountId = ‘0x000000000000000000000000000000000000beef’; retrieved.public.version = ‘0.2.0’; await runtime.description.setDescription(address, retrieved, accountId);
constructor¶
new Description(options);
Creates a new Description instance.
Parameters¶
options
-DescriptionOptions
: options for Description constructor.cryptoProvider
-CryptoProvider
:CryptoProvider
instancedfs
-DfsInterface
:DfsInterface
instanceexecutor
-Executor
:Executor
instancekeyProvider
-KeyProvider
:KeyProvider
instancenameResolver
-NameResolver
:NameResolver
instancecontractLoader
-ContractLoader
:ContractLoader
instanceweb3
-Web3
:Web3
instancelog
-Function
(optional): function to use for logging:(message, level) => {...}
logLevel
-LogLevel
(optional): messages with this level will be logged withlog
logLog
-LogLogInterface
(optional): container for collecting log messageslogLogLevel
-LogLevel
(optional): messages with this level will be pushed tologLog
Returns¶
Description
instance
Example¶
const description = new Description({
cryptoProvider,
dfs,
executor,
keyProvider,
nameResolver,
contractLoader,
web3,
});
getDescription¶
description.getDescription(address, accountId);
loads description envelope from ens or contract if an ENS address has a contract set as well and this contract has a defintion, the contract definition is preferred over the ENS definition and therefore returned
Parameters¶
address
-string
: The ens address or contract address where the description is storedaccountId
-string
: Account id to load the contract address for
Returns¶
Promise
returns Envelope
: description as an Envelope.
Example¶
const address = '0x9c0Aaa728Daa085Dfe85D3C72eE1c1AdF425be49';
const accountId = '0x000000000000000000000000000000000000beef';
const description = await runtime.description.getDescription(address, accountId);
console.dir(description);
// Output:
// { public:
// { name: 'DBCP sample greeter',
// description: 'smart contract with a greeting message and a data property',
// author: 'dbcp test',
// tags: [ 'example', 'greeter' ],
// version: '0.1.0',
// dbcpVersion: 2,
// abis: { own: [Array] } } }
setDescription¶
description.setDescription(address, envelope, accountId);
set description, can be used for contract addresses and ENS addresses
Parameters¶
address
-string
: contract address or ENS addressenvelope
-Envelope
: description as an envelopeaccountId
-string
: ETH account id
Returns¶
Promise
returns void
: resolved when done.
Example¶
const address = '0x...'; // or 'test.evan' as ens name
const accountId = '0x...';
const description = {
"public": {
"name": "DBCP sample contract",
"description": "DBCP sample contract description",
"author": "dbcp test",
"tags": [
"example",
"greeter"
],
"dbcpVersion": 2,
"version": "0.1.0"
}
};
await runtime.description.setDescription(address, description, accountId);
validateDescription¶
Descriptions are validated when setting them. A list of known DBCP definition schemas is maintained in description.schema.ts . If a description is set, its property dbcpVersion will be used for validating the description, if dbcpVersion is not provided, version 1 is used and a warning is logged.
Descriptions can be checked against the validator before setting them.
description.validateDescription(envelope);
try to validate description envelope; throw Error if validation fails
Parameters¶
envelope
-Envelope
: envelop with description data; private has to be unencrypted
Returns¶
Promise
returns boolean|any[]
: true if valid or array of issues.
Example¶
const brokenDescription = {
"public": {
"name": "DBCP sample contract with way to few properties",
}
};
console.log(runtime.description.validateDescription(brokenDescription));
// Output:
// [ { keyword: 'required',
// dataPath: '',
// schemaPath: '#/required',
// params: { missingProperty: 'description' },
// message: 'should have required property \'description\'' },
// { keyword: 'required',
// dataPath: '',
// schemaPath: '#/required',
// params: { missingProperty: 'author' },
// message: 'should have required property \'author\'' },
// { keyword: 'required',
// dataPath: '',
// schemaPath: '#/required',
// params: { missingProperty: 'version' },
// message: 'should have required property \'version\'' } ]
const workingDescription = {
"public": {
"name": "DBCP sample contract",
"description": "DBCP sample contract description",
"author": "dbcp test",
"tags": [
"example",
"greeter"
],
"version": "0.1.0"
}
};
console.log(runtime.description.validateDescription(workingDescription));
// Output:
// true
= Contract =¶
getDescriptionFromContract¶
description.getDescriptionFromContract(address, accountId);
loads description envelope from contract
Parameters¶
address
-string
: The ens address or contract address where the description is storedaccountId
-string
: Account id to load the contract address for
Returns¶
Promise
returns Envelope
: description as an Envelope.
Example¶
const address = '0x9c0Aaa728Daa085Dfe85D3C72eE1c1AdF425be49';
const accountId = '0x000000000000000000000000000000000000beef';
const description = await runtime.description.getDescriptionFromContract(address, accountId);
console.dir(description);
// Output:
// { public:
// { name: 'DBCP sample greeter',
// description: 'smart contract with a greeting message and a data property',
// author: 'dbcp test',
// tags: [ 'example', 'greeter' ],
// version: '0.1.0',
// dbcpVersion: 2,
// abis: { own: [Array] } } }
setDescriptionToContract¶
description.setDescriptionToContract(contractAddress, envelope, accountId);
store description at contract
Parameters¶
contractAddress
-string
: The contract address where description will be storedenvelope
-Envelope
: description as an envelopeaccountId
-string
: ETH account id
Returns¶
Promise
returns void
: resolved when done.
Example¶
const address = '0x...';
const accountId = '0x...';
const description = {
"public": {
"name": "DBCP sample contract",
"description": "DBCP sample contract description",
"author": "dbcp test",
"tags": [
"example",
"greeter"
],
"version": "0.1.0",
"dbcpVersion": 2
}
};
await runtime.description.setDescriptionToContract(address, description, accountId);
= ENS =¶
ENS addresses are able to hold multiple values at once. So they may be holding a contract address and a description. If this is the case and the contract at the ENS address has another description, the contracts description is preferred over the ENS description. If you explicitly intend to retrieve an ENS endpoints description and want to ignore the contracts description, use the function getDescriptionFromEns.
getDescriptionFromEns¶
description.getDescriptionFromEns(address);
loads description envelope from ens
Parameters¶
ensAddress
-string
: The ens address where the description is stored
Returns¶
Promise
returns Envelope
: description as an Envelope.
Example¶
const address = '0x9c0Aaa728Daa085Dfe85D3C72eE1c1AdF425be49';
const accountId = '0x000000000000000000000000000000000000beef';
const description = await runtime.description.getDescriptionFromContract(address, accountId);
console.dir(description);
// Output:
// { public:
// { name: 'DBCP sample greeter',
// description: 'smart contract with a greeting message and a data property',
// author: 'dbcp test',
// tags: [ 'example', 'greeter' ],
// version: '0.1.0',
// dbcpVersion": 2,
// abis: { own: [Array] } } }
setDescriptionToEns¶
description.setDescriptionToEns(ensAddress, envelope, accountId);
store description at contract
Parameters¶
contractAddress
-string
: The ens address where description will be storedenvelope
-Envelope
: description as an envelopeaccountId
-string
: ETH account id
Returns¶
Promise
returns void
: resolved when done.
Example¶
const address = '0x...';
const accountId = '0x...';
const description = {
"public": {
"name": "DBCP sample contract",
"description": "DBCP sample contract description",
"author": "dbcp test",
"tags": [
"example",
"greeter"
],
"version": "0.1.0",
"dbcpVersion": 2
}
};
await runtime.description.setDescriptionToEns(address, description, accountId);
Wallet¶
Class Name | Wallet |
---|---|
Extends | Logger |
Source | wallet.ts |
Examples | wallet.spec.ts |
The Wallet
module is a wrapper for the MultiSigWallet and allows to create wallets, manage owners and execte transactions with it.
One of the common use cases is setting confirmation count to 1 (which is the default value). This basically makes the wallets a multiowned account, where all parties are able to perform transactions on their own.
The Wallet
module is bound to a wallet contract instance. This instace can be loaded, which requires an existing MultiSigWallet contract and a user, that is able to work with it:
wallet.load('0x0123456789012345678901234567890123456789');
If no wallet exists, a new wallet can be created with:
// account id, that creates the wallet
const accountId = '0x0000000000000000000000000000000000000001';
// account, that will be able to manage the new wallet
const manager = '0x0000000000000000000000000000000000000001';
// wallet owners
const owners = [
'0x0000000000000000000000000000000000000001',
'0x0000000000000000000000000000000000000002',
];
await wallet.create(accountId, manager, owners);
The last example creates a wallet
- with the account
0x0000000000000000000000000000000000000001
(used asaccountId
) - that can be managed (adding/removing owners) by
0x0000000000000000000000000000000000000001
(used asmanager
) - that allows the accounts
0x0000000000000000000000000000000000000001
and0x0000000000000000000000000000000000000002
to perform transactions (used asowners
)
Creating wallets via the Wallet
module loads them to the module as well, so there is no need to call the load
function after that.
So now we have a valid and working wallet loaded to our module and start performing calls. Let’s say, we have an instance of an owned contract and want to transfer its ownership, we can do:
const accountId = '0x0000000000000000000000000000000000000001';
const newOwner = '0x0000000000000000000000000000000000000002';
await wallet.submitTransaction(ownedContract, 'transferOwnership', { from: accountId, }, newOwner);
Looks pretty simple, but comes with a few things to consider:
accountId
is the account, that performs the transaction from the “outside perspective” (if you look into a chain explorer like the evan.network Test-Explorer you’ll see, that accountaccountId
is actually performing the transaction and not the wallet contract)accountId
pays the gas cost for the transaction (obviously, when considering the last point)- from the perspective of the target contract
ownedContract
, the wallet contract (either loaded or created beforehand) is performing the transaction - taken our example transaction
transferOwnership
, the wallet contract has to be the current owner and not the accountaccountId

transaction flow in wallet based transactions
An implementation of an Executor
module, that uses a wallet for contract execution, has been created as ExecutorWallet
. Because the profiles are (externally owned) account based and many modules rely on profiles for data encryption and decryption, the ExecutorWallet
module should be used with care, when dealing with operations, that require en- or decryption.
constructor¶
new Wallet(options);
Creates a new Wallet instance.
Parameters¶
options
-WalletOptions
: options for Wallet constructor.contractLoader
-ContractLoader
:ContractLoader
instancedescription
-Description
:Description
instanceeventHub
-EventHub
:EventHub
instanceexecutor
-Executor
:Executor
instancenameResolver
-NameResolver
:NameResolver
instance
Returns¶
Wallet
instance
Example¶
const wallet = new Wallet({
contractLoader,
description,
eventHub,
executor,
nameResolver,
});
= Contract Management =¶
create¶
wallet.create(accountId, manager, owners);
Create a new wallet contract and uses it as its wallet contract.
Parameters¶
accountId
-string
: account id, that creates the walletmanager
-string
: account, that will be able to manage the new walletowners
-string[]
: wallet ownersconfirmations
-number
(optional): number of confirmations required to complete a transaction, defaults to1
Returns¶
Promise
returns void
: resolved when done
load¶
wallet.load(contractId[, walletType]);
Load wallet contract from address and uses it as its wallet contract.
Parameters¶
contractid
-string
: a wallet contract addresswalletType
-string
(optional): wallet contract type, defaults toMultiSigWallet
Returns¶
Promise
returns void
: resolved when done
Example¶
wallet.load('0x0123456789012345678901234567890123456789');
= Transactions =¶
submitTransaction¶
wallet.submitTransaction(target, functionName, inputOptions[, ...functionArguments]);
Submit a transaction to a wallet, as required is fixed to 1, this will immediately execute the transaction.
Parameters¶
target
-any
: contract of the submitted transactionfunctionName
-string
: name of the contract function to callinputOptions
-any
: currently supported: from, gas, value, event, getEventResult, eventTimeout, estimate, forcefunctionArguments
-any[]
: optional arguments to pass to contract transaction
Returns¶
Promise
returns any
: status information about transaction
Example¶
await wallet.submitTransaction(testContract, 'transferOwnership', { from: accounts[0], }, accounts[1]);
= Account Management =¶
addOwner¶
wallet.addOwner(accountId, toAdd);
Function description
Parameters¶
accountId
-string
: account with management permissions on wallettoAdd
-string
: account to add as an owner
Returns¶
Promise
returns void
: resolved when done
Votings¶
Class Name | Wallet |
---|---|
Extends | Logger |
Source | votings.ts |
Examples | votings.spec.ts |
The votings helper allows to hold votes over decisions and execute them, if enough votes have been submitted.
The usual flow for proposals has the following steps:
- if not already created, create a voting contract with createContract (this doesn’t have to be done when using a central voting contract (e.g. from a well known ENS address))
- create a proposal for a change with createProposal
- let participants vote with vote
- if enough time has passed and you have enough votes, you can finally execute your proposal with execute
constructor¶
new Votings(options);
Creates a new Votings instance.
Parameters¶
options
-VotingsOptions
: options for Votings constructor.contractLoader
-ContractLoader
:ContractLoader
instanceexecutor
-Executor
:Executor
instance
Returns¶
Votings
instance
Example¶
const votings = new Votings({
contractLoader,
executor,
});
= Contract =¶
createContract¶
votings.createContract(accountId, votingsContractOptions);
Create new voting contract instance.
Parameters¶
accountId
-string
: account that performs the actionvotingsContractOptions
-VotingsContractOptions
: additional options for votings contract
Returns¶
Promise
returns void
: resolved when done
Example¶
const votingsContract = await votings.createContract(
'0x1111111111111111111111111111111111111111',
{
minimumQuorumForProposals: 2,
minutesForDebate: 1,
marginOfVotesForMajority: 0,
},
);
= Members =¶
addMember¶
votings.addMember(votingsContract, votingsOwner, toInvite, memberOptions);
Add member to voting contract.
Parameters¶
contract
-string|any
: web3 voting contract instance or contract addressaccountId
-string
: account that performs the actiontargetAccount
-string
: account to add to votings contractmemberOptions
-MemberOptions
: options for new member
Returns¶
Promise
returns void
: resolved when done
Example¶
await votings.addMember(
'0x00000000000000000000000000000000c0274ac7',
'0x1111111111111111111111111111111111111111',
'0x2222222222222222222222222222222222222222',
{ name: 'Member Number 2' },
);
removeMember¶
votings.removeMember(votingsContract, votingsOwner, toRemove);
Remove member from votings contract.
Parameters¶
contract
-string|any
: web3 voting contract instance or contract addressaccountId
-string
: account that performs the actiontargetAccount
-string
: account to remove from votings contract
Returns¶
Promise
returns void
: resolved when done
Example¶
await votings.removeMember(
'0x00000000000000000000000000000000c0274ac7',
'0x1111111111111111111111111111111111111111',
'0x2222222222222222222222222222222222222222',
);
getMemberInfo¶
votings.getMemberInfo(votingsContract, accountId);
Get info of a member.
Parameters¶
contract
-string|any
: web3 voting contract instance or contract addresstargetAccount
-string
: account to get info for
Returns¶
Promise
returns MemberInfo
: member info
Example¶
console.dir(await votings.getMemberInfo(
'0x00000000000000000000000000000000c0274ac7',
'0x2222222222222222222222222222222222222222',
));
// Output:
// {
// address: '0x2222222222222222222222222222222222222222',
// name: 'Member Number 2',
// memberSince: 1544092270556
// }
isMember¶
votings.isMember(votingsContract, accountId);
Checks if a given account is member in voting contract.
Parameters¶
contract
-string|any
: web3 voting contract instance or contract addresstargetAccount
-string
: account to get info for
Returns¶
Promise
returns bool
: true if member
Example¶
console.dir(await votings.isMember(
'0x00000000000000000000000000000000c0274ac7',
'0x2222222222222222222222222222222222222222',
));
// Output:
// true
= Proposals =¶
createProposal¶
votings.createProposal(votingsContract, accountId, proposalOptions);
Create a new proposal in votings contract.
Parameters¶
contract
-string|any
: web3 voting contract instance or contract addressaccountId
-string
: account that performs the actionproposalOptions
-ProposalOptions
: options for proposal
Returns¶
Promise
returns string
: id of new proposal
Example¶
// make a proposal about a suggestion (text only)
const textProposal = await votings.createProposal(
'0x00000000000000000000000000000000c0274ac7',
'0x1111111111111111111111111111111111111111',
{ description: 'Change voting time to 2 hours.' },
);
// propose a transaction
const txProposal = await votings.createProposal(
'0x00000000000000000000000000000000c0274ac7',
'0x1111111111111111111111111111111111111111',
{
description: 'set data of this contract to "def"',
data: '0x47064d6a' +
'0000000000000000000000000000000000000000000000000000000000000020' +
'0000000000000000000000000000000000000000000000000000000000000003' +
'6465660000000000000000000000000000000000000000000000000000000000',
to: '0x000000000000000000000000a2074340c0274ac7',
},
);
getProposalCount¶
votings.getProposalCount(contract);
Get number of proposals in votings contract.
Parameters¶
contract
-string|any
: web3 voting contract instance or contract address
Returns¶
Promise
returns number
: number of proposals
Example¶
await votings.createProposal(
'0x00000000000000000000000000000000c0274ac7',
'0x1111111111111111111111111111111111111111',
{
description: 'set data of this contract to "def"',
data: '0x47064d6a' +
'0000000000000000000000000000000000000000000000000000000000000020' +
'0000000000000000000000000000000000000000000000000000000000000003' +
'6465660000000000000000000000000000000000000000000000000000000000',
to: '0x000000000000000000000000a2074340c0274ac7',
},
);
const count = await votings.getProposalCount('0x00000000000000000000000000000000c0274ac7');
console.log(count);
// Output:
// 1
getProposalInfo¶
votings.getProposalInfo(votingsContract, proposalId);
Gets info about a given proposal in contract.
Parameters¶
contract
-string|any
: web3 voting contract instance or contract addressproposalId
-string
: id of proposal to retrieve info for
Returns¶
Promise
returns ProposalInfo
: info about proposal
Example¶
console.dir(await votings.getProposalInfo(
'0x00000000000000000000000000000000c0274ac7',
'0',
));
// Output:
// {
// currentResult: '0',
// description: 'Change voting time to 2 hours.',
// executed: false,
// minExecutionDate: 1544093505000,
// numberOfVotes: '0',
// proposalHash: '0xa86d54e9aab41ae5e520ff0062ff1b4cbd0b2192bb01080a058bb170d84e6457',
// proposalPassed: false,
// to: '0x0000000000000000000000000000000000000000',
// value: '0'
// }
getProposalInfos¶
votings.getProposalInfos(contract[, count, offset, reverse]);
Get multiple proposals from votings contract.
Parameters¶
contract
-string|any
: web3 voting contract instance or contract addresscount
-number
(optional): number of items to retrieve, defaults to10
offset
-number
(optional): skip this many entries, defaults to0
reverse
-boolean
(optional): fetch entries, starting with last entry, defaults totrue
Returns¶
Promise
returns ProposalInfos
: proposals listing
Example¶
await votings.createProposal(
'0x00000000000000000000000000000000c0274ac7',
'0x1111111111111111111111111111111111111111',
{
description: 'set data of this contract to "def"',
data: '0x47064d6a' +
'0000000000000000000000000000000000000000000000000000000000000020' +
'0000000000000000000000000000000000000000000000000000000000000003' +
'6465660000000000000000000000000000000000000000000000000000000000',
to: '0x000000000000000000000000a2074340c0274ac7',
},
);
const proposals = await votings.getProposalInfos('0x00000000000000000000000000000000c0274ac7');
console.log(proposals.results.length);
// Output:
// 1
vote¶
votings.vote(votingsContract, accountId, proposal, accept[, comment]);
Vote for a proposal.
Parameters¶
contract
-string|any
: web3 voting contract instance or contract addressaccountId
-string
: account that performs the actionproposal
-string
: id of proposal to vote foraccept
-boolean
: accept proposal or notcomment
-string
(optional): comment for vote, left empty if omitted
Returns¶
Promise
returns void
: resolved when done
Example¶
await votings.vote(
'0x00000000000000000000000000000000c0274ac7',
'0x2222222222222222222222222222222222222222',
'1',
true,
);
execute¶
votings.execute(votingsContract, accountId, proposal[, data]);
Execute a proposal.
Parameters¶
contract
-string|any
: web3 voting contract instance or contract addressaccountId
-string
: account that performs the actionproposal
-string
: id of proposal to vote fordata
-string
(optional): transaction input bytes as string (0x${functionhash}${argumentsData}), defaults to0x
Returns¶
Promise
returns void
: resolved when done
Example¶
// execute proposal about a suggestion (text only)
await votings.execute(
'0x00000000000000000000000000000000c0274ac7',
'0x1111111111111111111111111111111111111111',
'0',
);
// execute proposal about a transaction
await votings.execute(
'0x00000000000000000000000000000000c0274ac7',
'0x1111111111111111111111111111111111111111',
'1',
'0x47064d6a' +
'0000000000000000000000000000000000000000000000000000000000000020' +
'0000000000000000000000000000000000000000000000000000000000000003' +
'6465660000000000000000000000000000000000000000000000000000000000',
);
= Additional Components =¶
Interfaces¶
MemberInfo¶
address
-string
: accountId of membername
-string
: description text of membermemberSince
-string
: date of joining votings contract
MemberOptions¶
name
-string
: description text of member
ProposalInfo¶
currentResult
-number
: current number of positive votesdescription
-string
: description textexecuted
-boolean
: true if already executedminExecutionData
-number
: earliest day of executionnumberOfVotes
-number
: number of submitted votesproposalHash
-string
: checksum of proposal: keccak256(beneficiary, weiAmount, transactionBytecode)proposalPassed
-boolean
: true if executed and proposal passedto
-string
: target of proposal (contract/account to send transaction to)value
-string
: amount of Wei to send to target
ProposalInfos¶
results
-ProposalInfo[]
: proposals of current page (length is 10)totalCount
-number
: total number of results
ProposalOptions¶
description
-string
: description textdata
-string
(optional): input data for proposal, defaults to0x
to
-string
(optional): target of proposal (contract/account to send transaction to), defaults to0x0000000000000000000000000000000000000000
value
-string
(optional): amount of Wei to send to target, defaults to0
VotingsContractOptions¶
minimumQuorumForProposals
-number
: votes that must have been given before any proposal is accepted; updates to this may affect running proposalsminutesForDebate
-number
: time to have passed before a proposal can be accepted; updates to this do not affect running proposalsmarginOfVotesForMajority
-number
: accepting votes that must have been given before any proposal is accepted; updates to this may affect running proposals
Payments¶
Class Name | Payments |
---|---|
Extends | Logger |
Source | payments.ts |
Examples | payments.spec.ts |
Payments are a Service to open unidirectional payment channels to other accounts. You can open a payment channel to another account and do some micropayments offchain.
The heart of the system lies in its sender -> receiver off-chain transactions. They offer a secure way to keep track of the last verified channel balance. The channel balance is calculated each time the sender pays for a resource. He is prompted to sign a so-called balance proof, i.e., a message that provably confirms the total amount of transferred tokens. This balance proof is then sent to the receiver’s server. If the balance proof checks out after comparing it with the last received balance and verifying the sender’s signature, the receiver replaces the old balance value with the new one.
constructor¶
new Payments(options);
Creates a new Payments instance.
Parameters¶
options
-PaymentOptions
: options for Votings constructor.accountStore
-AccountStore
:AccountStore
instancecontractLoader
-ContractLoader
:ContractLoader
instanceexecutor
-Executor
:Executor
instanceweb3
-Web3
:Web3
instance
Returns¶
Payments
instance
Example¶
const payments = new Payments({
accountStore,
contractLoader,
executor,
web3,
});
closeChannel¶
payments.closeChannel(closingSig);
Closes a given payment channel, when a closing signature is available, the channel will be closed cooperately, otherwise the the channel will be close uncooperately and the sender or receiver has to wait a given amount of blocks (500) to get the funds out of the payment channel
Parameters¶
closingSig
-string
(optional): Cooperative-close signature from receiver
Returns¶
Promise
returns void
: resolved when done
confirmPayment¶
payments.confirmPayment(proof);
Persists next_proof to proof. This method must be used after successful payment request, or right after signNewProof is resolved, if implementation don’t care for request status
Parameters¶
proof
-MicroProof
: given microproof object after calling incrementBalanceAndSign
Returns¶
Promise
returns void
: resolved when done
getChannelInfo¶
payments.getChannelInfo(channel);
Get channel details such as current state (one of opened, closed or settled), block in which it was set and current deposited amount
Parameters¶
channel
-MicroChannel
: Channel to get info from. Default to channel
Returns¶
Promise
returns MicroChannelInfo
: member info
getChallengePeriod¶
payments.getChallengePeriod();
Get contract’s configured challenge’s period. As it calls the contract method, can be used for validating that contract’s address has code in current network
Parameters¶
Returns¶
Promise
returns number
: challenge period number, in blocks
getClosingSig¶
payments.getClosingSig(account);
Get the closing balance signature signed from the defined account. This signature can be used to transfer it from the recevier to the sender when the sender wants to close the payment channel. Otherwise when the receiver wants to close the channel cooperative he uses the closign signature to close th channel directly.
Parameters¶
account
-string
: AccountId which should sign the closing signature (mostly the current active account)
Returns¶
Promise
returns string
: signed closing signature
isChannelValid¶
payments.isChannelValid(channel);
Health check for currently configured channel info
Parameters¶
channel
-MicroChannel
: Channel to get info from. Default to channel
Returns¶
boolean
: True if channel is valid, false otherwise
incrementBalanceAndSign¶
payments.incrementBalanceAndSign(amount);
Ask user for signing a payment, which is previous balance incremented of amount. Warnings from signNewProof applies.
Parameters¶
amount
-BigNumber|string
: Amount to increment in current balance
Returns¶
Promise
returns string
: signed signature
Example¶
console.dir(await payments.incrementBalanceAndSign(new BigNumber(1)));
// Output:
// 0x1234567890ABCDEF
loadChannelFromBlockchain¶
payments.loadChannelFromBlockchain(account, receiver);
Scan the blockchain for an open channel, and load it with 0 balance. The 0 balance may be overwritten with setBalance if server replies with a updated balance on first request. It should ask user for signing the zero-balance proof. Throws/reject if no open channel was found.
Parameters¶
account
-string
: Sender/client’s account addressreceiver
-string
: Receiver/server’s account address
Returns¶
Promise
returns MicroChannel
: channel info, if a channel was found
Example¶
await payments.loadChannelFromBlockchain('0x2222222222222222222222222222222222222222', '0x2222222222222222222222222222222222222223');
openChannel¶
payments.openChannel(account, receiver, deposit);
Open a channel for account to receiver, depositing some EVE on it. Replaces current channel data
Parameters¶
account
-string
: Sender/client’s account addressreceiver
-string
: Receiver/server’s account addressdeposit
-BigNumber|string
: deposit in WEI
Returns¶
Promise
returns MicroChannel
: channel info
Example¶
await payments.openChannel('0x2222222222222222222222222222222222222222', '0x2222222222222222222222222222222222222223', new BigNumber(5));
setChannelManager¶
payments.setChannelManager(channelManager);
sets a new channelmanager contract to the current instance
Parameters¶
channelManager
-string
: the new channelmanager address
Returns¶
void
setChannel¶
payments.setChannel(channel);
Set channel info. Can be used to externally [re]store an externally persisted channel info
Parameters¶
channelManager
-MicroChannel
: Channel info to be set
Returns¶
void
Example¶
payments.setChannel({
account: '0x1234',
receiver: '0x1234'
block: 12346,
proof: {
balance: 1,
sig: '0x12345677899'
}
});
signNewProof¶
payments.signNewProof(proof);
Ask user for signing a channel balance. Notice it’s the final balance, not the increment, and that the new balance is set in next_proof, requiring a confirmPayment call to persist it, after successful request.
Implementation can choose to call confirmPayment right after this call resolves, assuming request will be successful after payment is signed.
Parameters¶
proof
-MicroProof
(optional): Balance proof to be signed
Returns¶
Promise
returns MicroProof
: signature
signMessage¶
payments.signMessage(msg);
Ask user for signing a string with eth_accounts_sign
Parameters¶
msg
-string
: Data to be signed
Returns¶
Promise
returns string
: signed data
topUpChannel¶
payments.topUpChannel(deposit);
Top up current channel, by depositing some [more] EVE to it
Parameters¶
deposit
-BigNumber|string
: EVE (in wei) to be deposited in the channel
Returns¶
Promise
returns void
: resolved when done
Example¶
await payments.topUpChannel(new BigNumber(5));
= Additional Components =¶
Interfaces¶
MicroProof¶
balance
-BigNumber
: balance valuesig
-string
(optional): balance signature
MicroChannel¶
account
-string
: Sender/client’s account addressreceiver
-string
: Receiver/server’s account addressblock
-number
: Open channel block numberproof
-MicroProof
: Current balance proofnext_proof
-MicroProof
(optional): Next balance proof, persisted with confirmPaymentclosing_sig
-string
(optional): Cooperative close signature from receiver
MicroChannelInfo¶
state
-string
: Current channel state, one of ‘opened’, ‘closed’ or ‘settled’block
-number
: Block of current state (opened=open block number, closed=channel close requested block number, settled=settlement block number)deposit
-BigNumber
: Current channel deposited sumwithdrawn
-BigNumber
: Value already taken from the channel
This section contains modules, that deal with basic blockchain interactions, like
- performing calls and transaction to contracts
- signing transactions
- handle account private keys
- use on-chain services, like ENS name resolver and event emitting contracts
- describe contracts and ENS addresses
Common¶
Logger¶
Class Name | Logger |
---|---|
Source | logger.ts |
The Logger class is used throughout the package for logging events, updates and errors. Logs can be written by classes, that inherit from the Logger class, by using the this.log function. A log level can be set by its second parameter:
this.log('hello log', 'debug');
All log messages without a level default to level 'info'. If not configured otherwise, the following behavior is used:
- drop all log messages but errors
- log errors to console.error
It can be useful for analyzing issues to increase the log level. You can do this in two ways:
- Set the environment variable DBCP_LOGLEVEL to a level matching your needs, which increases the log level for all modules and works with the default runtime. For example:
export DBCP_LOGLEVEL=info
- When creating a custom runtime, set the logLevel property to a value matching your needs, when creating any module instance. This allows you to change log level for single modules, but requires you to create a custom runtime, e.g.:
const { ContractLoader } = require('@evan.network/dbcp');
const Web3 = require('web3');
// web3 instance for ContractLoader
const provider = new Web3.providers.WebsocketProvider({ '...' });
const web3 = new Web3(provider, null, { transactionConfirmationBlocks: 1 });
// custom log level 'info'
const contractLoader = new ContractLoader({ web3, logLevel: 'info', });
All loggers can have a custom LogLog storage where all logmessages with a given level will be stored. You can access the storage for the current logger module at the property logLog
. All messages are stored with the following markup:
{
timestamp, // current date in millis
level, // loglevel of the message
message // log message
}
You can configure the current LogLogLevel at the property logLogLevel
at instantiation of your module.
constructor¶
new Logger(options);
Creates a new Logger instance.
Parameters¶
options
-LoggerOptions
: options for Logger constructor.log
-Function
(optional): function to use for logging:(message, level) => {...}
logLevel
-LogLevel
(optional): messages with this level will be logged withlog
logLog
-LogLogInterface
(optional): container for collecting log messageslogLogLevel
-LogLevel
(optional): messages with this level will be pushed tologLog
Returns¶
Logger
instance
log¶
logger.log(message, level);
log message with given level
Parameters¶
message
-string
: log messagelevel
-string
: log level as string, defaults to ‘info’
Example¶
runtime.executor.log('test', 'error');
= Additional Components =¶
Validator¶
Class Name | Validator |
---|---|
Extends | Logger |
Source | validator.ts |
Examples | validator.spec.ts |
The Validator module can be used to verfiy given JSON schemas.
constructor¶
new Validator(options);
Creates a new Validator instance.
Parameters¶
options
-ValidatorOptions
: options for Validator constructor.schema
-any
: the validation schema definitionlog
-Function
(optional): function to use for logging:(message, level) => {...}
logLevel
-LogLevel
(optional): messages with this level will be logged withlog
logLog
-LogLogInterface
(optional): container for collecting log messageslogLogLevel
-LogLevel
(optional): messages with this level will be pushed tologLog
Returns¶
Validator
instance
Utils¶
Source | utils.ts |
---|
Utils contain helper functions which are used across the whole project
promisify¶
utils.promisify(funThis, functionName, ...args);
run given function from this, use function(error, result) {…} callback for promise resolve/reject
Parameters¶
funThis
-any
: the functions ‘this’ objectfunctionName
-string
: name of the contract function to call...args
-any
: any addtional parameters that should be passed to the called function
Returns¶
Promise resolves to any
: the result from the function(error, result) {…} callback.
Example¶
runtime.utils
.promisify(fs, 'readFile', 'somefile.txt')
.then(content => console.log('file content: ' + content))
obfuscate¶
utils.obfuscate(text);
obfuscates strings by replacing each character but the last two with ‘x’
Parameters¶
text
-string
: text to obfuscate
Returns¶
string
: obfuscated text
getSmartAgentAuthHeaders¶
utils.getSmartAgentAuthHeaders(runtime[, message]);
create auth header data to authenticate with current account against a smart agent server
Parameters¶
runtime
-Runtime
: an initialized runtimemessage
-string
(optional): message to sign, defaults to current timestamp
Returns¶
Promise resolves to string
: auth header value as string
Example¶
const authData = await getSmartAgentAuthHeaders(runtime);
console.log(authData);
// Output:
// EvanAuth 0x001De828935e8c7e4cb56Fe610495cAe63fb2612,EvanMessage 1566569193297,EvanSignedMessage 0x4ce5c94b3fb77e6fbd7dcbbedc564058d841c849020f11514b7e525776b033eb6cb54f480b604ae7dccb9858eb116267cfe547fab52679730b5e33ac975dbbab1b
This section contains modules, that are used througout the code, the Logger
for example is the base class for almost every module and enables them to log in a structured manner.
Contracts¶
Contract Loader¶
Class Name | ContractLoader |
---|---|
Extends | Logger |
Source | contract-loader.ts |
Examples | contract-loader.spec.ts |
The ContractLoader is used when loading contracts without a DBCP description or when creating new contracts via bytecode. In both cases additional information has to be passed to the ContractLoader constructor.
Loading contracts requires an abi interface as a JSON string and creating new contracts requires the bytecode as hex string. Compiling Ethereum smart contracts with solc provides these.
Abis, that are included by default are:
- AbstractENS
- Described
- EventHub
- Owned
- PublicResolver
Bytecode for these contracts is included by default:
- Described
- Owned
Following is an example for loading a contract with a custom abi. The contract is a Greeter Contract and a shortened interface containing only the greet function is used here.
They can be side-loaded into an existing contract loader instance, e.g. into a runtime:
runtime.contractLoader.contracts['Greeter'] = {
"interface": "[{\"constant\":true,\"inputs\":[],\"name\":\"greet\",\"outputs\":[{\"name\":\"\",\"type\":\"string\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"}]",
};
getCompiledContract¶
contractLoader.getCompiledContract(name);
gets contract from a solc compilation
Parameters¶
name
-string
: Contract name
Returns¶
any
: The compiled contract.
Example¶
const address = '0x9c0Aaa728Daa085Dfe85D3C72eE1c1AdF425be49';
const accountId = '0x000000000000000000000000000000000000beef';
const description = await runtime.description.getDescription(address, accountId);
console.dir(description);
// Output:
// { public:
// { name: 'DBCP sample greeter',
// description: 'smart contract with a greeting message and a data property',
// author: 'dbcp test',
// tags: [ 'example', 'greeter' ],
// version: '0.1.0',
// abis: { own: [Array] } } }
loadContract¶
contractLoader.loadContract(name, address);
creates a contract instance that handles a smart contract at a given address
Parameters¶
name
-string
: Contract nameaddress
-string
: Contract address
Returns¶
any
: contract instance.
Example¶
const greeter = runtime.contractLoader.loadContract('Greeter', '0x9c0Aaa728Daa085Dfe85D3C72eE1c1AdF425be49');
Rights and Roles¶
Class Name | RightsAndRoles |
---|---|
Extends | Logger |
Source | rights-and-roles.ts |
Examples | rights-and-roles.spec.ts |
The RightsAndRoles module follows the approach described in the evan.network wik at:
It allows to manage permissions for contracts, that use the authority DSRolesPerContract.sol for as its permission approach.
Contracts, that use DSRolesPerContract and therefore allow to configure its permissions with the RightsAndRoles
module are:
Also have a look at the Smart Contract Permissioning section in the evan.network wiki.
constructor¶
new RightsAndRole(options);
Creates new RightsAndRole instance.
Parameters¶
options
-RightsAndRolesOptions
: options for RightsAndRole constructor.contractLoader
-ContractLoader
:ContractLoader
instanceexecutor
-Executor
:Executor
instancenameResolver
-NameResolver
:NameResolver
instanceweb3
-Web3
:Web3
instancelog
-Function
(optional): function to use for logging:(message, level) => {...}
logLevel
-LogLevel
(optional): messages with this level will be logged withlog
logLog
-LogLogInterface
(optional): container for collecting log messageslogLogLevel
-LogLevel
(optional): messages with this level will be pushed tologLog
Returns¶
RightsAndRoles
instance
Example¶
const rightsAndRoles = new RightsAndRoles({
contractLoader,
executor,
nameResolver,
web3,
});
addAccountToRole¶
rightsAndRoles.addAccountToRole(contract, accountId, targetAccountId, role);
Adds the traget account to a specific role.
The main principle is that accounts can be assigned to roles and those roles can be granted capabilities. Function Permissions are basically the capability to call specific functions if the calling account belongs to a certain role. To add an account to the role ‘member’.
Parameters¶
contract
-string|any
: contractId or contract instanceaccountId
-string
: executing accountIdtargetAccountId
-string
: target accountIdrole
-number
: roleId
Returns¶
Promise
returns void
: resolved when done
Example¶
const contractOwner = '0x0000000000000000000000000000000000000001';
const newMember = '0x0000000000000000000000000000000000000002';
const memberRole = 1;
await rightsAndRoles.addAccountToRole(
contract, // contract to be updated
contractOwner, // account, that can change permissions
newMember, // add this account to role
memberRole, // role id, uint8 value
);
removeAccountFromRole¶
rightsAndRoles.removeAccountFromRole(contract, accountId, targetAccountId, role);
Removes target account from a specific role.
Parameters¶
contract
-string|any
: contractId or contract instanceaccountId
-string
: executing accountIdtargetAccountId
-string
: target accountIdrole
-number
: roleId
Returns¶
Promise
returns void
: resolved when done
Example¶
const contractOwner = '0x0000000000000000000000000000000000000001';
const newMember = '0x0000000000000000000000000000000000000002';
const memberRole = 1;
await rightsAndRoles.removeAccountFromRole(
contract, // contract to be updated
contractOwner, // account, that can change permissions
newMember, // remove this account from role
memberRole, // role id, uint8 value
);
getMembers¶
rightsAndRoles.getMembers(contract);
Returns all roles with all members.
The DSRolesPerContract authority tracks used roles and their members and allows to retrieve an overview with all roles and their members. To get this information, you can use the getMembes
function.
Parameters¶
contract
-string|any
: contractId or contract instance
Returns¶
Promise
returns any
: Object with mapping roleId -> [accountId, accountId,…]
Example¶
const members = await rightsAndRoles.getMembers(contract);
console.log(members);
// Output:
// {
// "0": [
// "0x0000000000000000000000000000000000000001"
// ],
// "1": [
// "0x0000000000000000000000000000000000000001",
// "0x0000000000000000000000000000000000000002"
// ]
// }
The contract from this example has an owner (0x0000000000000000000000000000000000000001
) and a member (0x0000000000000000000000000000000000000002
). As the owner account has the member role as well, it is listed among the members.
setFunctionPermission¶
rightsAndRoles.setFunctionPermission(contract, accountId, role, functionSignature, allow);
Allows or denies contract function for the accountId.
“Function permissions” are granted or denied by allowing a certain role to execute a specific function. The function is specified as the unhashed function selector and must follow its guidelines (no spaces, property typenames, etc.) for the function to be able to generate valid hashes for later validations. E.g. to grant the role “member” the permission to use the function addListEntries, that has two arguments (a bytes32
array and a bytes32
value), the function permission for addListEntries(bytes32[],bytes32[])
has to be granted.
Parameters¶
contract
-string|any
: contractId or contract instanceaccountId
-string
: executing accountIdrole
-number
: role idfunctionSignature
-string
: 4 Bytes function signatureallow
-boolean
: allow or deny function
Returns¶
Promise
returns void
: resolved when done
Example¶
const contractOwner = '0x0000000000000000000000000000000000000001';
const memberRole = 1;
await rightsAndRoles.setFunctionPermission(
contract, // contract to be updated
contractOwner, // account, that can change permissions
memberRole, // role id, uint8 value
'addListEntries(bytes32[],bytes32[])', // (unhashed) function selector
true, // grant this capability
);
setOperationPermission¶
rightsAndRoles.setOperationPermission(contract, accountId, role, propertyName, propertyType, modificationType, allow);
Allows or denies setting properties on a contract.
“Operation Permissions” are capabilities granted per contract logic. They have a bytes32
key, that represents the capability, e.g. in a DataContract a capability to add values to a certain list can be granted.
The way, those capability hashes are build, depends on the contract logic and differs from contract to contract. For example a capability check for validation if a member is allowed to add an item to the list “example” in a DataContract has four arguments, in this case:
- which role is allowed to do? (e.g. a member)
- what type of element is modified? (–> a list)
- which element is modified? (name of the list –> “example”)
- type of the modification (–> “set an item” (== “add an item”))
These four values are combined into one bytes32
value, that is used when granting or checking permissions, the setOperationPermission
function takes care of that.
Parameters¶
contract
-string|any
: contractId or contract instanceaccountId
-string
: executing accountIdrole
-number
: roleIdpropertyName
-string
: target property namepropertyType
-PropertyType
: list or entrymodificationType
-ModificationType
: set or removeallow
-boolean
: allow or deny
Returns¶
Promise
returns void
: resolved when done
Example¶
// make sure, you have required the enums from rights-and-roles.ts
import { ModificationType, PropertyType } from '@evan.network/api-blockchain-core';
const contractOwner = '0x0000000000000000000000000000000000000001';
const memberRole = 1;
await rightsAndRoles.setOperationPermission(
contract, // contract to be updated
contractOwner, // account, that can change permissions
memberRole, // role id, uint8 value
'example', // name of the object
PropertyType.ListEntry, // what type of element is modified
ModificationType.Set, // type of the modification
true, // grant this capability
);
hasUserRole¶
rightsAndRoles.hasUserRole(contract, accountId, targetAccountId, role);
Returns true or false, depending on if the account has the specific role.
Parameters¶
contract
-string|any
: contractId or contract instanceaccountId
-string
: executing accountIdtargetAccountId
-string
: to be checked accountIdrole
-number
: roleId
Returns¶
Promise
returns void
: resolved when done
Example¶
const accountToCheck = '0x0000000000000000000000000000000000000002';
const memberRole = 1;
const hasRole = await rightsAndRoles.hashUserRole(contract, null, accountToCheck, memberRole);
console.log(hasRole);
// Output:
// true
transferOwnership¶
rightsAndRoles.transferOwnership();
Function description
Parameters¶
contract
-string|any
: contractId or contract instanceaccountId
-string
: executing accountIdtargetAccountId
-string
: target accountId
Returns¶
Promise
returns void
: resolved when done
Example¶
const contractOwner = '0x0000000000000000000000000000000000000001';
const newOwner = '0x0000000000000000000000000000000000000002';
await rightsAndRoles.transferOwnership(
contract, // contract to be updated
contractOwner, // current owner
newOwner, // this account becomes new owner
);
Sharing¶
Class Name | Sharing |
---|---|
Extends | Logger |
Source | sharing.ts |
Examples | sharing.spec.ts |
For getting a better understanding about how Sharings and Multikeys work, have a look at Security in the evan.network wiki.
Following is a sample for a sharing info with these properties:
- three users
0x01
- owner of a contract0x02
- member of a contract0x03
- another member with differing permissions
- two timestamps
- block 82745 - first sharing
- block 90000 - splitting data, update sharings
- three sections
*
generic “catch all” used in first sharingsecret area
- available for all memberssuper secret area
- available for0x03
{
"0x01": {
"82745": {
"*": {
"private": "secret for 0x01, starting from block 82745 for all data",
"cryptoInfo": {
"originator": "0x01,0x01",
"keyLength": 256,
"algorithm": "aes-256-cbc"
}
}
},
"90000": {
"secret area": {
"private": "secret for 0x01, starting from block 90000 for 'secret area'",
"cryptoInfo": {
"originator": "0x01,0x01",
"keyLength": 256,
"algorithm": "aes-256-cbc"
}
},
"super secret area": {
"private": "secret for 0x01, starting from block 90000 for 'super secret area'",
"cryptoInfo": {
"originator": "0x01,0x01",
"keyLength": 256,
"algorithm": "aes-256-cbc"
}
}
}
},
"0x02": {
"82745": {
"*": {
"private": "secret for 0x02, starting from block 82745 for all data",
"cryptoInfo": {
"originator": "0x01,0x02",
"keyLength": 256,
"algorithm": "aes-256-cbc"
}
}
},
"90000": {
"secret area": {
"private": "secret for 0x02, starting from block 90000 for 'secret area'",
"cryptoInfo": {
"originator": "0x01,0x02",
"keyLength": 256,
"algorithm": "aes-256-cbc"
}
},
"super secret area": {
"private": "secret for 0x02, starting from block 90000 for 'super secret area'",
"cryptoInfo": {
"originator": "0x01,0x02",
"keyLength": 256,
"algorithm": "aes-256-cbc"
}
}
},
},
"0x03": {
"90000": {
"secret area": {
"private": "secret for 0x03, starting from block 90000 for 'secret area'",
"cryptoInfo": {
"originator": "0x01,0x03",
"keyLength": 256,
"algorithm": "aes-256-cbc"
}
}
}
}
}
More information about sharings can be found at the evan.network wiki.
There are two functions to share keys with another user:
- addSharing is used for easily sharing keys to another user. There is no need to explicitly share hash keys to this other user as this is automatically covered here. This approach make up to two transaction (1 for hash key and 1 for the content key), which may sum up to a whole bunch of transactions when sharing multiple keys to multiple users.
- extendSharing is used to edit a sharings configuration that has been pulled or “checked out” with getSharingsFromContract. Hash keys have to be shared manually, if required. extendSharing make no transaction, so the contract isn’t updated - this has to be done with saveSharingsToContract. See function documentation below for an example with hash key and storing updates.
Be careful when performing multiple updates to sharings synchronously. As sharings are retrieved as a single file from a smart contract, updated and then saved back to it, doing two or more updates in parallel may overwrite each other and lead to unexpected and most probably undesired results.
Perform sharing updates for the same contracts one after another, this goes for addSharing and for extendSharing. When wishing to speed things up, extendSharing can be used, but its updates need to be performed synchronously as well. Keep in mind, that single updates will be made off-chain and therefore be performed much faster than multiple updates with addSharing.
constructor¶
new Sharing(options);
Creates a new Sharing instance.
Parameters¶
options
-SharingOptions
: options for Sharing constructor.contractLoader
-ContractLoader
:ContractLoader
instancecryptoProvider
-CryptoProvider
:CryptoProvider
instancedescription
-Description
:Description
instancedfs
-DfsInterface
:DfsInterface
instanceexecutor
-Executor
:Executor
instancekeyProvider
-KeyProvider
:KeyProvider
instancenameResolver
-NameResolver
:NameResolver
instancedefaultCryptoAlgo
-string
(optional): crypto algorith name fromCryptoProvider
, defaults toaes
log
-Function
(optional): function to use for logging:(message, level) => {...}
logLevel
-LogLevel
(optional): messages with this level will be logged withlog
logLog
-LogLogInterface
(optional): container for collecting log messageslogLogLevel
-LogLevel
(optional): messages with this level will be pushed tologLog
Returns¶
Sharing
instance
Example¶
const sharing = new Sharing({
contractLoader,
cryptoProvider,
description,
executor,
dfs,
keyProvider,
nameResolver,
defaultCryptoAlgo: 'aes',
});
addSharing¶
sharing.addSharing(address, originator, partner, section, block, sharingKey[, context, isHashKey, sharingId]);
Add a sharing to a contract or an ENS address.
This function is primarily used for sharing single keys with one other users, when sharing multiple keys and/or sharing with multiple users, have a look at extendSharing.
Parameters¶
address
-string
: contract address or ENS addressoriginator
-string
: Ethereum account id of the sharing userpartner
-string
: Ethereum account id for which key shall be addedsection
-string
: data section the key is intended for or ‘*’block
-number|string
: starting with this block, the key is validsharingKey
-string
: key to sharecontext
-string
(optional): context to share key inisHashKey
-bool
(optional): indicates if given key already is a hash key, defaults tofalse
sharingId
-string
(optional): id of a sharing (when multi-sharings is used)
Returns¶
Promise
returns void
: resolved when done
Example¶
// two sample users, user1 wants to share a key with user2
const user1 = '0x0000000000000000000000000000000000000001';
const user2 = '0x0000000000000000000000000000000000000002';
// create a sample contract
// usually you would have an existing contract, for which you want to manage the sharings
const contract = await executor.createContract('Shared', [], { from: user1, gas: 500000, });
// user1 shares the given key with user2
// this key is shared for all contexts ('*') and valid starting with block 0
await sharing.addSharing(contract.options.address, user1, user2, '*', 0, 'i am the secred that will be shared');
extendSharing¶
sharing.extendSharing(address, originator, partner, section, block, sharingKey[, context, isHashKey]);
Extend an existing sharing info with given key.
This is done on a sharings object and does not perform a transaction on its own. This function extends a sharing object retrieved from getSharingsFromContract and does not update sharings at the smart contract. For updating smart contracts sharing use saveSharingsToContract.
This function is primarily used to prepare updates for multiple keys and/or multiple users and submitting the result in one single transaction. For simpler sharing scenarios have a look at addSharing.
Parameters¶
sharings
-any
: object with sharings infooriginator
-string
: Ethereum account id of the sharing userpartner
-string
: Ethereum account id for which key shall be addedsection
-string
: data section the key is intended for or ‘*’block
-number|string
: starting with this block, the key is validsharingKey
-string
: key to sharecontext
-string
(optional): context to share key in
Returns¶
Promise
returns any
: updated sharings info
Example¶
// two sample users, user1 wants to share a key with user2
const user1 = '0x0000000000000000000000000000000000000001';
const user2 = '0x0000000000000000000000000000000000000002';
// get current sharings
const sharings = await sharing.getSharingsFromContract(contract);
// if receiver of sharing hasn't been added to the contract yet, share hash key as well
const hashKeyToShare = await sharing.getHashKey(contract.options.address, user1);
await sharing.extendSharings(sharings, user1, user2, '*', 'hashKey', hashKeyToShare, null);
// get current block number, keys will be available starting from this block
const blockNr = await web3.eth.getBlockNumber();
// get current key for field or in this case fallback '*'
const contentKey = sharing.getKey(contract.options.address, user1, '*', blockNr);
// share this key
await sharing.extendSharings(sharings, user1, user2, '*', blockNr, contentKey);
// finally store to contract
await sharing.saveSharingsToContract(contract.options.address, sharings, user1);
trimSharings¶
sharing.trimSharings(sharings, partner[, partner, section, block);
Removes properties from given sharing. If a block is given, the specific blocks key is removed, if no block is given, all keys for this section are removed. The same goes for section and partner. Note that only the last properties can be omitted and not properties in between can be set to null. So for example it is not possible to remove the same field for all accounts by just setting partner to null.
Parameters¶
sharings
-any
: sharings to trimpartner
-string
: Ethereum account id to remove keys forsection
-string
: data section the key is intended for or ‘*’block
-number|string
: block to remove keys for
Returns¶
Promise
returns void
: resolved when done
Example¶
// this sample will undo undo the changes from the last example (extendSharings)
// two sample users, user1 wants to share a key with user2
const user1 = '0x0000000000000000000000000000000000000001';
const user2 = '0x0000000000000000000000000000000000000002';
// get current sharings
const sharings = await sharing.getSharingsFromContract(contract);
// remove key from last time
await sharing.trim(sharings, user2, '*', blockNr);
// finally store to contract
await sharing.saveSharingsToContract(contract.options.address, sharings, user1);
bumpSharings¶
sharing.bumpSharings(address, originator, partners, section, block, sharingKey);
Bump keys for given accounts by adding given key to their sharings. This is basically a shorthand
version for adding the new key for every account in the partners
array in a single transaction.
context
, hashKeys
and sharingId
are currently not supported.
Parameters¶
address
-string
: contract address or ENS addressoriginator
-string
: Ethereum account id of the sharing userpartner
-string
: Ethereum account id for which key shall be addedsection
-string
: data section the key is intended for or ‘*’block
-number|string
: starting with this block, the key is validsharingKey
-string
: key to share
Returns¶
Promise
returns void
: resolved when done
Example¶
// two sample users, user1 wants to bump keys for user2 and user3
const user1 = '0x0000000000000000000000000000000000000001';
const user2 = '0x0000000000000000000000000000000000000002';
const user3 = '0x0000000000000000000000000000000000000003';
// assume we have a contract with sharings for those accounts
const contractId = '0x00000000000000000000000000000000c027rac7';
await sharing.bumpSharings(contractId, user1, [ user2, user3 ], '*', 0, 'i am a bump key');
getKey¶
sharing.getKey(address, partner, section[, block, sharingId]);
Get a content key from the sharing of a contract.
Parameters¶
address
-string
: contract address or ENS addresspartner
-string
: Ethereum account id for which key shall be retrievedsection
-string
: data section the key is intended for or ‘*’block
-number|string
(optional): starting with this block, the key is valid, defaults toNumber.MAX_SAFE_INTEGER
sharingId
-string
(optional): id of a sharing (when multi-sharings is used), defaults tonull
Returns¶
Promise
returns string
: matching key
Example¶
// a sample user
const user2 = '0x0000000000000000000000000000000000000002';
// user2 wants to read a key after receiving a sharing
// the key requested should be valid for all contexts ('*') and valid up to and including block 100
const key = await sharing.getKey(contract.options.address, user2, '*', 100);
getKeyHistory¶
sharing.getKeyHistory(address, partner, section[, sharingId]);
Get history of keys for an account and a section.
Parameters¶
address
-string
: contract address or ENS addresspartner
-string
: Ethereum account id for which key shall be retrievedsection
-string
: data section the key is intended for or ‘*’sharingId
-string
(optional): id of a sharing (when multi-sharings is used), defaults tonull
Returns¶
Promise
returns any
: object with key: blockNr, value: key
Example¶
// a sample user
const user2 = '0x0000000000000000000000000000000000000002';
// user2 wants to retrieve all keys for '*'
const keyHistory = await sharing.getKeyHistory(contract.options.address, user2, '*');
ensureHashKey¶
sharing.ensureHashKey(address, originator, partner, hashKey[, context, sharingId]);
Give hash key “hashKey” to account “partner”, if this account does not have a hash key already.
Parameters¶
address
-string
: contract address or ENS addressoriginator
-string
: Ethereum account id of the sharing userpartner
-string
: Ethereum account id for which key shall be addedhashKey
-string
: key for DFS hashescontext
-string
(optional): context to share key insharingId
-string
(optional): id of a sharing (when multi-sharings is used)
Returns¶
Promise
returns void
: resolved when done
Example¶
const hashCryptor = cryptoProvider.getCryptorByCryptoAlgo('aesEcb');
const hashKey = await hashCryptor.generateKey();
await sharing.ensureHashKey(contract.options.address, accounts[0], accounts[1], hashKey);
getHashKey¶
sharing.getHashKey(address, partner[, sharingid]);
Function description
Parameters¶
address
-string
: contract address or ENS addresspartner
-string
: Ethereum account id for which key shall be retrievedsharingId
-string
(optional): id of a sharing (when multi-sharings is used)
Returns¶
Promise
returns string
: matching key
Example¶
const hashCryptor = cryptoProvider.getCryptorByCryptoAlgo('aesEcb');
const hashKey = await hashCryptor.generateKey();
await sharing.ensureHashKey(contract.options.address, accounts[0], accounts[1], hashKey);
const retrieved = sharing.getHashKey(contract.options.address, accounts[1]);
console.log(hashKey === retrieved);
// Output:
// true
getSharings¶
sharing.getSharings(address[, _partner, _section, _block, sharingId]);
Get sharing from a contract, if _partner, _section, _block matches.
Parameters¶
address
-string
: contract address or ENS address_partner
-string
(optional): Ethereum account id for which key shall be retrieved_section
-string
(optional): data section the key is intended for or ‘*’_block
-number
(optional): starting with this block, the key is validsharingId
-string
(optional): id of a sharing (when multi-sharings is used)
Returns¶
Promise
returns void
: resolved when done
Example¶
const randomSecret = `super secret; ${Math.random()}`;
await sharing.addSharing(testAddress, accounts[1], accounts[0], '*', 0, randomSecret);
const sharings = await sharing.getSharings(testAddress);
removeSharing¶
sharing.removeSharing(address, originator, partner, section[, sharingId]);
Remove a sharing key from a contract with sharing info.
Parameters¶
address
-string
: contract address or ENS addressoriginator
-string
: Ethereum account id of the sharing userpartner
-string
: Ethereum account id for which key shall be removedsection
-string
: data section of the keysharingId
-string
(optional): id of a sharing (when multi-sharings is used), defaults tonull
Returns¶
Promise
returns void
: resolved when done
Example¶
await sharing.addSharing(contract.options.address, accounts[0], accounts[1], '*', 0, randomSecret);
let sharings = await sharing.getSharings(contract.options.address);
console.log(Object.keys(sharings[nameResolver.soliditySha3(accounts[1])]).length);
// Output:
// 1
await sharing.removeSharing(contract.options.address, accounts[0], accounts[1], '*');
let sharings = await sharing.getSharings(contract.options.address);
console.log(Object.keys(sharings[nameResolver.soliditySha3(accounts[1])]).length);
// Output:
// 0
getSharingsFromContract¶
sharing.getSharingsFromContract(contract[, sharingId]);
Get encrypted sharings from smart contract.
This can be used in combination with getSharingsFromContract to bulk editing sharing info.
Parameters¶
contact
-any
: contract with sharing infosharingId
-string
(optional): id of a sharing in mutlisharings, defaults tonull
Returns¶
Promise
returns void
: resolved when done
Example¶
// get sharings (encrypted)
const sharings = await sharing.getSharingsFromContract(serviceContract, callIdHash);
// make changes to sharing
await sharing.extendSharings(sharings, accountId, target, section, 0, contentKeyToShare, null);
await sharing.extendSharings(sharings, accountId, target, '*', 'hashKey', hashKeyToShare, null);
// commit changes
await sharing.saveSharingsToContract(serviceContract.options.address, sharings, accountId, callIdHash);
saveSharingsToContract¶
sharing.saveSharingsToContract(contract, sharings, originator[, sharingId]);
Save sharings object with encrypted keys to contract.
This can be used to pull sharings, edit them offline and commit changes in a bulk. See example section for usage.
Parameters¶
contract
-string|any
: contract address or instancesharings
-any
: sharings object with encrypted keysoriginator
-string
: Ethereum account id of the sharing usersharingId
-string
(optional): id of a sharing (when multi-sharings is used)
Returns¶
Promise
returns void
: resolved when done
Example¶
// get sharings (encrypted)
const sharings = await sharing.getSharingsFromContract(serviceContract, callIdHash);
// make changes to sharing
await sharing.extendSharings(sharings, accountId, target, section, 0, contentKeyToShare, null);
await sharing.extendSharings(sharings, accountId, target, '*', 'hashKey', hashKeyToShare, null);
// commit changes
await sharing.saveSharingsToContract(serviceContract.options.address, sharings, accountId, callIdHash);
addHashToCache¶
sharing.addHashToCache(address, sharingHash[, sharingId]);
Add a hash to to cache, can be used to speed up sharing key retrieval, when sharings hash is already known.
Parameters¶
address
-string
: contract addresssharingHash
-string
: bytes32 hash of a sharingsharingId
-string
(optional): id of a multisharing, defaults tonull
clearCache¶
sharing.clearCache();
Clear caches and fetch new hashes and sharing on next request.
When sharings are fetched and not all results could be read, the result would stay the same in following requests due to the internal caching mechanism, even if a proper key has been shared with the user later on. To prevent such old values from showing up, the cache can be cleared.
Example¶
sharing.clearCache();
Base Contract¶
Class Name | BaseContract |
---|---|
Extends | Logger |
Source | base-contract.ts |
Examples | base-contract.spec.ts |
The BaseContract is the base contract class used for
Contracts, that inherit from BaseContracts
, are able to:
- manage a list of contract participants (called “members”)
- manage the own state (a flag, that indicate its own life cycle status)
- manage members state (a flag, that indicate the members state in the contract)
What members can do, what non-members cannot do depends of the implementatin of the inheriting contracts.
constructor¶
new BaseContract(options);
Creates a new BaseContract instance.
Parameters¶
options
-BaseContractOptions
: options for BaseContract constructor.executor
-Executor
:Executor
instanceloader
-ContractLoader
:ContractLoader
instancenameResolver
-NameResolver
:NameResolver
instancelog
-Function
(optional): function to use for logging:(message, level) => {...}
logLevel
-LogLevel
(optional): messages with this level will be logged withlog
logLog
-LogLogInterface
(optional): container for collecting log messageslogLogLevel
-LogLevel
(optional): messages with this level will be pushed tologLog
Returns¶
BaseContract
instance
Example¶
const baseContract = new BaseContract({
executor,
loader,
nameResolver,
});
createUninitialized¶
baseContract.createUninitialized(factoryName, accountId[, businessCenterDomain, descriptionDfsHash]);
Create new contract but do not initialize it yet.
The API supports creating contracts, that inhert from BaseContract
. This is done by calling the respective factory. The factory calls are done via a function with this interface:
/// @notice create new contract instance
/// @param businessCenter address of the BusinessCenter to use or 0x0
/// @param provider future owner of the contract
/// @param _contractDescription DBCP definition of the contract
/// @param ensAddress address of the ENS contract
function createContract(
address businessCenter,
address provider,
bytes32 contractDescription,
address ensAddress) public returns (address);
The API supports creating contracts with this function. Contracts created this way may not be ready to use and require an additional function at the contract to be called before usage. This function is usually called init
and its arguments and implementation depends of the specific contract.
The createUninitialized
function performs a lookup for the respective factory contract and calls the createContract
function at it.
Parameters¶
factoryName
-string
: contract factory name, used for ENS lookup; if the factory name contains periods, it is threaded as an absolute ENS domain and used as such, if not it will be used as${factoryName}.factory.${businessCenterDomain}
accountId
-string
: Ethereum account idbusinessCenterDomain
-string
(optional): business center in which the contract will be created; usenull
when working without business centerdescriptionDfsHash
-string
(optional): bytes32 hash for description in dfs
Returns¶
Promise
returns string
: Ethereum id of new contract
Example¶
const contractOwner = '0x...';
const businessCenterDomain = 'testbc.evan';
const contractId = await baseContract.createUninitialized(
'testdatacontract', // factory name
contractOwner, // account, that will be owner of the new contract
businessCenterDomain, // business center, where the new contract will be created
);
inviteToContract¶
baseContract.inviteToContract(businessCenterDomain, contract, inviterId, inviteeId);
Invite user to contract. To allow accounts to work with contract resources, they have to be added as members to the contract. This function does exactly that.
Parameters¶
businessCenterDomain
-string
: ENS domain name of the business center the contract was created in; use null when working without business centercontract
-string
: Ethereum id of the contractinviterId
-string
: account id of inviting userinviteeId
-string
: account id of invited user
Returns¶
Promise
returns void
: resolved when done
Example¶
const contractOwner = '0x0000000000000000000000000000000000000001';
const invitee = '0x0000000000000000000000000000000000000002';
const businessCenterDomain = 'testbc.evan';
const contract = loader.loadContract('BaseContractInterface', contractId);
await baseContract.inviteToContract(
businessCenterDomain,
contractId,
contractOwner,
invitee,
);
To check if an account is a member of a contract, the contract function isMember
can be used:
const isMember = await executor.executeContractCall(contract, 'isConsumer', invitee);
console.log(isMember);
// Output:
// true
removeFromContract¶
baseContract.removeFromContract(businessCenterDomain, contract, accountId, idToBeRemoved);
Remove user from contract. To deny previously invited accounts to work with contract resources, they have to be removed as members from the contract. This function does exactly that.
Parameters¶
businessCenterDomain
-string
: ENS domain name of the business center the contract was created in; use null when working without business centercontract
-string
: Ethereum id of the contractaccountId
-string
: account id of executing useridToBeRemoved
-string
: account id which should be removed
Returns¶
Promise
returns void
: resolved when done
Example¶
const contractOwner = '0x0000000000000000000000000000000000000001';
const idToBeRemoved = '0x0000000000000000000000000000000000000002';
const businessCenterDomain = 'testbc.evan';
const contract = loader.loadContract('BaseContractInterface', contractId);
await baseContract.removeFromContract(
businessCenterDomain,
contractId,
contractOwner,
idToBeRemoved,
);
To check if an account is a member of a contract, the contract function isMember
can be used:
const isMember = await executor.executeContractCall(contract, 'isConsumer', idToBeRemoved);
console.log(isMember);
// Output:
// false
changeConsumerState¶
baseContract.changeContractState(contract, accountId, consumerId, state);
set state of a consumer. A members state reflects this members status in the contract. These status values can for example be be Active, Draft or Terminated.
Parameters¶
contract
-string|any
: contract instance or contract idaccountId
-string
: Ethereum account idconsumerId
-string
: Ethereum account idstate
-ConsumerState
: new state
Returns¶
Promise
returns void
: resolved when done
Example¶
await baseContract.changeConsumerState(contractId, accountId, consumerId, ConsumerState.Active);
ConsumerState
is an enum in the BaseContract class, that holds the same state values as the BaseContract.sol. Alternatively integer values matching the enum in BaseContractInterface.sol can be used.
changeContractState¶
baseContract.changeContractState(contract, accountId, state);
Set state of the contract. The contracts state reflects the current state and how other members may be able to interact with it. So for example, a contract for tasks cannot have its tasks resolved, when the contract is still in Draft state. State transitions are limited to configured roles and allow going from one state to another only if configured for this role.
Parameters¶
contract
-string|any
: contract instance or contract idaccountId
-string
: Ethereum account idstate
-ContractState
: new state
Returns¶
Promise
returns void
: resolved when done
Example¶
await baseContract.changeContractState(contractId, contractOwner, ContractState.Active);
ContractState
is an enum in the BaseContract class, that holds the same state values as the BaseContract.sol. Alternatively integer values matching the enum in BaseContractInterface.sol can be used.
Additional Components¶
Enums¶
ContractState¶
Describes contracts overall state.
In most cases, this property can only be set by the contract owner.
export enum ContractState {
Initial,
Error,
Draft,
PendingApproval,
Approved,
Active,
VerifyTerminated,
Terminated,
};
ConsumerState¶
Describes the state of a consumer or owner in a contract.
In most cases, this can be set the the member, thats status is updated or by a more privileged role, like a contract owner.
export enum ConsumerState {
Initial,
Error,
Draft,
Rejected,
Active,
Terminated
};
Data Contract¶
Class Name | DataContract |
---|---|
Extends | BaseContract |
Source | data-contract.ts |
Examples | data-contract.spec.ts |
The DataContract is a secured data storage contract for single properties and lists. If created on its own, DataContracts cannot do very much. They rely on their authority to check which entries or lists can be used.
The following functions support the encryptionContext
argument:
If this argument is set, the data key in the data contracts sharing is encrypted by using a context key instead of the communication key between owner and contract member. This allows to omit key exchanges between contract owner and members and therefore enables the owner to write content to the smart contract, that can be used by a group of accounts, which only needs to hold the context key. So the encryptionContext
can be used to address a group of accounts instead of single accounts.
For more information about DataContracts purpose and their authorities see Data Contract in the evan.network wiki.
constructor¶
new DataContract(options);
Creates a new DataContract instance.
Parameters¶
options
-DataContractOptions
: options for DataContract constructor.cryptoProvider
-CryptoProvider
:CryptoProvider
instancedefaultCryptoAlgo
-string
(optional): crypto algorith name fromCryptoProvider
, defaults toaes
dfs
-DfsInterface
:DfsInterface
instanceexecutor
-Executor
:Executor
instanceloader
-ContractLoader
:ContractLoader
instancenameResolver
-NameResolver
:NameResolver
instancesharing
-Sharing
:Sharing
instancelog
-Function
(optional): function to use for logging:(message, level) => {...}
logLevel
-LogLevel
(optional): messages with this level will be logged withlog
logLog
-LogLogInterface
(optional): container for collecting log messageslogLogLevel
-LogLevel
(optional): messages with this level will be pushed tologLog
Returns¶
DataContract
instance
Example¶
const dataContract = new DataContract({
cryptoProvider,
description,
dfs,
executor,
loader,
nameResolver,
sharing,
web3,
});
create¶
dataContract.create(factoryName, accountId[, businessCenterDomain, contractDescription, allowConsumerInvite, sharingsHash]);
Create and initialize new contract.
Parameters¶
factoryName
-string
: contract factory name, used for ENS lookup; if the factory name contains periods, it is threaded as an absolute ENS domain and used as such, if not it will be used as${factoryName}.factory.${businessCenterDomain}
accountId
-string
: owner of the new contract and transaction executorbusinessCenterDomain
-string
(optional): ENS domain name of the business centercontractDescription
-string|any
(optional): bytes32 hash of DBCP description or a schema objectallowConsumerInvite
-bool
(optional): true if consumers are allowed to invite other consumersharingsHash
-string
(optional): existing sharing to add, defaults tonull
Returns¶
Promise
returns any
: contract instance
Example¶
Let’s say, we want to create a DataContract for a business center at the domain “samplebc.evan” and this business center has a DataContractFactory named “testdatacontract”. We want to have two users working in our DataContract, so we get these sample values:
const factoryName = 'testdatacontract';
const businessCenterDomain = 'samplebc.evan';
const accounts = [
'0x0000000000000000000000000000000000000001',
'0x0000000000000000000000000000000000000002',
];
Now create a contract with:
const contract = await dataContract.create(factoryName, accounts[0], businessCenterDomain);
Okay, that does not provide a description for the contract. Let’s add a description to the process. The definition is a DBCP contract definition and is stored in an Envelope
(see Encryption):
const definition: Envelope = {
"public": {
"name": "Data Contract Sample",
"description": "reiterance oxynitrate sat alternize acurative",
"version": "0.1.0",
"author": "evan GmbH",
"dataSchema": {
"list_settable_by_member": {
"$id": "list_settable_by_member_schema",
"type": "object",
"additionalProperties": false,
"properties": {
"foo": { "type": "string" },
"bar": { "type": "integer" }
}
},
"entry_settable_by_member": {
"$id": "entry_settable_by_member_schema",
"type": "integer",
}
}
}
};
definition.cryptoInfo = cryptoProvider.getCryptorByCryptoAlgo('aes').getCryptoInfo(accounts[0]);
const contract = await dataContract.create('testdatacontract', accounts[0], businessCenterDomain, definition);
Now we have a DataContract with a description. This contract is now able to be understood by other components, that understand the dbcp. And on top of that, we provided data schemas for the two properties list_settable_by_member
and entry_settable_by_member
(written for ajv). This means, that when someone adds or sets entries to or in those properties, the incoming data is validated before actually encrypting and storing it.
To allow other users to work on the contract, they have to be invited with:
await dataContract.inviteToContract(businessCenterDomain, contract.options.address, accounts[0], accounts[1]);
Now the user accounts[1]
can use functions from the contract, but to actually store data, the user needs access to the data key for the DataContract. This can be done via updating the contracts sharing:
const blockNr = await web3.eth.getBlockNumber();
const contentKey = await sharing.getKey(contract.options.address, accounts[0], '*', blockNr);
await sharing.addSharing(contract.options.address, accounts[0], accounts[1], '*', blockNr, contentKey);
Now the contract has been created, has a sharing and another user has been granted access to it. Variable names from this section will be used in the rest of the document as example values.
createSharing¶
dataContract.createSharing(accountId);
Create initial sharing for contract.
Parameters¶
accountId
-string
: owner of the new contract
Returns¶
Promise
returns any
: sharing info with { contentKey, hashKey, sharings, sharingsHash, }
Example¶
const sharing = await dataContract.createSharing(profileReceiver);
= Entries =¶
setEntry¶
dataContract.setEntry(contract, entryName, value, accountId[, dfsStorage, encryptedHashes, encryption);
Set entry for a key.
Parameters¶
contract
-any|string
: contract or contractIdentryName
-string
: entry namevalue
-any
: value to setaccountId
-string
: Ethereum account iddfsStorage
-Function
(optional): store values in dfs, defaults totrue
encryptedHashes
-boolean
(optional): encrypt hashes from values, defaults totrue
encryption
-string
(optional): encryption algorithm to use, defaults todefaultCryptoAlgo
(set in constructor)encryptionContext
-string
(optional): plain text name of an encryption context, defaults toaccountId
Returns¶
Promise
returns void
: resolved when done
Example¶
const sampleValue = 123;
await dataContract.setEntry(contract, 'entry_settable_by_owner', sampleValue, accounts[0]);
Entries are automatically encrypted before setting it in the contract. If you want to use values as is, without encrypting them, you can add them in raw mode, which sets them as bytes32
values:
const sampleValue = '0x000000000000000000000000000000000000007b';
await dataContract.setEntry(contract, 'entry_settable_by_owner', sampleValue, accounts[0], true);
getEntry¶
dataContract.getEntry(contract, entryName, accountId[, dfsStorage, encryptedHashes]);
Return entry from contract.
Parameters¶
contract
-any|string
: contract or contractIdentryName
-string
: entry nameaccountId
-string
: Ethereum account iddfsStorage
-Function
(optional): store values in dfs, defaults totrue
encryptedHashes
-boolean
(optional): decrypt hashes from values, defaults totrue
Returns¶
Promise
returns any
: entry
Example¶
Entries can be retrieved with:
const retrieved = await dataContract.getEntry(contract, 'entry_settable_by_owner', accounts[0]);
Raw values can be retrieved in the same way:
const retrieved = await dataContract.getEntry(contract, 'entry_settable_by_owner', accounts[0], true);
= List Entries =¶
addListEntries¶
dataContract.addListEntries(contract, listName, values, accountId[, dfsStorage, encryptedHashes, encryption]);
Add list entries to lists.
List entries support the raw mode as well. To use raw values, pass true
in the same way as wehn using the entries functions.
List entries can be added in bulk, so the value argument is an array with values. This array can be arbitrarily large up to a certain degree. Values are inserted on the blockchain side and adding very large arrays this way may take more gas during the contract transaction, than may fit into a single transaction. If this is the case, values can be added in chunks (multiple transactions).
Parameters¶
contract
-any|string
: contract or contractIdlistName
-string
: name of the list in the data contractvalues
-any[]
: values to addaccountId
-string
: Ethereum account iddfsStorage
-string
(optional): store values in dfs, defaults totrue
encryptedHashes
-boolean
(optional): encrypt hashes from values, defaults totrue
encryption
-string
(optional): encryption algorithm to use, defaults todefaultCryptoAlgo
(set in constructor)encryptionContext
-string
(optional): plain text name of an encryption context, defaults toaccountId
Returns¶
Promise
returns void
: resolved when done
Example¶
const sampleValue = {
foo: 'sample',
bar: 123,
};
await dataContract.addListEntries(contract, 'list_settable_by_member', [sampleValue], accounts[0]);
When using lists similar to tagging list entries with metadata, entries can be added in multiple lists at once by passing an array of list names:
const sampleValue = {
foo: 'sample',
bar: 123,
};
await dataContract.addListEntries(contract, ['list_1', 'list_2'], [sampleValue], accounts[0]);
getListEntryCount¶
dataContract.getListEntryCount(contract, listName, index, accountId[, dfsStorage, encryptedHashes]);
Return number of entries in the list. Does not try to actually fetch and decrypt values, but just returns the count.
Parameters¶
contract
-any|string
: contract or contractIdlistName
-string
: name of the list in the data contract
Returns¶
Promise
returns number
: list entry count
getListEntries¶
dataContract.getListEntries(contract, listName, accountId[, dfsStorage, encryptedHashes, count, offset, reverse]);
Return list entries from contract. Note, that in the current implementation, this function retrieves the entries one at a time and may take a longer time when querying large lists, so be aware of that, when you retrieve lists with many entries.
Parameters¶
contract
-any|string
: contract or contractIdlistName
-string
: name of the list in the data contractaccountId
-string
: Ethereum account iddfsStorage
-string
(optional): store values in dfs, defaults totrue
encryptedHashes
-boolean
(optional): decrypt hashes from values, defaults totrue
count
-number
(optional): number of elements to retrieve, defaults to10
offset
-number
(optional): skip this many items when retrieving, defaults to0
reverse
-boolean
(optional): retrieve items in reverse order, defaults tofalse
Returns¶
Promise
returns any[]
: list entries
getListEntry¶
dataContract.getListEntry(contract, listName, index, accountId[, dfsStorage, encryptedHashes]);
Return a single list entry from contract.
Parameters¶
contract
-any|string
: contract or contractIdlistName
-string
: name of the list in the data contractindex
-number
: list entry id to retrieveaccountId
-string
: Ethereum account iddfsStorage
-string
(optional): store values in dfs, defaults totrue
encryptedHashes
-boolean
(optional): decrypt hashes from values, defaults totrue
Returns¶
Promise
returns any
: list entry
Example¶
const itemIndex = 0;
await dataContract.getListEntry(contract, 'list_settable_by_member', itemIndex, accounts[0]));
removeListEntry¶
dataContract.removeListEntry(contract, listName, entryIndex, accountId);
Remove list entry from list.
This will reposition last list entry into emptied slot.
Attention¶
If the data contract was created by the container by the DigitalTwin
API you need to grant the permissions for
removing list entries manually. To do this you can use the RightsAndRoles
API. The following example shows
how to grant permissions to delete list entries from list exampleList to group 0.
// make sure, you have required the enums from rights-and-roles.ts
import { ModificationType, PropertyType } from '@evan.network/api-blockchain-core';
const contract = '0x0000000000000000000000000000000000000123';
const contractOwner = '0x0000000000000000000000000000000000000001';
await rightsAndRoles.setOperationPermission(
contract, // contract to be updated
contractOwner, // account, that can change permissions
0, // role id, uint8 value
'exampleList', // name of the object
PropertyType.ListEntry, // what type of element is modified
ModificationType.Remove, // type of the modification
true, // grant this capability
);
Parameters¶
contract
-any|string
: contract or contractIdlistName
-string
: name of the list in the data contractindex
-number
: index of the entry to remove from listaccountId
-string
: Ethereum account id
Returns¶
Promise
returns void
: resolved when done
Example¶
const listName = 'list_removable_by_owner'
const itemIndexInList = 1;
await dataContract.removeListEntry(contract, listNameF, itemIndexInList, accounts[0]);
moveListEntry¶
dataContract.moveListEntry(contract, listNameFrom, entryIndex, listNamesTo, accountId);
Move one list entry to one or more lists.
Note, that moving items requires the executing account to have remove
permissions on the list listNameFrom
. If this isn’t the case, the transaction will not be exetured and not updates will be made.
Parameters¶
contract
-any|string
: contract or contractIdlistNameFrom
-string
: origin listindex
-number
: index of the entry to move in the origin listlistNamesTo
-string
: lists to move data intoaccountId
-string
: Ethereum account id
Returns¶
Promise
returns void
: resolved when done
Example¶
const listNameFrom = 'list_removable_by_owner';
const listNameTo = 'list_settable_by_member';
const itemIndexInFromList = 1;
await dataContract.moveListEntry(contract, listNameFrom, itemIndexInFromList, [listNameTo], accounts[0]);
= Mappings =¶
setMappingValue¶
dataContract.setMappingValue(contract, mappingName, entryName, value, accountId[, dfsStorage, encryptedHashes, encryption]);
Set entry for a key in a mapping. Mappings are basically dictionaries in data contracts. They are a single permittable entry, that allows to set any keys to it. This can be used for properties, that should be extended during the contracts life as needed, but without the need to update its permission settings.
Parameters¶
contract
-any|string
: contract or contractIdmappingName
-string
: name of a data contracts mapping propertyentryName
-string
: entry name (property in the mapping)value
-any
: value to addaccountId
-string
: Ethereum account iddfsStorage
-string
(optional): store values in dfs, defaults totrue
encryptedHashes
-boolean
(optional): encrypt hashes from values, defaults totrue
encryption
-string
(optional): encryption algorithm to use, defaults todefaultCryptoAlgo
(set in constructor)encryptionContext
-string
(optional): plain text name of an encryption context, defaults toaccountId
Returns¶
Promise
returns void
: resolved when done
Example¶
await dataContract.setMappingValue(
contract,
'mapping_settable_by_owner',
'sampleKey',
'sampleValue',
accounts[0],
storeInDfs,
);
getMappingValue¶
dataContract.getMappingValue(contract, listName, index, accountId[, dfsStorage, encryptedHashes]);
Return a value from a mapping. Looks up a single key from a mapping and returns its value.
Parameters¶
contract
-any|string
: contract or contractIdmappingName
-string
: name of a data contracts mapping propertyentryName
-string
: entry name (property in the mapping)accountId
-string
: Ethereum account iddfsStorage
-string
(optional): store values in dfs, defaults totrue
encryptedHashes
-boolean
(optional): encrypt hashes from values, defaults totrue
encryption
-string
(optional): encryption algorithm to use, defaults todefaultCryptoAlgo
(set in constructor)
Returns¶
Promise
returns any
: mappings value for given key
Example¶
const value = await dataContract.getMappingValue(
contract,
'mapping_settable_by_owner',
'sampleKey',
accounts[0],
storeInDfs,
);
= Encryption =¶
encrypt¶
dataContract.encrypt(toEncrypt, contract, accountId, propertyName, block[, encryption]);
Encrypt incoming envelope.
Parameters¶
toEncrypt
-Envelope
: envelope with data to encryptcontract
-any
: contract instance or contract idaccountId
-string
: encrypting accountpropertyName
-string
: property in contract, the data is encrypted forblock
-block
: block the data belongs toencryption
-string
: encryption name, defaults todefaultCryptoAlgo
(set in constructor)
Returns¶
Promise
returns string
: encrypted envelope or hash as string
Example¶
const data = {
public: {
foo: 'example',
},
private: {
bar: 123,
},
cryptoInfo: cryptor.getCryptoInfo(nameResolver.soliditySha3(accounts[0])),
};
const encrypted = await dataContract.encrypt(data, contract, accounts[0], 'list_settable_by_member', 12345);
decrypt¶
dataContract.decrypt(toDecrypt, contract, accountId, propertyName, block[, encryption]);
Decrypt input envelope return decrypted envelope.
Parameters¶
toDecrypt
-string
: data to decryptcontract
-any
: contract instance or contract idaccountId
-string
: account id that decrypts the datapropertyName
-string
: property in contract that is decrypted
Returns¶
Promise
returns Envelope
: decrypted envelope
Example¶
const encrypted = await dataContract.decrypt(encrypted, contract, accounts[0], 'list_settable_by_member');
encryptHash¶
dataContract.encryptHash(toEncrypt, contract, accountId);
Encrypt incoming hash. This function is used to encrypt DFS file hashes, uses AES ECB for encryption.
Parameters¶
toEncrypt
-Envelope
: hash to encryptcontract
-any
: contract instance or contract idaccountId
-string
: encrypting account
Returns¶
Promise
returns string
: hash as string
Example¶
const hash = '0x1111111111111111111111111111111111111111111111111111111111111111';
const encrypted = await dataContract.encryptHash(hash, contract, accounts[0]);
decryptHash¶
dataContract.encrypt(toEncrypttoDecrypt, contract, accountId, propertyName, block[, encryption]);
Decrypt input hash, return decrypted hash. This function is used to decrypt encrypted DFS file hashes, uses AES ECB for decryption.
Parameters¶
toDecrypt
-Envelope
: hash to decryptcontract
-any
: contract instance or contract idaccountId
-string
: encrypting account
Returns¶
Promise
returns string
: decrypted hash
Example¶
const encryptedHash = '0x2222222222222222222222222222222222222222222222222222222222222222';
const encrypted = await dataContract.decryptHash(encryptedHash, contract, accounts[0]);
Service Contract¶
Class Name | ServiceContract |
---|---|
Extends | Logger |
Source | service-contract.ts |
Examples | service-contract.spec.ts |
constructor¶
new ServiceContract(options);
Creates a new ServiceContract instance.
Parameters¶
options
-ServiceContractOptions
: options for ServiceContract constructor.cryptoProvider
-CryptoProvider
:CryptoProvider
instancedfs
-DfsInterface
:DfsInterface
instancekeyProvider
-KeyProvider
:KeyProvider
instancesharing
-Sharing
:Sharing
instanceweb3
-Web3
:Web3
instancedefaultCryptoAlgo
-string
(optional): crypto algorith name fromCryptoProvider
, defaults toaes
log
-Function
(optional): function to use for logging:(message, level) => {...}
logLevel
-LogLevel
(optional): messages with this level will be logged withlog
logLog
-LogLogInterface
(optional): container for collecting log messageslogLogLevel
-LogLevel
(optional): messages with this level will be pushed tologLog
Returns¶
ServiceContract
instance
Example¶
const serviceContract = new ServiceContract({
cryptoProvide,
dfs,
executor,
keyProvider,
loader,
nameResolver,
sharing,
web3,
});
create¶
serviceContract.create(accountId, businessCenterDomain, service[, descriptionDfsHash]);
create and initialize new contract
Parameters¶
accountId
-string
: owner of the new contract and transaction executorbusinessCenterDomain
-string
: ENS domain name of the business centerservice
-any
: service definitiondescriptionHash
-string
(optional): bytes2 hash of DBCP description, defaults to0x0000000000000000000000000000000000000000000000000000000000000000
Returns¶
Promise
returns any
: contract instance
Example¶
const serviceContract = await serviceContract.create(accounts[0], businessCenterDomain, sampleService);
= Service =¶
The service is the communication pattern definition for the ServiceContract
. A single service contract can only have one service definition and all calls and answers must follow its defition.
To create calls and answers with different patterns, create a new ServiceContract
and use an updated service definition there.
setService¶
serviceContract.setService(contract, accountId, service, businessCenterDomain[, skipValidation]);
Set service description.
Parameters¶
contract
-any|string
: smart contract instance or contract IDaccountId
-string
: Ethereum account IDservice
-any
: service to setbusinessCenterDomain
-string
: domain of the business the service contract belongs toskipValidation
-bool
(optional): skip validation of service definition, validation is enabled by default
Returns¶
Promise
returns void
: resolved when done
Example¶
await serviceContract.setService(contract, accounts[0], sampleService, businessCenterDomain);
getService¶
serviceContract.getService(contract, accountId);
Gets the service of a service contract.
Parameters¶
contract
-any|string
: smart contract instance or contract IDaccountId
-string
: Ethereum account ID
Returns¶
Promise
returns string
: service description as JSON string
= Calls =¶
Calls are the requests done by authors, that initiate a service conversation. They are basically the first part of conversations and allow answers to be added to them. Calls are usually broadcasted or multicasted.
Samples for calls are:
- capacity requests
- information requests
- information broadcasts
sendCall¶
serviceContract.sendCall(contract, accountId, call);
Send a call to a service.
Parameters¶
contract
-any|string
: smart contract instance or contract IDaccountId
-string
: Ethereum account IDcall
-any
: call to send
Returns¶
Promise
returns number
: id of new call
getCalls¶
serviceContract.getCalls(contract, accountId[, count, offset, reverse]);
Get all calls from a contract.
Parameters¶
contract
-any|string
: smart contract instance or contract IDaccountId
-string
: Ethereum account IDcount
-number
(optional): number of elments to retrieve, defaults to10
offset
-number
(optional): skip this many elements, defaults to0
reverse
-boolean
(optional): retrieve last elements first, defaults tofalse
Returns¶
Promise
returns any[]
: the calls
getCall¶
serviceContract.getCall(contract, accountId, callId);
Get a call from a contract.
Parameters¶
contract
-any|string
: smart contract instance or contract IDaccountId
-string
: Ethereum account IDcallId
-number
: index of the call to retrieve
Returns¶
Promise
returns any
: a single call
getCallCount¶
serviceContract.getCallCount(contract);
Get number of calls of a contract.
Parameters¶
contract
-any|string
: smart contract instance or contract ID
Returns¶
Promise
returns number
: number of calls
Example¶
let callCount = await serviceContract.getCallCount(contract);
console.log(callCount);
// Output:
// 2
await serviceContract.sendCall(contract, accounts[0], sampleCall);
callCount = await serviceContract.getCallCount(contract);
console.log(callCount);
// Output:
// 3
getCallOwner¶
serviceContract.getCallOwner(contract, callId);
Gets the owner/creator of a call.
Parameters¶
contract
-any|string
: smart contract instance or contract IDcallId
-number
: index of the call to retrieve owner for
Returns¶
Promise
returns string
: account id of call owner
Example¶
console.log(await serviceContract.getCallOwner(contract, 2));
// Output:
0x0000000000000000000000000000000000000001
addToCallSharing¶
serviceContract.addToCallSharing(contract, accountId, callId, to[, hashKey, contentKey, section]);
Adds list of accounts to a calls sharings list.
Parameters¶
contract
-any|string
: smart contract instance or contract IDaccountId
-string
: Ethereum account IDcallId
-number
: id of the call to retrieveto
-string[]
: accountIds, to add sharings forhashKey
-string
(optional): hash key to share, if omitted, key is retrieved withaccountId
contentKey
-string
(optional): content key to share, if omitted, key is retrieved withaccountId
section
-string
(optional): section to share key for, defaults to ‘*’
Returns¶
Promise
returns void
: resolved when done
Example¶
// account[0] adds accounts[2] to a sharing
await serviceContract.addToCallSharing(contract, accounts[0], callId, [accounts[2]]);
= Answers =¶
Answers are replies to calls. Answers can only be created as answers to calls. Answers are usually directed to the author of a call.
Examples are
- capacity replies
- information responses
sendAnswer¶
serviceContract.sendAnswer(contract, accountId, answer, callId, callAuthor);
Send answer to service contract call.
Parameters¶
contract
-any|string
: smart contract instance or contract IDaccountId
-string
: Ethereum account IDanswer
-any
: answer to sendcallId
-number
: index of the call to which the answer was createdcallAuthor
-string
: Ethereum account ID of the creator of the initial call
Returns¶
Promise
returns number
: id of new answer
Example¶
await serviceContract.inviteToContract(businessCenterDomain, contract.options.address, accounts[0], accounts[2]);
const contentKey = await sharing.getKey(contract.options.address, accounts[0], '*', 0);
await sharing.addSharing(contract.options.address, accounts[0], accounts[2], '*', 0, contentKey);
await serviceContract.sendCall(contract, accounts[0], sampleCall);
const call = await serviceContract.getCall(contract, accounts[0], 0);
const answerId = await serviceContract.sendAnswer(contract, accounts[2], sampleAnswer, 0, call.metadata.author);
getAnswers¶
serviceContract.getAnswers(contract, accountId, callid[, count, offset, reverse]);
Retrieves answers for a given call.
Parameters¶
contract
-any|string
: smart contract instance or contract IDaccountId
-string
: Ethereum account IDcallId
-number
: index of the call to which the answers were createdcount
-number
(optional): number of elements to retrieve, defaults to10
offset
-number
(optional): skip this many elements, defaults to0
reverse
-boolean
(optional): retrieve last elements first, defaults tofalse
Returns¶
Promise
returns any[]
: the answers
getAnswer¶
serviceContract.getAnswer(contract, accountId, answerIndex);
Get a answer from a contract.
Parameters¶
contract
-any|string
: smart contract instance or contract IDaccountId
-string
: Ethereum account IDcallId
-number
: index of the call to which the answer was createdanswerIndex
-number
: index of the answer to retrieve
Returns¶
Promise
returns any
: a single answer
getAnswerCount¶
serviceContract.getAnswerCount(contract, callId);
Retrieves number of answers for a given call.
Parameters¶
contract
-any|string
: smart contract instance or contract IDcallId
-number
: index of the call to which the answer was created
Returns¶
Promise
returns number
: number of answers
Example¶
const sampleCallId = 3;
let answerCount = await serviceContract.getAnswerCount(contract, sampleCallId);
console.log(answerCount);
// Output:
// 2
await serviceContract.sendAnswer(contract, accounts[0], sampleAnswer, sampleCallId, accounts[1]);
answerCount = await serviceContract.getAnswerCount(contract, sampleCallId);
console.log(answerCount);
// Output:
// 3
Digital Twin Usage Examples¶
This section shows a few usage examples that can occur in common digital twin usage scenarios and cover handling of the modules DigitalTwin and Container. The examples in here are build around the management of data for heavy construction machines and cover common events link storing data, sharing data, etc.
- manufacturer: original manufacturer of the heavy machine
- customer: a user, that has bought the physical heavy machine
- service-technician: hired by the customer to perform maintenance on the heavy machine
The examples in this section use these variables for aforementioned users:
const manufacturer = '0x0000000000000000000000000000000000000001';
const customer = '0x0000000000000000000000000000000000000002';
const serviceTechnician = '0x0000000000000000000000000000000000000003';
Create a Digital Twin¶
Digital Identities are collections of data related to a “thing”. A “thing” can be basically anything, a bird, a plane or someone from the planet Krypton. Jokes aside, it most commonly describes a physical object - like in our example here a heavy machine.
So let’s create a digital twin four our heavy machine “Big Crane 250”, which is done with the DigitalTwin.create
function:
const bigCrane250 = await DigitalTwin.create(runtime, { accountId: manufacturer });
This creates a new digital twin for the account manufacturer
, which can now add containers to it or set other properties.
The DigitalTwin.create
config argument function supports more properties than just accountId.
You can and should give your digital twin a DBCP description. To do this pass it to the new digital twin in the config property.
const description = {
name: 'Big Crane 250',
description: 'Digital Twin for my heavy machine "Big Crane 250"',
author: 'Manufacturer',
version: '0.1.0',
dbcpVersion: 2,
};
const bigCrane250 = await DigitalTwin.create(
runtime, { accountId: manufacturer, description });
If you do not set a description, at creation time, a default description is set. This description is available at the DigitalTwin.defaultDescription
and can be used as a starting point for your own description. A description can be updated later on as well, see digitalTwin.setDescription
.
So let’s say, we have created a digital twin four our heavy machine with the setup from the last code example. We now have the following setup:

manufacturer created a digital twin
Add Containers to Digital Twin¶
Continuing with the digital twin from the last section we add a container, that holds manufacturers private data with information about the production process and a link to a manual file. This can be done with the digitalTwin.createContainers
function:
const { data } = await bigCrane250.createContainers({
data: {},
});
The manufacturer account now has created a Container instance called data
. This can be customized as described at Container.create
.

manufacturer added a container to the twin
Add Data to the Container¶
Continuing the example, the manufacturer adds data to the container.
await data.setEntry(
'productionProfile',
{
id: 'BC250-4711',
dateOfManufacturing: '1554458858126',
category: 'hem-c',
},
);
await data.setEntry('manual', 'https://a-link-the-manual...');
As these properties are new, container.setEntry
adds a role for each property and the owner of the digital twin joins this role. During this role 0
to 63
are skipped as they are system reserved and can be used for more complex contract role setups. So the roles 64
(for productionProfile
) and 65
(for manual
) are created.
For each new property a new encryption key is generated and stored in the contracts Sharings. When new properties are added, this key is only shared for the owner of the digital twin, so only the owner can access the data stored in the contract.
Data can be read from the containers with container.getEntry
:
const productionProfile = await data.getEntry('productionProfile');

manufacturer added entries to the container
Cloning Containers¶
If customer
wants to re-use data from a data container or an entire data container but have ownership over it, it can clone it and use it in an own digital twin contract. This can be done with Container.clone
:
const dataClone = await Container.clone(
runtime, { accountId: customer }, dataLoadedFromCustomer);
This clone can be linked to a digital twin owner by customer
. So let’s create a new one and add the clone to it:
const customersDescription = {
name: 'My own Big Crane 250',
description: 'I bought a Big Crane 250 and this is my collection of data for it',
author: 'Customer',
version: '0.1.0',
dbcpVersion: 2,
};
const customersBigCrane250 = await DigitalTwin.create(
runtime, { accountId: customer, description: customersDescription });
await customersBigCrane250.setEntry(
'machine-data',
dataClone,
DigitalTwinEntryType.Container,
);
Note that the container is not named data
like in the original twin but called machine-data
here. Names can be reassigned as desired.

customer cloned data container
Granting Write Access¶
Properties at Containers can be “entries” as used in the last examples or “list entries”. To add data to lists call container.addListEntries
:
await dataClone.addListEntries(
'usagelog',
[ 'I started using my new Big Crane 250' ]
);
Now customer
wants to invite serviceTechnician
and allow this account to add entries to the list usagelog
as well. To do this, the list is shared the same way as in the previous example, but the field is shared as readWrite
:
await dataClone.shareProperties([
{ accountId: customer, readWrite: ['usagelog'] }
]);
serviceTechnician
can now write to the list usagelog
and we now have the following setup:

customer invited service technician
Handling Files¶
Containers can hold files as well. File handling follows a few simple principles:
- files are stored encrypted (as everything in containers is stored encrypted)
- files are always stored as an array of files (think of it like a folder with files)
- files are encrypted, uploaded and a reference is stored as a file at the contract (sounds like the default Hybrid Storage) approach, but is a reapplication to itself, as encrypted additional files with references to the original encrypted files are stored at the contract
Okay, let’s add some files to a container (taken from our tests).
A file needs to be provided as a buffer. In NodeJs, this can be done with fs.readFile
import { promisify } from 'util';
import { readFile } from 'fs';
const file = await promisify(readFile)(
`${__dirname}/testfiles/animal-animal-photography-cat-96938.jpg`);
The file is expected to be wrapped in a specific container format, which is defined in the ContainerFile
interface. So let’s build such a file object and store it in an object including a property called files, as files are always provided as arrays of ContainerFile
instances to the API:
const sampleFiles = {
files:[{
name: 'animal-animal-photography-cat-96938.jpg',
fileType: 'image/jpeg',
file,
}]
};
If not already done, create (or load) a container:
const container = await Container.create(runtime, config);
If not already done, add a field for files to our container, for this the static property Container.defaultTemplates
can be useful:
await container.ensureProperty('sampleFiles', Container.defaultSchemas.filesEntry);
So now everything is set up and we can store our file:
await container.setEntry('sampleFiles', sampleFiles);
And later on we can retrieve our file with:
await container.getEntry('sampleFiles');
That’s it for the simple case. If you want to get fancy, you can have a look at the more complex examples in the tests. With the build in file handling you can:
- store lists of files in an entry (this example)
test path:Container/when setting entries/can handle files
- store lists of files in complex objects (e.g. if you want to annotate them)
test path:Container/when setting entries/can handle files in complex objects
- store a list of lists of files (hands up, who tripped, when reading this, me too, it’s basically a list of directories),
this can be used to store different versions of files or separate file groups which have no relations between them
test path:
Container/when setting list entries/can handle files
- store a list of lists of files (a combination between lists and complex objects)
test path:Container/when setting list entries/can handle files in complex objects
Digital Twin¶
Class Name | DigitalTwin |
---|---|
Extends | Logger |
Source | digital-twin.ts |
Examples | digital-twin.spec.ts |
TL;DR: usage examples and a data flow can be found here.
A DigitalTwin
is a wrapper, that holds data or references to data. This data can be
- a
Container
- This is the most common use case, actual data is stored in the container and theDigitalTwin
merely holds a reference to the container. - an
DigitalTwin
- DigitalTwins can be linked together, so an entry can be anotherDigitalTwin
, which allows to navigate through twins to retrieve data properties from linked twins, see getEntry - an account address / a contract address
bytes32
hashes (e.g. file hashes)
constructor¶
new DigitalTwin(options, config);
Create new DigitalTwin
instance. This will not create a smart contract contract but is used to
load existing digital twins. To create a new contract, use the static create function.
Parameters¶
options
-DigitalTwinOptions
: runtime-like object with required modulescontractLoader
-ContractLoader
:ContractLoader
instancecryptoProvider
-CryptoProvider
:CryptoProvider
instancedataContract
-DataContract
:DataContract
instancedescription
-Description
:Description
instanceexecutor
-Executor
:Executor
instancelog
-Function
(optional): function to use for logging:(message, level) => {...}
logLevel
-LogLevel
(optional): messages with this level will be logged withlog
logLog
-LogLogInterface
(optional): container for collecting log messageslogLogLevel
-LogLevel
(optional): messages with this level will be pushed tologLog
nameResolver
-NameResolver
:NameResolver
instanceprofile
-Profile
:Profile
instancerightsAndRoles
-RightsAndRoles
:RightsAndRoles
instancesharing
-Sharing
:Sharing
instanceverifications
-Verifications
:Verifications
instanceweb3
-Web3
:Web3
instance
config
-DigitalTwinConfig
: digital twin related configaccountId
-string
: account id of user, that interacts with digital twincontainerConfig
-ContainerConfig
: address of aDigitalTwin
instance, can be ENS or contract addressaddress
-string
(optional): address of anDigitalTwin
instance, can be ENS or contract addressdescription
-string
: description has to be passed to.create
to apply it to to contractfactoryAddress
-string
(optional): factory address can be passed to.create
for customer digital twin factory
Returns¶
DigitalTwin
instance
Example¶
const digitalTwin = new DigitalTwin(
runtime,
{
accountId: '0x0000000000000000000000000000000000000000',
address: 'sample-digital-twin.somewhere.evan',
},
);
= Creating Digital Identities =¶
create¶
DigitalTwin.create(runtime, config);
Create digital twin contract.
Note, that this function is static. It is used on the DigitalTwin
class object and returns a DigitalTwin
class instance.
The options argument has the same structure as the options object that is passed to the constructor as it is used for the new DigitalTwin
instance. The config
argument requires a proper value for the property description
.
Parameters¶
options
-ContainerOptions
: runtime-like object with required modulescontractLoader
-ContractLoader
:ContractLoader
instancecryptoProvider
-CryptoProvider
:CryptoProvider
instancedataContract
-DataContract
:DataContract
instancedescription
-Description
:Description
instanceexecutor
-Executor
:Executor
instancenameResolver
-NameResolver
:NameResolver
instancerightsAndRoles
-RightsAndRoles
:RightsAndRoles
instancesharing
-Sharing
:Sharing
instanceverifications
-Verifications
:Verifications
instanceweb3
-Web3
:Web3
instancelog
-Function
(optional): function to use for logging:(message, level) => {...}
logLevel
-LogLevel
(optional): messages with this level will be logged withlog
logLog
-LogLogInterface
(optional): container for collecting log messageslogLogLevel
-LogLevel
(optional): messages with this level will be pushed tologLog
config
-DigitalTwinConfig
: digital twin related configaccountId
-string
: account id of user, that interacts with digital twincontainerConfig
-ContainerConfig
: config, that will be used, when containers are createdaddress
-string
(optional): ENS address used for digital twindescription
-string
: description has to be passed to.create
to apply it to to contractfactoryAddress
-string
(optional): factory address can be passed to.create
for customer digital twin factory
Returns¶
Promise
returns DigitalTwin
: new instance bound to new DigitalTwin
Example¶
const digitalTwin = await DigitalTwin.create(options, config);
console.log(await digitalTwin.getContractAddress());
// Output:
// 0x0000000000000000000000000000000000001234
= Container =¶
createContainers¶
digitalTwin.createContainers(containers);
Create new Container instances and add them as entry to twin.
When a container entry fetched with getEntry or getEntry, the value will become a Container
instance and can be used as such.
Parameters¶
containers
-{ [id: string]: Partial<ContainerConfig> }
: object with containers to create, name is used as entry name in twin
Returns¶
Promise
returns { [id: string]: Container }
: map with Container
instances
Example¶
const containers = await twin.createContainers({
entry1: { template: 'metadata' },
entry2: { template: 'metadata' },
});
= Entries =¶
setEntry¶
digitalTwin.setEntry(name, value, entryType);
Set entry in index contract; entries are unique, setting the same name a second time will overwrite the first value.
Parameters¶
name
-string
: entry namevalue
-string
: value to setentryType
-DigitalTwinType
: type of given value
Returns¶
Promise
returns void
: resolved when done
Example¶
await digitalTwin.setEntry('myId', accountId, DigitalTwinEntryType.AccountId);
console.log((await digitalTwin.getEntry('myId')).value);
// Output:
// 0x0000000000000000000000000000000000000001
setEntries¶
digitalTwin.setEntries(arguments);
Set multiple entries at index contract.
Parameters¶
entries
-{[id: string]: DigitalTwinIndexEntry}
: entries to set
Returns¶
Promise
returns void
: resolved when done
Example¶
const sampleContractId = '0x00000000000000000000000000000000c0274ac7';
await digitalTwin.setEntries({
'account': { value: accountId, entryType: DigitalTwinEntryType.AccountId },
'contract': { value: sampleContractId, entryType: DigitalTwinEntryType.GenericContract },
});
const result = (await digitalTwin.getEntries()).map(entry => value);
console.log(result.account.value);
// Output:
// 0x0000000000000000000000000000000000000001
console.log(result.contract.value);
// Output:
// 0x00000000000000000000000000000000c0274ac7
getEntry¶
digitalTwin.getEntry(name);
Get single entry from index contract.
When this twin has other twins as its entries, properties from those can be selected by building a path of properties.
For example a twin called car
may have a link to another twin under the name tire
. The twin tire
has an entry called metadata
. It is possible to retrieve this entry from the twin car
with:
const tireMetadata = await car.getEntry('tire/metadata');
Parameters¶
name
-string
: entry name or path to data in linked twin
Returns¶
Promise
returns DigitalTwinIndexEntry
: entry object
Example¶
await digitalTwin.setEntry('myId', accountId, DigitalTwinEntryType.AccountId);
console.log((await digitalTwin.getEntry('myId')).value);
// Output:
// 0x0000000000000000000000000000000000000001
getEntries¶
digitalTwin.getEntries();
Get all entries from index contract.
Returns¶
Promise
returns {[id: string]: DigitalTwinIndexEntry}
: key-value map with all entries
Example¶
const sampleContractId = '0x00000000000000000000000000000000c0274ac7';
await digitalTwin.setEntries({
'account': { value: accountId, entryType: DigitalTwinEntryType.AccountId },
'contract': { value: sampleContractId, entryType: DigitalTwinEntryType.GenericContract },
});
const result = (await digitalTwin.getEntries()).map(entry => value);
console.log(result.account.value);
// Output:
// 0x0000000000000000000000000000000000000001
console.log(result.contract.value);
// Output:
// 0x00000000000000000000000000000000c0274ac7
= Verifications =¶
addVerifications¶
digitalTwin.addVerifications(verifications);
Add verifications to this twin; this will also add verifications to contract description.
If the calling account is the owner of the identity of the digital twin
- the description will is automatically updated with tags for verifications
- verifications issued with this function will be accepted automatically
See interface DigitalTwinVerificationEntry
for input data format.
Parameters¶
verifications
-DigitalTwinVerificationEntry[]
: list of verifications to add
Returns¶
Promise
returns void
: resolved when done
getVerifications¶
digitalTwin.getVerifications();
Gets verifications from description and fetches list of verifications for each of them.
See Verifications
documentation for details on output data format.
Returns¶
Promise
returns any
: list of verification lists from Verifications
, getVerifications
Example¶
await digitalTwin.addVerifications([{ topic: 'exampleVerification' }]);
const verifications = await digitalTwin.getVerifications());
= Descriptions =¶
getDescription¶
digitalTwin.getDescription();
Returns description from digital twin.
Returns¶
Promise
returns any
: public part of the description
Example¶
const description = await container.getDescription();
console.dir(description);
// Output:
// { name: 'test twin',
// description: 'twin from test run',
// author: 'evan GmbH',
// version: '0.1.0',
// dbcpVersion: 2,
// tags: [ 'evan-digital-twin' ],
// identity:
// '0x1a496043385fec8d52f61e2b700413f8e12eb6e7e11649f80c8f4716c1063d06' }
setDescription¶
digitalTwin.setDescription(description);
Write given description to digital twins DBCP.
Parameters¶
description
-any
: description (public part)
Returns¶
Promise
returns void
: resolved when done
Example¶
// get current description
const description = await digitalTwin.getDescription();
console.dir(description);
// Output:
// { name: 'test twin',
// description: 'twin from test run',
// author: 'evan GmbH',
// version: '0.1.0',
// dbcpVersion: 2,
// tags: [ 'evan-digital-twin' ],
// identity:
// '0x1a496043385fec8d52f61e2b700413f8e12eb6e7e11649f80c8f4716c1063d06' }
// update description
description.version = '0.1.1';
await digitalTwin.setDescription(description);
// fetch again
console.dir(await digitalTwin.getDescription());
// Output:
// { name: 'test twin',
// description: 'twin from test run',
// author: 'evan GmbH',
// version: '0.1.1',
// dbcpVersion: 2,
// tags: [ 'evan-digital-twin' ],
// identity:
// '0x1a496043385fec8d52f61e2b700413f8e12eb6e7e11649f80c8f4716c1063d06' }
= Profile =¶
addAsFavorite¶
digitalTwin.addAsFavorite();
Add the digital twin with given address to profile.
Returns¶
Promise
returns void
: resolved when done
Example¶
const digitalTwin = new DigitalTwin(options.config);
if (await digitalTwin.isFavorite()) {
console.log('I know this digital twin!');
} else {
await digitalTwin.addToFavorites();
console.log('bookmarked digital twin');
}
getFavorites¶
DigitalTwin.getFavorites();
Gets bookmarked twins from profile.
Note, that this function is called on the Class DigitalTwin and not on an instance of it.
Parameters¶
options
-ContainerOptions
: runtime-like object with required modulescontractLoader
-ContractLoader
:ContractLoader
instancecryptoProvider
-CryptoProvider
:CryptoProvider
instancedataContract
-DataContract
:DataContract
instancedescription
-Description
:Description
instanceexecutor
-Executor
:Executor
instancenameResolver
-NameResolver
:NameResolver
instancerightsAndRoles
-RightsAndRoles
:RightsAndRoles
instancesharing
-Sharing
:Sharing
instanceverifications
-Verifications
:Verifications
instanceweb3
-Web3
:Web3
instancelog
-Function
(optional): function to use for logging:(message, level) => {...}
logLevel
-LogLevel
(optional): messages with this level will be logged withlog
logLog
-LogLogInterface
(optional): container for collecting log messageslogLogLevel
-LogLevel
(optional): messages with this level will be pushed tologLog
Returns¶
Promise
returns void
: resolved when done
Example¶
const favorites = await DigitalTwin.getFavorites(options);
console.dir(favorites);
// Output:
// [
// 'example.somewhere.evan',
// 'another.example.somewhere.else.evan',
// '0x0000000000000000000000000000000000001234'
// ]
isFavorite¶
digitalTwin.isFavorite();
Check if this digital twin is bookmarked in profile.
Returns¶
Promise
returns boolean
: true if bookmarked
Example¶
const digitalTwin = new DigitalTwin(options.config);
if (await digitalTwin.isFavorite()) {
console.log('I know this digital twin!');
} else {
await digitalTwin.addToFavorites();
console.log('bookmarked digital twin');
}
removeFromFavorites¶
digitalTwin.removeFromFavorites();
Removes the current twin from the favorites in profile.
Returns¶
Promise
returns void
: resolved when done
Example¶
const digitalTwin = new DigitalTwin(options.config);
if (await digitalTwin.isFavorite()) {
await digitalTwin.removeFromFavorites();
console.log('removed digital twin from favorites');
}
= Utilities =¶
getValidity¶
DigitalTwin.getValidity(options, ensAddress);
Check if a valid contract is located under the specified address, which allows to check for twins before actually loading them.
Return value properties have the following meaning:
valid
:true
if contract could not be found or if it doesn’t have the tag “evan-digital-twin”exists
:true
if a contract address could be found at given ENS addresserror
: an error object, if one of the other properties isfalse
Note, that this function is called on the Class DigitalTwin and not on an instance of it.
Parameters¶
options
-DigitalTwinOptions
: twin runtime optionscontractLoader
-ContractLoader
:ContractLoader
instancecryptoProvider
-CryptoProvider
:CryptoProvider
instancedataContract
-DataContract
:DataContract
instancedescription
-Description
:Description
instanceexecutor
-Executor
:Executor
instancenameResolver
-NameResolver
:NameResolver
instancerightsAndRoles
-RightsAndRoles
:RightsAndRoles
instancesharing
-Sharing
:Sharing
instanceverifications
-Verifications
:Verifications
instanceweb3
-Web3
:Web3
instancelog
-Function
(optional): function to use for logging:(message, level) => {...}
logLevel
-LogLevel
(optional): messages with this level will be logged withlog
logLog
-LogLogInterface
(optional): container for collecting log messageslogLogLevel
-LogLevel
(optional): messages with this level will be pushed tologLog
ensAddress
-string
: ens address that should be checked
Returns¶
Promise
returns { valid: boolean, exists: boolean, error: Error }
: resolved when done
Example¶
const { valid } = await DigitalTwin.getValidity(runtime, address);
if (!valid) {
throw new Error(`no valid digital twin found at "${address}"`);
}
ensureContract¶
digitalTwin.ensureContract();
Check if digital twin contract already has been loaded, load from address / ENS if required. Throws if contract could not be loaded.
This function is more commonly used for internal checks in the DigitalTwin
module. For checking, if a given address can be used, it is recommended to use getValidity.
Returns¶
Promise
returns void
: resolved when done
Example¶
let digitalTwin;
try {
digitalTwin = new DigitalTwin(options, config);
await digitalTwin.ensureContract();
// use digital twin
} catch (ex) {
console.error(`could use digital twin; ${ex.message || ex}`);
}
getContractAddress¶
digitalTwin.getContractAddress();
Get contract address of underlying DigitalTwin.
Returns¶
Promise
returns string
: contract address
Example¶
const digitalTwin = new DigitalTwin(options, config);
console.log(await digitalTwin.getContractAddress());
// Output:
// 0x000000000000000000000000000000001d327171
Additional Components¶
Public Properties¶
Enums¶
DigitalTwinEntryType¶
possible entry types for entries in index
AccountId
Container
FileHash
GenericContract
Hash
DigitalTwin
Interfaces¶
DigitalTwinConfig¶
config for digital twin
accountId
-string
: account id of user, that interacts with digital twincontainerConfig
-ContainerConfig
: address of aDigitalTwin
instance, can be ENS or contract addressaddress
-string
(optional): address of anDigitalTwin
instance, can be ENS or contract addressdescription
-string
(optional): description has to be passed to.create
to apply it to to contractfactoryAddress
-string
(optional): factory address can be passed to.create
for customer digital twin factory
DigitalTwinIndexEntry¶
container for digital twin entry values
entryType
-DigitalTwinEntryType
(optional): type of entry in indexraw
-any
(optional): raw value (bytes32
hash)value
-any
(optional): decrypted/loaded value
DigitalTwinVerificationEntry¶
data for verifications for digital twins
topic
-string
: name of the verification (full path)descriptionDomain
-string
(optional): domain of the verification, this is a subdomain under ‘verifications.evan’, so passing ‘example’ will link verificationsdisableSubVerifications
-boolean
(optional): if true, verifications created under this path are invalid, defaults tofalse
expirationDate
-number
(optional): expiration date, for the verification, defaults to 0 (does not expire)verificationValue
-any
(optional): json object which will be stored in the verification
Container¶
Class Name | Container |
---|---|
Extends | Logger |
Source | container.ts |
Examples | container.spec.ts |
TL;DR: usage examples and a data flow can be found here.
The Container
is an API layer over DataContract and combines its functionalities into a more use case oriented straight forward interface.
To reduce complexity the most common usage patterns from DataContract have been set as fixed in the Container
implementation. Therefore the Container
follows these principles:
- data is always encrypted
- each entry gets an own key for encryption
- each entry get an own role for granting write permissions
- an identity always is created for the container
- adding verifications adds the verification topic to the contract description to allow listing of all verifications of this container
- a property called
type
is added to theContainer
at creation type and marks its template type
constructor¶
new Container(options, config);
Create new Container
instance. This will not create a smart contract contract but is used to
load existing containers. To create a new contract, use the static create function.
Parameters¶
options
-ContainerOptions
: runtime for new containercontractLoader
-ContractLoader
:ContractLoader
instancecryptoProvider
-CryptoProvider
:CryptoProvider
instancedataContract
-DataContract
:DataContract
instancedescription
-Description
:Description
instanceexecutor
-Executor
:Executor
instancenameResolver
-NameResolver
:NameResolver
instancerightsAndRoles
-RightsAndRoles
:RightsAndRoles
instancesharing
-Sharing
:Sharing
instanceverifications
-Verifications
:Verifications
instanceweb3
-Web3
:Web3
instancelog
-Function
(optional): function to use for logging:(message, level) => {...}
logLevel
-LogLevel
(optional): messages with this level will be logged withlog
logLog
-LogLogInterface
(optional): container for collecting log messageslogLogLevel
-LogLevel
(optional): messages with this level will be pushed tologLog
config
-DigitalTwinconfIg
: config for new containeraccountId
-string
: account id of user, that interacts with containeraddress
-string
: address of aDataContract
instance, can be ENS or contract address
Returns¶
Container
instance
Example¶
const container = new Container(
runtime,
{
accountId: '0x0000000000000000000000000000000000000000',
address: 'samplecontainer.somewhere.evan',
},
);
= Creating Containers =¶
create¶
Container.create(runtime, config);
Creates a new digital container contract on the blockchain.
Note, that this function is static. It is used on the Container
class object and returns a Container
class instance.
The options argument has the same structure as the options object that is passed to the constructor as it is used for the new Container
instance. The config
argument requires a proper value for the property description
.
Parameters¶
options
-ContainerOptions
: runtime for new containercontractLoader
-ContractLoader
:ContractLoader
instancecryptoProvider
-CryptoProvider
:CryptoProvider
instancedataContract
-DataContract
:DataContract
instancedescription
-Description
:Description
instanceexecutor
-Executor
:Executor
instancenameResolver
-NameResolver
:NameResolver
instancerightsAndRoles
-RightsAndRoles
:RightsAndRoles
instancesharing
-Sharing
:Sharing
instanceverifications
-Verifications
:Verifications
instanceweb3
-Web3
:Web3
instancelog
-Function
(optional): function to use for logging:(message, level) => {...}
logLevel
-LogLevel
(optional): messages with this level will be logged withlog
logLog
-LogLogInterface
(optional): container for collecting log messageslogLogLevel
-LogLevel
(optional): messages with this level will be pushed tologLog
config
-DigitalTwinconfIg
: config for new containeraccountId
-string
: account id of user, that interacts with containeraddress
-string
: ENS address used for containerdescription
-string
: description has to be passed to.create
to apply it to to contractfactoryAddress
-string
(optional): factory address can be passed to.create
for customer container factoryplugin
-string|ContainerPlugin
(optional): plugin to be used in.create
, can be string with name or aContainerPlugin
Returns¶
Promise
returns Container
: new instance bound to new DataContract
Example¶
const container = await Container.create(options, config);
console.log(await container.getContractAddress());
// Output:
// 0x0000000000000000000000000000000000001234
clone¶
Container.clone(options, config, source[, copyValues]);
Clone Container
instance into plugin and creates new Container
with it.
Cloning containers:
is done with account from
config.accountId
, this account will be owner of the new contractcopies all fields from source container to new container (including roles, that have permissions on them)
copies values for entry-fields (no lists) to new container, if
copyValues
is setdoes not copy role membership
config.accountId
is the owner of the new contract and also a member of the contract (role 0 and 1)- other roles receive permissions on fields, but do not get members added to them
does not copy sharings
- a new sharing with new keys is generated for this container
- only the owner of the container receives keys shared to it for this container
does not copy verifications
does not copy the description
config.description
is used for the cloned contract- fields are dynamically added to the description when generating the clone
Parameters¶
options
-ContainerOptions
: runtime for new containercontractLoader
-ContractLoader
:ContractLoader
instancecryptoProvider
-CryptoProvider
:CryptoProvider
instancedataContract
-DataContract
:DataContract
instancedescription
-Description
:Description
instanceexecutor
-Executor
:Executor
instancenameResolver
-NameResolver
:NameResolver
instancerightsAndRoles
-RightsAndRoles
:RightsAndRoles
instancesharing
-Sharing
:Sharing
instanceverifications
-Verifications
:Verifications
instanceweb3
-Web3
:Web3
instancelog
-Function
(optional): function to use for logging:(message, level) => {...}
logLevel
-LogLevel
(optional): messages with this level will be logged withlog
logLog
-LogLogInterface
(optional): container for collecting log messageslogLogLevel
-LogLevel
(optional): messages with this level will be pushed tologLog
config
-DigitalTwinconfIg
: config for new containeraccountId
-string
: account id of user, that interacts with containeraddress
-string
: ENS address used for containerdescription
-string
: description has to be passed to.create
to apply it to to contractfactoryAddress
-string
(optional): factory address can be passed to.create
for customer container factoryplugin
-string|ContainerPlugin
(optional): plugin to be used in.create
, can be string with name or aContainerPlugin
source
-Container
: container to clonecopyValues
-boolean
: copy entry values from source contract to new contract
Returns¶
Promise
returns Container
: new instance bound to new DataContract
and a copy of source
Example¶
const container = await Container.create(options, config);
console.log(await container.getContractAddress());
// Output:
// 0x0000000000000000000000000000000000001234
const clone = await Container.clone(options, config, container);
console.log(await container.getContractAddress());
// Output:
// 0x0000000000000000000000000000000000005678
deleteContainerPlugin¶
container.deleteContainerPlugin(profile);
Remove a container plugin from a users profile.
Returns¶
Promise
returns void
getContainerPlugin¶
container.getContainerPlugin(profile, name);
Get one container plugin for a users profile by name.
Returns¶
Promise
returns ContainerPlugin
Example¶
const accountId1 = '0x0000000000000000000000000000000000000001';
const plugin = await Container.getContainerPlugin(profile, 'awesomeplugin');
// create container with accountId1
const container = await Container.create(options, {
...config,
accountId: accountId1,
description: plugin.description,
plugin: plugin,
});
getContainerPlugins¶
container.getContainerPlugins(profile);
Get all container plugins for a users profile
Parameters¶
Profile
-Profile
: profile instanceloadContracts
- boolean (default = true): run loadBcContract directly for all saved entries (if false, unresolved ipld tree will be returned as value)
Returns¶
Promise
returns Array<ContainerPlugin>
Example¶
const accountId1 = '0x0000000000000000000000000000000000000001';
const plugins = await Container.getContainerPlugins(profile);
// create container with accountId1
const container = await Container.create(options, {
...config,
accountId: accountId1,
description: plugins['awesomeplugin'].description,
plugin: plugins['awesomeplugin'],
});
saveContainerPlugin¶
container.saveContainerPlugin(profile, name, plugin);
Persists a plugin including an dbcp description to the users profile.
Parameters¶
Profile
-Profile
: profile instancename
-string
: plugin nameplugin
-ContainerPlugin
: container plugin objectbeforeName
-strinf
: remove previous plugin instance when it was renamed
Returns¶
Promise
returns void
toPlugin¶
container.toPlugin([getValues]);
Export current container state as plugin. If getValues
is true
, exports entry values as
well.
This plugin can be passed to create and used to create new containers.
Parameters¶
getValues
-boolean
: export entry values or not (list entries are always excluded)
Returns¶
Promise
returns ContainerPlugin
: plugin build from current container
Example¶
const sampleValue = 123;
await container.setEntry('numberField', sampleValue);
console.dir(await container.toPlugin(true));
= Entries =¶
setEntry¶
container.setEntry(entryName, value);
Set a value for an entry.
Parameters¶
entryName
-string
: name of an entry in the containervalue
-any
: value to set
Returns¶
Promise
returns void
: resolved when done
Example¶
const sampleValue = 123;
await container.setEntry('numberField', sampleValue);
console.log(await container.getEntry('numberField'));
// Output:
// 123
getEntry¶
container.getEntry(entryName);
Return entry from contract.
Parameters¶
entryName
-string
: entry name
Returns¶
Promise
returns any
: entry value
Example¶
Entries can be retrieved with:
const sampleValue = 123;
await container.setEntry('numberField', sampleValue);
console.log(await container.getEntry('numberField'));
// Output:
// 123
removeEntries¶
container.removeEntries(entries);
Remove multiple entries from the container, including data keys and sharings. Can also pass a single property instead of an array. Retrieves dynamically all sharings for the passed entries and runs unshareProperties for them.
Parameters¶
entries
-string
/string[]
: name / list of entries, that should be removed
Returns¶
Promise
returns void
: resolved when done
Example¶
const accountId1 = '0x0000000000000000000000000000000000000001';
const accountId2 = '0x0000000000000000000000000000000000000002';
// open container with accountId1
const container = new Container(options, { ...config, accountId: accountId1 });
// assuming, that entry 'myField' has been shared with accountId2
// remove the whole property from the container
await container.removeEntries(['myField']);
// fetch value with accountId2 and with accountId1
const accountId2Container = new Container(options, { ...config, accountId: accountId2 });
let value;
try {
value = await accountId2Container.getEntry('myField');
console.log(value);
} catch (ex) {
console.error('could not get entry');
}
// also the owner cannot get this entry anymore
try {
value = await container.getEntry('myField');
console.log(value);
} catch (ex) {
console.error('could not get entry');
}
// Output:
// could not get entry
= List Entries =¶
addListEntries¶
container.addListEntries(listName, values);
Add list entries to a list list property.
List entries can be added in bulk, so the value argument is an array with values. This array can be arbitrarily large up to a certain degree. Values are inserted on the blockchain side and adding very large arrays this way may take more gas during the contract transaction, than may fit into a single transaction. If this is the case, values can be added in chunks (multiple transactions).
Parameters¶
listName
-string
: name of the list in the containervalues
-any[]
: values to add
Returns¶
Promise
returns void
: resolved when done
Example¶
const listName = 'exampleList';
console.log(await container.getListEntryCount(listName));
// Output:
// 0
const sampleValue = {
foo: 'sample',
bar: 123,
};
await container.addListEntries(listName, [sampleValue]);
console.log(await container.getListEntryCount(listName));
// Output:
// 1
console.dir(await container.getListEntries(listName));
// Output:
// [{
// foo: 'sample',
// bar: 123,
// }]
getListEntryCount¶
container.getListEntryCount(listName);
Return number of entries in the list. Does not try to actually fetch and decrypt values, but just returns the count.
Parameters¶
listName
-string
: name of a list in the container
Returns¶
Promise
returns number
: list entry count
Example¶
const listName = 'exampleList';
console.log(await container.getListEntryCount(listName));
// Output:
// 0
const sampleValue = {
foo: 'sample',
bar: 123,
};
await container.addListEntries(listName, [sampleValue]);
console.log(await container.getListEntryCount(listName));
// Output:
// 1
console.dir(await container.getListEntries(listName));
// Output:
// [{
// foo: 'sample',
// bar: 123,
// }]
getListEntries¶
container.getListEntries(contract, listName, accountId[, dfsStorage, encryptedHashes, count, offset, reverse]);
Return list entries from contract. Note, that in the current implementation, this function retrieves the entries one at a time and may take a longer time when querying large lists, so be aware of that, when you retrieve lists with many entries.
Parameters¶
listName
-string
: name of the list in the containercount
-number
(optional): number of elements to retrieve, defaults to10
offset
-number
(optional): skip this many items when retrieving, defaults to0
reverse
-boolean
(optional): retrieve items in reverse order, defaults tofalse
Returns¶
Promise
returns any[]
: list entries
Example¶
const listName = 'exampleList';
console.log(await container.getListEntryCount(listName));
// Output:
// 0
const sampleValue = {
foo: 'sample',
bar: 123,
};
await container.addListEntries(listName, [sampleValue]);
console.log(await container.getListEntryCount(listName));
// Output:
// 1
console.dir(await container.getListEntries(listName));
// Output:
// [{
// foo: 'sample',
// bar: 123,
// }]
getListEntry¶
container.getListEntry(listName, index);
Return a single list entry from contract.
Parameters¶
listName
-string
: name of the list in the containerindex
-number
: list entry id to retrieve
Returns¶
Promise
returns any
: list entry
Example¶
const listName = 'exampleList';
console.log(await container.getListEntryCount(listName));
// Output:
// 0
const sampleValue = {
foo: 'sample',
bar: 123,
};
await container.addListEntries(listName, [sampleValue]);
const count = await container.getListEntryCount(listName);
console.log(count);
// Output:
// 1
console.dir(await container.getListEntry(listName, count - 1));
// Output:
// {
// foo: 'sample',
// bar: 123,
// }
= Store multiple properties =¶
storeData¶
container.storeData(data);
- Store data to a container. This allows to
- store data into already existing entries and/or list entries
- implicitely create new entries and/or list entries (the same logic for deciding on their type is applied as in setEntry/addListEntries is applied here)
- in case of entries, their value is overwritten
- in case of list entries, given values are added to the list
Parameters¶
data
-object
: object with keys, that are names of lists or entries and values, that are the values to store to them
Returns¶
Promise
returns void
: resolved when done
Example¶
const sampleValue = 123;
await container.storeData({
'numberField': sampleValue,
});
console.log(await container.getEntry('numberField'));
// Output:
// 123
= Verifying Containers =¶
addVerifications¶
container.addVerifications(verifications);
Add verifications to this container; this will also add verifications to contract description.
If the calling account is the owner of the identity of the container
- the description will is automatically updated with tags for verifications
- verifications issued with this function will be accepted automatically
See interface ContainerVerificationEntry
for input data format.
Parameters¶
verifications
-ContainerVerificationEntry[]
: list of verifications to add
Returns¶
Promise
returns void
: resolved when done
getOwner¶
container.getOwner();
Gets the owner account id for the container.
Returns¶
Promise
returns string
: owner account id
getVerifications¶
container.getVerifications();
Gets verifications from description and fetches list of verifications for each of them.
See Verifications
documentation for details on output data format.
Returns¶
Promise
returns any
: list of verification lists from Verifications
, getVerifications
Example¶
await container.addVerifications([{ topic: 'exampleVerification' }]);
const verifications = await container.getVerifications());
= Working with Container Descriptions =¶
getDescription¶
container.getDescription();
Get description from container contract.
Returns¶
Promise
returns any
: public part of the description
Example¶
const description = await container.getDescription();
console.dir(description);
// Output:
// { name: 'test container',
// description: 'container from test run',
// author: 'evan GmbH',
// version: '0.1.0',
// dbcpVersion: 2,
// identity:
// '0x70c969a64e880fc904110ce9ab72ba5f95f706a252ac085ae0525bd7a284337c',
// dataSchema: { type: { type: 'string', '$id': 'type_schema' } } }
setDescription¶
container.setDescription(description);
Write given description to containers DBCP.
Parameters¶
description
-any
: description (public part)
Returns¶
Promise
returns void
: resolved when done
Example¶
// get current description
const description = await container.getDescription();
console.dir(description);
// Output:
// { name: 'test container',
// description: 'container from test run',
// author: 'evan GmbH',
// version: '0.1.0',
// dbcpVersion: 2,
// identity:
// '0x70c969a64e880fc904110ce9ab72ba5f95f706a252ac085ae0525bd7a284337c',
// dataSchema: { type: { type: 'string', '$id': 'type_schema' } } }
// update description
description.version = '0.1.1';
await container.setDescription(description);
// fetch again
console.dir(await container.getDescription());
// Output:
// { name: 'test container',
// description: 'container from test run',
// author: 'evan GmbH',
// version: '0.1.1',
// dbcpVersion: 2,
// identity:
// '0x70c969a64e880fc904110ce9ab72ba5f95f706a252ac085ae0525bd7a284337c',
// dataSchema: { type: { type: 'string', '$id': 'type_schema' } } }
= Utilities =¶
getContractAddress¶
container.getContractAddress();
Get contract address of underlying DataContract
.
Returns¶
Promise
returns string
: address of the DataContract
Example¶
const container = await Container.create(options, config);
console.log(await container.getContractAddress());
// Output:
// 0x0000000000000000000000000000000000001234
ensureProperty¶
container.ensureProperty(propertyName, dataSchema[, propertyType]);
Ensure that container supports given property.
Returns¶
Promise
returns void
: resolved when done
Example¶
await container.ensureProperty('testField', Container.defaultSchemas.stringEntry);
Additional Components¶
Interfaces¶
ContainerConfig¶
config properties, specific to Container instances
accountId
-string
: account id of user, that interacts with containeraddress
-string
(optional): address of aDataContract
instance, can be ENS or contract addressdescription
-string
(optional): description has to be passed to.create
to apply it to to contractfactoryAddress
-string
(optional): factory address can be passed to.create
for customer container factoryplugin
-string|ContainerPlugin
(optional): plugin to be used in.create
, can be string with name or aContainerPlugin
ContainerFile¶
description and content of a single file, usually used in arrays (add/get/set operations)
name
-string
: filename, e.g.animal-animal-photography-cat-96938.jpg
fileType
-string
: mime type of the file, e.g.image/jpeg
file
-Buffer
: file data as Buffer
ContainerPlugin¶
base definition of a container instance, covers properties setup and permissions
description
-any
: type of the template (equals name of the template)template
-ContainerTemplate
: template for container instances, covers properties setup and permissions
ContainerTemplate¶
template for container instances, covers properties setup and permissions
type
-string
: type of the template (equals name of the template)properties
-{ [id: string]: ContainerTemplateProperty; }
(optional): list of properties included in this template, key is field name, value is property setup
ContainerTemplateProperty¶
config for sharing multiple fields to one account (read and/or readWrite access)
dataSchema
-any
: Ajv data schema for fieldpermissions
-{ [id: number]: string[] }
: permissions for this template, key is role id, value is array with ‘set’ and/or ‘remove’type
-string
: type of property (entry/list)value
-any
(optional): value of property
ContainerVerificationEntry¶
data for verifications for containers
topic
-string
: verification pathdescriptionDomain
-string
(optional): domain, where the description of this verification is storeddisableSubverifications
-boolean
(optional): if set, verification created in a sub-path are invalid by default, defaults tofalse
expirationDate
-number
(optional): expiration date, verifications do not expire if omitted, defaults to0
verificationValue
-string
(optional): reference to additional verification details
Public Properties¶
defaultDescription (static)¶
Default description used when no specific description is given to .create.
defaultSchemas (static)¶
Predefined simple schemas, contains basic schemas for files, number, object, string entries and their list variants.
defaultTemplate (static)¶
Default template used when no specific description is given to .create. Default template is metadata
.
profileTemplatesKey (static)¶
Key that is used in user profile to store templates, default is templates.datacontainer.digitaltwin.evan
templates (static)¶
Predefined templates for containers, currently only contains the metadata
template.
This section includes modules, that deal with smart contract interactions, which includes:
- contract helper libraries, e.g. for
BaseContract
DataContract
ServiceContract
- permission management
- sharing keys for contracts
DFS (Distributed File System)¶
DFS Interface¶
Interface Name | DfsInterface |
---|---|
Source | dfs-interface.ts |
The DfsInterface is used to add or get files from the distributed file system. It is the only class, that has to be used before having access to a runtime, when using the createDefaultRuntime.
Internally the modules use the DfsInterface to access data as well. As the actual implementation of the file access may vary, an instance of the interface has to be created beforehand and passed to the createDefaultRuntime function. An implementation called Ipfs, that relies on the IPFS framework is included as in the package.
add¶
dfs.add(name, data);
add content to dfs file content is converted to Buffer (in NodeJS) or an equivalent “polyfill” (in browsers)
Parameters¶
name
-string
: name of the added filedata
-buffer
: data (as buffer) of the added file
Returns¶
string
: hash of the data.
Example¶
const fileHash = await runtime.dfs.add(
'about-maika-1.txt',
Buffer.from('we have a cat called "Maika"', 'utf-8'),
);
console.log(fileHash);
// Output:
// 0x695adc2137f1f069ff697aa287d0eae486521925a23482f180b3ae4e6dbf8d70
addMultiple¶
dfs.addMultiple(files);
Multiple files can be added at once. This way of adding should be preferred for performance reasons, when adding files, as requests are combined.
Parameters¶
files
-FileToAdd[]
: array with files to add
Returns¶
Promise
resolves to string[]
: hash array of the data.
Example¶
const fileHashes = await runtime.dfs.addMultiple([{
path: 'about-maika-1.txt',
content: Buffer.from('we have a cat called "Maika"', 'utf-8'),
}, {
path: 'about-maika-2.txt',
content: Buffer.from('she can be grumpy from time to time"', 'utf-8'),
}
]);
console.dir(fileHashes);
// Output:
// [ '0x695adc2137f1f069ff697aa287d0eae486521925a23482f180b3ae4e6dbf8d70',
// '0x6b85c8b24b59b12a630141143c05bbf40a8adc56a8753af4aa41ebacf108b2e7' ]
get¶
dfs.get(hash, returnBuffer);
get data from dfs by hash
Parameters¶
hash
-string
: hash (or bytes32 encoded) of the datareturnBuffer
-bool
: should the function return the plain buffer, defaults tofalse
Returns¶
Promise
resolves to string | buffer
: data as text or buffer.
Example¶
const fileBuffer = await runtime.dfs.get('0x695adc2137f1f069ff697aa287d0eae486521925a23482f180b3ae4e6dbf8d70');
console.log(fileBuffer.toString('utf-8'));
// Output:
// we have a cat called "Maika"
remove¶
dfs.remove(hash);
removes data by hash reference
Parameters¶
hash
-string
: hash (or bytes32 encoded) of the data
Returns¶
Promise
resolves to void
: resolved when done
Example¶
const fileBuffer = await runtime.dfs.remove('0x695adc2137f1f069ff697aa287d0eae486521925a23482f180b3ae4e6dbf8d70');
= Additional Components =¶
IPFS¶
Class Name | Ipfs |
---|---|
Implements | DfsInterface |
Extends | Logger |
Source | ipfs.ts |
Examples | ipfs.spec.ts |
This is DfsInterface implementation, that relies on the IPFS framework.
constructor¶
new Ipfs(options);
Creates a new IPFS instance.
Parameters¶
options
-IpfsOptions
: options for IPFS constructor.remoteNode
-any
: ipfs-api instance to remote servercache
-DfsCacheInterface
(optional):DfsCacheInterface
instancelog
-Function
(optional): function to use for logging:(message, level) => {...}
logLevel
-LogLevel
(optional): messages with this level will be logged withlog
logLog
-LogLogInterface
(optional): container for collecting log messageslogLogLevel
-LogLevel
(optional): messages with this level will be pushed tologLog
Returns¶
Ipfs
instance
ipfsHashToBytes32¶
dfs.ipfsHashToBytes32(hash);
convert IPFS hash to bytes 32 see https://www.reddit.com/r/ethdev/comments/6lbmhy/a_practical_guide_to_cheap_ipfs_hash_storage_in
Parameters¶
hash
-string
: IPFS hash
Returns¶
string
: bytes32 string.
Example¶
runtime.dfs.ipfsHashToBytes32('QmWmyoMoctfbAaiEs2G46gpeUmhqFRDW6KWo64y5r581Vz')
// returns 0x7D5A99F603F231D53A4F39D1521F98D2E8BB279CF29BEBFD0687DC98458E7F89
bytes32ToIpfsHash¶
dfs.bytes32ToIpfsHash(str);
convert bytes32 to IPFS hash see https://www.reddit.com/r/ethdev/comments/6lbmhy/a_practical_guide_to_cheap_ipfs_hash_storage_in
Parameters¶
str
-string
: bytes32 string
Returns¶
string
: IPFS Hash.
Example¶
runtime.dfs.ipfsHashToBytes32('0x7D5A99F603F231D53A4F39D1521F98D2E8BB279CF29BEBFD0687DC98458E7F8')
// returns QmWmyoMoctfbAaiEs2G46gpeUmhqFRDW6KWo64y5r581Vz
add¶
dfs.add(name, data);
add content to ipfs file content is converted to Buffer (in NodeJS) or an equivalent “polyfill” (in browsers)
Parameters¶
name
-string
: name of the added filedata
-buffer
: data (as buffer) of the added file
Returns¶
string
: ipfs hash of the data.
Example¶
const fileHash = await runtime.dfs.add(
'about-maika-1.txt',
Buffer.from('we have a cat called "Maika"', 'utf-8'),
);
console.log(fileHash);
// Output:
// 0x695adc2137f1f069ff697aa287d0eae486521925a23482f180b3ae4e6dbf8d70
addMultiple¶
dfs.addMultiple(files);
Multiple files can be added at once. This way of adding should be preferred for performance reasons, when adding files, as requests are combined.
Parameters¶
files
-FileToAdd[]
: array with files to add
Returns¶
Promise
resolves to string[]
: ipfs hash array of the data.
Example¶
const fileHashes = await runtime.dfs.addMultiple([{
path: 'about-maika-1.txt',
content: Buffer.from('we have a cat called "Maika"', 'utf-8'),
}, {
path: 'about-maika-2.txt',
content: Buffer.from('she can be grumpy from time to time"', 'utf-8'),
}
]);
console.dir(fileHashes);
// Output:
// [ '0x695adc2137f1f069ff697aa287d0eae486521925a23482f180b3ae4e6dbf8d70',
// '0x6b85c8b24b59b12a630141143c05bbf40a8adc56a8753af4aa41ebacf108b2e7' ]
pinFileHash¶
dfs.pinFileHash(hash);
pins file hashes on ipfs cluster
Parameters¶
hash
-string
: filehash of the pinned item
Returns¶
Promise
resolves to void
: resolved when done.
Example¶
const fileBuffer = await runtime.dfs.pinFileHash('QmWmyoMoctfbAaiEs2G46gpeUmhqFRDW6KWo64y5r581Vz');
get¶
dfs.get(hash, returnBuffer);
get data from ipfs by ipfs hash
Parameters¶
hash
-string
: ipfs hash (or bytes32 encoded) of the datareturnBuffer
-bool
: should the function return the plain buffer, defaults tofalse
Returns¶
Promise
resolves to string | buffer
: data as text or buffer.
Example¶
const fileBuffer = await runtime.dfs.get('0x695adc2137f1f069ff697aa287d0eae486521925a23482f180b3ae4e6dbf8d70');
console.log(fileBuffer.toString('utf-8'));
// Output:
// we have a cat called "Maika"
= Additional Components =¶
IPLD¶
Class Name | Ipld |
---|---|
Extends | Logger |
Source | ipld.ts |
Examples | ipld.spec.ts |
IPLD is a way to store data as trees. The used implementation relies on js-ipld-graph-builder for iterating over tree nodes and setting new subtrees, but uses a few modifications to the standard: - nodes are not stored as IPFS DAGs, but stored as play JSON IPFS files - nodes, that are encrypted, contain the property cryptoInfo for decryption (see Encryption)
constructor¶
new IPLD(options);
Creates a new Ipld instance.
Requires
Parameters¶
options
-IpldOptions
: The options used for callingcryptoProvider
-CryptoProvider
:CryptoProvider
instancedefaultCryptoAlgo
-string
: default encryption algorithmipfs
-Ipfs
:Ipfs
instancekeyProvider
-KeyProviderInterface
:KeyProviderInterface
instanceoriginator
-string
: originator of tree (default encryption context)nameResolver
-NameResolver
:NameResolver
instancelog
-Function
(optional): function to use for logging:(message, level) => {...}
logLevel
-LogLevel
(optional): messages with this level will be logged withlog
logLog
-LogLogInterface
(optional): container for collecting log messageslogLogLevel
-LogLevel
(optional): messages with this level will be pushed tologLog
Returns¶
IpldOptions
instance
store¶
ipld.store(toSet);
Store tree, if tree contains merklefied links, stores tree with multiple linked subtrees. Hashes returned from this function represent the the final tree, that can be stored as bytes32 hashes in smart contracts, etc.
Parameters¶
toSet
-any
: tree to store
Returns¶
Promise
returns string
: hash reference to a tree with with merklefied links
Example¶
const sampleObject = {
personalInfo: {
firstName: 'eris',
},
};
const stored = await ipld.store(Object.assign({}, sampleObject));
console.log(stored);
// Output:
// 0x12f6526dbe223eddd6c6a0fb7df118c87c56d34bf0c845b54bdca2fec0f3017d
When storing nested trees created with _ipld_set_, subtrees at junction points are stored as separate trees, then converted to serialized buffers, which are automatically deserialized and cast back when calling ipld_getLinkedGraph.
console.log(JSON.stringify(extended, null, 2));
const extendedstored = await ipld.store(Object.assign({}, extended));
// Output:
// "0xc74f6946aacbbd1418ddd7dec83a5bcd3710b384de767d529e624f9f08cbf9b4"
const loaded = await ipld.getLinkedGraph(extendedstored, '');
console.log(JSON.stringify(Ipld.purgeCryptoInfo(loaded), null, 2));
// Output:
//
// "personalInfo": {
// "firstName": "eris"
// },
// "dapps": {
// "/": {
// "type": "Buffer",
// "data": [ 18, 32, 246, 21, 166, 135, 236, 212, 70, 130, 94, 47, 81, 135, 153, 154, 201, 69, 109, 249, 97, 84, 252, 56, 214, 195, 149, 133, 116, 253, 19, 87, 217, 66 ]
// }
// }
//
getLinkedGraph¶
ipld.getLinkedGraph(graphReference[, path]);
Get a path from a tree; resolve subtrees only if required (depends on requested path).
Parameters¶
graphReference
-string | Buffer | any
: hash/buffer to look up or a graph objectpath
-string
(optional): path in the tree, defaults to''
Returns¶
Promise
returns any
: linked graph
Example¶
To retrieve data from IPLD trees, use the bytes32 hash from storing the data:
const stored = '0x12f6526dbe223eddd6c6a0fb7df118c87c56d34bf0c845b54bdca2fec0f3017d';
const loaded = await ipld.getLinkedGraph(stored, '');
console.dir(Ipld.purgeCryptoInfo(loaded));
// Output:
// { personalInfo: { firstName: 'eris' } }
For info about the Ipld.purgeCryptoInfo
part see Encryption.
The second argument is the path inside the tree. Passing ‘’ means “retrieve data from root level”. To get more specifc data, provide a path:
const stored = '0x12f6526dbe223eddd6c6a0fb7df118c87c56d34bf0c845b54bdca2fec0f3017d';
const loaded = await ipld.getLinkedGraph(stored, 'personalInfo');
console.dir(Ipld.purgeCryptoInfo(loaded));
// Output:
// { firstName: 'eris' }
const stored = '0x12f6526dbe223eddd6c6a0fb7df118c87c56d34bf0c845b54bdca2fec0f3017d';
const loaded = await ipld.getLinkedGraph(stored, 'personalInfo/firstName');
console.dir(Ipld.purgeCryptoInfo(loaded));
// Output:
// 'eris'
getResolvedGraph¶
ipld.getResolvedGraph(graphReference[, path, depth]);
Get a path from a tree; resolve links in paths up to depth (default is 10).
This function is for debugging and analysis purposes only, it tries to resolve the entire graph, which would be too much requests in most scenarios. If resolving graphs, prefer using ipld_getLinkedGraph, with specific queries into the tree, that limit the resolve requests.
Parameters¶
graphReference
-string | Buffer | any
: hash/buffer to look up or a graph objectpath
-string
(optional): path in the tree, defaults to''
depth
-number
(optional): resolve up do this many levels of depth, defaults to10
Returns¶
Promise
returns any
: resolved graph
Example¶
const treeHash = '0xc74f6946aacbbd1418ddd7dec83a5bcd3710b384de767d529e624f9f08cbf9b4';
console.dir(await ipld.getResolvedGraph(treeHash, ''));
// Output:
// { personalInfo: { firstName: 'eris' },
// dapps: { '/': { contracts: [Array], cryptoInfo: [Object] } },
// cryptoInfo:
// { originator: '0xd7c759941fa3962e4833707f2f44f8cb11b471916fb6f9f0facb03119628234e',
// keyLength: 256,
// algorithm: 'aes-256-cbc' } }
Compared to ipld_getLinkedGraph:
const treeHash = '0xc74f6946aacbbd1418ddd7dec83a5bcd3710b384de767d529e624f9f08cbf9b4';
console.dir(await ipld.getLinkGraph(treeHash, ''));
// Output:
// { personalInfo: { firstName: 'eris' },
// dapps:
// { '/':
// Buffer [18, 32, 246, 21, 166, 135, 236, 212, 70, 130, 94, 47, 81, 135, 153, 154, 201, 69, 109, 249, 97, 84, 252, 56, 214, 195, 149, 133, 116, 253, 19, 87, 217, 66] },
// cryptoInfo:
// { originator: '0xd7c759941fa3962e4833707f2f44f8cb11b471916fb6f9f0facb03119628234e',
// keyLength: 256,
// algorithm: 'aes-256-cbc' } }
set¶
ipld.set(tree, path, subtree[, plainObject, cryptoInfo]);
Set a value to a tree node; inserts new element as a linked subtree by default.
What’s pretty useful about IPLD graphs is, that not only plain JSON trees can be stored, but that those trees can be linked to other graphs, which makes it possible to build very powerful tree structures, that consist of multiple separate trees, that can be used on their own or in a tree, that combines all of those. The resulting hash is again bytes32
hash and this can be stored in smart contracts like any other IPFS hash.
This function adds the given subtree under a path in the existing tree. Different subtrees can be added by using this function multiple times. The final tree can then be stored to IPFS with ipld_store.
Parameters¶
tree
-any
: tree to extendpath
-string
: path of inserted elementsubtree
-any
: element that will be addedplainObject
-boolean
(optional): do not link values as new subtree, defaults tofalse
cryptoInfo
-CryptoInfo
(optional): crypto info for encrypting subtree
Returns¶
Promise
returns any
: tree with merklefied links
Example¶
const sampleObject = {
personalInfo: {
firstName: 'eris',
},
};
const sub = {
contracts: ['0x01', '0x02', '0x03']
};
const extended = await ipld.set(
sampleObject, // extend this graph
'dapps', // attach the subgraph under the path "dapps"
sub, // attach this graph as a subgraph
);
console.log(JSON.stringify(extended, null, 2));
// Output:
// {
// "personalInfo": {
// "firstName": "eris"
// },
// "dapps": {
// "/": {
// "contracts": [
// "0x01",
// "0x02",
// "0x03"
// ]
// }
// }
// }
remove¶
ipld.remove(tree, path);
Delete a value from a tree node.
Parameters¶
tree
-any
: tree to extendstring
-string
: path of inserted element
Returns¶
Promise
returns any
: tree with merklefied links
Example¶
const treeHash = '0xc74f6946aacbbd1418ddd7dec83a5bcd3710b384de767d529e624f9f08cbf9b4';
const loaded = await ipld.getLinkedGraph(treeHash, '');
console.log(loaded);
// Output:
// { personalInfo: { firstName: 'eris' },
// dapps:
// { '/': <Buffer 12 20 f6 15 a6 87 ec d4 46 82 5e 2f 51 87 99 9a c9 45 6d f9 61 54 fc 38 d6 c3 95 85 74 fd 13 57 d9 42> },
// cryptoInfo:
// { originator: '0xd7c759941fa3962e4833707f2f44f8cb11b471916fb6f9f0facb03119628234e',
// keyLength: 256,
// algorithm: 'aes-256-cbc' } }
const updated = await ipld.remove(loaded, 'dapps');
console.log(updated);
// Output:
// { personalInfo: { firstName: 'eris' },
// cryptoInfo:
// { originator: '0xd7c759941fa3962e4833707f2f44f8cb11b471916fb6f9f0facb03119628234e',
// keyLength: 256,
// algorithm: 'aes-256-cbc' } }
purgeCryptoInfo¶
Ipld.purgeCryptoInfo(toPurge);
(static class function)
Remove all cryptoInfos from tree.
Some example here use Ipld.purgeCryptoInfo
to cleanup the objects before logging them. This is done, because IPLD graphs are encrypted by default, which has a few impact on the data stored:
- The root node of a tree is “encrypted” with the encryption algorithm “unencrypted”, resulting in the root node having its data stored as a Buffer. This is done to keep the root node in the same format as the other nodes, as:
- Nodes in the Tree are encrypted. This encryption is specified in the constructor as defaultCryptoAlgo.
- All nodes are en- or decrypted with the same account or “originator”. The originator, that is used, is specified in the constructor as “originator”. This means, that the IPLD instance is account bound and a new instance has to be created if another account should be used.
Parameters¶
toPurge
-any
: The options used for calling
Returns¶
void
Example¶
To show the difference, without purging:
const stored = '0x12f6526dbe223eddd6c6a0fb7df118c87c56d34bf0c845b54bdca2fec0f3017d';
const loaded = await ipld.getLinkedGraph(stored, '');
console.dir(loaded);
// Output:
// { personalInfo: { firstName: 'eris' },
// cryptoInfo:
// { originator: '0xd7c759941fa3962e4833707f2f44f8cb11b471916fb6f9f0facb03119628234e',
// keyLength: 256,
// algorithm: 'aes-256-cbc' } }
//
With purging:
const stored = '0x12f6526dbe223eddd6c6a0fb7df118c87c56d34bf0c845b54bdca2fec0f3017d';
const loaded = await ipld.getLinkedGraph(stored, '');
console.dir(Ipld.purgeCryptoInfo(loaded));
// Output:
// { personalInfo: { firstName: 'eris' } }
The DFS section handles modules, that deal with managing data in distributed file system, like the DFS interface, its implementation for IPFS and the IPLD graph builder, that works on top of the IPFS impementation.
Encryption¶
Encryption Wrapper¶
Class Name | EncryptionWrapper |
---|---|
Extends | Logger |
Source | encryption-wrapper.ts |
Examples | encryption-wrapper.spec.ts |
Encryption processes othen deal with the following questions:
- Where to get a key from?
- Do I need to generate a new key? How can I store this?
- How to fetch a matching crypto?
- How to encrypt data?
EncryptionWrapper
handles these topcis and offers a fast way to work with encryption.
constructor¶
new EncryptionWrapper(options);
Create new EncryptionWrapper
instance.
Parameters¶
options
-DigitalTwinOptions
: runtime-like object with required modulescryptoProvider
-CryptoProvider
:CryptoProvider
instancenameResolver
-NameResolver
:NameResolver
instanceprofile
-Profile
:Profile
instancesharing
-Sharing
:Sharing
instanceweb3
-Web3
:Web3
instancelog
-Function
(optional): function to use for logging:(message, level) => {...}
logLevel
-LogLevel
(optional): messages with this level will be logged withlog
logLog
-LogLogInterface
(optional): container for collecting log messageslogLogLevel
-LogLevel
(optional): messages with this level will be pushed tologLog
factory
Returns¶
EncryptionWrapper
instance
Example¶
const encryptionWrapper = new EncryptionWrapper(runtime);
= CryptoInfos =¶
getCryptoInfo¶
encryptionWrapper.getCryptoInfo(keyContext, keyType, cryptorType[, artifacts])
CryptoInfo
s are descriptors for encrypted documents. They are stored alongside the encrypted data and provide a hint about the context of the data and how to decrypt them. In the EncryptionWrapper
they are also used as an option parameter for the encrypt
function.
Parameters¶
keyContext
-any
: used to identify key, can be any string (but must not have colons)keyType
-EncryptionWrapperKeyType
: defines where keys are storedcryptorType
-EncryptionWrapperCryptorType
: cryptor to useartifacts
-any
: (optional) additional information for encryption may be required, depends onkeyType
, see section below for details
artifacts¶
Depending on keyType
different properties are required. artifacts
can be omitted, if used keyType
is not listed below.
EncryptionWrapperKeyType.Sharing
:sharingContractId
-string
: contract address ofShared
orMultiShared
contractsharingId
-string
(optional): id in aMultiShared
contract and only used for them, defaults tonull
Returns¶
Promise
returns CryptoInfo
: crypto info built out of input arguments
Example¶
const keyContext = 'my key 15';
const cryptoInfo = await encryptionWrapper.getCryptoInfo(
keyContext,
EncryptionWrapperKeyType.Profile,
EncryptionWrapperCryptorType.Content,
);
console.dir(cryptoInfo);
// Output:
// { algorithm: 'aes-256-cbc',
// block: 198543,
// originator: 'profile:my key 15' }
= Key Handling =¶
generateKey¶
encryptionWrapper.generateKey(cryptoInfo);
Generates a new encryption key. Crypto algorithm in cryptoInfo
is used to decide on which Cryptor
to pick for this.
Parameters¶
cryptoInfo
-CryptoInfo
: details for encryption, can be created with getCryptoInfo
Returns¶
Promise
returns any
: key to encrypt/decrypt data
Example¶
const key = await encryptionWrapper.generateKey(cryptoInfo);
console.dir(key);
// Output:
// 'd387d41011a2f04f18930e982ad30c537d29bc12588164cb978d0f70a5d11b3f'
storeKey¶
encryptionWrapper.storeKey(cryptoInf[, artifacts]);
Store key in respective storage location, depending on given cryptoInfo, additional information may be required, which can be given via artifacts
.
Parameters¶
cryptoInfo
-CryptoInfo
: details for encryption, can be created with getCryptoInfokey
-any
: key to storeartifacts
-any
: (optional) additional information for encryption may be required, depends oncryptoInfo.originator
, see section below for details
artifacts¶
Depending on cryptoInfo.originator
different properties are required. artifacts
can be omitted, if used cryptoInfo.originator
schema is not listed below. Note, that cryptoInfo.originator
schema depends on with which EncryptionWrapperKeyType
getCryptoInfo was called.
sharing:.*
:accountId
-string
: accountId, that is used to share keys from, executes the internal transactionreceiver
-string
(optional): accountId, that receives the key, defaults toaccountId
Returns¶
Promise
returns void
: resolved when done
Example¶
const key = await encryptionWrapper.generateKey(cryptoInfo);
await encryptionWrapper.storeKey(cryptoInfo, key);
getKey¶
encryptionWrapper.getKey(cryptoInf[, artifacts]);
Get key for given cryptoInfo
. Can when storing keys in custom storage locations.
Parameters¶
cryptoInfo
-CryptoInfo
: details for encryption, can be created with getCryptoInfoartifacts
-any
: (optional) additional information for encryption may be required, depends oncryptoInfo.originator
, see section below for details
artifacts¶
Depending on cryptoInfo.originator
different properties are required. artifacts
can be omitted, if used cryptoInfo.originator
schema is not listed below. Note, that cryptoInfo.originator
schema depends on with which EncryptionWrapperKeyType
getCryptoInfo was called.
sharing:.*
:accountId
-string
: accountId, that accesses data, is used to get shared keys withpropertyName
-string
(optional): property, that is decrypted, defaults to'*'
custom:.*
:key
-string
: accountId, that accesses data, is used to get shared keys with
Returns¶
Promise
returns void
: resolved when done
Example¶
const keyContext = 'my key 15';
const cryptoInfo = await encryptionWrapper.getCryptoInfo(
keyContext,
EncryptionWrapperKeyType.Profile,
EncryptionWrapperCryptorType.Content,
);
console.dir(await encryptionWrapper.getKey(cryptoInfo));
// Output:
// '08bca9594ebaa7812f030f299fa30b51c5a7c3e7b2b66cd0a18c5cf46314aab7'
= Encryption =¶
encrypt¶
encryptionHandler.encrypt(toEncrypt, cryptoInfo[, artifacts]);
Encrypt given object, depending on given cryptoInfo
, additional information may be required, which can be given via artifacts
Parameters¶
toEncrypt
-any
: object to encryptcryptoInfo
-CryptoInfo
: details for encryption, can be created withgetCryptoInfos
artifacts
-any
: (optional) additional information for encryption may be required, depends oncryptoInfo.originator
, see section below for details
artifacts¶
Depending on cryptoInfo.originator
different properties are required. artifacts
can be omitted, if used cryptoInfo.originator
schema is not listed below. Note, that cryptoInfo.originator
schema depends on with which EncryptionWrapperKeyType
getCryptoInfo was called.
sharing:.*
:accountId
-string
: accountId, that accesses data, is used to get shared keys withpropertyName
-string
(optional): property, that is encrypted, defaults to'*'
custom:.*
:key
-string
: accountId, that accesses data, is used to get shared keys with
Returns¶
Promise
returns Envelope
: envelope with encrypted data
Example¶
const sampleData = {
foo: TestUtils.getRandomBytes32(),
bar: Math.random(),
};
const keyContext = 'my key 15';
const cryptoInfo = await encryptionWrapper.getCryptoInfo(
keyContext,
EncryptionWrapperKeyType.Profile,
EncryptionWrapperCryptorType.Content,
);
const encrypted = await encryptionWrapper.encrypt(sampleData, cryptoInfo);
// Output:
// { private:
// 'ec6a2e0401e6270c50a88db31d0a22b677516162925a87bb7ec11a80613275817b883e75ee4bc8f82fe681d3462cf8ad49fce9d08797045b0c4bf6e3407b507f610a6c9678b6d3525c3b951189e4fec5bcbe2e71d5e471c43e6a9b69bbfc2144b59bb56ef57267c3a31c575afc1dcb4cad6aaccd4f71db8e7e40c08910710ea0',
// cryptoInfo:
// { algorithm: 'aes-256-cbc',
// block: 198573,
// originator:
// 'profile:0xb1c492ee6085679497c73008100c3b3136a75a8519c2a0016fec686a05f1c7f0' } }
decrypt¶
encryptionHandler.decrypt(toDecrypt[, artifacts]);
Decrypt given Envelope
.
Parameters¶
toDecrypt
-any
: encrypted envelopartifacts
-any
: (optional) additional information for decrypting
artifacts¶
Depending on cryptoInfo.originator
different properties are required. artifacts
can be omitted, if used cryptoInfo.originator
schema is not listed below. Note, that cryptoInfo.originator
schema depends on with which EncryptionWrapperKeyType
getCryptoInfo was called.
sharing:.*
:accountId
-string
: accountId, that accesses data, is used to get shared keys withpropertyName
-string
(optional): property, that is decrypted, defaults to'*'
custom:.*
:key
-string
: accountId, that accesses data, is used to get shared keys with
Returns¶
Promise
returns Envelope
: envelope with encrypted data
Example¶
const sampleData = {
foo: TestUtils.getRandomBytes32(),
bar: Math.random(),
};
const keyContext = 'my key 15';
const cryptoInfo = await encryptionWrapper.getCryptoInfo(
keyContext,
EncryptionWrapperKeyType.Profile,
EncryptionWrapperCryptorType.Content,
);
const encrypted = await encryptionWrapper.encrypt(sampleData, cryptoInfo);
const decrypted = await encryptionWrapper.decrypt(encrypted);
console.dir(decrypt);
// Output:
// { foo:
// '0x746dccef8a185d9e34a2778af51e8ee7e513e4035f7a5e2c2d122904a21f32e6',
// bar: 0.618861426409717 }
Additional Components¶
Enums¶
DigitalTwinEntryType¶
Content
: content encryption is used for generic data (strings, in memory objects)File
: file encryption is used for binary file dataUnencrypted
: unencrypted data encryption can be used to embed unencrypted data in encryption containers
EncryptionWrapperKeyType¶
Custom
: custom key handling means that the key is handled elsewhere and has to be given to profileProfile
: key is stored in profile, usually in property “encryptionKeys”Sharing
: key is stored in Shared or MultiShared contract
Key Provider¶
Class Name | KeyProvider |
---|---|
Implements | KeyProviderInterface |
Extends | Logger |
Source | key-provider.ts |
The KeyProvider returns given decryption/encryption keys for a given CryptoInfo. They use a given evan.network profile to retrieve the needed keys to encrypt/decrypt the envelope
constructor¶
new KeyProvider(options);
Creates a new KeyProvider instance.
Parameters¶
options
-KeyProviderOptions
: options for KeyProvider constructor.keys
-any
(optional): object with key mappings of accountslog
-Function
(optional): function to use for logging:(message, level) => {...}
logLevel
-LogLevel
(optional): messages with this level will be logged withlog
logLog
-LogLogInterface
(optional): container for collecting log messageslogLogLevel
-LogLevel
(optional): messages with this level will be pushed tologLog
Returns¶
KeyProvider
instance
init¶
keyProvider.init(_profile);
initialize a new KeyProvider with a given evan.network Profile
Parameters¶
_profile
-Profile
: initialized evan.network profile
getKey¶
keyProvider.getKey(info);
get a encryption/decryption key for a specific CryptoInfo from the associated AccountStore or the loaded evan.network profile
Parameters¶
cryptoAlgo
-string
: crypto algorithm
Returns¶
Promise resolves to string
: the found key for the cryptoinfo.
Example¶
const cryptoInfo = {
"public": {
"name": "envelope example"
},
"private": "...",
"cryptoInfo": {
"algorithm": "unencrypted",
"keyLength": 256,
"originator": "0x0000000000000000000000000000000000000001,0x0000000000000000000000000000000000000002",
"block": 123
}
};
const key = runtime.keyProvider.getKey(info);
Crypto Provider¶
Class Name | CryptoProvider |
---|---|
Extends | CryptoProvider |
Source | crypto-provider.ts |
The CryptoProvider is a container for supported Cryptors and is able to determine, which Cryptor to use for encryption / decryption.
constructor¶
new CryptoProvider(cryptors);
Creates a new CryptoProvider instance.
Returns¶
CryptoProvider
instance
Example¶
const serviceContract = new CryptoProvider({
cryptors: {
aes: new Aes(),
unencrypted: new Unencrypted()
}
});
getCryptorByCryptoAlgo¶
cryptoProvider.getCryptorByCryptoAlgo(cryptoAlgo);
get a Cryptor matching the crypto algorithm
Parameters¶
cryptoAlgo
-string
: crypto algorithm
Returns¶
Cryptor
: matching cryptor.
getCryptorByCryptoInfo¶
cryptoProvider.getCryptorByCryptoInfo(info);
get a Cryptor matching the provided CryptoInfo
Parameters¶
info
-CryptoInfo
: details about en-/decryption
Returns¶
Cryptor
: matching cryptor.
Example¶
const cryptoInfo = {
"public": {
"name": "envelope example"
},
"private": "...",
"cryptoInfo": {
"algorithm": "unencrypted",
"keyLength": 256,
"originator": "0x0000000000000000000000000000000000000001,0x0000000000000000000000000000000000000002",
"block": 123
}
};
const cryptor = runtime.cryptoProvider.getCryptorByCryptoInfo(cryptoInfo);
= Additional Components =¶
Interfaces¶
Cryptor¶
options
-any
: options which will passed to the cryptor to work (like key for encryption)generateKey
-function
: generates a random key for encryption/decryptiongetCryptoInfo
-function
: returns a empty CryptoInfo object for the current Cryptorencrypt
-function
: function to encrypt a given messagedecrypt
-function
: function to decrypt a given message
Envelope¶
algorithm
-string
: algorithm used for encryptionblock
-number
(optional): block number for which related item is encryptedcryptorVersion
-number
(optional): version of the cryptor used. describes the implementation applied during decryption and not the algorithm version.originator
-string
(optional): context for encryption, this can be- a context known to all parties (e.g. key exchange)
- a key exchanged between two accounts (e.g. bmails)
- a key from a sharings info from a contract (e.g. DataContract)
defaults to 0
keyLength
-number
(optional): length of the key used in encryption
CryptoInfo¶
public
-any
(optional): unencrypted part of the data; will stay as is during encryptionprivate
-any
(optional): encrypted part of the data. If encrypting, this part will be encrypted, depending on the encryption. If already encrypted, this will be the encrypted valuecryptoInfo
-CryptoInfo
: describes used encryption
Cryptor - AES CBC¶
Class Name | Aes |
---|---|
Implements | Cryptor |
Extends | Logger |
Source | aes.ts |
Examples | aes.spec.ts |
The AES cryptor encodes and decodes content with aes-cbc.
constructor¶
new Aes(options);
Creates a new Aes instance.
Parameters¶
options
-AesOptions
: options for Aes constructor.log
-Function
(optional): function to use for logging:(message, level) => {...}
logLevel
-LogLevel
(optional): messages with this level will be logged withlog
logLog
-LogLogInterface
(optional): container for collecting log messageslogLogLevel
-LogLevel
(optional): messages with this level will be pushed tologLog
Returns¶
Aes
instance
getCryptoInfo¶
cryptor.getCryptoInfo(originator);
create new crypto info for this cryptor
Parameters¶
originator
-string
: originator or context of the encryption
Returns¶
CryptoInfo
: details about encryption for originator with this cryptor.
generateKey¶
cryptor.generateKey();
generate key for cryptor/decryption
Returns¶
Promise resolves to string
: key used for encryption.
encrypt¶
cryptor.encrypt(message, options);
‘encrypt’ a message (serializes message)
Parameters¶
message
-string
: message which should be encryptedoptions
-any
: cryptor optionskey
-string
: key used for encryption
Returns¶
Promise resolves to string
: encrypted message.
Example¶
const cryptor = new Aes();
const cryptoInfo = cryptor.encrypt('Hello World', { key: '0x12345' });
decrypt¶
cryptor.decrypt(message, options);
‘decrypt’ a message (deserializes message)
Parameters¶
message
-Buffer
: message which should be decryptedoptions
-any
: cryptor optionskey
-string
: key used for encryption
Returns¶
Promise resolves to any
: decrypted message.
Example¶
const cryptor = new Aes();
const cryptoInfo = cryptor.decrypt('afeweq41f1e61e3f', { key: '0x12345' });
Cryptor - AES ECB¶
Class Name | AesEcb |
---|---|
Implements | Cryptor |
Extends | Logger |
Source | aes-ecb.ts |
Examples | aes-ecb.spec.ts |
The AES ECB cryptor encodes and decodes content with aes-ecb.
constructor¶
new AesEcb(options);
Creates a new AesEcb instance.
Parameters¶
options
-AesEcbOptions
: options for AesEcb constructor.log
-Function
(optional): function to use for logging:(message, level) => {...}
logLevel
-LogLevel
(optional): messages with this level will be logged withlog
logLog
-LogLogInterface
(optional): container for collecting log messageslogLogLevel
-LogLevel
(optional): messages with this level will be pushed tologLog
Returns¶
AesEcb
instance
getCryptoInfo¶
cryptor.getCryptoInfo(originator);
create new crypto info for this cryptor
Parameters¶
originator
-string
: originator or context of the encryption
Returns¶
CryptoInfo
: details about encryption for originator with this cryptor.
generateKey¶
cryptor.generateKey();
generate key for cryptor/decryption
Returns¶
Promise resolves to string
: key used for encryption.
encrypt¶
cryptor.encrypt(message, options);
‘encrypt’ a message (serializes message)
Parameters¶
message
-string
: message which should be encryptedoptions
-any
: cryptor optionskey
-string
: key used for encryption
Returns¶
Promise resolves to string
: encrypted message.
Example¶
const cryptor = new Unencrypted();
const cryptoInfo = cryptor.encrypt('Hello World', { key: '0x12345' });
decrypt¶
cryptor.decrypt(message, options);
‘decrypt’ a message (deserializes message)
Parameters¶
message
-Buffer
: message which should be decryptedoptions
-any
: cryptor optionskey
-string
: key used for encryption
Returns¶
Promise resolves to any
: decrypted message.
Example¶
const cryptor = new Unencrypted();
const cryptoInfo = cryptor.decrypt('afeweq41f1e61e3f', { key: '0x12345' });
Cryptor - AES Blob¶
Class Name | AesBlob |
---|---|
Implements | Cryptor |
Extends | Logger |
Source | aes-blob.ts |
Examples | aes-blob.spec.ts |
The AES Blob cryptor encodes and decodes content with aes-cbc.
constructor¶
new AesBlob(options);
Creates a new AesBlob instance.
Parameters¶
options
-AesBlobOptions
: options for AesBlob constructor.dfs
-DfsInterface
:DfsInterface
instancelog
-Function
(optional): function to use for logging:(message, level) => {...}
logLevel
-LogLevel
(optional): messages with this level will be logged withlog
logLog
-LogLogInterface
(optional): container for collecting log messageslogLogLevel
-LogLevel
(optional): messages with this level will be pushed tologLog
Returns¶
AesBlob
instance
getCryptoInfo¶
cryptor.getCryptoInfo(originator);
create new crypto info for this cryptor
Parameters¶
originator
-string
: originator or context of the encryption
Returns¶
CryptoInfo
: details about encryption for originator with this cryptor.
generateKey¶
cryptor.generateKey();
generate key for cryptor/decryption
Returns¶
Promise resolves to string
: key used for encryption.
encrypt¶
cryptor.encrypt(message, options);
‘encrypt’ a message (serializes message)
Parameters¶
message
-string
: message which should be encryptedoptions
-any
: cryptor optionskey
-string
: key used for encryption
Returns¶
Promise resolves to string
: encrypted message.
Example¶
const cryptor = new AesBlob();
const cryptoInfo = cryptor.encrypt('Hello World', { key: '0x12345' });
decrypt¶
cryptor.decrypt(message, options);
‘decrypt’ a message (deserializes message)
Parameters¶
message
-Buffer
: message which should be decryptedoptions
-any
: cryptor optionskey
-string
: key used for encryption
Returns¶
Promise resolves to any
: decrypted message.
Example¶
const cryptor = new AesBlob();
const cryptoInfo = cryptor.decrypt('afeweq41f1e61e3f', { key: '0x12345' });
Cryptor - Unencrypted¶
Class Name | Unencrypted |
---|---|
Implements | Cryptor |
Extends | Logger |
Source | unencrypted.ts |
The Unencrypted cryptor encodes and decodes content “unencrypted” this means no encryption is applied to the content. So simply the content is public, only HEX encoded.
constructor¶
new Unencrypted(options);
Creates a new Unencrypted instance.
Parameters¶
options
-UnencryptedOptions
: options for Unencrypted constructor.log
-Function
(optional): function to use for logging:(message, level) => {...}
logLevel
-LogLevel
(optional): messages with this level will be logged withlog
logLog
-LogLogInterface
(optional): container for collecting log messageslogLogLevel
-LogLevel
(optional): messages with this level will be pushed tologLog
Returns¶
Unencrypted
instance
getCryptoInfo¶
cryptor.getCryptoInfo(originator);
create new crypto info for this cryptor
Parameters¶
originator
-string
: originator or context of the encryption
Returns¶
CryptoInfo
: details about encryption for originator with this cryptor.
generateKey¶
cryptor.generateKey();
generate key for cryptor/decryption
Returns¶
Promise resolves to string
: key used for encryption.
encrypt¶
cryptor.encrypt(message, options);
‘encrypt’ a message (serializes message)
Parameters¶
message
-string
: message which should be encryptedoptions
-any
: cryptor optionskey
-string
: key used for encryption
Returns¶
Promise resolves to string
: encrypted message.
Example¶
const cryptor = new Unencrypted();
const cryptoInfo = cryptor.encrypt('Hello World', { key: '0x12345' });
decrypt¶
cryptor.decrypt(message, options);
‘decrypt’ a message (deserializes message)
Parameters¶
message
-Buffer
: message which should be decryptedoptions
-any
: cryptor optionskey
-string
: key used for encryption
Returns¶
Promise resolves to any
: decrypted message.
Example¶
const cryptor = new Unencrypted();
const cryptoInfo = cryptor.decrypt('afeweq41f1e61e3f', { key: '0x12345' });
To allow extended data security, contents added to DFS can be encrypted before storing them and decrypted before reading them. To allow this encryption support has been added to the library.
Data is encrypted and stored in so called “Envelopes”, which act as container for the data itself and contain enough information for the API to determine which key to use for decryption and where to retrieve the key from. If you were wondering why the descriptions had the property public, this is the right section for you.
{
"public": {
"name": "envelope example"
},
"private": "...",
"cryptoInfo": {
"algorithm": "unencrypted",
"keyLength": 256,
"originator": "0x0000000000000000000000000000000000000001,0x0000000000000000000000000000000000000002",
"block": 123
}
}
The “public” section contains data, that is visible without any knowledge of the encryption key. The “private” section can only be decrypted if the user that tries to read the data has access to the encryption key. The cryptoInfo part is used to determine which decryption algorithm to use and where to look for it.
When decrypted, the private section takes precedence over the public section. This can lead to the private section overwriting sections of the public part. For example a public title may be replace with a “true” title (only visible for a group of people) from the private section.
Profile¶
Profile¶
Class Name | Profile |
---|---|
Extends | Logger |
Source | profile.ts |
Examples | profile.spec.ts |
A users profile is its personal storage for - contacts - encryption keys exchanged with contacts - an own public key for exchanging keys with new contacts - bookmarked ÐAPPs - created contracts
This data is stored as an IPLD Graphs per type and stored in a users profile contract. These graphs are independant from each other and have to be saved separately.
This contract is a DataContract and can be created via the factory at profile.factory.evan and looked up at the global profile index profile.evan. The creation process and landmap looks like this:

Basic Usage¶
// the bookmark we want to store
const sampleDesc = {
title: 'sampleTest',
description: 'desc',
img: 'img',
primaryColor: '#FFFFFF',
};
// create new profile, set private key and keyexchange partial key
await profile.createProfile(keyExchange.getDiffieHellmanKeys());
// add a bookmark
await profile.addDappBookmark('sample1.test', sampleDesc);
// store tree to contract
await profile.storeForAccount(profile.treeLabels.bookmarkedDapps);
constructor¶
new Profile(options);
Creates a new Profile instance.
Parameters¶
options
-ProfileOptions
: options for Profile constructoraccountId
-string
: account, that is the profile ownercontractLoader
-ContractLoader
:ContractLoader
instancedataContract
-DataContract
:DataContract
instanceexecutor
-Executor
:Executor
instanceipld
-Ipld
:Ipld
instancenameResolver
-NameResolver
:NameResolver
instancedefaultCryptoAlgo
-string
(optional): crypto algorith name fromCryptoProvider
, defaults toaes
log
-Function
(optional): function to use for logging:(message, level) => {...}
logLevel
-LogLevel
(optional): messages with this level will be logged withlog
logLog
-LogLogInterface
(optional): container for collecting log messageslogLogLevel
-LogLevel
(optional): messages with this level will be pushed tologLog
trees
-object
(optional): precached profile data, defaults to{}
Returns¶
Profile
instance
Example¶
const profile = new Profile({
accountId: accounts[0],
contractLoader,
dataContract,
executor,
ipld,
nameResolver,
});
createProfile¶
profile.createProfile(keys)
Create new profile, store it to profile index initialize addressBook and publicKey.
Parameters¶
keys
-any
: diffie hell man keys for account, created byKeyExchange
privateKey
-Buffer
: private key for key exchangepublicKey
-Buffer
: combination of shared secret and own private key
Returns¶
Promise
returns void
: resolved when done
checkCorrectProfileData¶
profile.checkCorrectProfileData();
Check if profile data is correct, according to a specific profile type. Throws, when the data is invalid.
Parameters¶
data
-object
: profile data (accountDetails, registration, contact, …) (see setProfileProperties for example values)type
-string
: profileType (user, company, device)
Returns¶
Promise
returns void
: true if a contract was registered, false if not
Example¶
console.log(await Profile.checkCorrectProfileData({
"accountDetails": {
"accountName": "Test",
"profileType": "company"
},
"registration": {
"company": "Company Name",
"court": "register court1",
"register": "hrb",
"registerNumber": "Registration Number",
"salesTaxID": "tax id"
},
"contact": {
"country": "DE",
"city": "City",
"postalCode": "12345",
"streetAndNumber": "street",
"website": "https://evan.network"
}
}, 'company'));
// Output:
// true
exists¶
profile.exists();
Check if a profile has been stored for current account.
Parameters¶
options
-object
: The options used for calling
Returns¶
Promise
returns void
: true if a contract was registered, false if not
getContactKnownState¶
profile.getContactKnownState(accountId);
Check, known state for given account.
Parameters¶
accountId
-string
: account id of a contact
Returns¶
Promise
returns void
: true if known account
getProfileProperty¶
profile.getProfileProperty(property);
Return the saved profile information according to the specified profile type. No type directly uses “user” type.
Parameters¶
property
-string
: Restrict properties that should be loaded.
Returns¶
Promise
returns void
: true if known account
Example¶
console.log(await profile.getProfileProperty('accountDetails'));
// Output:
// {
// "accountName": "Test",
// "profileType": "company"
// }
setContactKnownState¶
profile.setContactKnownState(accountId, contactKnown);
Store given state for this account.
Parameters¶
accountId
-string
: account id of a contactcontactKnown
-boolean
: true if known, false if not
Returns¶
Promise
returns void
: resolved when done
setProfileProperties¶
profile.setProfileProperties(payload);
Takes a set of profile properties and saves them into the profile DataContainer. Throws errors, if not the correct properties are applied for the specified account type.
Parameters¶
payload
-any
: Object that should saved. Each entry will be saved as seperated entry.
Returns¶
Promise
returns void
: resolved when done
Example¶
// mark accountId as a known contact
profile.setProfileProperties({
"accountDetails": {
"accountName": "Test",
"profileType": "company"
},
"registration": {
"company": "Company Name",
"court": "register court1",
"register": "hrb",
"registerNumber": "Registration Number",
"salesTaxID": "tax id"
},
"contact": {
"country": "DE",
"city": "Cirty",
"postalCode": "12345",
"streetAndNumber": "street",
"website": "https://evan.network"
}
});
loadForAccount¶
profile.loadForAccount([tree]);
Load profile for given account from global profile contract, if a tree is given, load that tree from ipld as well.
Parameters¶
tree
-string
(optional): tree to load (‘bookmarkedDapps’, ‘contracts’, …), profile.treeLabels properties can be passed as arguments
Returns¶
Promise
returns void
: resolved when done
storeForAccount¶
profile.storeForAccount(tree);
Stores profile tree or given hash to global profile contract.
Parameters¶
tree
-string
: tree to store (‘bookmarkedDapps’, ‘contracts’, …)ipldHash
-string
(optional): store this hash instead of the current tree for account
Returns¶
Promise
returns void
: resolved when done
loadFromIpld¶
profile.loadFromIpld(tree, ipldIpfsHash);
Load profile from ipfs via ipld dag via ipfs file hash.
Parameters¶
tree
-string
: tree to load (‘bookmarkedDapps’, ‘contracts’, …)ipldIpfsHash
-string
: ipfs file hash that points to a file with ipld a hash
Returns¶
Promise
returns Profile
: this profile
storeToIpld¶
profile.storeToIpld(tree);
Store profile in ipfs as an ipfs file that points to a ipld dag.
Parameters¶
tree
-string
: tree to store (‘bookmarkedDapps’, ‘contracts’, …)
Returns¶
Promise
returns string
: hash of the ipfs file
Example¶
const storedHash = await profile.storeToIpld(profile.treeLabels.contracts);
= addressBook =¶
addContactKey¶
profile.addContactKey(address, context, key);
Add a key for a contact to bookmarks.
Parameters¶
address
-string
: account key of the contactcontext
-string
: store key for this context, can be a contract, bc, etc.key
-string
: communication key to store
Returns¶
Promise
returns void
: resolved when done
addProfileKey¶
profile.addProfileKey(address, key, value);
Add a profile value to an account.
Parameters¶
address
-string
: account key of the contactkey
-string
: store key for the account like alias, etc.value
-string
: value of the profile key
Returns¶
Promise
returns void
: resolved when done
Example¶
await profile.addProfileKey(accounts[0], 'email', 'sample@example.org');
await profile.addProfileKey(accounts[0], 'alias', 'Sample Example');
getAddressBookAddress¶
profile.getAddressBookAddress(address);
Function description
Parameters¶
address
-string
: contact address
Returns¶
Promise
returns any
: bookmark info
getAddressBook¶
profile.getAddressBook();
Get the whole addressBook.
Parameters¶
(none)
Returns¶
any
: entire address book
getContactKey¶
profile.getContactKey(address, context);
Get a communication key for a contact from bookmarks.
Parameters¶
address
-string`
: account key of the contactcontext
-string`
: store key for this context, can be a contract, bc, etc.
Returns¶
Promise
returns void
: matching key
getProfileKey¶
profile.getProfileKey(address, key);
Get a key from an address in the address book.
Parameters¶
address
-string
: address to look upkey
-string
: type of key to get
Returns¶
Promise
returns any
: key
removeContact¶
profile.removeContact(address);
Remove a contact from bookmarkedDapps.
Parameters¶
address
-string
: account key of the contact
Returns¶
Promise
returns void
: resolved when done
Example¶
await profile.removeContact(address);
= bookmarkedDapps =¶
addDappBookmark¶
profile.addDappBookmark(address, description);
Add a bookmark for a dapp.
Parameters¶
address
-string
: ENS name or contract address (if no ENS name is set)description
-DappBookmark
: description for bookmark
Returns¶
Promise
returns void
: resolved when done
Example¶
const bookmark = {
"name": "taskboard",
"description": "Create todos and manage updates.",
"i18n": {
"description": {
"de": "Erstelle Aufgaben und überwache Änderungen",
"en": "Create todos and manage updates"
},
"name": {
"de": "Task Board",
"en": "Task Board"
}
},
"imgSquare": "...",
"standalone": true,
"primaryColor": "#e87e23",
"secondaryColor": "#fffaf5",
};
await profile.addDappBookmark('sampletaskboard.evan', bookmark);
getDappBookmark¶
profile.getDappBookmark(address);
Get a bookmark for a given address if any.
Parameters¶
address
-string
: ENS name or contract address (if no ENS name is set)
Returns¶
Promise
returns any
: bookmark info
getBookmarkDefinition¶
profile.getBookmarkDefinition();
Get all bookmarks for profile.
Parameters¶
(none)
Returns¶
Promise
returns any
: all bookmarks for profile
removeDappBookmark¶
profile.removeDappBookmark(address);
Remove a dapp bookmark from the bookmarkedDapps.
Parameters¶
address
-string
: address of the bookmark to remove
Returns¶
Promise
returns void
: resolved when done
setDappBookmarks¶
profile.setDappBookmarks(bookmarks);
Set bookmarks with given value.
Parameters¶
bookmarks
-any
: The options used for calling
Returns¶
Promise
returns void
: resolved when done
Example¶
const bookmarks = await profile.getBookmarkDefinitions();
// update bookmarks
// ...
await profile.setDappBookmarks(bookmarks);
= contracts =¶
addContract¶
profile.addContract(address, data);
Add a contract to the current profile.
Parameters¶
address
-string
: contract addressdata
-any
: bookmark metadata
Returns¶
Promise
returns void
: resolved when done
getContracts¶
profile.getContracts();
Get all contracts for the current profile.
Parameters¶
(none)
Returns¶
Promise
returns any
: contracts info
getContract¶
profile.getContract(address);
Get a specific contract entry for a given address.
Parameters¶
address
-string
: contact address
Returns¶
Promise
returns any
: bookmark info
addBcContract¶
profile.addBcContract(bc, address, data)
Add a contract (task contract etc. ) to a business center scope of the current profile
Parameters¶
bc
-string
: business center ens address or contract addressaddress
-string
: contact addressdata
-any
: bookmark metadata
Returns¶
Promise
returns void
: resolved when done
getBcContract¶
profile.getBcContract(bc, address);
Get a specific contract entry for a given address.
Parameters¶
bcc
-string
: business center ens address or contract addressaddress
-string
: contact address
Returns¶
Promise
returns any
: bookmark info
getBcContracts¶
profile.getBcContracts(bc, address);
Get all contracts grouped under a business center.
Parameters¶
bcc
-string
: business center ens address or contract address
Returns¶
Promise
returns any
: bookmark info
removeContract¶
profile.removeBcContract(address, data);
removes a contract (task contract etc. ) from a business center scope of the current profile
Parameters¶
bc
-string
: business center ens address or contract addressaddress
-any
: contact address
Returns¶
Promise
returns void
: resolved when done
Example¶
await profile.removeBcContract('testbc.evan', '0x');
= publicKey =¶
addPublicKey¶
profile.addPublicKey(key);
Add a key for a contact to bookmarks.
Parameters¶
key
-string
: public Diffie Hellman key part to store
Returns¶
Promise
returns void
: resolved when done
getPublicKey¶
profile.getPublicKey();
Get public key of profiles.
Parameters¶
(none)
Returns¶
Promise
returns any
: public key
loadActiveVerifications¶
profile.loadActiveVerifications();
Load all verificationss that should be displayed for this profile within the ui.
Parameters¶
(none)
Returns¶
Promise
returns string[]
: array of topics of verificationss that should be displayed (e.g. [ ‘/company/tuev’, ‘/test/1234’ ] )
setActiveVerifications¶
profile.setActiveVerifications(bookmarks);
Save an array of active verificationss to the profile.
Parameters¶
bookmarks
-string[]
: bookmarks to set
Returns¶
Promise
returns void
: resolved when saving is done
Example¶
await bcc.profile.setActiveVerifications([ '/company/tuev', '/test/1234' ]);
Business Center Profile¶
Class Name | BusinessCenterProfile |
---|---|
Extends | Logger |
Source | business-center-profile.ts |
Examples | business-center-profile.spec.ts |
The BusinessCenterProfile
module allows to create profiles in a business center.
These profiles are like business cards for specific contexts and can be used to share data like contact data or certificates under this business centers context.
Basic Usage¶
// update/set contact card locally
await profile.setContactCard(JSON.parse(JSON.stringify(sampleProfile)));
// store to business center
await profile.storeForBusinessCenter(businessCenterDomain, accounts[0]);
// load from business center
await profile.loadForBusinessCenter(businessCenterDomain, accounts[0]);
const loadedProfile = await profile.getContactCard();
constructor¶
new BusinessCenterProfile(options);
Creates a new BusinessCenterProfile instance.
Parameters¶
options
-BusinessCenterProfileOptions
: options for BusinessCenterProfile constructor.bcAddress
-string
: ENS address (domain name) of the business center, the module instance is scoped tocryptoProvider
-CryptoProvider
:CryptoProvider
instancedefaultCryptoAlgo
-string
: crypto algorith name fromCryptoProvider
ipld
-Ipld
:Ipld
instancenameResolver
-NameResolver
:NameResolver
instanceipldData
-any
(optional): preloaded profile datalog
-Function
(optional): function to use for logging:(message, level) => {...}
logLevel
-LogLevel
(optional): messages with this level will be logged withlog
logLog
-LogLogInterface
(optional): container for collecting log messageslogLogLevel
-LogLevel
(optional): messages with this level will be pushed tologLog
Returns¶
BusinessCenterProfile
instance
Example¶
const businessCenterProfile = new BusinessCenterProfile({
ipld,
nameResolver,
defaultCryptoAlgo: 'aes',
bcAddress: businessCenterDomain,
cryptoProvider,
});;
setContactCard¶
businessCenterProfile.setContactCard();
Set contact card on current profile.
Parameters¶
contactCard
-any
: contact card to store
Returns¶
Promise
returns any
: updated tree
getContactCard¶
businessCenterProfile.getContactCard();
Get contact card from.
Parameters¶
(none)
Returns¶
Promise
returns any
: contact card
storeForBusinessCenter¶
businessCenterProfile.storeForBusinessCenter(businessCenterDomain, account);
Stores profile to business centers profile store.
Parameters¶
businessCenerDomain
-string
: ENS domain name of a business centeraccount
-string
: Ethereum account id
Returns¶
Promise
returns void
: resolved when done
Example¶
await businessCenterProfile.setContactCard(contactCard);
await businessCenterProfile.storeForBusinessCenter(businessCenterDomain, accounts[0]);
loadForBusinessCenter¶
businessCenterProfile.loadForBusinessCenter(businessCenterDomain, account);
Function description
Parameters¶
businessCenerDomain
-string
: ENS domain name of a business centeraccount
-string
: Ethereum account id
Returns¶
Promise
returns void
: resolved when done
Example¶
await newProfilebusinessCenterProfile.loadForBusinessCenter(businessCenterDomain, accounts[0]);
const contactCard = await businessCenterProfile.getContactCard();
storeToIpld¶
businessCenterProfile.storeToIpld();
Store profile in ipfs as an ipfs file that points to a ipld dag.
Parameters¶
(none)
Returns¶
Promise
returns string
: hash of the ipfs file
loadFromIpld¶
businessCenterProfile.loadFromIpld(tree, ipldIpfsHash);
Load profile from ipfs via ipld dag via ipfs file hash.
Parameters¶
ipldIpfsHash
-string
: ipfs file hash that points to a file with ipld a hash
Returns¶
Promise
returns BusinessCenterProfile
: this profile
Example¶
businessCenterProfile.loadFromIpld(ipldIpfsHash);
Onboarding¶
Class Name | Onboarding |
---|---|
Extends | Logger |
Source | onboarding.ts |
Examples | onboarding.spec.ts |
The onboarding process is used to enable users to invite other users, where no blockchain account id is known. It allows to send an email to such contacts, that contains a link. This link points to a evan.network ÐApp, that allows accept the invitation by either creating a new account or by accepting it with an existing account.
It uses the Key Exchange module described in the last section for its underlying key exchange process but moves the process of creating a new communication key to the invited user.
To get in contact with a user via email, a smart agent is used. This smart agent has to be added as a contact and a regular key exchange with the smart agent is performed. The agent accepts the invitation automatically and the inviting user sends a bmail (blockchain mail) with the contact details of the user, that should be invited, and an amount of welcome EVEs to the smart agent.
The onboarding smart creates a session on his end and sends an email to the invited user, that includes the session token, with which the invited user can claim the welcome EVEs.
The invited user now creates or confirms an account and start the key exchange process on his or her end. The rest of the flow is as described in Key Exchange.
To start the process at from the inviting users side, make sure that this user has exchanged keys with the onboarding smart agent.
constructor¶
new Onboarding(options);
Creates a new Onboarding instance.
Parameters¶
options
-OnboardingOptions
: options for Onboarding constructorexecutor
-Executor
:Executor
instancemailbox
-Mailbox
:Mailbox
instancesmartAgentId
-string
: account id of onboarding smart agentlog
-Function
(optional): function to use for logging:(message, level) => {...}
logLevel
-LogLevel
(optional): messages with this level will be logged withlog
logLog
-LogLogInterface
(optional): container for collecting log messageslogLogLevel
-LogLevel
(optional): messages with this level will be pushed tologLog
Returns¶
Onboarding
instance
Example¶
const onboarding = new Onboarding({
mailbox,
smartAgentId: config.smartAgents.onboarding.accountId,
executor,
});
sendInvitation¶
onboarding.sendInvitation(invitation, weiToSend);
Send invitation to another user via smart agent that sends a mail.
Parameters¶
invitation
-invitation
: mail that will be sent to invited personweiToSend
-string
: amount of ETC to transfert to new member, can be created with web3.utils.toWei(10, ‘ether’) [web3 >=1.0] / web.toWei(10, ‘ether’) [web3 < 1.0]
Returns¶
Promise
returns void
: resolved when done
Example¶
await onboarding.sendInvitation({
fromAlias: 'example inviter',
to: 'example invitee <example.invitee@evan.network>',
lang: 'en',
subject: 'evan.network Onboarding Invitation',
body: 'I\'d like to welcome you on board.',
}, web3.utils.toWei('1'));
createMnemonic¶
Onboarding.createMnemonic();
(static class function)
Generates a new random Mnemonic
Returns¶
string
Example¶
To show the difference, without purging:
const mnemnonic = Onboarding.createMnemnonic();
console.log(mnemnoic);
// prints out a random 12 word mnemnonic
createNewProfile¶
Onboarding.createNewProfile(mnemnonic, password, profileProperties);
(static class function)
Creates a new full blown profile on a given evan network (testcore/core) and returns the mnemonic, password and a configuration for the runtime initalization
Parameters¶
mnemnonic
-string
: 12 word mnemnonic as stringpassword
-string
: password of the new created profileprofileProperties
-any
: Properties for the profile to be created
Returns¶
Promise
returns any
: object with the mnemonic, password and the config object for the runtime
Example¶
const originRuntime = await TestUtils.getRuntime(accounts[0]);
const mnemonic = Onboarding.createMnemonic();
await Onboarding.createNewProfile(originRuntime, mnemonicNew, 'Test1234', {
accountDetails: {
profileType: 'company',
accountName: 'test account'
}});
Key Exchange¶
Class Name | KeyExchange |
---|---|
Extends | Logger |
Source | keyExchange.ts |
Examples | keyExchange.spec.ts |
The KeyExchange
module is used to exchange communication keys between two parties, assuming that both have created a profile and have a public facing partial Diffie Hellman key part (the combination of their own secret and the shared secret). The key exchange consists of three steps:
- create a new communication key, that will be used by both parties for en- and decryption and store it on the initiators side
- look up the other parties partial Diffie Hellman key part and combine it with the own private key to create the exchange key
- use the exchange key to encrypt the communication key and send it via bmail (blockchain mail) to other party
Basic Usage¶
Starting the Key Exchange Process¶
This example retrieves public facing partial Diffie Hellman key part from a second party and sends an invitation mail to it:
// account, that initiates the invitation
const account1 = '0x0000000000000000000000000000000000000001';
// account, that will receive the invitation
const account2 = '0x0000000000000000000000000000000000000002';
// profile from user, that initiates key exchange
const profile1 = {};
await profile1.loadForAccount();
// profile from user, that is going to receive the invitation
const profile2 = {};
await profile2.loadForAccount();
// key exchange instance for account1
const keyExchange1 = {};
// key exchange instance for account2
const keyExchange2 = {};
const foreignPubkey = await profile2.getPublicKey();
const commKey = await keyExchange1.generateCommKey();
await keyExchange1.sendInvite(account2, foreignPubkey, commKey, {
fromAlias: 'Bob', // initiating user states, that his name is 'Bob'
});
await profile1.addContactKey(account2, 'commKey', commKey);
await profile1.storeForAccount(profile1.treeLabels.addressBook);
Finishing the Key Exchange Process¶
Let’s assume that the communication key from the last example has been successfully sent to the other party and continue at there end from here. To keep the roles from the last example, the variables profile1, profile2 will belong to the same accounts:
const encryptedCommKey = '...'; // key sent by account1
const profile1 = await profile1.getPublicKey();
const commSecret = keyExchange2.computeSecretKey(profile1);
const commKey = await keyExchange2.decryptCommKey(encryptedCommKey, commSecret.toString('hex'));
constructor¶
new KeyExchange(options);
Creates a new KeyExchange instance.
Parameters¶
options
-KeyExchangeOptions
: options for KeyExchange constructor.account
-string
: account, that will perform actionscryptoProvider
-CryptoProvider
:CryptoProvider
instancedefaultCryptoAlgo
-string
: default encryption algorithmkeyProvider
-KeyProviderInterface
:KeyProviderInterface
instancemailbox
-Mailbox
:Mailbox
instancelog
-Function
(optional): function to use for logging:(message, level) => {...}
logLevel
-LogLevel
(optional): messages with this level will be logged withlog
logLog
-LogLogInterface
(optional): container for collecting log messageslogLogLevel
-LogLevel
(optional): messages with this level will be pushed tologLog
privateKey
-object
(optional): private key for key exchange, ifprivateKey
orpublicKey
is omitted, new keys are generatedpublicKey
-object
(optional): public key for key exchange, ifprivateKey
orpublicKey
is omitted, new keys are generated
Returns¶
KeyExchange
instance
Example¶
const keyExchange = new KeyExchange({
mailbox,
cryptoProvider,
defaultCryptoAlgo: 'aes',
account: accounts[0],
keyProvider,
});
computeSecretKey¶
keyExchange.computeSecretKey(partialKey);
Combines given partial key from another profile with own private key.
Parameters¶
partialKey
-string
: The options used for calling
Returns¶
string
combined exchange key
Example¶
// encrypted communication key sent from account 1 to account 2
const encryptedKey = '...'
// (profile 1 belongs to account 1, keyExchange 2 to account 2)
const publicKeyProfile1 = await profile1.getPublicKey();
const commSecret = keyExchange2.computeSecretKey(publicKeyProfile1);
commKey = await keyExchange2.decryptCommKey(encryptedKey, commSecret.toString('hex'));
decryptCommKey¶
keyExchange.decryptCommKey(encryptedCommKey, exchangeKey);
Decrypts a given communication key with an exchange key.
Parameters¶
encryptedCommKey
-string
: encrypted communications key received from another accountexchangeKey
-string
: Diffie Hellman exchange key from computeSecretKey
Returns¶
Promise
returns Buffer
: commKey as a buffer
Example¶
// encrypted communication key sent from account 1 to account 2
const encryptedKey = '...'
// (profile 1 belongs to account 1, keyExchange 2 to account 2)
const publicKeyProfile1 = await profile1.getPublicKey();
const commSecret = keyExchange2.computeSecretKey(publicKeyProfile1);
commKey = await keyExchange2.decryptCommKey(encryptedKey, commSecret.toString('hex'));
getDiffieHellmanKeys¶
keyExchange.getDiffieHellmanKeys();
Returns the public and private key from the diffieHellman.
Parameters¶
(void)
Returns¶
Promise
returns any
: object with public and private keys
Example¶
console.dir(await keyExchange.getDiffieHellmanKeys());
// Output:
// {
// private: '...',
// public: '...',
// }
generateCommKey¶
keyExchange.generateCommKey();
Generates a new communication key end returns the hex string.
Parameters¶
(none)
Returns¶
Promise
returns string
: comm key as string
Example¶
console.dir(await keyExchange.generateCommKey());
// Output:
// '1c967697c192235680efbb24b980981b4778c8058b5e0864f1471fc1d941499d'
getExchangeMail¶
keyExchange.getExchangeMail(from, mailContent[, encryptionCommKey]);
Creates a bmail for exchanging comm keys.
Parameters¶
from
-string
: sender accountIdmailContent
-any
: bmail metadataencryptedCommKey
-string
(optional): comm key, that should be exchanged
Returns¶
Promise
returns Mail
: mail for key exchange
Example¶
const commKey = '1c967697c192235680efbb24b980981b4778c8058b5e0864f1471fc1d941499d';
const mail = keyExchange.getExchangeMail(
'0x0000000000000000000000000000000000000001',
{ fromAlias: 'user 1', fromMail: 'user1@example.com', title:'sample', body:'sample', }
);
console.log(mail);
// Output:
// { content:
// { from: '0x0000000000000000000000000000000000000001',
// fromAlias: 'user 1',
// fromMail: 'user1@example.com',
// title: 'sample',
// body: 'sample',
// attachments: [ [Object] ] } }
sendInvite¶
keyExchange.sendInvite(targetAccount, targetPublicKey, commKey, mailContent);
Sends a mailbox mail to the target account with the partial key for the key exchange.
Parameters¶
string
-targetAccount
: receiver of the invitationstring
-targetPublicKey
: combination of shared secret plus targetAccounts private secretstring
-commKey
: communication key between sender and targetAccountany
-mailContent
: mail to send
Returns¶
Promise
returns void
: resolved when done
Example¶
const foreignPubkey = await profile2.getPublicKey();
const commKey = await keyExchange1.generateCommKey();
await keyExchange1.sendInvite(accounts[1], foreignPubkey, commKey, { fromAlias: 'Bob', });
await profile.addContactKey(accounts[1], 'commKey', commKey);
await profile.storeForAccount(profile.treeLabels.addressBook);
setPublicKey¶
keyExchange.setPublicKey(publicKey, privateKey);
Set the private and public key on the current diffieHellman object.
Parameters¶
publicKey
-string
: public Diffie Hellman keyprivateKey
-string
: private Diffie Hellman key
Returns¶
(no return value)
Example¶
keyExchange.setPublicKey('...', '...');
Mailbox¶
Class Name | Mailbox |
---|---|
Extends | Logger |
Source | mailbox.ts |
Examples | mailbox.spec.ts |
The Mailbox module is used for sending and retrieving bmails (blockchain mails) to other even.network members. Sending regular bmails between to parties requires them to have completed a Key Exchange before being able to send encrypted messages. When exchanging the keys, bmails are encrypted with a commonly known key, that is only valid is this case and the underlying messages, that contain the actual keys are encrypted with Diffie Hellman keys, to ensure, that keys are exchanged in a safe manner (see Key Exchange for details).
The mailbox is a smart contract, that holds
bytes32
hashes, that are the encrypted contents of the mails- basic metadata about the mails, like
- recipient of a mail
- sender of a mail
- amount of EVEs, that belongs to the bmail
- if the mail is an answer to another mail, the reference to the original mail
constructor¶
new Mailbox(options);
Creates a new Mailbox instance.
Instances created with the constructor are not usable right from the start. They require the init() function to be called, before they are ready to use.
Parameters¶
options
-MailboxOptions
: options for Mailbox constructor.contractLoader
-ContractLoader
:ContractLoader
instancecryptoProvider
-CryptoProvider
:CryptoProvider
instancedefaultCryptoAlgo
-string
: crypto algorith name fromCryptoProvider
ipfs
-Ipfs
:Ipfs
instancekeyProvider
-KeyProviderInterface
:KeyProviderInterface
instancemailboxOwner
-string
: account, that will be used, when working with the mailboxnameResolver
-NameResolver
:NameResolver
instanceexecutor
-Executor
(optional):Executor
instancelog
-Function
(optional): function to use for logging:(message, level) => {...}
logLevel
-LogLevel
(optional): messages with this level will be logged withlog
logLog
-LogLogInterface
(optional): container for collecting log messageslogLogLevel
-LogLevel
(optional): messages with this level will be pushed tologLog
Returns¶
Mailbox
instance
Example¶
const mailbox = new Mailbox({
mailboxOwner,
nameResolver,
ipfs,
contractLoader,
cryptoProvider,
keyProvider,
defaultCryptoAlgo: 'aes',
});
await mailbox.init();
init¶
mailbox.init();
Initialize mailbox module.
This function needs to be called, before the mailbox module can be used.
Parameters¶
(none)
Returns¶
Promise
returns void
: resolved when done
Example¶
const mailbox = new Mailbox({
mailboxOwner,
nameResolver,
ipfs,
contractLoader,
cryptoProvider,
keyProvider,
defaultCryptoAlgo: 'aes',
});
await mailbox.init();
sendMail¶
mailbox.sendMail(mail, from, to[, value, context]);
Sends a mail to given target.
Parameters¶
mail
-Mail
: a mail to sendfrom
-string
: account id to send mail fromto
-string
: account id to send mail tovalue
-string
(optional): amount of EVEs to send with mail in Wei, can be created withweb3[.utils].toWei(...)
, defaults to0
context
-string
(optional): encryption context for bmail, if a special context should be used (e.g.keyExchange
)
Returns¶
Promise
returns void
: resolved when done
Example¶
// account, that sends the mail
const account1 = '0x0000000000000000000000000000000000000001';
// account, that receives the mail
const account2 = '0x0000000000000000000000000000000000000002';
// mailbox of the sender
const mailbox1 = {};
// mailbox of the receiver
const mailbox2 = {};
const bmail = {
content: {
from: account1,
to,
title: 'Example bmail',
body: 'This is a little example to demonstrate sending a bmail.',
attachments: [ ]
}
};
await mailbox1.sendMail(bmail, account1, account2);
sendAnswer¶
mailbox.sendAnswer(mail, from, to[, value, context]);
Send answer to a mail.
Parameters¶
mail
-Mail
: a mail to send,mail.parentId
must be set to mailId of mail, that is answeredfrom
-string
: account id to send mail fromto
-string
: account id to send mail tovalue
-string
(optional): amount of EVEs to send with mail in Wei, can be created withweb3[.utils].toWei(...)
, defaults to0
context
-string
(optional): encryption context for bmail, if a special context should be used (e.g.keyExchange
)
Returns¶
Promise
returns void
: resolved when done
Example¶
// account, that sends the answer
const account1 = '0x0000000000000000000000000000000000000001';
// account, that receives the answer
const account2 = '0x0000000000000000000000000000000000000002';
// mailbox of the sender
const mailbox1 = {};
// mailbox of the receiver
const mailbox2 = {};
const bmail = {
content: {
from: account1,
to,
title: 'Example bmail',
body: 'This is a little example to demonstrate sending a bmail.',
attachments: [ ]
},
parentId: '0x0000000000000000000000000000000000000000000000000000000000000012',
};
await mailbox1.sendAnswer(bmail, account1, account2);
getMails¶
mailbox.getMails([count, offset, type]);
Gets the last n mails, resolved contents.
Parameters¶
count
-number
(optional): retrieve up to this many answers (for paging), defaults to10
offset
-number
(optional): skip this many answers (for paging), defaults to0
type
-string
(optional): retrieve sent or received mails, defaults to'Received'
Returns¶
Promise
returns any
: resolved mails
Example¶
const received = await mailbox2.getMails();
console.dir(JSON.stringify(received[0], null, 2));
// Output:
// {
// "mails": {
// "0x000000000000000000000000000000000000000e": {
// "content": {
// "from": "0x0000000000000000000000000000000000000001",
// "to": "0x0000000000000000000000000000000000000002",
// "title": "Example bmail",
// "body": "This is a little example to demonstrate sending a bmail.",
// "attachments": [ ],
// "sent": 1527083983148
// },
// "cryptoInfo": {
// "originator": "0x549704d235e1fe5cd7326a1eb0c44c1e0a5434799ba6ff2370c2955730b66e2b",
// "keyLength": 256,
// "algorithm": "aes-256-cbc"
// }
// }
// },
// "totalResultCount": 9
// }
Results can be paged with passing arguments for page size and offsetto the getMails
function:
const received = await mailbox2.getMails(3, 0);
console.dir(JSON.stringify(received[0], null, 2));
// Output:
// { mails:
// { '0x000000000000000000000000000000000000000e': { content: [Object], cryptoInfo: [Object] },
// '0x000000000000000000000000000000000000000d': { content: [Object], cryptoInfo: [Object] },
// '0x000000000000000000000000000000000000000c': { content: [Object], cryptoInfo: [Object] } },
// totalResultCount: 9 }
To get bmails sent by an account, use (the example account hasn’t sent any bmail yet):
const received = await mailbox2.getMails(3, 0, 'Sent');
console.dir(JSON.stringify(received[0], null, 2));
// Output:
// { mails: {}, totalResultCount: 0 }
getMail¶
mailbox.getMail(mail);
Gets one single mail directly.
Parameters¶
mail
-string
: mail to resolve (mailId or hash)
Returns¶
Promise
returns void
: resolved when done
Example¶
const mailId = '0x0000000000000000000000000000000000000000000000000000000000000012';
const bmail = await mailbox.getMail(mailId);
getAnswersForMail¶
mailbox.getAnswersForMail(mailId[, count, offset]);
Gets answer tree for mail, traverses subanswers as well.
Parameters¶
mailId
-string
: mail to resolvecount
-number
(optional): retrieve up to this many answers, defaults to5
offset
-number
(optional): skip this many answers, defaults to0
Returns¶
Promise
returns any
: answer tree for mail
Example¶
const mailId = '0x0000000000000000000000000000000000000000000000000000000000000012';
const answers = await mailbox.getAnswersForMail(mailId);
getBalanceFromMail¶
mailbox.getBalanceFromMail(mailId);
Returns amount of EVE deposited for a mail.
Bmails can contain EVEs for the recipient as well. Because retrieving bmails is a reading operation, funds send with a bmail have to be retrieved separately.
Parameters¶
mailId
-string
: mail to resolve
Returns¶
Promise
returns string
: balance of the mail in Wei, can be converted with web3[.utils].fromWei(…)
Example¶
const bmail = {
content: {
from: account1,
to,
title: 'Example bmail',
body: 'This is a little example to demonstrate sending a bmail.',
attachments: [ ]
}
};
await mailbox1.sendMail(bmail, account1, account2, web3.utils.toWei('0.1', 'Ether'));
const received = await mailbox2.getMails(1, 0);
const mailBalance = await mailbox2.getBalanceFromMail(Object.keys(received)[0]);
console.log(mailBalance);
// Output:
// 100000000000000000
withdrawFromMail¶
mailbox.withdrawFromMail(mailId, recipient);
Funds from bmails can be claimed with the account, that received the bmail. Funds are transferred to a specified account, which can be the claiming account or another account of choice.
Parameters¶
mailId
-string
: mail to resolverecipient
-string
: account, that receives the EVEs
Returns¶
Promise
returns void
: resolved when done
Example¶
const received = await mailbox2.getMails(1, 0);
const mailBalance = await mailbox2.getBalanceFromMail(Object.keys(received)[0]);
console.log(mailBalance);
// Output:
// 100000000000000000
await mailbox2.withdrawFromMail(received)[0], accounts2);
const mailBalance = await mailbox2.getBalanceFromMail(Object.keys(received)[0]);
console.log(mailBalance);
// Output:
// 0
Verifications¶
Class Name | Verifications |
---|---|
Extends | Logger |
Source | verifications.ts |
Tests | verifications.spec.ts |
The Verifications
module allows to
- issue verifications about oneself or about other parties
- confirm or delete verifications about oneself
Verifications have a pattern similar to file paths, a verification for an account called “foo” being an employee of a company called “bar” may look like this:
/company/bar/employee
Under this “path” a set of values can be found. These value describe the verification, the subject of the verification and optional its response to it. Basically an issuer
creates a verification
about a subject
The values are:
verification (name)
full path to a verification, for example/company/bar/employee/foo
, settable by thesubject
of the parent verification/company/bar/employee
subject
an account, a verification has been issued for, can be a group/wallet or an externally owned account being thesubject
of averification
basically means to be the owner of the verification and allows to create subverifications below the own verification pathissuer
an account (group/wallet or externally owned) that creates a verification, to be able to issue a verification, theissuer
has to be thesubject
of the parent verification/company/bar/employee
data
The hash of the verification data, sitting in another location, a bit-mask, call data, or actual data based on the verification scheme.uri
The location of the verification, this can be HTTP links, swarm hashes, IPFS hashes, and such.status
this represents averifications
status, values areuint8
range from 0 to 255, the currently used values are: - 0: Issued - 1: Confirmedsignature
Signature which is the proof that the verification issuer issued a verification of topic for this identity. It MUST be a signed message of the following structure: keccak256(address identityHolder_address, uint256 _ topic, bytes data)creationDate
creationDate of the verificationid
id of the current verificationvalid
check if the verification has a valid signature
For a explanation on how to use verification API, possible flows and meaning of the results have a look at the verifications usage example.
constructor¶
new Verifications(options);
Creates a new Verifications instance.
Note, that the option properties registry
and resolver
are optional but should be provided
in most cases. As the module allows to create an own ENS structure, that includes an own ENS
registry and an own default resolver for it, setting them beforehand is optional.
Parameters¶
options
-VerificationsOptions
: options for Verifications constructor.accountStore
-AccountStore
:AccountStore
instanceconfig
-any
: config object withNameResolver
configcontractLoader
-ContractLoader
:ContractLoader
instancedescription
-Description
:Description
instancedfs
-DfsInterface
:DfsInterface
instanceexecutor
-Executor
:Executor
instancenameResolver
-NameResolver
:NameResolver
instancelog
-Function
(optional): function to use for logging:(message, level) => {...}
logLevel
-LogLevel
(optional): messages with this level will be logged withlog
logLog
-LogLogInterface
(optional): container for collecting log messageslogLogLevel
-LogLevel
(optional): messages with this level will be pushed tologLog
registry
-string
(optional): contract address of the identity storage registrystorage
-string
(optional): contract address of the identity storage registry
Returns¶
Verifications
instance
Example¶
const verifications = new Verifications({
accountStore,
config,
contractLoader,
description,
dfs,
executor,
nameResolver,
storage: '0x0000000000000000000000000000000000000001',
});
= Issuers =¶
createIdentity¶
verifications.createIdentity(accountId[, contractId, updateDescription]);
Creates a new identity for account or contract and registers them on the storage. Returned identity is either a 20B contract address (for account identities) or a 32B identity hash contract identities.
Parameters¶
accountId
-string
: account that runs transaction, receiver of identity when omitting the other argumentscontractId
-string
: (optional) contract address to create the identity for, creates account identity foraccountId
if omittedupdateDescription
-boolean
(optional): update description of contract, defaults totrue
Returns¶
Promise
returns void
: resolved when done
Example¶
const identity = await verifications.createIdentity(accounts[0]);
console.log(identity);
// Output:
// 0x1fE5F7235f1989621135466Ff8882287C63A5bae
identityAvailable¶
verifications.identityAvailable(subject);
Checks if a account has already an identity contract.
Parameters¶
subject
-string
: target subject to check
Returns¶
Promise
returns boolean
: true if identity exists, otherwise false
Example¶
console.log(await verifications.identityAvailable(accounts[0]);
// Output:
// false
await await verifications.createIdentity(accounts[0]);
console.log(await verifications.identityAvailable(accounts[0]);
// Output:
// true
getIdentityForAccount¶
verifications.getIdentityForAccount(subject);
Gets the identity contract for a given account id or contract.
Parameters¶
subject
-string
: target subject to get identity for
Returns¶
Promise
returns any
: identity contract instance
setVerification¶
verifications.setVerification(issuer, subject, topic, expirationDate, verificationValue, descriptionDomain, disableSubVerifications);
Sets or creates a verification; this requires the issuer to have permissions for the parent verification (if verification name seen as a path, the parent ‘folder’).
The “verificationValue” field can also be set to a custom JSON object with any data. For example DID, VC’s, documents or any other custom value you want to attach to the verification.
Parameters¶
issuer
-string
: issuer of the verificationsubject
-string
: subject of the verification and the owner of the verification nodetopic
-string
: name of the verification (full path)expirationDate
-number
(optional): expiration date, for the verification, defaults to0
(does not expire)verificationValue
-any
(optional): json object which will be stored in the verificationdescriptionDomain
-string
(optional): domain of the verification, this is a subdomain under ‘verifications.evan’, so passing ‘example’ will link verifications description to ‘example.verifications.evan’, unset if omitteddisableSubVerifications
-boolean
(optional): invalidate all verifications that gets issued as children of this verification (warning will include the disableSubVerifications warning)isIdentity
-boolean
(optional): boolean value if the subject is already a identity address (default false)uri
-string
(optional): adds a specific URI to the verification
Returns¶
Promise
returns string
: id of new verification
Example¶
// accounts[0] issues verification '/company' for accounts[1]
const firstVerification = await verifications.setVerification(accounts[0], accounts[1], '/company');
// accounts[0] issues verification '/companyData' for accounts[1] with additional data attached
const secondVerification = await verifications.setVerification(accounts[0], accounts[1], '/companyData', 0, {
additionalDocument: <binary buffer>
vcDid: {
"@context": [
"https://www.w3.org/2018/credentials/v1",
"https://www.w3.org/2018/credentials/examples/v1"
],
"id": "http://example.edu/credentials/3732",
"type": ["VerifiableCredential", "UniversityDegreeCredential"],
"credentialSubject": {
"id": "did:example:ebfeb1f712ebc6f1c276e12ec21",
"degree": {
"type": "BachelorDegree",
"name": "Bachelor of Science and Arts"
}
},
"proof": { }
}
});
// accounts[0] issues verification '/company' for accounts[1], sets an expiration date
// and links to description domain 'sample'
const thirdVerification = await verifications.setVerification(
accounts[0], accounts[1], '/company', expirationDate, verificationValue, 'example');
getVerifications¶
verifications.getVerifications(subject, topic, isIdentity]);
Gets verification information for a verification name from a given account; results has the following properties: creationBlock, creationDate, data, description, expirationDate, id, issuer, name, signature, status, subject, topic, uri, valid.
Parameters¶
subject
-string
: subject of the verificationstopic
-string
: name (/path) of a verificationisIdentity
-string
(optional): indicates if the subject is already an identity
Returns¶
Promise
returns any[]
: verification info array,
Verifications have the following properties:
creationBlock
-string
: block number at which verification was issuedcreationDate
-string
: UNIX timestamp (in seconds), at which verification was issueddata
-string
: 32Bytes hash of data stored in DFSdescription
-any
: DBCP descriptiondisableSubVerifications
-boolean
:true
if this verification does not allow verifications at subtopicsexpirationDate
-string
:string
: UNIX timestamp (in seconds), null if verification does not expireexpired
-boolean
: ticket expiration stateid
-string
: 32Bytes id of verificationissuer
-string
: account address of issuers identity contractname
-string
: topic of verificationrejectReason
-any
: object with information from subject about rejectionsignature
-string
: arbitrary length hex string with signature of verification data, signed by issuerstatus
-number
: 0 (Issued) || 1 (Confirmed) || 2 (Rejected)subject
-string
: accountId of subjecttopic
-string
: keccak256 hash of the topic name, converted to uint256uri
-string
: link to ipfs file of datavalid
-boolean
:true
if issuer has been correctly confirmed as the signer ofsignature
and ifsignature
is related tosubject
,topic
anddata
Example¶
const verificationId = await verifications.setVerification(
accounts[0], accounts[1], '/example1');
console.log(verificationId);
// Output:
// 0xb4843ed5177433312dd2c7c4f8065ce84f37bf96c04db2775c16c9455ad96270
const issued = await verifications.getVerifications(accounts[1], '/example1');
console.dir(issued);
// Output:
// [ {
// creationBlock: '186865',
// creationDate: '1558599441',
// data: '0x0000000000000000000000000000000000000000000000000000000000000000',
// description: null,
// disableSubVerifications: false,
// expirationDate: null,
// expired: false,
// id: '0xb4843ed5177433312dd2c7c4f8065ce84f37bf96c04db2775c16c9455ad96270',
// issuer: '0xe560eF0954A2d61D6006E8547EC769fAc322bbCE',
// name: '/example1',
// rejectReason: undefined,
// signature: '0x6a2b41714c1faac09a5ec06024c8931ad6e3aa902c502e3d1bc5d5c4577288c04e9be136c149b569e0456dfec9d50a2250bf405443ae9bccd460c49a2c4287df1b',
// status: 0,
// subject: '0x0030C5e7394585400B1FB193DdbCb45a37Ab916E',
// topic: '34884897835812838038558016063403566909277437558805531399344559176587016933548',
// uri: '',
// valid: true
// } ]
getNestedVerifications¶
getNestedVerifications(subject, topic, isIdentity);
Get all the verifications for a specific subject, including all nested verifications for a deep integrity check.
Parameters¶
subject
-string
: subject to load the verifications for.topic
-string
: topic to load the verifications for.isIdentity
-boolean
: optional indicates if the subject is already a identity
Returns¶
Promise
returns Array<any>
: all the verifications with the following properties.
Example¶
const nestedVerifications = await getNestedVerifications('0x123...', '/test')
// will return
[
{
// creator of the verification
issuer: '0x1813587e095cDdfd174DdB595372Cb738AA2753A',
// topic of the verification
name: '/company/b-s-s/employee/swo',
// -1: Not issued => no verification was issued
// 0: Issued => status = 0, warning.length > 0
// 1: Confirmed => issued by both, self issued state is 2, values match
status: 2,
// verification for account id / contract id
subject: subject,
// ???
value: '',
// ???
uri: '',
// ???
signature: ''
// icon for cards display
icon: 'icon to display',
// if the verification was rejected, a reject reason could be applied
rejectReason: '' || { },
// subjec type
subjectType: 'account' || 'contract',
// if it's a contract, it can be an contract
owner: 'account' || 'contract',: 'account' || 'contract',
// warnings
[
// parent verification does not allow subverifications
'disableSubVerifications',
// verification has expired
'expired',
// signature does not match requirements, this could be because it hasn't been signed by
// correct account or underlying checksum does not match
// ``subject``, ``topic`` and ``data``
'invalid',
// verification has been issued, but not accepted or rejected by subject
'issued',
// verification has not been issued
'missing',
// given subject has no identity
'noIdentity',
// verification path has a trusted root verification topic, but this verification is not
// signed by a trusted instance
'notEnsRootOwner',
// parent verification is missing in path
'parentMissing',
// verification path cannot be traced back to a trusted root verification
'parentUntrusted',
// verification has been issued and then rejected by subject
'rejected',
// verification issuer is the same account as the subject
'selfIssued',
],
parents: [ ... ],
parentComputed: [ ... ]
}
]
getNestedVerificationsV2¶
getNestedVerificationsV2(subject, topic[, isIdentity, queryOptions]);
Get verifications and their parent paths for a specific subject, then format it to updated result format.
Parameters¶
subject
-string
: subject (account/contract or identity)topic
-string
: topic (verification name) to checkisIdentity
-boolean
: true if subject is identityqueryOptions
-VerificationsQueryOptions
: options for query and status computation
Returns¶
Promise
returns VerificationsResultV2
: verification result object with status, verification data and tree
Example¶
const validationOptions: VerificationsValidationOptions = {
disableSubVerifications: VerificationsStatusV2.Red,
expired: VerificationsStatusV2.Red,
invalid: VerificationsStatusV2.Red,
issued: VerificationsStatusV2.Yellow,
missing: VerificationsStatusV2.Red,
noIdentity: VerificationsStatusV2.Red,
notEnsRootOwner: VerificationsStatusV2.Yellow,
parentMissing: VerificationsStatusV2.Yellow,
parentUntrusted: VerificationsStatusV2.Yellow,
rejected: VerificationsStatusV2.Red,
selfIssued: VerificationsStatusV2.Yellow,
};
const queryOptions: VerificationsQueryOptions = {
validationOptions: validationOptions,
};
const nestedVerificationsV2 = await verifications.getNestedVerificationsV2(
accounts[1], '/example1', false, queryOptions);
console.dir(nestedVerificationsV2);
// Output:
// { verifications:
// [ { details:
// { creationDate: 1561722858000,
// ensAddress:
// '4d2027082fdec4ee253363756eccb1b5492f61fb6329f25d8a7976d7909c10ac.example1.verifications.evan',
// id:
// '0x855a3c10b9cd6d42da5fd5e9b61e0f98a5af79b1acbfee57a9e4f3c9721f9c5d',
// issuer: '0x5035aEe29ea566F3296cdD97C29baB2b88C17c25',
// issuerIdentity: '0xD2860FeC7A198A646f9fD1207B59aD42f00c3189',
// subject: '0x9aE6533e7a2C732863C0aF792D5EA358518cd757',
// subjectIdentity: '0x9F870954c615E4457660D22BE0F38FE0200b1Ed9',
// subjectType: '0x9F870954c615E4457660D22BE0F38FE0200b1Ed9',
// topic: '/example1',
// status: 'green' },
// raw:
// { creationBlock: '224038',
// creationDate: '1561722858',
// data:
// '0x0000000000000000000000000000000000000000000000000000000000000000',
// disableSubVerifications: false,
// signature:
// '0x941f316d77f5c1dc8b38000ecbb60304554ee2fb36453487ef7822ce6d8c7ce5267bb62396cfb08191028099de2e28d0ffd4012608e8a622e9e7a6a9570a88231b',
// status: 1,
// topic:
// '34884897835812838038558016063403566909277437558805531399344559176587016933548' },
// statusFlags: [] } ],
// levelComputed:
// { subjectIdentity: '0x9F870954c615E4457660D22BE0F38FE0200b1Ed9',
// subjectType: 'account',
// topic: '/example1',
// subject: '0x9aE6533e7a2C732863C0aF792D5EA358518cd757' },
// status: 'green' }
computeVerifications¶
bcService.computeVerifications(topic, verifications);
Takes an array of verifications and combines all the states for one quick view.
Parameters¶
topic
-string
: topic of all the verificationsverifications
-Array<any>
: all verifications of a specific topic
Returns¶
any
: computed verification including latest creationDate, displayName
Example¶
// load all sub verifications
verification.parents = await verifications.getNestedVerifications(verification.issuerAccount, verification.parent || '/', false);
// use all the parents and create a viewable computed tree
const computed = verifications.computeVerifications(verification.topic, verification.parents)
// returns =>
// const computed:any = {
// verifications: verifications,
// creationDate: null,
// displayName: topic.split('/').pop() || 'evan',
// loading: verifications.filter(verification => verification.loading).length > 0,
// name: topic,
// status: -1,
// subjects: [ ],
// warnings: [ ],
// }
getComputedVerification¶
getComputedVerification(subject, topic, isIdentity);
Loads a list of verifications for a topic and a subject and combines to a single view for a simple verification status check, by combining getNestedVerifications
with computeVerifications
.
Parameters¶
subject
-string
: subject to load the verifications for.topic
-string
: topic to load the verifications for.isIdentity
-boolean
: optional indicates if the subject is already a identity
Returns¶
any
: computed verification including latest creationDate, displayName
Example¶
// use all the parents and create a viewable computed tree
const computed = verifications.getComputedVerification(subject, topic)
// returns =>
// const computed:any = {
// verifications: verifications,
// creationDate: null,
// displayName: topic.split('/').pop() || 'evan',
// loading: verifications.filter(verification => verification.loading).length > 0,
// name: topic,
// status: -1,
// subjects: [ ],
// warnings: [ ],
// }
validateVerification¶
verifications.validateVerification(subject, verificationId, isIdentity]);
validates a given verificationId in case of integrity
Parameters¶
subject
-string
: subject of the verificationsverificationId
-string
: The verification identifierisIdentity
-boolean
(optional): indicates if the subject is already an identity, defaults tofalse
Returns¶
Promise
returns boolean
: resolves with true if the verification is valid, otherwise false
Example¶
console.dir(await verifications.validateVerification(
accounts[1]),
'0x0000000000000000000000000000000000000000000000000000000000000000',
);
// Output:
true
deleteVerification¶
verifications.deleteVerification(accountId, subject, verificationId[, isIdentity]);
Delete a verification. This requires the accountId to have permissions for the parent verification (if verification name seen as a path, the parent ‘folder’). Subjects of a verification may only delete it, if they are the issuer as well. If not, they can only react to it by confirming or rejecting the verification.
Parameters¶
accountid
-string
: account, that performs the actionsubject
-string
: the subject of the verificationverificationId
-string
: id of a verification to deleteisIdentity
-bool
(optional):true
if givensubject
is an identity, defaults tofalse
Returns¶
Promise
returns void
: resolved when done
Example¶
const verificationId = await verifications.setVerification(accounts[0], accounts[1], '/company');
await verifications.deleteVerification(accounts[0], accounts[1], verificationId);
= Subjects =¶
confirmVerification¶
verifications.confirmVerification(accountId, subject, verificationId[, isIdentity]);
Confirms a verification; this can be done, if a verification has been issued for a subject and the subject wants to confirm it.
Parameters¶
accountId
-string
: account, that performs the actionsubject
-string
: verification subjectverificationId
-string
: id of a verification to confirmisIdentity
-bool
(optional):true
if givensubject
is an identity, defaults tofalse
Returns¶
Promise
returns void
: resolved when done
Example¶
const newVerification = await verifications.setVerification(accounts[0], accounts[1], '/company');
await verifications.confirmVerification(accounts[0], accounts[1], newVerification);
rejectVerification¶
verifications.rejectVerification(accountId, subject, verificationId[, rejectReason, isIdentity]);
Reject a Verification. This verification will be marked as rejected but not deleted. This is important for tracking reasons. You can also optionally add a reject reason as JSON object to track additional informations about the rejection. Issuer and Subject can reject a special verification.
Parameters¶
accountid
-string
: account, that performs the actionsubject
-string
: the subject of the verificationverificationId
-string
: id of a verification to deleterejectReason
-object
(optional): JSON Object of the rejection reasonisIdentity
-bool
(optional):true
if givensubject
is an identity, defaults tofalse
Returns¶
Promise
returns void
: resolved when done
Example¶
const verificationId = await verifications.setVerification(accounts[0], accounts[1], '/company');
await verifications.rejectVerification(accounts[0], accounts[1], verificationId, { rejected: "because not valid anymore"});
= Delegated Verifications =¶
signSetVerificationTransaction¶
verifications.signSetVerificationTransaction(issuer, subject, topic[, expirationDate, verificationValue, descriptionDomain, disableSubVerifications, isIdentity, executionNonce]);
Signs a verification (offchain) and returns data, that can be used to submit it later on. Return value can be passed to executeVerification
.
Note that, when creating multiple signed verification transactions, the nonce
argument has to be specified and incremented between calls, as the nonce is included in transaction data and restricts the order of transactions, that can be made.
Parameters¶
issuer
-string
: issuer of the verificationsubject
-string
: subject of the verification and the owner of the verification nodetopic
-string
: name of the verification (full path)expirationDate
-number
(optional): expiration date, for the verification, defaults to0
(does not expire)verificationValue
-any
(optional): json object which will be stored in the verificationdescriptionDomain
-string
(optional): domain of the verification, this is a subdomain under ‘verifications.evan’, so passing ‘example’ will link verifications description to ‘example.verifications.evan’, unset if omitteddisableSubVerifications
-boolean
(optional): invalidate all verifications that gets issued as children of this verification (warning will include the disableSubVerifications warning)isIdentity
-boolean
(optional): true if given subject is identity, defaults tofalse
executionNonce
-number
(optional): current execution nonce of issuer identity contract, defaults to-1
(fetch dynamically)uri
-string
(optional): adds a specific URI to the verification
Returns¶
Promise
returns VerificationsDelegationInfo
: data for submitting delegated verifications
Example¶
// accounts[0] wants to issue a verification for accounts[1] via delegation
const txInfo = await verifications.signSetVerificationTransaction(
accounts[0], accounts[1], '/company');
executeVerification¶
verifications.executeVerification(accountId, txInfo);
Executes a pre-signed verification transaction with given account.
This account will be the origin of the transaction and not of the verification.
Second argument is generated with signSetVerificationTransaction
.
Parameters¶
accountId
-string
: account, that submits the transactiontxInfo
-VerificationsDelegationInfo
: information with verification tx data
Returns¶
Promise
returns string
: id of new verification
Example¶
// accounts[0] wants to issue a verification for accounts[1] via delegation
const txInfo = await verifications.signSetVerificationTransaction(
accounts[0], accounts[1], '/company');
// accounts[2] submits transaction, that actually issues verification
const verificationId = await verifications.executeVerification(accounts[2], txInfo);
getExecutionNonce¶
verifications.getExecutionNonce(issuer[, isIdentity]);
Gets current execution nonce for an identity or an accounts identity.
Nonce is returned as string
. When using nonces for preparing multiple transactions, small nonces can just be parsed to a number and then incremented as needed. Consider using BigNumber or similar modules to deal with large numbers if required.
Parameters¶
issuer
-string
: account or identity to get execution nonce forisIdentity
-boolean
(optional): true if given issuer is an identity, defaults tofalse
Returns¶
Promise
returns string
: execution nonce
Example¶
// nonce in this example is relatively small, so we can just parse it and use it as a number
// consider using BigNumber or similar to deal with larger numbers if required
let nonce = JSON.parse(await verifications.getExecutionNonce(accounts[0]));
const txInfos = await Promise.all(['/example1', '/example2', '/example3'].map(
topic => verifications.signSetVerificationTransaction(
accounts[0], accounts[1], topic, 0, null, null, false, false, nonce++)
));
= Delegated Transactions =¶
signTransaction¶
verifications.signTransaction(contract, functionName, options[, ...args]);
Signs a transaction from an identity (offchain) and returns data, that can be used to submit it later on. Return value can be passed to executeTransaction
.
Note that, when creating multiple signed transactions, the nonce
argument has to be specified and incremented between calls, as the nonce is included in transaction data and restricts the order of transactions, that can be made.
Parameters¶
contract
-any
: target contract of transcation ornull
if just sending fundsfunctionName
-string
: function for transaction ornull
if just sending fundsoptions
-any
: options for transaction, supports from, to, nonce, input, valueargs
-any[]
(optional): arguments for function transaction
Returns¶
Promise
returns VerificationsDelegationInfo
: prepared transaction for executeTransaction
Example¶
// create test contract
const testContract = await executor.createContract(
'TestContract', ['old data'], { from: accounts[0], gas: 500000 });
let data = await executor.executeContractCall(testContract, 'data');
// on account[0]s side
const txInfo = await verifications.signTransaction(
testContract,
'setData',
{ from: accounts[0] },
'new data',
);
// on account[2]s side
await verifications.executeTransaction(accounts[2], txInfo);
// now check
data = await executor.executeContractCall(testContract, 'data');
executeTransaction¶
verifications.executeTransaction(accountId, txInfo);
Executes a pre-signed transaction from signTransaction
of an identity. This can be and usually is a transaction, that has been prepared by the identity owner and is now submitted to the chain and executed by another account.
Parameters¶
accountId
-string
: account, that sends transaction to the blockchain and pays for ittxInfo
-VerificationsDelegationInfo
: details about the transactionpartialOptions
-any
(optional): data for handling event triggered by this transaction
Returns¶
Promise
returns any
: result of transaction (if received from event)
Example¶
// create test contract
const testContract = await executor.createContract(
'TestContract', ['old data'], { from: accounts[0], gas: 500000 });
let data = await executor.executeContractCall(testContract, 'data');
// on account[0]s side
const txInfo = await verifications.signTransaction(
testContract,
'setData',
{ from: accounts[0] },
'new data',
);
// on account[2]s side
await verifications.executeTransaction(accounts[2], txInfo);
// now check
data = await executor.executeContractCall(testContract, 'data');
= Descriptions =¶
setVerificationDescription¶
verifications.setVerificationDescription(accountId, topic, domain, description);
Set description for a verification under a domain owned by given account. This sets the description at the ENS endpoint for a verification.
Notice, that this will not insert a description at the verification itself. Consider it as setting a global registry with the description for your verifications and not as a label attached to a single verification.
So a setting a description for the verification /some/verification
the subdomain example
registers this at the ENS path ${sha3(‘/some/verification’)}example.verifications.evan`.
When this description has been set, it can be used when setting verifications, e.g. with
verifications.setVerification(accounts[0], accounts[1], '/some/verification', expirationDate, verificationValue, 'example');
A description can be setup even after verifications have been issued. So it is recommended to use the verification domain when setting up verifications, even if the description isn’t required at the moment, when verifications are set up.
Parameters¶
accountId
-string
: accountId, that performs the description updatetopic
-string
: name of the verification (full path) to set descriptiondomain
-string
: domain of the verification, this is a subdomain under ‘verifications.evan’, so passing ‘example’ will link verifications description to ‘example.verifications.evan’description
-string
: DBCP description of the verification; can be an Envelope but only public properties are used
Returns¶
Promise
returns void
: resolved when done
Example¶
const sampleVerificationsDomain = 'sample';
const sampleVerificationTopic = '/company';
const sampleDescription = {
name: 'sample verification',
description: 'I\'m a sample verification',
author: 'evan.network',
version: '1.0.0',
dbcpVersion: 1,
};
await verifications.setVerificationDescription(accounts[0], sampleVerificationTopic, sampleVerificationsDomain, sampleDescription);
await verifications.setVerification(accounts[0], accounts[1], sampleVerificationTopic, null, null, sampleVerificationsDomain);
const verificationsForAccount = await verifications.getVerifications(accounts[1], sampleVerificationTopic);
const last = verificationsForAccount.length - 1;
console.dir(verificationsForAccount[last].description);
// Output:
// {
// name: 'sample verification',
// description: 'I\'m a sample verification',
// author: 'evan.network',
// version: '1.0.0',
// dbcpVersion: 1,
// }
getVerificationEnsAddress¶
verifications.getVerificationEnsAddress(topic);
Map the topic of a verification to it’s default ens domain.
Parameters¶
topic
-string
: verification topic
Returns¶
string
: The verification ens address
Example¶
const ensAddress = verifications.getVerificationEnsAddress('/evan/test');
// will return test.verifications.evan
ensureVerificationDescription¶
verifications.ensureVerificationDescription(verification);
Gets and sets the default description for a verification if it does not exists.
Parameters¶
verification
-any
: verification topic
Example¶
verifications.ensureVerificationDescription(verification);
= Utilities =¶
createStructure¶
verifications.createStructure(accountId);
Create a new verifications structure; this includes a userregistry and the associated libraries. This isn’t required for creating a module instance, its is solely used for creating new structures on the blockchain.
Parameters¶
accountId
-string
: account, that execute the transaction and owner of the new registry
Returns¶
Promise
returns any
: object with property ‘storage’, that is a web3js
contract instance
Example¶
const verificationsStructure = await verifications.createStructure(accountId);
console.log(verificationsStructure.storage.options.address);
// Output:
// 0x000000000000000000000000000000000000000a
deleteFromVerificationCache¶
verifications.deleteFromVerificationCache(subject, topic);
Delete a single entry from the verification cache object using subject and topic
Parameters¶
subject
-string
: the subject that should be removedtopic
-string
: the topic that should be removed
Example¶
verifications.deleteFromVerificationCache(accounts[1], '/some/verification');
trimToStatusTree¶
verifications.trimToStatusTree(result);
Trim VerificationsResultV2
result down to statusFlags and status values for analysis purposes and debugging.
Parameters¶
inputResult
-VerificationsResultV2
: result to trim down
Returns¶
Promise
returns any
: trimmed down tree
Example¶
const validationOptions: VerificationsValidationOptions = {
disableSubVerifications: VerificationsStatusV2.Red,
expired: VerificationsStatusV2.Red,
invalid: VerificationsStatusV2.Red,
issued: VerificationsStatusV2.Yellow,
missing: VerificationsStatusV2.Red,
noIdentity: VerificationsStatusV2.Red,
notEnsRootOwner: VerificationsStatusV2.Yellow,
parentMissing: VerificationsStatusV2.Yellow,
parentUntrusted: VerificationsStatusV2.Yellow,
rejected: VerificationsStatusV2.Red,
selfIssued: VerificationsStatusV2.Yellow,
};
const queryOptions: VerificationsQueryOptions = {
validationOptions: validationOptions,
};
const nestedVerificationsV2 = await verifications.getNestedVerificationsV2(
accounts[1], '/example1', false, queryOptions);
console.dir(nestedVerificationsV2);
// Output:
// { verifications:
// [ { details:
// { creationDate: 1561722858000,
// ensAddress:
// '4d2027082fdec4ee253363756eccb1b5492f61fb6329f25d8a7976d7909c10ac.example1.verifications.evan',
// id:
// '0x855a3c10b9cd6d42da5fd5e9b61e0f98a5af79b1acbfee57a9e4f3c9721f9c5d',
// issuer: '0x5035aEe29ea566F3296cdD97C29baB2b88C17c25',
// issuerIdentity: '0xD2860FeC7A198A646f9fD1207B59aD42f00c3189',
// subject: '0x9aE6533e7a2C732863C0aF792D5EA358518cd757',
// subjectIdentity: '0x9F870954c615E4457660D22BE0F38FE0200b1Ed9',
// subjectType: '0x9F870954c615E4457660D22BE0F38FE0200b1Ed9',
// topic: '/example1',
// status: 'green' },
// raw:
// { creationBlock: '224038',
// creationDate: '1561722858',
// data:
// '0x0000000000000000000000000000000000000000000000000000000000000000',
// disableSubVerifications: false,
// signature:
// '0x941f316d77f5c1dc8b38000ecbb60304554ee2fb36453487ef7822ce6d8c7ce5267bb62396cfb08191028099de2e28d0ffd4012608e8a622e9e7a6a9570a88231b',
// status: 1,
// topic:
// '34884897835812838038558016063403566909277437558805531399344559176587016933548' },
// statusFlags: [] } ],
// levelComputed:
// { subjectIdentity: '0x9F870954c615E4457660D22BE0F38FE0200b1Ed9',
// subjectType: 'account',
// topic: '/example1',
// subject: '0x9aE6533e7a2C732863C0aF792D5EA358518cd757' },
// status: 'green' }
const trimmed = verifications.trimToStatusTree(nestedVerificationsV2);
console.dir(trimmed);
// Output:
// { status: 'green',
// verifications:
// [ { details: { status: 'green', topic: '/example1' },
// statusFlags: [] } ] }
Enums¶
VerificationsStatus¶
verification status from blockchain
Issued
: issued by a non-issuer parent verification holder, self issued state is 0Confirmed
: issued by a non-issuer parent verification holder, self issued state is 0Rejected
: verification rejected status
VerificationsStatusFlagsV2¶
status annotations about verification, depending on defined VerificationsQueryOptions
, this may lead to the verification to be invalid or less trustworthy
disableSubVerifications
: parent verification does not allow subverificationsexpired
: verification has expiredinvalid
: signature does not match requirements, this could be because it hasn’t been signed by correct account or underlying checksum does not match subject, topic and dataissued
: verification has been issued, but not accepted or rejected by subjectmissing
: verification has not been issuednoIdentity
: given subject has no identitynotEnsRootOwner
: verification path has a trusted root verification topic, but this verification is not signed by a trusted instanceparentMissing
: parent verification is missing in pathparentUntrusted
: verification path cannot be traced back to a trusted root verificationrejected
: verification has been issued and then rejected by subjectselfIssued
: verification issuer is the same account as the subject
VerificationsStatusV2¶
represents the status of a requested verification topic after applying rules in VerificationsQueryOptions
Green
: verification is valid according toVerificationsQueryOptions
Yellow
: verification may be valid but more checks may be required more for trusting it, see status flags for detailsRed
: verification is invalid, see status flags for details
Interfaces¶
VerificationsDelegationInfo¶
information for submitting a delegated transaction, created with signSetVerificationTransaction
consumed by executeVerification
sourceIdentity
-string
: address of identity contract, that issues verificationvalue
-number
: value to transfer, usually 0input
-string
: abi encoded input for transactionsignedTransactionInfo
-string
: signed data from transactionnonce
- ``string``(optional): source identity contract execution nonce for this transactiontargetIdentity
-string``(optional): address of identity contract, that receives verification, either this or ``to
has to be givento
-string
(optional): address of target of transaction, either this or targetIdentity has to be given
VerificationsQueryOptions¶
options for getNestedVerificationsV2
, define how to calculate status of verification
statusComputer
-VerificationsStatusComputer
(optional): function for setting verification with custom logicvalidationOptions
-VerificationsValidationOptions
(optional): specification of how to handle status flags of each single verification
VerificationsResultV2¶
result of a verification query
status
-VerificationsStatusV2
: overall status of verificationverifications
-VerificationsVerificationEntry[]
: (optional): list of verifications on same topic and subjectlevelComputed
(optional): consolidated information about verificationsubjectIdentity
-string
: identity contract address or hash of subjectsubjectType
-string
: type of subject (account/contract)topic
-string
: topic (name) of verificationexpirationDate
-number
(optional): timestamp, when verification will expire, js timestampparents
-VerificationsResultV2
(optional): verifications of parent path, issued for all issuers of verifications on this levelsubject
-number
(optional): subject accountId/contractId (if query was issued withisIdentity
set tofalse
)
VerificationsVerificationEntry¶
a single verification; usually used in VerificationsResultV2
details
: details about verificationcreationDate
-number
: js timestamp of verification creationensAddress
-string
: ens address of description for this verificationid
-string
: id in verification holder / verifications registryissuer
-string
: account id of verification issuerissuerIdentity
-string
: issuers identity contract idsubjectIdentity
-string
: identity (contract or identity hash) of subjectsubjectType
-string
: type of subject (account/contract)topic
-string
: topic of identity (name)data
-any
(optional): 32B data hash string of identitydescription
-any
(optional): only if actually setexpirationDate
-number
(optional): expiration date of verification (js timestamp)rejectReason
-string
(optional): if applicable, reason for verification rejectionstatus
-VerificationsStatusV2
(optional): status of verification, is optional during result computation and required when donesubject
-string
(optional): subject accountId/contractId (if query was issued withisIdentity
set tofalse
)
raw
(optional): raw data about verification from contractcreationBlock
-string
: block in which verification was issuedcreationDate
-string
: unix timestamp is s when verification was issueddata
-string
: 32B data hash string of identity, bytes32 zero if unsetdisableSubVerifications
-boolean
: true if subverification are not allowedsignature
-string
: signature over verification datastatus
-number
: status of verification, (issued, accepted, rejected, etc.)topic
-string
: uint string of verification name (topic), is uint representation of sha3 of name
statusFlags
-string[]
(optional): all found flags, those may not have impact on status, depends onVerificationsStatusFlagsV2
VerificationsVerificationEntryStatusComputer¶
Computes status for a single verification. verification, partialResult.
Parameters¶
verification
-Partial<VerificationsVerificationEntry>
: current verification result (without status)partialResult
-Partial<VerificationsResultV2>
: options for verifications query
Returns¶
Promise
returns VerificationsStatusV2
: status for this verification
VerificationsStatusComputer¶
Computes status from overall verifications result. This function is applied after each verification has received an own computed status.
Parameters¶
partialResult
-Partial<VerificationsResultV2>
: current verification result (without status)queryOptions
-VerificationsQueryOptions
: options for verifications querycurrentStatus
-VerificationsStatusV2
: current status of verification
Returns¶
Promise
returns Promise<VerificationsStatusV2>
: updated status, will be used at verification status
VerificationsValidationOptions¶
Options for verification status computation. Keys are string representations of
VerificationsStatusFlagsV2
, values can be VerificationsStatusV2
or functions.
If value is VerificationsStatusV2
, then finding given status flag sets verification value
to given VerificationsStatusV2
(if not already at a higher trust level).
If value is function, pass verification to this function and set verification status to
return value (if not already at a higher trust level).
[id: string]
-VerificationsStatusV2 | VerificationsVerificationEntryStatusComputer
: each key is a status flag and usually an enum value fromVerificationsStatusFlagsV2
, though it is possible to use custom status flags
Verifications Examples¶
This sections aims to help getting started with the verifications service. Herein are shown a few examples on
- how to set verifications
- how to get verifications
- how to handle verifications for externally owned accounts and contracts
- how to check verifications for validity
Verifications can be issued with the Verification API. Their smart contract implementation follow the principles outlined in ERC-725 and ERC-735.
About the Code Examples¶
Many code examples are taken from the verification tests. You can a look at those for more examples or to have a look at in which context the test are run in.
Code examples on this page use an initialized module called verifications
, which is an instance of the verification module Verification API. When using a runtime this module is available as runtime.verifications
.
Many code examples here use variable naming from the tests. So there are a few assumptions about variables used here:
accounts
is an array with addresses of externally owned accounts, of which private keys are known to the runtime/executor/signer instance to make transaction with themaccounts[0]
usually takes the role of issuing verificationsaccounts[1]
is usually an account that responds to actions fromaccounts[0]
accounts[2]
is usually an account, that has no direct relation to the former two accountscontractId
refers to the address of a contract, that is owned byaccounts[0]
, this contract usually has a DBCP description
Different Types of Identities¶
Okay, this page is about verifications, so why does the first heading talk about some kind of identities?
The answer for this is pretty simple simple: Verifications are issued by identities.
So what exactly is an identity?
An identity is an instance, that is able to issue and hold verifications (therefore the technical name VerificationHolder.
Technically speaking, identities are like Wallet Contracts, that have a certificate store attached to them. Identities can be traced back to an externally owned account, that owns this wallet contract and vice versa the matching identity (wallet) contract can be looked up for any given externally owned account, if this account has created and registered an identity contract.
Because of their wallet-like behavior, identity contracts require a calling instance, for example an externally owned account or another wallet to call them for managing their verifications. For example to issue a verification for another identity, a user makes a transaction against its own identity contract, which itself makes a transaction to create a verification in the other identity.
This works pretty well and comes with useful features like preparing “outgoing” transactions to be made from ones own identity, that can be paid by another party, but has some implications when applied as “smart contract identities” instead of “account identities”. These smart contracts would need to be owner of their own identities and working with verifications would require the contracts to have functions for issuing, rejecting, etc. verification or offer wallet like functionalities themselves, which would make it often pretty hard to introduce verifications in an existing smart contract infrastructure and it would often have an impact on these contracts costs as these extra functionalities have to be added to the contract.
To allow for a more easy integration, contract identities have been added as a 32 Bytes identities or pseudonyms, which can be created with a registry contract. These 32 Bytes identities are IDs in a central registry, that offers basically the same functionalities as the single identity contracts. Identities at the registry are owned by the account, that created them (ownership can be transfered) and ownership over such an identity grants the permission to make transactions for it the same way as for the own account identity.
So let’s get to the code examples.
Account Identities¶
Note that the creation example can be omitted when using an account creating during the visual onboarding flow, as this includes creating an identity.
If you want to check if your account already has an identity, you can try to get its identity contracts address with identityAvailable:
if (await verifications.identityAvailable(accounts[0])) {
console.log(`account "${accounts[0]}" has an identity`);
} else {
console.log(`account "${accounts[0]}" does not have an identity`);
}
Account identities can be created straight forward by calling createIdentity and passing the account to it, an identity should be created for.
const identity = await verifications.createIdentity(accounts[0]);
console.log(identity);
// Output:
// 0x1fE5F7235f1989621135466Ff8882287C63A5bae
This returns the 40Bytes contract address of the accounts identity contract.
The given account now has an identity attached to it, which is a requirement for interacting with the rest of the verifications API and only has to be done once per externally owned account.
Contract Identities / Pseudonym Identities¶
Contract identities are created “on behalf of” a contract. An externally owned account, often the owner of the contract, usually does the following:
- creating an identity for the contract
- linking contract and identity
- providing the information of which identity belongs to a contract to other parties
Creating a contract identity registers a new contract identity at the registry, this identity is then owned by the executing accountId.
Linking is done by registering the contract address as the receiver of the identity, this is done at the registry as well.
When third parties want to check verifications of a contract, they need a way to get the identity for a contract. This can be done by adding an extra function to the contract, by setting up a lookup mechanism, etc. DBCP is a description language used throughout evan.network, which provides a way to add meta information to smart contracts. The contract identity is usually added to this DBCP description of a contract.
The aforementioned three steps are covered by the createIdentity function, which can be called with:
const contractIdentity = await verifications.createIdentity(accounts[0], contractId);
console.log(idencontractIdentitytity);
// Output:
// 0x4732281e708aadbae13f0bf4dd616de86df3d3edb3ead21604a354101de45316
When using contracts without descriptions or when handling the relation between contracts and an identity elsewhere, the process of updating the description can be omitted. For this set the updateDescription
argument to false
:
const contractIdentity = await verifications.createIdentity(accounts[0], contractId, false);
console.log(idencontractIdentitytity);
// Output:
// 0x4732281e708aadbae13f0bf4dd616de86df3d3edb3ead21604a354101de45316
Pseudonyms can be handled the same way. Just set the flag to link given identity to false:
const contractIdentity = await verifications.createIdentity(accounts[0], null, false, false);
console.log(idencontractIdentitytity);
// Output:
// 0x4732281e708aadbae13f0bf4dd616de86df3d3edb3ead21604a354101de45316
This returns an identity, that is owned by accountId
and can be used to issue verifications for.
Issue verifications¶
Verifications are statements, issued by an account called issuer
, towards target, called subject
. This basically means something like “The person issuer
says, a statement applies to subject
”. The subject may or may not react to it by confirming or rejecting it. Technically speaking, the issuer
identity issues the verification with the statement to subject
`s identity and the subjects
`s identity may react to it.
Issue verifications for an account¶
const verificationId = await verifications.setVerification(
accounts[0], accounts[1], '/example1');
console.log(verificationId);
// Output:
// 0xb4843ed5177433312dd2c7c4f8065ce84f37bf96c04db2775c16c9455ad96270
const issued = await verifications.getVerifications(accounts[1], '/example1');
console.dir(issued);
// Output:
// [ {
// creationBlock: '186865',
// creationDate: '1558599441',
// data: '0x0000000000000000000000000000000000000000000000000000000000000000',
// description: null,
// disableSubVerifications: false,
// expirationDate: null,
// expired: false,
// id: '0xb4843ed5177433312dd2c7c4f8065ce84f37bf96c04db2775c16c9455ad96270',
// issuer: '0xe560eF0954A2d61D6006E8547EC769fAc322bbCE',
// name: '/example1',
// rejectReason: undefined,
// signature: '0x6a2b41714c1faac09a5ec06024c8931ad6e3aa902c502e3d1bc5d5c4577288c04e9be136c149b569e0456dfec9d50a2250bf405443ae9bccd460c49a2c4287df1b',
// status: 0,
// subject: '0x0030C5e7394585400B1FB193DdbCb45a37Ab916E',
// topic: '34884897835812838038558016063403566909277437558805531399344559176587016933548',
// uri: '',
// valid: true
// } ]
Have a look at getVerifications or the section on this page for the meaning of the returned values, for how to find out, if the returned verification is trustworthy, have a look at Validating Verifications.
Issue verifications for a contract with a description¶
const verificationId = await verifications.setVerification(
accounts[0], contractId, '/example2');
console.log(verificationId);
// Output:
// 0x2bc6d5fdb937f6808252b837437220d8e16b92a974367f224260d028413e7c6e
const issued = await verifications.getVerifications(contractId, '/example2');
console.dir(issued);
// [ {
// creationBlock: '187823',
// creationDate: '1558621998',
// data: '0x0000000000000000000000000000000000000000000000000000000000000000',
// description: null,
// disableSubVerifications: false,
// expirationDate: null,
// expired: false,
// id: '0x2bc6d5fdb937f6808252b837437220d8e16b92a974367f224260d028413e7c6e',
// issuer: '0xe560eF0954A2d61D6006E8547EC769fAc322bbCE',
// name: '/example2',
// rejectReason: undefined,
// signature: '0x0f4f19a369645a0ec2795bd2836fad0857ef82169c7e5800d7a06fb162583c9c14a731f4e942cf30d67fb10a551d9060f71642d25bb6c2c226bae47b3acb13581b',
// status: 0,
// subject: '0x005C5FF57D4d6Bf105Bf3bF16ffCd8Ac143B3Ef0',
// topic: '107276559880603231420598591656057035604273757486333915273364042567965107775848',
// uri: '',
// valid: true
// } ]
Have a look at getVerifications or the section on this page for the meaning of the returned values, for how to find out, if the returned verification trustworthy, have a look at Validating Verifications.
Note that for contracts with descriptions the contractId can be given to setVerification
and getVerifications
. The contract identity is fetched from the contract description automatically.
Issue verifications for a contract without using a description¶
// assume, we have created an identity for our contract and stored this identity as the variable ``contractIdentity``
const verificationId = await verifications.setVerification(
accounts[0], contractIdentity, '/example3', 0, null, null, false, true));
console.log(verificationId);
// Output:
// 0x2bc6d5fdb937f6808252b837437220d8e16b92a974367f224260d028413e7c6e
const issued = await verifications.getVerifications(contractIdentity, '/example3', true);
console.dir(issued);
// [ {
// creationBlock: '187823',
// creationDate: '1558621998',
// data: '0x0000000000000000000000000000000000000000000000000000000000000000',
// description: null,
// disableSubVerifications: false,
// expirationDate: null,
// expired: false,
// id: '0x2bc6d5fdb937f6808252b837437220d8e16b92a974367f224260d028413e7c6e',
// issuer: '0xe560eF0954A2d61D6006E8547EC769fAc322bbCE',
// name: '/example2',
// rejectReason: undefined,
// signature: '0x0f4f19a369645a0ec2795bd2836fad0857ef82169c7e5800d7a06fb162583c9c14a731f4e942cf30d67fb10a551d9060f71642d25bb6c2c226bae47b3acb13581b',
// status: 0,
// subject: '0x005C5FF57D4d6Bf105Bf3bF16ffCd8Ac143B3Ef0',
// topic: '107276559880603231420598591656057035604273757486333915273364042567965107775848',
// uri: '',
// valid: true
// } ]
In case you’re wondering: contractIdentity
is the same identity as returned in our Contract Identities / Pseudonym Identities example.
Have a look at getVerifications for the meaning of the returned values, for how to find out, if the returned verification trustworthy, have a look at Validating Verifications.
Note that for contracts without descriptions contractIdentity
is given and the last argument (isIdentity
) is set to true. The functions setVerification
and getVerifications
support passing a contract identity to them as well and they also have the argument isIdentity
, which is set to true, when passing contract identities to them.
Delegated verification issuing¶
The transaction that issues a verification can be done by an account, that is neither issuer
nor subject
. This means, that it is possible to let another account pay transaction costs but issuing the verification itself is done from the original identity.
For example: Alice wants to issue a verification to Bob, but should not pay for the transaction costs. Alice can now prepare the transaction to be done from her identity contract towards Bobs identity contract and send the prepared transaction data to Clarice. Clarice then can submit this data to Alice’s identity contract, which will issue the verification.
const [ alice, bob, clarice ] = accounts;
// on Alice's side
const txInfo = await verifications.signSetVerificationTransaction(alice, bob, '/example');
// on Clarice's side
const verificationId = await verifications.executeVerification(clarice, txInfo);
Note that transactions prepared with signSetVerificationTransaction
can only be executed once and only with the arguments of the original data. To prevent multiple repetitions of the transaction, a nonce at the issuers identity contract is used. This nonce is retrieved from the identity contract automatically when calling signSetVerificationTransaction
, but when preparing multiple transactions and not submitting them immediately, the nonce would stay the same. Therefore the nonce has to be increased by hand when preparing multiple transactions from the same identity contract.
Nonces determine the order in which prepared transactions can be performed from issuers identity contract, so execute prepared transactions in order of their nonces.
const [ alice, bob, clarice ] = accounts;
// on Alice's side
// nonce in this example is relatively small, so we can just parse it and use it as a number
// consider using BigNumber or similar to deal with larger numbers if required
let nonce = JSON.parse(await verifications.getExecutionNonce(alice));
const txInfos = await Promise.all(['/example1', '/example2', '/example3'].map(
topic => verifications.signSetVerificationTransaction(
alice, bob, topic, 0, null, null, false, false, nonce++)
));
// on Clarice's side
const verificationIds = [];
for (let txInfo of txInfos) {
verificationIds.push(await verifications.executeVerification(clarice, txInfo));
}
Validating Verifications¶
Verifications can be retrieved with two different functions:
- getVerifications: simple “fetch all” verifications for a topic, returns all verifications and detailed validity checks have to be made by hand
- getNestedVerification: return verifications with default checks and inspects parent verifications as well, used for verifications, that should be traced back to a trusted root verifier
getVerifications¶
The example for getVerifications is the same we used when creating a verification for and account:
const verificationId = await verifications.setVerification(
accounts[0], accounts[1], '/example1');
console.log(verificationId);
// Output:
// 0xb4843ed5177433312dd2c7c4f8065ce84f37bf96c04db2775c16c9455ad96270
const issued = await verifications.getVerifications(accounts[1], '/example1');
console.dir(issued);
// Output:
// [ {
// creationBlock: '186865',
// creationDate: '1558599441',
// data: '0x0000000000000000000000000000000000000000000000000000000000000000',
// description: null,
// disableSubVerifications: false,
// expirationDate: null,
// expired: false,
// id: '0xb4843ed5177433312dd2c7c4f8065ce84f37bf96c04db2775c16c9455ad96270',
// issuer: '0xe560eF0954A2d61D6006E8547EC769fAc322bbCE',
// name: '/example1',
// rejectReason: undefined,
// signature: '0x6a2b41714c1faac09a5ec06024c8931ad6e3aa902c502e3d1bc5d5c4577288c04e9be136c149b569e0456dfec9d50a2250bf405443ae9bccd460c49a2c4287df1b',
// status: 0,
// subject: '0x0030C5e7394585400B1FB193DdbCb45a37Ab916E',
// topic: '34884897835812838038558016063403566909277437558805531399344559176587016933548',
// uri: '',
// valid: true
// } ]
As stated above, only basic validations have been made on the data of the verifications, so conclusions have to be drawn by based on the data returned here. For a full list of explanations to the properties have a look at the API documentation, but the ones you will be most probably using the most are:
status
andrejectReason
:status
-number
:- 0 (Issued) || 1 (Confirmed) || 2 (Rejected)
- reflects how the subject responded (1|2) to the verification or if no response has been made (0)
rejectReason
-any
: object with information from subject about rejection
valid
-boolean
:true
if issuer has been correctly confirmed as the signer ofsignature
- also checks if provided
signature
has been correctly built as checksum oversubject
,topic
anddata
expired
andexpirationDate
:expired
-boolean
: ticket expiration stateexpirationDate
-string
: UNIX timestamp (in seconds), null if verification does not expire
issuer
-string
:- account address of issuers identity contract, can be used to check if the issuer is an account, that you trust
data
anduri
:data
-string
: 32Bytes hash of data stored in DFSuri
-string
: link to ipfs file of data- these two properties point to data, that has been attached to your verification (attaching data is optional)
- the data referred here is the data provided as
verificationValue
in setVerification - data content handling, especially encryption and key management has be be handled in custom logic and is not covered in here
A sample, on how these properties can be used to determine the trustworthiness of a verification can be found at hem workshop project.
getNestedVerifications¶
For this section we take the last example and issue two subverifications. We add /example1/example1_child
as the direct child of it and /example1/example1_child/example1_grandchild
as a subverification below the first this child.
const verificationId = await verifications.setVerification(
accounts[0], accounts[0], '/example4');
const verificationId = await verifications.setVerification(
accounts[0], accounts[0], '/example4/child');
const verificationId = await verifications.setVerification(
accounts[0], accounts[0], '/example4/child/grandchild');
const issued = await verifications.getNestedVerifications(accounts[0], '/example1/example1_child/example1_grandchild');
console.dir(issued);
// Output:
// [ {
// name: '/example4/child/grandchild',
// parent: '/example4/child',
// warnings: [ 'issued', 'selfIssued', 'parentUntrusted' ],
// id: '0x1adef760f5a8d153aeeeda7a6e4f8c950fa93b0cb5d3218c6a9389cd05f5f7f6',
// issuer: '0xe560eF0954A2d61D6006E8547EC769fAc322bbCE',
// status: 0,
// subject: '0x001De828935e8c7e4cb56Fe610495cAe63fb2612',
// subjectIdentity: '0xe560eF0954A2d61D6006E8547EC769fAc322bbCE',
// subjectType: 'account',
// issuerAccount: '0x001De828935e8c7e4cb56Fe610495cAe63fb2612',
// parents:
// [ {
// name: '/example4/child',
// parent: '/example4',
// warnings: [ 'issued', 'selfIssued', 'parentUntrusted' ],
// id: '0x28e1df758883bb3d4d5e7e0fa978ff673bc749ade0a3d78ad952a30d0a0e2a01',
// issuer: '0xe560eF0954A2d61D6006E8547EC769fAc322bbCE',
// status: 0,
// subject: '0x001De828935e8c7e4cb56Fe610495cAe63fb2612',
// subjectIdentity: '0xe560eF0954A2d61D6006E8547EC769fAc322bbCE',
// subjectType: 'account',
// issuerAccount: '0x001De828935e8c7e4cb56Fe610495cAe63fb2612',
// parents:
// [ {
// name: '/example4',
// parent: '',
// warnings: [ 'issued' ],
// id: '0x18fb0ef05d96cba2a57c6de6d8cfd031e16367f6484f20797a39d25a3e76e20a',
// issuer: '0xe560eF0954A2d61D6006E8547EC769fAc322bbCE',
// status: 0,
// subject: '0x001De828935e8c7e4cb56Fe610495cAe63fb2612',
// subjectIdentity: '0xe560eF0954A2d61D6006E8547EC769fAc322bbCE',
// subjectType: 'account',
// issuerAccount: '0x001De828935e8c7e4cb56Fe610495cAe63fb2612',
// parents: [],
// } ],
// } ],
// } ]
The output above has been heavily trimmed down to show differences between both functions and highlight parent to child relations and warnings. To view full output have a look at the full output.
To create a simple chain of verifications, we have used the following structure:
- accounts[0]
creates a verification for itself, called /example4
- then creates a subverification under called /example4/child
for itself under this
- then creates another subverification (under the first subverification) called /example4/child/grandchild
for itself
The call verifications.getNestedVerifications(accounts[0], '/example1/example1_child/example1_grandchild')
now inspects what verifications and possible relations to parent verifications exits and it finds the following possible issues:
/example4/child/grandchild
:warnings: [ 'issued', 'selfIssued', 'parentUntrusted' ]
issued
means, that is is only issued and not confirmed, we can see its status is0
, so yes, it is unconfirmed (and if we look above, we actually didn’t confirm the verification)selfIssued
, yes,issuer
equalssubjectIndentity
, thereforeselfIssued
and thinking back, we did issue this verification to ourselfparentUntrusted
, this means that the parent verification hasn’t been accepted, its status is0
, so yes, only issued and not confirmed
following the parent verifications, we find basically the same on the next level
/example4/child`
:warnings: [ 'issued', 'selfIssued', 'parentUntrusted' ]
- the same reasons and explanations apply here, so let’s continue to the last on in the verification path
/example4
:warnings: [ 'issued' ]
issued
: yep, status is0
therefore it is only issued and not confirmedno
parentUntrusted
? as this verification is a root verification, there is not parentno
selfIssued
?the path is
/example4
, which makes this verification a root verificationroot verifications can be issued by any party without being flagged as
selfIssued
, to allow building own verification chainsto narrow this down to a limited set of trusts, there are basically two solutions:
- own checks can be made, e.g. check if the issuer of the root verification is a well known and trusted account
- use
/evan
derived verification paths, the root verification/evan
is only trusted, if it is issued by a trusted root issuer, get in contact with us via info@evan.team for details on how to obtain a subverification like/evan/myOwnTrustedVerification
, that can be used for building widely accepted verification paths
getNestedVerificationsV2¶
The output from the last example has some aspects, where it could perform better:
- the output is a bit lengthy and looks unstructured, some of the information here may not be useful in most situations and relies on predefined defaults (e.g. a default description, that isn’t actually set is returned if no description is defined, which may lead to the opinion, that a description has been set)
- it is quite hard to determine with a simple query and not further processing to determine if a valid verification is present or not
- documentation about properties returned in verification is a bit sparse in some points
An updated version of the getNestedVerifications
has been added as getNestedVerificationsV2
. This version will replace the current one soon, but is available for now under the V2 name. This version is under development and may undergo further changes but the basic behavior will not change and it will replace the regular one at some point of time.
A usage example:
const validationOptions: VerificationsValidationOptions = {
disableSubVerifications: VerificationsStatusV2.Red,
expired: VerificationsStatusV2.Red,
invalid: VerificationsStatusV2.Red,
issued: VerificationsStatusV2.Yellow,
missing: VerificationsStatusV2.Red,
noIdentity: VerificationsStatusV2.Red,
notEnsRootOwner: VerificationsStatusV2.Yellow,
parentMissing: VerificationsStatusV2.Yellow,
parentUntrusted: VerificationsStatusV2.Yellow,
rejected: VerificationsStatusV2.Red,
selfIssued: VerificationsStatusV2.Yellow,
};
const queryOptions: VerificationsQueryOptions = {
validationOptions: validationOptions,
};
const nestedVerificationsV2 = await verifications.getNestedVerificationsV2(
accounts[1], '/example1', false, queryOptions);
console.dir(nestedVerificationsV2);
// Output:
// { verifications:
// [ { details:
// { creationDate: 1561722858000,
// ensAddress:
// '4d2027082fdec4ee253363756eccb1b5492f61fb6329f25d8a7976d7909c10ac.example1.verifications.evan',
// id:
// '0x855a3c10b9cd6d42da5fd5e9b61e0f98a5af79b1acbfee57a9e4f3c9721f9c5d',
// issuer: '0x5035aEe29ea566F3296cdD97C29baB2b88C17c25',
// issuerIdentity: '0xD2860FeC7A198A646f9fD1207B59aD42f00c3189',
// subject: '0x9aE6533e7a2C732863C0aF792D5EA358518cd757',
// subjectIdentity: '0x9F870954c615E4457660D22BE0F38FE0200b1Ed9',
// subjectType: '0x9F870954c615E4457660D22BE0F38FE0200b1Ed9',
// topic: '/example1',
// status: 'green' },
// raw:
// { creationBlock: '224038',
// creationDate: '1561722858',
// data:
// '0x0000000000000000000000000000000000000000000000000000000000000000',
// disableSubVerifications: false,
// signature:
// '0x941f316d77f5c1dc8b38000ecbb60304554ee2fb36453487ef7822ce6d8c7ce5267bb62396cfb08191028099de2e28d0ffd4012608e8a622e9e7a6a9570a88231b',
// status: 1,
// topic:
// '34884897835812838038558016063403566909277437558805531399344559176587016933548' },
// statusFlags: [] } ],
// levelComputed:
// { subjectIdentity: '0x9F870954c615E4457660D22BE0F38FE0200b1Ed9',
// subjectType: 'account',
// topic: '/example1',
// subject: '0x9aE6533e7a2C732863C0aF792D5EA358518cd757' },
// status: 'green' }
The variable validationOptions
from the example is a set of rules for about how to interpret the statusFlags
from the verifications
. The last example no flags, but possible issues are tracked as status flags and are evaluated by given rules. The rules are explained in the respective interface and mostly match the warnings explained in the section below.
Warnings in Verifications¶
getNestedVerification returns a set of different warnings, that can be used to decide if a certification is valid or not. Those warnings are stored in the .warnings
property, warnings, that can be returned are:
disableSubVerifications
: parent verification does not allow subverificationsexpired
: verification has expiredinvalid
: signature does not match requirements, this could be because it hasn’t been signed by correct account or underlying checksum does not matchsubject
,topic
anddata
issued
: verification has been issued, but not accepted or rejected by subjectmissing
: verification has not been issuednoIdentity
: given subject has no identitynotEnsRootOwner
: verification path has a trusted root verification topic, but this verification is not signed by a trusted instanceparentMissing
: parent verification is missing in pathparentUntrusted
: verification path cannot be traced back to a trusted root verificationrejected
: verification has been issued and then rejected by subjectselfIssued
: verification issuer is the same account as the subject
Data in Verifications¶
Unencrypted Data in Verifications¶
Additional data can be given when creating a verification. For this pass an object, that can be serialized to JSON as the verificationValue
argument to setVerification
. As this argument is placed after the expirationDate
argument, we set this argument as well.
const verificationId = await verifications.setVerification(
accounts[0], accounts[1], '/example1', 0, { foo: 'bar' });
console.log(verificationId);
// Output:
// 0x5ea689a7ed1d56d948dc8223dcd60866746bc7bea47617c19b63df75d63c9194
const issued = await verifications.getVerifications(accounts[1], '/example1');
console.dir(issued);
// Output:
// [ { creationBlock: '198673',
// creationDate: '1559913567',
// data:
// '0xc710c57357d3862f351c00ff77a5ef90bb4491851f11c3e8ea010c16745c468e',
// description: null,
// disableSubVerifications: false,
// expirationDate: null,
// expired: false,
// id:
// '0x5ea689a7ed1d56d948dc8223dcd60866746bc7bea47617c19b63df75d63c9194',
// issuer: '0x6d2b20d6bf2B848D64dFE0B386636CDbFC521d4f',
// name: '/example1',
// rejectReason: undefined,
// signature:
// '0xf7ce3cc2f50ef62783ef293f8f45814b3ae868e614042cc05154853d00a694c176f8bdd94700736a137f92ff9a87639aade3f31724bb1eb7fe7f143df4c62c571c',
// status: 0,
// subject: '0x0030C5e7394585400B1FB193DdbCb45a37Ab916E',
// topic:
// '34884897835812838038558016063403566909277437558805531399344559176587016933548',
// uri:
// 'https://ipfs.test.evan.network/ipfs/Qmbjig3cZbUUufWqCEFzyCppqdnmQj3RoDjJWomnqYGy1f',
// valid: true } ]
const data = JSON.parse(await dfs.get(issued[0].data));
console.dir(data);
// Output:
// { foo: 'bar' }
Encrypted Data in Verifications¶
Data added to the verification can be encrypted as well. Encryption is done outside of the verification service and has to be done before settin a verification and after getting the verification.
As key handling, storage and encryption itself is handled outside of the verification service, there are different ways for doing this. The suggested way to do this though, is using the EncryptionWrapper. See the example below and its documentation for how it can be used.
const unencrypted = {foo: 'bar'};
const cryptoInfo = await encryptionWrapper.getCryptoInfo('test', EncryptionWrapperKeyType.Custom);
const key = await encryptionWrapper.generateKey(cryptoInfo);
const encrypted = await encryptionWrapper.encrypt(unencrypted, cryptoInfo, { key });
const verificationId = await verifications.setVerification(
accounts[0], accounts[1], '/example1', 0, encrypted);
console.log(verificationId);
// Output:
// 0xdaa700acd52af1690c394445cc7908d01bef9a6c0c209dd4590cf869aa801586
const issued = await verifications.getVerifications(accounts[1], '/example1');
console.dir(issued);
// Output:
// [ { creationBlock: '198706',
// creationDate: '1559915070',
// data:
// '0xb2eca508b635094d642950d3715783d744eac6771ff665303196040c6778cbc3',
// description: null,
// disableSubVerifications: false,
// expirationDate: null,
// expired: false,
// id:
// '0xdaa700acd52af1690c394445cc7908d01bef9a6c0c209dd4590cf869aa801586',
// issuer: '0x6d2b20d6bf2B848D64dFE0B386636CDbFC521d4f',
// name: '/example1',
// rejectReason: undefined,
// signature:
// '0x8ce1f239b254f2a4453e704cf5bd50f1aef215c5843408dc94ba3d128bba75d346a0b7945dd49f78b16cfd312ba51f68d10cee0e6fa17de66efb1b0d583925911b',
// status: 0,
// subject: '0x0030C5e7394585400B1FB193DdbCb45a37Ab916E',
// topic:
// '34884897835812838038558016063403566909277437558805531399344559176587016933548',
// uri:
// 'https://ipfs.test.evan.network/ipfs/QmaP6Zyz2Mw4uBX1veuxQJSnvZnG3MLFxLGrPxbc2Y4pnn',
// valid: true } ]
const retrieved = JSON.parse(await dfs.get(issued[0].data));
console.dir(retrieved);
// Output:
// { private:
// '017b0c07256180a69457f5c9a4e52431424532f698deaf401b754414bb070649',
// cryptoInfo:
// { algorithm: 'aes-256-cbc',
// block: 198705,
// originator: 'custom:test' } }
const decrypted = await encryptionWrapper.decrypt(retrieved, { key });
console.dir(decrypt);
// Output:
// { foo: 'bar' }
Verifications Examples - Full Output¶
This page shows the full output from the first nested verification example on verification-usage-examples.
[ { creationBlock: '188119',
creationDate: 1558697814000,
data:
'0x0000000000000000000000000000000000000000000000000000000000000000',
description:
{ author: '0x0000000000000000000000000000000000000000',
dbcpVersion: 1,
description: '/example4/child/grandchild',
name: '/example4/child/grandchild',
version: '1.0.0',
i18n: { name: { en: 'grandchild' } } },
disableSubVerifications: false,
expirationDate: null,
expired: false,
id:
'0x1adef760f5a8d153aeeeda7a6e4f8c950fa93b0cb5d3218c6a9389cd05f5f7f6',
issuer: '0xe560eF0954A2d61D6006E8547EC769fAc322bbCE',
name: '/example4/child/grandchild',
rejectReason: undefined,
signature:
'0x80e79018b417d750e5ed74f6180d7d5481e797e16835a829a0df860c57617a167ce9d678f73916937d777cb84d9e2605028fc94ea734f535149b5e3466fe95431c',
status: 0,
subject: '0x001De828935e8c7e4cb56Fe610495cAe63fb2612',
topic:
'318220210852970580957416696069631559919889705746195074742792477435870915475',
uri: '',
valid: true,
displayName: 'grandchild',
parent: '/example4/child',
warnings: [ 'issued', 'selfIssued', 'parentUntrusted' ],
subjectIdentity: '0xe560eF0954A2d61D6006E8547EC769fAc322bbCE',
subjectType: 'account',
issuerAccount: '0x001De828935e8c7e4cb56Fe610495cAe63fb2612',
ensAddress:
'00b41b33a2396efb6fd434bc67d84b47a32eee9a9a275ee6384f5c32f2b12b93.example4.verifications.evan',
topLevelEnsOwner: '0x0000000000000000000000000000000000000000',
parents:
[ { creationBlock: '188118',
creationDate: 1558697805000,
data:
'0x0000000000000000000000000000000000000000000000000000000000000000',
description:
{ author: '0x0000000000000000000000000000000000000000',
dbcpVersion: 1,
description: '/example4/child',
name: '/example4/child',
version: '1.0.0',
i18n: { name: { en: 'child' } } },
disableSubVerifications: false,
expirationDate: null,
expired: false,
id:
'0x28e1df758883bb3d4d5e7e0fa978ff673bc749ade0a3d78ad952a30d0a0e2a01',
issuer: '0xe560eF0954A2d61D6006E8547EC769fAc322bbCE',
name: '/example4/child',
rejectReason: undefined,
signature:
'0x568770823b2b541c24deddfa403f82f883ac73cbdaae99d3b4a112bb36ec391d374c824f15e279474f072f180b0aa94670b289f7a0e62df63bc1b30d319f45321b',
status: 0,
subject: '0x001De828935e8c7e4cb56Fe610495cAe63fb2612',
topic:
'77917584097763165263567038986179239309321992426417843471841530443014147675245',
uri: '',
valid: true,
displayName: 'child',
parent: '/example4',
warnings: [ 'issued', 'selfIssued', 'parentUntrusted' ],
subjectIdentity: '0xe560eF0954A2d61D6006E8547EC769fAc322bbCE',
subjectType: 'account',
issuerAccount: '0x001De828935e8c7e4cb56Fe610495cAe63fb2612',
ensAddress:
'ac43ca2dd23f1c08f2c2c6b22dcf233346588a5043ab7c4380656a2f7ac0146d.example4.verifications.evan',
topLevelEnsOwner: '0x0000000000000000000000000000000000000000',
parents:
[ { creationBlock: '188117',
creationDate: 1558697790000,
data:
'0x0000000000000000000000000000000000000000000000000000000000000000',
description:
{ author: '0x0000000000000000000000000000000000000000',
dbcpVersion: 1,
description: '/example4',
name: '/example4',
version: '1.0.0',
i18n: { name: { en: 'example4' } } },
disableSubVerifications: false,
expirationDate: null,
expired: false,
id:
'0x18fb0ef05d96cba2a57c6de6d8cfd031e16367f6484f20797a39d25a3e76e20a',
issuer: '0xe560eF0954A2d61D6006E8547EC769fAc322bbCE',
name: '/example4',
rejectReason: undefined,
signature:
'0x081dec25292eeea7a969ec662a85b4160b8090227afff998c71d14d49f669e192569b4b76d5adbf4e7f9883bc560fdb5a92288238f243a322c6bdc81097a81da1c',
status: 0,
subject: '0x001De828935e8c7e4cb56Fe610495cAe63fb2612',
topic:
'66865638538889962651480090943794875041354346360740147141539983678449951391661',
uri: '',
valid: true,
displayName: 'example4',
parent: '',
warnings: [ 'issued' ],
subjectIdentity: '0xe560eF0954A2d61D6006E8547EC769fAc322bbCE',
subjectType: 'account',
issuerAccount: '0x001De828935e8c7e4cb56Fe610495cAe63fb2612',
ensAddress:
'93d49c39618452a1dcf4a52f91c7d50634851b5082233671e10070a3c73b3fad.example4.verifications.evan',
topLevelEnsOwner: '0x0000000000000000000000000000000000000000',
parents: [],
levelComputed:
{ creationDate: 1558697790000,
disableSubVerifications: false,
displayName: 'example4',
loading: false,
name: '/example4',
status: 0,
subjects: [ '0x001De828935e8c7e4cb56Fe610495cAe63fb2612' ],
verifications: [Circular],
warnings: [ 'issued' ],
description:
{ author: '0x0000000000000000000000000000000000000000',
dbcpVersion: 1,
description: '/example4',
name: '/example4',
version: '1.0.0',
i18n: { name: { en: 'example4' } } },
ensAddress:
'93d49c39618452a1dcf4a52f91c7d50634851b5082233671e10070a3c73b3fad.example4.verifications.evan',
topLevelEnsOwner: '0x0000000000000000000000000000000000000000',
expirationDate: null } } ],
parentComputed:
{ creationDate: 1558697790000,
disableSubVerifications: false,
displayName: 'example4',
loading: false,
name: '/example4',
status: 0,
subjects: [ '0x001De828935e8c7e4cb56Fe610495cAe63fb2612' ],
verifications:
[ { creationBlock: '188117',
creationDate: 1558697790000,
data:
'0x0000000000000000000000000000000000000000000000000000000000000000',
description:
{ author: '0x0000000000000000000000000000000000000000',
dbcpVersion: 1,
description: '/example4',
name: '/example4',
version: '1.0.0',
i18n: { name: { en: 'example4' } } },
disableSubVerifications: false,
expirationDate: null,
expired: false,
id:
'0x18fb0ef05d96cba2a57c6de6d8cfd031e16367f6484f20797a39d25a3e76e20a',
issuer: '0xe560eF0954A2d61D6006E8547EC769fAc322bbCE',
name: '/example4',
rejectReason: undefined,
signature:
'0x081dec25292eeea7a969ec662a85b4160b8090227afff998c71d14d49f669e192569b4b76d5adbf4e7f9883bc560fdb5a92288238f243a322c6bdc81097a81da1c',
status: 0,
subject: '0x001De828935e8c7e4cb56Fe610495cAe63fb2612',
topic:
'66865638538889962651480090943794875041354346360740147141539983678449951391661',
uri: '',
valid: true,
displayName: 'example4',
parent: '',
warnings: [ 'issued' ],
subjectIdentity: '0xe560eF0954A2d61D6006E8547EC769fAc322bbCE',
subjectType: 'account',
issuerAccount: '0x001De828935e8c7e4cb56Fe610495cAe63fb2612',
ensAddress:
'93d49c39618452a1dcf4a52f91c7d50634851b5082233671e10070a3c73b3fad.example4.verifications.evan',
topLevelEnsOwner: '0x0000000000000000000000000000000000000000',
parents: [],
levelComputed:
{ creationDate: 1558697790000,
disableSubVerifications: false,
displayName: 'example4',
loading: false,
name: '/example4',
status: 0,
subjects: [ '0x001De828935e8c7e4cb56Fe610495cAe63fb2612' ],
verifications: [Circular],
warnings: [ 'issued' ],
description:
{ author: '0x0000000000000000000000000000000000000000',
dbcpVersion: 1,
description: '/example4',
name: '/example4',
version: '1.0.0',
i18n: { name: { en: 'example4' } } },
ensAddress:
'93d49c39618452a1dcf4a52f91c7d50634851b5082233671e10070a3c73b3fad.example4.verifications.evan',
topLevelEnsOwner: '0x0000000000000000000000000000000000000000',
expirationDate: null } } ],
warnings: [ 'issued' ],
description:
{ author: '0x0000000000000000000000000000000000000000',
dbcpVersion: 1,
description: '/example4',
name: '/example4',
version: '1.0.0',
i18n: { name: { en: 'example4' } } },
ensAddress:
'93d49c39618452a1dcf4a52f91c7d50634851b5082233671e10070a3c73b3fad.example4.verifications.evan',
topLevelEnsOwner: '0x0000000000000000000000000000000000000000',
expirationDate: null },
levelComputed:
{ creationDate: 1558697805000,
disableSubVerifications: false,
displayName: 'child',
loading: false,
name: '/example4/child',
status: 0,
subjects: [ '0x001De828935e8c7e4cb56Fe610495cAe63fb2612' ],
verifications: [Circular],
warnings: [ 'issued', 'selfIssued', 'parentUntrusted' ],
description:
{ author: '0x0000000000000000000000000000000000000000',
dbcpVersion: 1,
description: '/example4/child',
name: '/example4/child',
version: '1.0.0',
i18n: { name: { en: 'child' } } },
ensAddress:
'ac43ca2dd23f1c08f2c2c6b22dcf233346588a5043ab7c4380656a2f7ac0146d.example4.verifications.evan',
topLevelEnsOwner: '0x0000000000000000000000000000000000000000',
expirationDate: null } } ],
parentComputed:
{ creationDate: 1558697805000,
disableSubVerifications: false,
displayName: 'child',
loading: false,
name: '/example4/child',
status: 0,
subjects: [ '0x001De828935e8c7e4cb56Fe610495cAe63fb2612' ],
verifications:
[ { creationBlock: '188118',
creationDate: 1558697805000,
data:
'0x0000000000000000000000000000000000000000000000000000000000000000',
description:
{ author: '0x0000000000000000000000000000000000000000',
dbcpVersion: 1,
description: '/example4/child',
name: '/example4/child',
version: '1.0.0',
i18n: { name: { en: 'child' } } },
disableSubVerifications: false,
expirationDate: null,
expired: false,
id:
'0x28e1df758883bb3d4d5e7e0fa978ff673bc749ade0a3d78ad952a30d0a0e2a01',
issuer: '0xe560eF0954A2d61D6006E8547EC769fAc322bbCE',
name: '/example4/child',
rejectReason: undefined,
signature:
'0x568770823b2b541c24deddfa403f82f883ac73cbdaae99d3b4a112bb36ec391d374c824f15e279474f072f180b0aa94670b289f7a0e62df63bc1b30d319f45321b',
status: 0,
subject: '0x001De828935e8c7e4cb56Fe610495cAe63fb2612',
topic:
'77917584097763165263567038986179239309321992426417843471841530443014147675245',
uri: '',
valid: true,
displayName: 'child',
parent: '/example4',
warnings: [ 'issued', 'selfIssued', 'parentUntrusted' ],
subjectIdentity: '0xe560eF0954A2d61D6006E8547EC769fAc322bbCE',
subjectType: 'account',
issuerAccount: '0x001De828935e8c7e4cb56Fe610495cAe63fb2612',
ensAddress:
'ac43ca2dd23f1c08f2c2c6b22dcf233346588a5043ab7c4380656a2f7ac0146d.example4.verifications.evan',
topLevelEnsOwner: '0x0000000000000000000000000000000000000000',
parents:
[ { creationBlock: '188117',
creationDate: 1558697790000,
data:
'0x0000000000000000000000000000000000000000000000000000000000000000',
description:
{ author: '0x0000000000000000000000000000000000000000',
dbcpVersion: 1,
description: '/example4',
name: '/example4',
version: '1.0.0',
i18n: { name: { en: 'example4' } } },
disableSubVerifications: false,
expirationDate: null,
expired: false,
id:
'0x18fb0ef05d96cba2a57c6de6d8cfd031e16367f6484f20797a39d25a3e76e20a',
issuer: '0xe560eF0954A2d61D6006E8547EC769fAc322bbCE',
name: '/example4',
rejectReason: undefined,
signature:
'0x081dec25292eeea7a969ec662a85b4160b8090227afff998c71d14d49f669e192569b4b76d5adbf4e7f9883bc560fdb5a92288238f243a322c6bdc81097a81da1c',
status: 0,
subject: '0x001De828935e8c7e4cb56Fe610495cAe63fb2612',
topic:
'66865638538889962651480090943794875041354346360740147141539983678449951391661',
uri: '',
valid: true,
displayName: 'example4',
parent: '',
warnings: [ 'issued' ],
subjectIdentity: '0xe560eF0954A2d61D6006E8547EC769fAc322bbCE',
subjectType: 'account',
issuerAccount: '0x001De828935e8c7e4cb56Fe610495cAe63fb2612',
ensAddress:
'93d49c39618452a1dcf4a52f91c7d50634851b5082233671e10070a3c73b3fad.example4.verifications.evan',
topLevelEnsOwner: '0x0000000000000000000000000000000000000000',
parents: [],
levelComputed:
{ creationDate: 1558697790000,
disableSubVerifications: false,
displayName: 'example4',
loading: false,
name: '/example4',
status: 0,
subjects: [ '0x001De828935e8c7e4cb56Fe610495cAe63fb2612' ],
verifications: [Circular],
warnings: [ 'issued' ],
description:
{ author: '0x0000000000000000000000000000000000000000',
dbcpVersion: 1,
description: '/example4',
name: '/example4',
version: '1.0.0',
i18n: { name: { en: 'example4' } } },
ensAddress:
'93d49c39618452a1dcf4a52f91c7d50634851b5082233671e10070a3c73b3fad.example4.verifications.evan',
topLevelEnsOwner: '0x0000000000000000000000000000000000000000',
expirationDate: null } } ],
parentComputed:
{ creationDate: 1558697790000,
disableSubVerifications: false,
displayName: 'example4',
loading: false,
name: '/example4',
status: 0,
subjects: [ '0x001De828935e8c7e4cb56Fe610495cAe63fb2612' ],
verifications:
[ { creationBlock: '188117',
creationDate: 1558697790000,
data:
'0x0000000000000000000000000000000000000000000000000000000000000000',
description:
{ author: '0x0000000000000000000000000000000000000000',
dbcpVersion: 1,
description: '/example4',
name: '/example4',
version: '1.0.0',
i18n: { name: { en: 'example4' } } },
disableSubVerifications: false,
expirationDate: null,
expired: false,
id:
'0x18fb0ef05d96cba2a57c6de6d8cfd031e16367f6484f20797a39d25a3e76e20a',
issuer: '0xe560eF0954A2d61D6006E8547EC769fAc322bbCE',
name: '/example4',
rejectReason: undefined,
signature:
'0x081dec25292eeea7a969ec662a85b4160b8090227afff998c71d14d49f669e192569b4b76d5adbf4e7f9883bc560fdb5a92288238f243a322c6bdc81097a81da1c',
status: 0,
subject: '0x001De828935e8c7e4cb56Fe610495cAe63fb2612',
topic:
'66865638538889962651480090943794875041354346360740147141539983678449951391661',
uri: '',
valid: true,
displayName: 'example4',
parent: '',
warnings: [ 'issued' ],
subjectIdentity: '0xe560eF0954A2d61D6006E8547EC769fAc322bbCE',
subjectType: 'account',
issuerAccount: '0x001De828935e8c7e4cb56Fe610495cAe63fb2612',
ensAddress:
'93d49c39618452a1dcf4a52f91c7d50634851b5082233671e10070a3c73b3fad.example4.verifications.evan',
topLevelEnsOwner: '0x0000000000000000000000000000000000000000',
parents: [],
levelComputed:
{ creationDate: 1558697790000,
disableSubVerifications: false,
displayName: 'example4',
loading: false,
name: '/example4',
status: 0,
subjects: [ '0x001De828935e8c7e4cb56Fe610495cAe63fb2612' ],
verifications: [Circular],
warnings: [ 'issued' ],
description:
{ author: '0x0000000000000000000000000000000000000000',
dbcpVersion: 1,
description: '/example4',
name: '/example4',
version: '1.0.0',
i18n: { name: { en: 'example4' } } },
ensAddress:
'93d49c39618452a1dcf4a52f91c7d50634851b5082233671e10070a3c73b3fad.example4.verifications.evan',
topLevelEnsOwner: '0x0000000000000000000000000000000000000000',
expirationDate: null } } ],
warnings: [ 'issued' ],
description:
{ author: '0x0000000000000000000000000000000000000000',
dbcpVersion: 1,
description: '/example4',
name: '/example4',
version: '1.0.0',
i18n: { name: { en: 'example4' } } },
ensAddress:
'93d49c39618452a1dcf4a52f91c7d50634851b5082233671e10070a3c73b3fad.example4.verifications.evan',
topLevelEnsOwner: '0x0000000000000000000000000000000000000000',
expirationDate: null },
levelComputed:
{ creationDate: 1558697805000,
disableSubVerifications: false,
displayName: 'child',
loading: false,
name: '/example4/child',
status: 0,
subjects: [ '0x001De828935e8c7e4cb56Fe610495cAe63fb2612' ],
verifications: [Circular],
warnings: [ 'issued', 'selfIssued', 'parentUntrusted' ],
description:
{ author: '0x0000000000000000000000000000000000000000',
dbcpVersion: 1,
description: '/example4/child',
name: '/example4/child',
version: '1.0.0',
i18n: { name: { en: 'child' } } },
ensAddress:
'ac43ca2dd23f1c08f2c2c6b22dcf233346588a5043ab7c4380656a2f7ac0146d.example4.verifications.evan',
topLevelEnsOwner: '0x0000000000000000000000000000000000000000',
expirationDate: null } } ],
warnings: [ 'issued', 'selfIssued', 'parentUntrusted' ],
description:
{ author: '0x0000000000000000000000000000000000000000',
dbcpVersion: 1,
description: '/example4/child',
name: '/example4/child',
version: '1.0.0',
i18n: { name: { en: 'child' } } },
ensAddress:
'ac43ca2dd23f1c08f2c2c6b22dcf233346588a5043ab7c4380656a2f7ac0146d.example4.verifications.evan',
topLevelEnsOwner: '0x0000000000000000000000000000000000000000',
expirationDate: null },
levelComputed:
{ creationDate: 1558697814000,
disableSubVerifications: false,
displayName: 'grandchild',
loading: false,
name: '/example4/child/grandchild',
status: 0,
subjects: [ '0x001De828935e8c7e4cb56Fe610495cAe63fb2612' ],
verifications: [Circular],
warnings: [ 'issued', 'selfIssued', 'parentUntrusted' ],
description:
{ author: '0x0000000000000000000000000000000000000000',
dbcpVersion: 1,
description: '/example4/child/grandchild',
name: '/example4/child/grandchild',
version: '1.0.0',
i18n: { name: { en: 'grandchild' } } },
ensAddress:
'00b41b33a2396efb6fd434bc67d84b47a32eee9a9a275ee6384f5c32f2b12b93.example4.verifications.evan',
topLevelEnsOwner: '0x0000000000000000000000000000000000000000',
expirationDate: null } } ]
DID¶
Class Name | Did |
---|---|
Extends | Logger |
Source | did.ts |
Tests | did.spec.ts |
The Did module allows to interact with DIDs on evan.network. As development of identity and DID handling on evan.network is an ongoing process, this document describes the current interoperability of DIDs on evan.network and can be seen as a work-in-progress state of the current implementation.
constructor¶
new Did(options);
Creates a new Did instance.
Parameters¶
options
-DidOptions
: options for Did constructor.contractLoader
-ContractLoader
:ContractLoader
instancedfs
-DfsInterface
:DfsInterface
instanceexecutor
-Executor
:Executor
instancenameResolver
-NameResolver
:NameResolver
instancesignerIdentity
-SignerIdentity
:SignerIdentity
instanceweb3
-Web3
:Web3
instancelog
-Function
(optional): function to use for logging:(message, level) => {...}
logLevel
-LogLevel
(optional): messages with this level will be logged withlog
logLog
-LogLogInterface
(optional): container for collecting log messageslogLogLevel
-LogLevel
(optional): messages with this level will be pushed tologLog
Returns¶
Did
instance
Example¶
const did = new Did({
contractLoader,
dfs,
executor,
nameResolver,
signerIdentity,
web3,
});
= Working with DID documents =¶
setDidDocument¶
did.setDidDocument(did, document);
Store given DID document for given DID.
Parameters¶
did
-string
: DID to store DID document fordocument
-any
: DID document to store,getDidDocumentTemplate
can be used as a starting point for DID documents
Returns¶
Promise
returns void
: resolved when done
Example¶
const identity = await runtime.verifications.getIdentityForAccount(accountsId, true);
const did = await runtime.did.convertIdentityToDid(identity);
const document = await runtime.did.getDidDocumentTemplate();
await runtime.did.setDidDocument(did, document);
getDidDocument¶
did.getDidDocument([did]);
Get DID document for given DID.
Parameters¶
did
-string
: DID to fetch DID document for.
Returns¶
Promise
returns any
: a DID document that MAY resemble DidDocumentTemplate format
Example¶
const identity = await runtime.verifications.getIdentityForAccount(accountsId, true);
const did = await runtime.did.convertIdentityToDid(identity);
const document = await runtime.did.getDidDocumentTemplate();
await runtime.did.setDidDocument(did, document);
const retrieved = await runtime.did.getDidDocument(did);
setService¶
did.setService(service[, did]);
Sets service in DID document.
Parameters¶
did
-string
: DID name to set service forservice
-DidServiceEntry[] | DidServiceEntry
: service to set
Returns¶
Promise
returns void
: resolved when done
Example¶
const document = await runtime.did.getDidDocumentTemplate();
const identity = await runtime.verifications.getIdentityForAccount(account, true);
const did = await runtime.did.convertIdentityToDid(identity);
await runtime.did.setDidDocument(did, document);
const service = [{
id: `${did}#randomService`,
type: `randomService-${random}`,
serviceEndpoint: `https://openid.example.com/${random}`,
}];
await runtime.did.setService(did, service);
getService¶
did.getService([did]);
Get service from DID document.
Parameters¶
did
-string
: DID to fetch DID service for.
Returns¶
Promise
returns DidServiceEntry[] | DidServiceEntry
: service
Example¶
const document = await runtime.did.getDidDocumentTemplate();
const identity = await runtime.verifications.getIdentityForAccount(account, true);
const did = await runtime.did.convertIdentityToDid(identity);
await runtime.did.setDidDocument(did, document);
const service = [{
id: `${did}#randomService`,
type: `randomService-${random}`,
serviceEndpoint: `https://openid.example.com/${random}`,
}];
await runtime.did.setService(did, service);
const retrieved = await runtime.did.getService(did);
= utilities =¶
convertDidToIdentity¶
did.convertDidToIdentity(did);
Converts given DID to a evan.network identity.
Parameters¶
did
-string
: a DID like “did:evan:testcore:0x000000000000000000000000000000000000001234”
Returns¶
Promise
returns string
: evan.network identity like “0x000000000000000000000000000000000000001234”
Example¶
const did = 'did:evan:testcore:0x000000000000000000000000000000000000001234';
const identity = await did.convertDidToIdentity(did);
console.log(identity);
// Output:
// 0x000000000000000000000000000000000000001234
convertIdentityToDid¶
did.convertIdentityToDid(identity);
Converts given evan.network identity hash to DID.
Parameters¶
identity
-string
: evan.network identity like “0x000000000000000000000000000000000000001234”
Returns¶
Promise
returns string
: a DID like “did:evan:testcore:0x000000000000000000000000000000000000001234”
Example¶
const identity = '0x000000000000000000000000000000000000001234';
const did = await did.convertIdentityToDid(identity);
console.log(did);
// Output:
// did:evan:testcore:0x000000000000000000000000000000000000001234
getDidDocumentTemplate¶
did.getDidDocumentTemplate([]);
Gets a DID document for currently configured account/identity pair. Notice, that this document may a complete DID document for currently configured active identity, a part of it or not matching it at all. You can use the result of this function to build a new DID document but should extend it or an existing DID document, if your details derive from default format.
All three arguments are optional. When they are used, all of them have to be given and the result then describes a contracts DID document. If all of them are omitted the result describes an accounts DID document.
Parameters¶
did
-string
(optional): contract DIDcontrollerDid
-string
(optional): controller of contracts identity (DID)authenticationKey
-string
(optional): authentication key used for contract
Returns¶
Promise
returns DidDocumentTemplate
: template for DID document
Example¶
const document = await runtime.did.getDidDocumentTemplate();
console.log(JSON.stringify(document, null, 2));
// Output:
// {
// "@context": "https://w3id.org/did/v1",
// "id": "did:evan:testcore:0x126E901F6F408f5E260d95c62E7c73D9B60fd734",
// "publicKey": [
// {
// "id": "did:evan:testcore:0x126E901F6F408f5E260d95c62E7c73D9B60fd734#key-1",
// "type": [
// "Secp256k1SignatureVerificationKey2018",
// "ERC725ManagementKey"
// ],
// "publicKeyHex": "045adfd502c0bc55f4fcb90eea36368d7e19c5b3045aa6f51dfa3699046e9751251d21bc6bdd06c1ff0014fcbbf9f1d83c714434f2b33d713aaf46760f2d53f10d"
// }
// ],
// "authentication": [
// "did:evan:testcore:0x126E901F6F408f5E260d95c62E7c73D9B60fd734#key-1"
// ]
// }
VC¶
Class Name | Vc |
---|---|
Extends | Logger |
Source | vc.ts |
Tests | vc.spec.ts |
The Vc module allows to create, store, retrieve and revoke VCs on evan.network. As development of identities, and DID and VC handling on evan.network is an ongoing process, this document describes the current interoperability of VCs on evan.network and can be seen as a work-in-progress state of the current implementation.
constructor¶
new Vc(options, did);
Creates a new Vc instance.
Parameters¶
options
-VcOptions
: options for Vc constructor.accountStore
-AccountStore
:AccountStore
instanceactiveAccount
-string
: ID of the active accountcontractLoader
-ContractLoader
:ContractLoader
instancedfs
-DfsInterface
:DfsInterface
instancedid
-Did
:Did
instance for resolving and validatingexecutor
-Executor
:Executor
instancenameResolver
-NameResolver
:NameResolver
instancesignerIdentity
-SignerIdentity
:SignerIdentity
instanceverifications
-Verifications
:Verifications
instanceweb3
-Web3
:Web3
instancelog
-Function
(optional): function to use for logging:(message, level) => {...}
logLevel
-LogLevel
(optional): messages with this level will be logged withlog
logLog
-LogLogInterface
(optional): container for collecting log messageslogLogLevel
-LogLevel
(optional): messages with this level will be pushed tologLog
config
-VcConfig
: custom configuration for Vc constructor.credentialStatusEndpoint
-string
: URL of the credential status endpoint
Returns¶
Vc
instance
Example¶
const vc = new Vc(
{
accountStore,
activeIdentity
contractLoader,
dfs,
did,
executor,
nameResolver,
signerIdentity,
verifications,
web3,
},
{ credentialStatusEndpoint },
);
= Working with VC documents =¶
createId¶
Claim a new ID in the VC registry which can be used later to store a VC on-chain.
vc.createId();
Returns¶
Promise
returns string
: A new ID string
Example¶
const newRegisteredId = await runtime.vc.createId();
const myVcDocument = {
// Data here,
id: newRegisteredId
};
await runtime.vc.storeVc(myVcDocument);
createVc¶
Create a signed off-chain VC document
vc.createVc(vcData);
Parameters¶
vcData
- DocumentTemplate: Collection of mandatory and optional VC properties to store in the VC document
Returns¶
Promise
returns VcDocument
: The final VC document
Example¶
const minimalVcData = {
id: 'randomCustomId',
issuer: {
did: 'someDid',
},
credentialSubject: {
did: 'someOtherDid',
},
validFrom: new Date(Date.now()).toISOString()
};
const offchainVc = await runtime.vc.createVc(minimalVcData);
getVc¶
Get VC document for given VC ID.
vc.getVc(vcId, encryptionInfo);
Parameters¶
vcId
-string
: ID to fetch VC document for. Can be either a full VC URI (starting withvc:evan:
) or just the VC ID (starting with0x
)encryptionInfo
- EncryptionInfo: (optional): Information required for decryption
Returns¶
Promise
returns VcDocument
: A VC document
Example¶
const storedVcDoc = await vc.getVc('0x2a838a6961be98f6a182f375bb9158848ee9760ca97a379939ccdf03fc442a23');
const otherStoredVcDoc = await vc.getVc('vc:evan:testcore:0x2a838a6961be98f6a182f375bb9158848ee9760ca97a379939ccdf03fc442a23');
// using encryption
encryptionInfo = { key: vcKey };
const EncryptedVcDoc = await vc.getVc( 'vc:evan:testcore:0x5f7514378963d3a1211a3b015c51dd9fbd1e52d66a2fbb411fcdf80fdfd7bbd4', encryptionInfo);
storeVc¶
vc.storeVc(vcData, encryptionInfo);
Create a new VC that holds the given data and store it on the chain.
Whether a new ID should be registered with the VC registry or the given ID in the document should be used depends of if vcData.id
is set. If set, the method calls createId()
to generate a new ID.
Parameters¶
vcData
- DocumentTemplate: Collection of mandatory and optional VC properties to store in the VC documentencryptionInfo
- EncryptionInfo: (optional): Information required for encryption
Returns¶
Promise
returns VcDocument
: Returns the VC document as stored on the chain.
Example¶
const minimalVcData = {
issuer: {
did: 'someDid',
},
credentialSubject: {
did: 'someOtherDid',
},
validFrom: new Date(Date.now()).toISOString()
};
const createdVcDoc = await runtime.vc.storeVc(minimalVcData);
const permanentVcAddress = createdVcDoc.id;
const myRegisteredId = await runtime.vc.createId();
const minimalVcData = {
issuer: {
did: 'someDid',
},
credentialSubject: {
did: 'someOtherDid'
},
validFrom: new Date(Date.now()).toISOString()
};
minimalVcData.id = myRegisteredId;
const createdVcDoc = await runtime.vc.storeVc(minimalVcData);
const permanentVcAddress = createdVcDoc.id;
revokeVc¶
vc.revokeVc(vcId);
Sets a revoke status flag for the VC.
Parameters¶
vcId
-string
: ID for VC document to be revoked.
Returns¶
Promise
returns void
: resolved when done
Example¶
const storedVcDoc = await vc.getVc(permanentVcAddress);
const vcId = storedVcDoc.id;
const revokeProcessed = await vc.revokeVc(vcId);
getRevokeVcStatus¶
vc.getRevokeVcStatus(vcId);
Gets the revoke status flag for the VC.
Parameters¶
vcId
-string
: ID for VC document whose status needs to be retrieved.
Returns¶
Promise
returns bool
: true for revoked, false for not revoked
Example¶
const storedVcDoc = await vc.getVc(permanentVcAddress);
const vcId = storedVcDoc.id;
const vcRevokeStatus = await vc.getRevokeVcStatus(vcId);
Additional Components¶
Interfaces¶
EncryptionInfo¶
configuration settings required for the encryption and decryption
key
-string
: the encryption key required for encrypting and decrypting the VC
DocumentTemplate¶
Template for the VC document containing the relevant data
id
-string
: the id of the VCtype
-string
: set of unordered URIsissuer
- VcIssuer: VC issuer detailsvalidFrom
-string
: date from which the VC is validvalidUntil
-string
(optional): date until which the VC is validcredentialSubject
- VcCredentialSubject: subject details of VCcredentialStatus
- VcCredentialStatus (optional): details regarding the status of VCproof
- VcProof (optional): proof of the respective VC
VcIssuer¶
Template for the VC Issuer containing the relevant data
id
-string
: the id of the issuername
-string
(optional): name of the issuer
VcCredentialSubject¶
Template for the VC credential subject containing the relevant data
id
-string
: the id of the subjectdata
-VcCredentialSubjectPayload
(optional): data payload for subjectdescription
-string
(optional): description about subjecturi
-string
(optional): uri of subject
VcCredentialStatus¶
Template for the VC credential status containing the status data
id
-string
: the id of the VCtype
-string
: VC status type
VcProof¶
proof for VC, contains JWS and metadata
type
-string
: VC status typecreated
-string
: date when the proof was createdproofPurpose
-string
: purpose of the proofverificationmethod
-string
: method used for verificationjws
-string
: JSON Web Signature
Profiles are personal data for accounts. They can be shared with other accounts or used for storing own data. This section contains modules for maintaining profile and interacting with profiles from other accounts.
Two types of profiles are supported:
- personal profiles, that hold users data like contacts, bookmarks, encryption keys
- business center profiles, that are like contact cards and hold data intended for other participants