Example of a Product
A Tracker certificate
import Web3 from 'web3';
import BigNumber from 'bignumber.js';
import fs from 'fs';
import { AP, APTypes } from '@verified-network/protocol';
import ADDRESS_BOOK from '@verified-network/protocol/ap-chain/addresses.json';
import CERTFTerms from './CERTFTerms.json';
import { keys, rpcURL } from './secret.json';
import SettlementTokenArtifact from '@verified-network/protocol/build/contracts/contracts/tokens/SettlementToken.sol/SettlementToken.json';
(async () => {
const web3 = new Web3(new Web3.providers.HttpProvider(rpcURL));
const SecurityTokenArtifact = JSON.parse(fs.readFileSync('./abi/Security.json', 'utf8'));
const fdt = new web3.eth.Contract(SecurityTokenArtifact.abi, '0xd74109546668c7Fb97a093D9E888D6BF65eadfF0');
// setup accounts
keys.forEach((pk: string) => web3.eth.accounts.wallet.add(web3.eth.accounts.privateKeyToAccount(pk)));
const creator = (await web3.eth.getAccounts())[5]; // creator of the asset
const manager = (await web3.eth.getAccounts())[6]; // manager of the asset
const anyone = (await web3.eth.getAccounts())[2]; // used to make calls that could be made by any address
const holder = (await web3.eth.getAccounts())[3]; // future holder of FDTs created by asset manager
// initialize AP with web3 object and addressBook
const ap = await AP.init(web3, ADDRESS_BOOK);
// Deploy Settlement Token
// @ts-ignore
const settlementToken = await (new web3.eth.Contract(SettlementTokenArtifact.abi)).deploy(
{ data: SettlementTokenArtifact.bytecode }
).send({ from: creator, gas: 2000000 });
// create the term sheet by setting the currency to the Settlement Token contract we just deployed
const terms = { ...CERTFTerms };
// set up ownership
const ownership = {
creatorObligor: manager, // account which has to fulfill investor obligations (such as the initial exchange)
creatorBeneficiary: manager, // account which receives positive cashflows for the investor (such as redemptions)
counterpartyObligor: creator, // account which has to fulfill issuer obligations (such as paying redemptions)
counterpartyBeneficiary: creator, //account which receives positive cashflows for the issuer (such as the principal)
};
// create new CERTF asset
const initializeAssetTx = await ap.contracts.certfActor.methods.initialize(
terms,
[], // optionally pass custom schedule,
ownership,
ap.contracts.certfEngine.options.address,
ap.utils.constants.ZERO_ADDRESS,
ap.utils.constants.ZERO_ADDRESS
).send({ from: creator, gas: 2000000 });
// retrieve the AssetId from the transaction event logs
const assetId = initializeAssetTx.events.InitializedAsset.returnValues.assetId;
console.log('AssetId: ' + assetId);
// get asset terms
console.log('Terms: ', ap.utils.conversion.parseWeb3Response<APTypes.UTerms>(
await ap.contracts.certfRegistry.methods.getTerms(assetId).call())
);
// get asset state
console.log('State: ', ap.utils.conversion.parseWeb3Response<APTypes.UState>(
await ap.contracts.certfRegistry.methods.getState(assetId).call())
);
// get next scheduled event for the asset from the CERTF Registry and decode it
const nextScheduledEvent = await ap.contracts.certfRegistry.methods.getNextScheduledEvent(assetId).call();
const decodedEvent = ap.utils.schedule.decodeEvent(nextScheduledEvent);
// in our case that the IED (Initial Exchange event for transferring the principal from the investor to the issuer)
console.log('Next scheduled event: ', decodedEvent);
//compute pay off using engine
const payoff =
await ap.contracts.certfEngine.methods.computePayoffForEvent(
await ap.contracts.certfRegistry.methods.getTerms(assetId).call(),
await ap.contracts.certfRegistry.methods.getState(assetId).call(),
nextScheduledEvent,
web3.eth.abi.encodeParameter('uint256', decodedEvent.scheduleTime)
).call();
console.log("Pay off: ", payoff);
// approve actor to execute settlement payment (must be called before progressing the asset)
// manager has to give allowance to the actor to transfer the principal to the issuer
await ap.contracts.erc20(terms.currency).methods.approve(
ap.contracts.certfActor.options.address,
payoff
).send({ from: manager, gas: 2000000 });
// progress the asset - can be called by any account
await ap.contracts.certfActor.methods.progress(assetId).send({ from: manager, gas: 2000000 });
const isEventSettled = await ap.contracts.certfRegistry.methods.isEventSettled(
web3.utils.toHex(assetId), nextScheduledEvent
).call();
console.log("Is event settled: ", isEventSettled);
const projectedNextState =
await ap.contracts.certfEngine.methods.computeStateForEvent(
await ap.contracts.certfRegistry.methods.getTerms(assetId).call(),
await ap.contracts.certfRegistry.methods.getState(assetId).call(),
nextScheduledEvent,
web3.utils.toHex(0)
).call();
console.log("Projected next state: ", projectedNextState);
// creator sells 50% of his FDTs to a third party
await fdt.methods.transfer(
holder,
new BigNumber(await fdt.methods.balanceOf(manager).call()).dividedBy(2).toString()
).send({ from: manager, gas: 1000000 });
// set FDT contract as new beneficiary for asset
// in our case the FDT will receive and distribute all future payments
await ap.contracts.certfRegistry.methods.setCreatorBeneficiary(
assetId,
fdt.options.address
).send({ from: manager, gas: 2000000 });
// approve actor to execute settlement payment
// debtor has to give allowance to the Actor to transfer the first payment
await settlementToken.methods.approve(
ap.contracts.certfActor.options.address,
'25479452054794518000'
).send({ from: creator, gas: 2000000 });
// update internal balances in the FDT (can be called by any account)
await fdt.methods.updateFundsReceived().send({ from: holder, gas: 2000000 })
// check withdrawable funds for fractional owner after calling updateFundsReceived
const withdrawableAmount = await fdt.methods.withdrawableFundsOf(holder).call()
// Holder received 50% of the first interst payment
console.log('Withdrawable Balance of Holder: ' + withdrawableAmount.toString());
})();
Last updated