The wallet library is a high level library that allows for easy interaction with the Arianee protocol in a multichain wallet context.
npm install @arianee/wallet
The libray can be initialized without any parameter.
Default values are:
chainType
:"testnet"
auth
: a randomly generated wallet using@arianee/core
i18nStrategy
:"raw"
fetchLike
:window.fetch
in browser environment,node-fetch
in node environmenteventManagerParams
: undefinedarianeeAccessToken
: aArianeeAccessToken
instance from@arianee/arianee-access-token
using the core instance derived from passed autharianeeAccessTokenPrefix
: an optionalstring
that can be added before the arianee access token payload to sign. This is useful to let the user know what they are signing and why.storage
: aMemoryStorage
from@arianee/utils
transactionStrategy
: either to wait for transaction receipt or not. The recommended value for most users is'WAIT_TRANSACTION_RECEIPT'
(its default value). If'WAIT_TRANSACTION_RECEIPT'
is passed, theWallet
will wait for the transaction receipt, ensuring that the transaction has been successful, and methods will return aContractTransactionReceipt
. If'DO_NOT_WAIT_TRANSACTION_RECEIPT'
is passed, theWallet
will not wait for the receipt and methods will return aContractTransactionResponse
. This means the transaction might fail without notification. The latter is suitable for programs that utilize transaction queues and cannot wait for transaction confirmations. If the@arianee/core
instance you are using has a customsendTransaction
method for queuing transactions (one that resolves to{ skipResponse: true }
), you need to use'DO_NOT_WAIT_TRANSACTION_RECEIPT'
.
First, you need to import the Wallet
class:
import { Wallet } from '@arianee/wallet';
const wallet = new Wallet();
const wallet = new Wallet({
chainType: 'mainnet',
});
The wallet supports 3 ways of authentication:
- an
@arianee/core
instance - mnemonic
- private key
Authentication is passed to the constructor under the auth
key.
// with core instance
const wallet = new Wallet({
auth: {
core: Core.fromRandom(),
},
});
// with mnemonic
const wallet = new Wallet({
auth: {
mnemonic: 'your mnemonic ...',
},
});
// with private key
const wallet = new Wallet({
auth: {
privateKey: '123456',
},
});
You can pass a storage
object (that implements the Web Storage API
) to the wallet constructor under the storage
key.
This is particularly useful for frontend applications, as it allows for the wallet to persist data such as the arianee access token between page reloads through the use of the sessionStorage
or localStorage
object of the browser.
Example, persisting arianee access token over page refresh:
const wallet = new Wallet({
storage: sessionStorage,
});
You can pass an array of user preferred languages to the wallet constructor under the i18nStrategy
key.
When this key is passed, all i18n content will be returned in one of the preferred languages if possible. The languages should be sorted in order of preference, with the lowest index corresponding to the highest preference. If no content is available in any of the preferred languages, the content will be returned in the default language.
const wallet = new Wallet({
i18nStrategy: {
useLanguages: ['en-US', 'fr-FR'],
},
});
Sometimes you may want to use a custom WalletApiClient
instance or your own arianee access token instance. In such case, make sure to use the same instance of ArianeeAccessToken
both for the WalletApiClient
instance and the Wallet
instance. This way, the lib will request you to sign an arianee access token only once (it would request it twice if you don't share the instances).
Example:
const core = Core.fromRandom();
const arianeeAccessToken = new ArianeeAccessToken(core);
const prefix = 'Sign this Arianee access token to authenticate\n\n';
const testnetWalletApiClient = new WalletApiClient('testnet', core, {
apiURL: 'http://127.0.0.1:3000/',
arianeeAccessToken,
arianeeAccessTokenPrefix: prefix,
});
const testnetWallet = new Wallet({
auth: { core },
walletAbstraction: testnetWalletApiClient,
arianeeAccessToken,
arianeeAccessTokenPrefix: prefix,
});
The wallet exposes several methods to interact with the Arianee protocol.
It allows for retrieval of content of smart assets, messages, identities.
const wallet = new Wallet();
// smart asset methods
wallet.smartAsset.get(...);
wallet.smartAsset.getOwned(...);
wallet.smartAsset.getFromLink(...);
wallet.smartAsset.claim(...);
wallet.smartAsset.acceptEvent(...);
wallet.smartAsset.refuseEvent(...);
wallet.smartAsset.createLink(...);
wallet.smartAsset.isProofValidFromLink(...);
// events
wallet.smartAsset.received // emits when user received a smart asset from someone
wallet.smartAsset.transferred // emits when user transferred a smart asset to someone
wallet.smartAsset.updated
wallet.smartAsset.arianeeEventReceived
// message methods
wallet.message.get(...);
wallet.message.getReceived(...);
wallet.message.readMessage(...);
// events
wallet.message.received
wallet.message.read
// identity methods
wallet.identity.get(...);
wallet.identity.getOwnedSmartAssetsIdentities(...);
// events
wallet.identity.updated
// utils
wallet.getAddress();
wallet.authenticate(); // force generate a wallet scoped arianee access token, useful when you want to control when a signature request is made to the user with metamask / walletconnect etc.
The wallet emits events that can be listened to. It uses a pull mechanism under the hood, the pull interval can be passed to the constructor under the eventManagerParams.pullInterval
key. Events will be pulled every pullInterval
milliseconds if and only if there is at least one listener.
Default pull interval is 5 seconds.
// pull events every 2 seconds
const wallet = new Wallet({
eventManagerParams: {
pullInterval: 2000,
},
});
// listen to smart asset received event
wallet.smartAsset.received.addListener((event) => {
const { certificateId, protocol } = event;
console.log(`Smart asset (id ${certificateId}) received on ${protocol.name} (chain ${protocol.chainId})`);
});
// remove listener
wallet.smartAsset.received.removeListener(listener);
// remove all listeners
wallet.smartAsset.received.removeAllListeners();
Smart asset proofs can be verified using the isProofValidFromLink
method either by importing it or from the smartAsset
property of the Wallet
class.
If the proof is valid, the method resolves to true, otherwise it throws an error explaining why the proof is invalid.
Possible errors are: ProofCreatorIsNotOwnerError
, ProofExpiredError
, ProofKeyNotValidError
, NotAProofLinkError
, ProofKeyNotFoundError
.
The method accepts one required parameter (the proof link) and two optional parameters (arianeeApiUrl and proofValidityWindow).
- proofLink: the proof link to verify
- arianeeApiUrl (optional): the url of arianee api to use to fetch NFT data etc.
- proofValidityWindow (optional): the validity window of the proof in seconds. Default is 3 days (86400 * 3). This means that any proof generated between now and 3 days ago is considered valid (if all the other criterias are valid).
import Wallet, { isProofValidFromLink } from '@arianee/wallet';
try {
const wallet = new Wallet();
const isValid = await wallet.smartAsset.isProofValidFromLink('https://test.arian.ee/proof/9995851,d8cbfwnz12lh');
console.log('isValid', isValid);
} catch (e) {
console.log('Proof not valid', e?.message);
}
// or
try {
const isValid = await isProofValidFromLink('https://test.arian.ee/proof/9995851,d8cbfwnz12lh');
console.log('isValid', isValid);
} catch (e) {
console.log('Proof not valid', e?.message);
}
Unit tests can be ran with:
npm run test:wallet
We created examples of a simple multichain wallet using various web frameworks. \
A multichain wallet built with React, you can run it with:
npm run react-wallet
The source is located in apps/arianee-react-wallet/
A multichain wallet built with Angular, you can run it with:
npm run angular-wallet
The source is located in apps/angular-wallet/
When using the lib in browser environment, you may need to install polyfills because the library uses ethers
under the hood.
You need to use react-app-rewired to override the webpack config.
Install these packages:
npm install --save-dev react-app-rewired crypto-browserify stream-browserify browserify-zlib assert stream-http https-browserify os-browserify url buffer process
Create a config-overrides.js
file in the root of your project folder
const webpack = require('webpack');
module.exports = function override(config) {
const fallback = config.resolve.fallback || {};
Object.assign(fallback, {
crypto: require.resolve('crypto-browserify'),
stream: require.resolve('stream-browserify'),
assert: require.resolve('assert'),
http: require.resolve('stream-http'),
https: require.resolve('https-browserify'),
os: require.resolve('os-browserify'),
url: require.resolve('url'),
zlib: require.resolve('browserify-zlib'),
tls: false,
net: false,
});
config.resolve.fallback = fallback;
config.plugins = (config.plugins || []).concat([
new webpack.ProvidePlugin({
process: 'process/browser',
Buffer: ['buffer', 'Buffer'],
}),
]);
config.ignoreWarnings = [/Failed to parse source map/];
config.module.rules.push({
test: /\.(js|mjs|jsx)$/,
enforce: 'pre',
loader: require.resolve('source-map-loader'),
resolve: {
fullySpecified: false,
},
});
return config;
};
Update your package.json
with:
"scripts": {
"start": "react-app-rewired start",
"build": "react-app-rewired build",
"test": "react-app-rewired test",
"eject": "react-scripts eject"
},
Install these packages:
npm install --save-dev crypto-browserify stream-browserify browserify-zlib assert stream-http https-browserify os-browserify process buffer url
Create empty tls.d.ts
and net.d.ts
at the root of your project (or wherever you want but make sure to include the correct path) and update your tsconfig.json
with
{
"compilerOptions": {
"paths": {
"crypto": ["./node_modules/crypto-browserify"],
"stream": ["./node_modules/stream-browserify"],
"assert": ["./node_modules/assert"],
"http": ["./node_modules/stream-http"],
"https": ["./node_modules/https-browserify"],
"os": ["./node_modules/os-browserify"],
"process": ["./node_modules/process"],
"zlib": ["./node_modules/browserify-zlib"]
}
},
"include": ["src/**/*.ts", "tls.d.ts", "net.d.ts"]
}
Add to polyfills.ts
import { Buffer } from 'buffer';
(window as any).global = window;
global.Buffer = Buffer;
global.process = {
env: { DEBUG: undefined },
version: '',
} as any;