Page: Contracts service
2019-12-13 20:12
-
Contracts Service
- Topic: Java API
- Overview
- Token-type contracts
- Shares-type contract
- Notary-type contract
- Contract with two signatures
- Escrow contract
- Slot contract
- UNS1 contract
- Follower contract
- Revocation of contracts
- Exchanging the contracts
- References
- Parcel and paying parcel
- Rate limit disabling contract
- Release notes
Contracts Service
Topic: Java API
See other Java API features at Software Developer Central: Java API at whole, Contracts Service, Distributed Storage, etc.
To start using Java API, you can add com.icodici:universa_core:3.14.4 dependency from Universa public Maven repository. See more details at Maven repository page.
This feature is available in package com.icodici.universa.contract
, as the ContractsService
class; see it on GitHub:
Overview
The Contracts Service is a service that helps to create various types of contracts, implement and execute various common operations with them.
The Contracts Service allows you to:
- create fixed supply token-type contract;
- create mintable token-type contract;
- splitting and joining token-type contracts;
- create shares-type contract;
- create notary-type contract;
- create contract with two signatures;
- create Slot contract;
- create UNS1 contract;
- create Follower contract;
- revocation of contracts;
- exchange some contracts;
- add references;
- create parcel and paying parcel;
- create rate limit disabling contract;
- and possibly other features.
Token-type contracts
The Contracts Service makes it possible to create a simple (non-mintable, fixed supply) template token contract as easy as a mintable (dynamic-supply) template token contract. And also allows to split and join token amounts, for example, to make or receive payments.
Fixed-supply token contract
Creates a simple (fixed supply) template token contract for given keys:
Contract createTokenContract(Set<PrivateKey> issuerKeys, Set<PublicKey> ownerKeys, BigDecimal amount, BigDecimal minValue, String currency, String name, String description)
Contract createTokenContract(Set<PrivateKey> issuerKeys, Set<PublicKey> ownerKeys, BigDecimal amount, BigDecimal minValue)
Contract createTokenContract(Set<PrivateKey> issuerKeys, Set<PublicKey> ownerKeys, BigDecimal amount)
issuerKeys
is issuer private keys;ownerKeys
is owner public keys;amount
is issued tokens amount;minValue
is minimum token value;currency
is token currency code;name
is token currency name;description
is token currency description;returns
signed and sealed contract, ready for register.
The method creates a fixed-supply templated token contract, signed and sealed and ready for register, containing:
issuer
,creator
andowner
roles properly defined;change_owner
permission for owner,revoke
permissions for owner and issuer andsplit_join
permission for owner.
The Split_join
permission has the following parameters:
params.set("min_value", minValue.toString());
params.set("min_unit", minValue.toString());
params.set("field_name", "amount");
listFields.add("state.origin");
params.set("join_match_fields", listFields);
By default expires_at time
is set to 60 months from now.
The owner can split and join tokens, for example, to make payment or receive payments. To do this, you must use the split and join methods.
Use the code:
Contract tokenContract = ContractsService.createTokenContract(issuerPrivateKeys,ownerPublicKeys, new BigDecimal("1000000"));
ItemResult itemResult = client.register(tokenContract.getPackedTransaction(), 5000);
Mintable token contract
The “mintable token”-type contract lets you to issue multiple tokens contracts unlike the “fixed supply token“ that is only issued once. To create a templated mintable token-type contract, you must use the following methods:
Contract createMintableTokenContract(Set<PrivateKey> issuerKeys, Set<PublicKey> ownerKeys, BigDecimal amount, BigDecimal minValue, String currency, String name, String description)
Contract createMintableTokenContract(Set<PrivateKey> issuerKeys, Set<PublicKey> ownerKeys, BigDecimal amount, BigDecimal minValue)
Contract createMintableTokenContract(Set<PrivateKey> issuerKeys, Set<PublicKey> ownerKeys, BigDecimal amount)
issuerKeys
contains the issuer private keys. Keep it the same for all issued contracts of the same currency!;ownerKeys
contains the owner public keys;amount
contains the initial token amoun;minValue
contains the minimum token value;currency
is token currency code. Keep it the same for all issued contracts of the same currency!;name
is token currency name;description
is token currency description;returns
signed and sealed contract, ready for register.
The method creates a templated mintable token-type contract, signed and sealed and ready for register, containing:
issuer
,creator
andowner
roles properly defined;change_owner
permission for owner,revoke
permissions for owner and issuer andsplit_join
permission for owner.
Whenever you need to execute an additional emission of this token (“mint” more of this token), you should use the same create…
methods, providing them with the same issuerKeys
and currency
. This will cause the newly-created tokens to be compatible (for split/join operations) with the previous emission(s).
Note: the previous methods to create the mintable tokens and to create the new emissions, createTokenContractWithEmission
and createTokenEmission
, are now deprecated.
Split_join
permission has following params:
params.set("min_value", minValue.toString());
params.set("min_unit", minValue.toString());
params.set("field_name", "amount");
listFields.add("definition.issuer");
listFields.add("definition.data.currency");
params.set("join_match_fields", listFields);
Modify_data
permission has following params fields: "amount
".
By default expires_at time
is set to 60 months from now.
The owner can split and join mintable token, for example, to make payment or receive payments. To do this, you must use the split and join methods.
Use the code:
Contract mintableTokenContract1 = ContractsService.createMintableTokenContract(issuerPrivateKeys, ownerPublicKeys, new BigDecimal("300000000000"));
Contract mintableTokenContract2 = ContractsService.createMintableTokenContract(issuerPrivateKeys, ownerPublicKeys, new BigDecimal("100000000000"));
ItemResult itemResult = client.register(mintableTokenContract1.getPackedTransaction(), 5000);
ItemResult itemResult = client.register(mintableTokenContract2.getPackedTransaction(), 5000);
Contract joinedContract = ContractsService.createJoin(mintableTokenContract1,mintableTokenContract2,"amount",ownerPrivateKeys)
itemResult = client.register(joinedContract.getPackedTransaction(), 5000);
Split method
This method creates a new revision of given contract, and splits it to the pair of contracts with split amount:
Contract createSplit(Contract c, BigDecimal amount, String fieldName, Set<PrivateKey> keys)
Contract createSplit(Contract c, BigDecimal amount, String fieldName, Set<PrivateKey> keys, boolean andSetCreator)
c
is a contract that must be split. Note that this contract must have asplit_join
permission for the specified keys;amount
is value that should be split from given contract;fieldName
is name of field that should be split;keys
is one or more keys that together can play the role assigned to thesplit_join
permission;andSetCreator
if true set owners as creator in both contracts;returns
a ready sealed contract, that must be registered with Universa to complete the split contract procedure.
100"]-->A["Contract A
70"] C["Contract C
100"]-->B["Contract B
30"]
Upon the successful registration the source contract will be revoked.
Use the code:
Contract contractC = ContractsService.createTokenContract(issuerPrivateKeys,ownerPublicKeys, new BigDecimal("100"));
ItemResult itemResult = client.register(contractC.getPackedTransaction(), 5000);
Contract contractA = ContractsService.createSplit(contractC, new BigDecimal("30"), "amount", issuerPrivateKeys2, true);
Contract contractB = contractA.getNew().get(0);
itemResult = client.register(contractA.getPackedTransaction(), 5000);
Join method
This method creates a new revision of the first contract, updates the amount
field with the sum of amount fields in the both contracts, and puts the second contract into the revoking
items of the just-created new revision.
Contract createJoin(Contract contract1, Contract contract2, String fieldName, Set<PrivateKey> keys)
contract1
is a contract that must be joined to;contract2
is a contract that is being joined. Note that this contracts must have a compatiblesplit_join
permission for the specified keys;fieldName
is name of field that should be joined;keys
is one or more keys that together can play the role assigned to thesplit_join
permission;returns
a ready sealed contract, that must be registered with Universa to complete the split contract procedure.
70"]-->C["Contract C
100"] B["Contract B
30"]-->C["Contract C
100"]
Upon the successful registration the contract A and contract B will be revoked.
Use the code:
Contract contractC = ContractsService.createJoin(contractA, contractB, "amount", issuerPrivateKeys2);
ItemResult itemResult = client.register(contractC.getPackedTransaction(), 5000);
Shares-type contract
You can very easily create a templated shares contract for the given keys. Use the method:
Contract createShareContract(Set<PrivateKey> issuerKeys, Set<PublicKey> ownerKeys, BigDecimal amount)
issuerKeys
is issuer private keys;ownerKeys
is owner public keys;amount
is maximum shares number;returns
signed and sealed contract, ready for register.
The method creates a simple template share contract, signed and sealed and ready for register, containing:
issuer
,creator
andowner
roles properly defined;change_owner
permission for owner,revoke
permissions for owner and issuer andsplit_join
permission for owner.
Split_join
permission has the following parameters:
params.set("min_value", new BigDecimal(1));
params.set("min_unit", new BigDecimal(1));
params.set("field_name", "amount");
listFields.add("state.origin");
params.set("join_match_fields", listFields);
By default expires_at time
is set to 60 months from now.
Use the code:
Contract shareContract = ContractsService.createShareContract(issuerPrivateKeys, ownerPublicKeys, new BigDecimal("100"));
ItemResult itemResult = client.register(shareContract.getPackedTransaction(), 5000);
Notary-type contract
Create notary-type contract
Methods creates a simple notary contract for given keys, attach the data file to notary contract and attach the data file descriptions:
Contract createNotaryContract(Set
issuerKeys, Set ownerKeys) Contract createNotaryContract(Set
issuerKeys, Set ownerKeys, List filePaths) Contract createNotaryContract(Set
issuerKeys, Set ownerKeys, List filePaths, List fileDescriptions)
issuerKeys
is issuer private keys;ownerKeys
is owner public keys;filePaths
is path to data file;fileDescriptions
is data file descriptions.
Returns signed and sealed contract, ready for register.
The method creates a simple templated notary contract, signed and sealed and ready for register, containing:
issuer
,creator
andowner
roles properly defined;change_owner
permission for owner andrevoke
permissions for owner and issuer.
By default expires_at time
is set to 60 months from now.
Use the code:
String pathToAttachments = "./path/to/attachments/";
List<String> fileNames = new ArrayList<>();
fileNames.add(pathToAttachments+"attachment.bin");
List<String> filesDesc = new ArrayList<>();
filesDesc.add("attachment description");
Contract notaryContract = ContractsService.createNotaryContract(issuerKeys,ownerKeys,fileNames,filesDesc);
ItemResult itemResult = client.register(notaryContract.getPackedTransaction(), 5000);
Check the data attached to the notary contract
After you have created a notarized contract, you can check the compliance of the data attached to the notarial contract with the original data. For this you need to use the method:
Contract checkAttachNotaryContract(Contract notaryContract, String filePaths)
notaryContract
is notary-type contract;filePaths
is path to attached file or folder with files.
Returns result of checking the data attached to the notary contract.
The method can check the compliance of the file attached to the notary contract with the file at the specified path.
Use the code:
String pathToAttachment = "./path/to/attachment.bin";
List<String> fileNames = new ArrayList<>();
fileNames.add(pathToAttachment);
Contract notaryContract = ContractsService.createNotaryContract(issuerKeys, ownerKeys, fileNames);
if (checkAttachNotaryContract(notaryContract, pathToAttachment))
client.register(notaryContract.getPackedTransaction(), 5000);
You can also specify the path to the directory with files, among which will be selected suitable for checking. If the notary contract contains several attached files, then you must specify the path to the directory with the files and the method will check the compliance of all files attached to the notary contract.
Use the code:
String pathToAttachments = "./path/to/attachments/";
List<String> fileNames = new ArrayList<>();
fileNames.add(pathToAttachments + "attachment1.bin");
fileNames.add(pathToAttachments + "attachment2.bin");
Contract notaryContract = ContractsService.createNotaryContract(issuerKeys, ownerKeys, fileNames);
if (checkAttachNotaryContract(notaryContract, pathToAttachments))
client.register(notaryContract.getPackedTransaction(), 5000);
Contract with two signatures
This method creates a contract which requires two signatures to present, to become valid (often called “multisig” in other architectures). It can not be registered until both parts of the deal have signed it. This feature allows you to make sure that both parties agree with the contract:
Contract createTwoSignedContract(Contract baseContract, Set<PrivateKey> fromKeys, Set<PublicKey> toKeys, boolean createNewRevision)
baseContract
is base contract;fromKeys
is own private keys;toKeys
is foreign public keys;createNewRevision
create new revision from base contract if true;returns
contract with two signatures that should be send from first part to partner.
In order to understand how this looks in practice, consider in more detail: we have the opportunity to create a simple exchange contract aimed at sending something with the approval of the recipient before the transfer.
Participant A sends something (for example, money) to participant B and sends him a contract for two signatures. Participant B signs the contract, but he can not register it. Then participant B returns the contract to participant A.
Participant A signs the contract. Now a contract for two signatures can be registered with Universa.
Participant A is confident and can prove that B has a copy of the receiving contract.
Use the code:
// participant A
Contract twoSignContract = ContractsService.createTwoSignedContract(baseContract, partAPrivateKeys, partBPublicKeys, false);
// participant B
twoSignContract.addSignatureToSeal(partBPrivateKeys);
// participant A
twoSignContract.addSignatureToSeal(partAPrivateKeys);
ItemResult itemResult = client.register(twoSignContract.getPackedTransaction(), 5000);
Escrow contract
An Escrow contract involves a contract for the blocking of payment received from the depositor
(customer) with a view to transferring it to another person the beneficiary
(executor) in the event that the grounds provided for by the contract arise and with the participation of the third line escrow agent
(arbitrator).
The fact of occurrence of the terms provided by the agreement is accepted by the joint decision of the depositor
(customer) and the beneficiary
(executor),for example:
or by the decision of the escrow agent
(arbitrator) and any of the participants, as a result of which the payment becomes available to the beneficiary
(executor):
Similarly, a decision is made to cancel the escrow contract, as a result of which the payment is returned to the depositor
(customer):
In other words, the escrow contract allows you to enter into an agreement in which the depositor
undertakes to transfer the payment to the escrow agent
in order to fulfill the obligation of the depositor
to transfer it to another person in favor of which the deposit is made (the beneficiary
). And the escrow agent
is obliged to transfer it to thebeneficiary
if the grounds indicated in the contract arise, otherwise return the payment to the depositor
.
Create Escrow contract
The Escrow contract is an External Escrow contract (container) that containing an Internal Escrow contract, as well as a payment contract or several payment contracts:
Method for create Escrow contract
Method createEscrowContract is basic, in most cases sufficient to create a escrow contract.
Method creates an external escrow contract containing an internal escrow contract. Contracts are linked by internal escrow contract origin.
To internal escrow contract establishes the owner role, on the basis of the quorum of 2 of 3 roles: customer, executor and arbitrator.
This role is granted exclusive permission to change the value of the status field of internal escrow contract (state.data.status).
Possible values for the internal escrow contract status field are: opened
, completed
and canceled
. External and internal escrow contracts create for a expiration period of 5 years.
Contract createEscrowContract(Collection
issuerKeys, Collection customerKeys, Collection executorKeys, Collection arbitratorKeys)
issuerKeys
are issuer escrow contract private keys;-
customerKeys
are customer public keys; -
executorKeys
are executor public keys; -
arbitratorKeys
are arbitrator public key.
Returns external escrow contract.
If necessary, the contents and parameters (expiration period, for example) of escrow contracts can be changed before sealing and registration.
If internal escrow contract origin has changed, need re-create external escrow contract by Contracts service method createExternalEscrowContract.
Use the code:
Contract escrow = ContractsService.createEscrowContract(issuerPrivateKeys, customerPublicKeys, executorPublicKeys, arbitratorPublicKeys);
Method for create Internal Escrow contract
Method createInternalEscrowContract is used to create a escrow contract without creating a container (external escrow contract).
Method сreates Internal escrow contract for a expiration period of 5 years. To internal escrow contract establishes the owner role, ListRole on the basis of the quorum of 2 of 3 roles: customer, executor and arbitrator.
This role is granted exclusive permission to change the value of the status field of internal escrow contract (state.data.status).
Possible values for the internal escrow contract status field are: opened
, completed
and canceled
.
Contract createInternalEscrowContract( Collection
issuerKeys, Collection customerKeys, Collection executorKeys, Collection arbitratorKeys)
issuerKeys
are issuer escrow contract private keys;customerKeys
are customer public keys;executorKeys
are executor public keys;arbitratorKeys
are arbitrator public keys.
Returns internal escrow contract.
If necessary, the contents and parameters (expiration period, for example) of escrow contract can be changed before sealing and registration.
If internal escrow contract origin has changed, need re-create external escrow contract (if used) by createExternalEscrowContract.
Use the code:
Contract escrow = ContractsService.createInternalEscrowContract(issuerPrivateKeys, customerPublicKeys, executorPublicKeys, arbitratorPublicKeys);
Modification Escrow contract
If necessary, fields containing additional data can be added to the escrow contract (external and internal). Also, the contents and parameters of escrow contract can be changed.
Example adding field:
internalEscrow.getStateData().set("description", "internal escrow contract");
internalEscrow.seal();
Changes in the external contract do not impose any special restrictions. If you change the internal contract (if it is root and the origin changes), you need re-create external escrow contract (if used).
Method createExternalEscrowContract сreates external escrow contract for a expiration period of 5 years. External escrow contract includes internal escrow contract. Contracts are linked by internal escrow contract origin. Method should be used to re-create external escrow contract, if internal escrow contract origin has changed.
Contract createExternalEscrowContract(Contract internalEscrow, Collection
issuerKeys)
internalEscrow
is internal escrow contract;issuerKeys
are issuer escrow contract private keys.
Returns external escrow contract.
Use the code:
escrow = ContractsService.createExternalEscrowContract(internalEscrow, issuerPrivateKeys);
Payment contract for Escrow contract
The Escrow contract may include (or be associated with) one or more payment contracts.
Add payment contract
Method addPaymentToEscrowContract check external escrow contract and add payment contract to it.
To payment contract is added Transactional
section with 2 references: send_payment_to_executor
, return_payment_to_customer
.
The owner of payment contract is set to ListRole contains customer role with return_payment_to_customer
reference
and executor role with send_payment_to_executor
reference. Any of these roles is sufficient to own a payment contract.
boolean addPaymentToEscrowContract( Contract escrow, Contract payment, Collection
paymentOwnerKeys, Collection customerKeys, Collection executorKeys)
escrow
contract (external) to use with payment. Must be returned from createEscrowContract or createExternalEscrowContract;payment
contract to update. Must not be registered (new root or new revision);paymentOwnerKeys
are keys required for use payment contract (usually, owner private keys). May be null, if payment will be signed later;customerKeys
are customer public keys of escrow contract;executorKeys
are executor public keys of escrow contract.
Returns result of checking external escrow contract and adding payment to it.
Use the code:
Contract escrow = ContractsService.createEscrowContract(issuerPrivateKeys, customerPublicKeys, executorPublicKeys, arbitratorPublicKeys);
boolean result = ContractsService.addPaymentToEscrowContract(escrow, payment, customerPrivateKeys, customerPublicKeys, executorPublicKeys);
Modify payment contract
Method modifyPaymentForEscrowContract modifies payment contract by making ready for escrow. Method is used for payments of internal escrow contract.
To payment contract is added Transactional
section with two references: send_payment_to_executor
, return_payment_to_customer
. The owner of payment contract is set to ListRole contains customer role with return_payment_to_customer
reference and executor role with send_payment_to_executor
reference. Any of these roles is sufficient to own a payment contract.
Contract modifyPaymentForEscrowContract( Contract escrow, Contract payment, Collection
paymentOwnerKeys, Collection customerKeys, Collection executorKeys) Contract modifyPaymentForEscrowContract( String escrowOrigin, Contract payment, Collection
paymentOwnerKeys, Collection customerKeys, Collection executorKeys)
escrow
is internal escrow contract to use with payment. Must be returned from ContractsService.createInternalEscrowContract;escrowOrigin
is origin (base64 string) of internal escrow contract to use with payment;payment
contract to update. Must not be registered (new root or new revision);paymentOwnerKeys
are keys required for use payment contract (usually, owner private keys). May be null, if payment will be signed later;customerKeys
are customer public keys of escrow contract;executorKeys
are executor public keys of escrow contract.
Returns payment contract ready for escrow.
Use the code:
Contract escrow = ContractsService.createInternalEscrowContract(issuerPrivateKeys, customerPublicKeys, executorPublicKeys, arbitratorPublicKeys);
payment = ContractsService.modifyPaymentForEscrowContract(escrow, payment, customerPrivateKeys, customerPublicKeys, executorPublicKeys);
Complete escrow contract
Method completeEscrowContract completes escrow contract. All linked payments are made available to the executor. For registration completed escrow contract require quorum of 2 of 3 roles: customer, executor and arbitrator. After the completion of the escrow contract, it can not be canceled or reopened.
public static Contract completeEscrowContract(Contract escrow)
escrow
contract (external with internal or only internal) to complete. Must be registered for creation new revision.
Returns completed internal escrow contract or null if error occurred.
Use the code:
Contract completedEscrow = ContractsService.completeEscrowContract(escrow);
Cancel escrow contract
Method cancelEscrowContract сancels escrow contract. All linked payments are made available to the customer. For registration canceled escrow contract require quorum of 2 of 3 roles: customer, executor and arbitrator. After the cancellation of the escrow contract, it can not be completed or reopened.
public static Contract cancelEscrowContract(Contract escrow)
escrow
contract (external with internal or only internal) to cancel. Must be registered for creation new revision.
Returns canceled internal escrow contract or null if error occurred.
Use the code:
Contract canceledEscrow = ContractsService.cancelEscrowContract(escrow);
Transfer payment contract to new owner
Method takeEscrowPayment transfers payment contract to new owner on the result of escrow. Use payment contract that was added to external escrow contract by addPaymentToEscrowContract or linked with internal escrow contract by modifyPaymentForEscrowContract.
Executor can take the payment contract, if escrow contract are completed. Customer can take the payment contract, if escrow contract are canceled. For registration payment contract (returned by this method) add result internal escrow contract by TransactionPack.addReferencedItem.
Contract takeEscrowPayment(Collection
newOwnerKeys, Contract payment)
newOwnerKeys
are private keys of new owner of payment;payment
contract to take by new owner. Must be registered for creation new revision.
Returns new revision of payment contract with new owner.
Use the code:
Contract takedPayment = ContractsService.takeEscrowPayment(ownerKeys, payment);
Examples
The following are examples of two standard methods of using the escrow contract.
The first way involves creating an external escrow contract and adding payment contracts directly to it. This allows you to register escrow in the one parcel. The example also shows the completion of escrow contract and the transfer of payment contract to the executor.
// create external escrow contract
Contract escrow = ContractsService.createEscrowContract(issuerPrivateKeys, customerPublicKeys, executorPublicKeys, arbitratorPublicKeys);
// add payment to escrow contract
boolean result = ContractsService.addPaymentToEscrowContract(escrow, payment, customerPrivateKeys, customerPublicKeys, executorPublicKeys);
assertTrue(result);
node.registerItem(escrow);
// complete escrow contract(by external escrow contract)
Contract completedEscrow = ContractsService.completeEscrowContract(escrow);
// sign completed internal escrow contract by issuer
completedEscrow.addSignatureToSeal(issuerPrivateKeys);
// sign completed internal escrow contract by customer
completedEscrow.addSignatureToSeal(customerPrivateKeys);
// sign completed internal escrow contract by executor
completedEscrow.addSignatureToSeal(executorPrivateKeys);
// register signed escrow contract
node.registerItem(completedEscrow);
// transfer payment to executor
Contract newPayment = ContractsService.takeEscrowPayment(executorPrivateKeys, payment);
// internal escrow contract for checking references
newPayment.getTransactionPack().addReferencedItem(completedEscrow);
// register result executor payment
node.registerItem(newPayment);
The second way is to create an internal escrow contract and link payment contracts with it. This allows you to abandon the use of an external escrow contract (container). Also in the example is the cancellation of escrow contract and the return of payment contract to the customer.
// create internal escrow contract
Contract escrow = ContractsService.createInternalEscrowContract(issuerPrivateKeys, customerPublicKeys, executorPublicKeys, arbitratorPublicKeys);
// modify payment for escrow contract
payment = ContractsService.modifyPaymentForEscrowContract(escrow, payment, customerPrivateKeys, customerPublicKeys, executorPublicKeys);
// register escrow contract and payment
node.registerItem(escrow);
node.registerItem(payment);
// cancel escrow contract(by external escrow contract)
Contract canceledEscrow = ContractsService.cancelEscrowContract(escrow);
// sign canceled internal escrow contract by issuer
canceledEscrow.addSignatureToSeal(issuerPrivateKeys);
// sign canceled internal escrow contract by customer
canceledEscrow.addSignatureToSeal(customerPrivateKeys);
// sign canceled internal escrow contract by arbitrator
canceledEscrow.addSignatureToSeal(arbitratorPrivateKeys);
// register signed escrow contract
node.registerItem(canceledEscrow);
// return payment to customer
Contract newPayment = ContractsService.takeEscrowPayment(customerPrivateKeys, payment);
// internal escrow contract for checking references
newPayment.getTransactionPack().addReferencedItem(canceledEscrow);
// register result customer payment
node.registerItem(newPayment);
Slot contract
The “Slot contract” is one of several types of smart contracts that can be run on the node. Slot contract provides paid storing of other contracts at the distributed store, control storing time and control storing revisions of tracking contract.
Method creates a ready-made Slot contract with specified permissions and values:
SlotContract createSlotContract(Set<PrivateKey> issuerKeys, Set<PublicKey> ownerKeys, NSmartContract.NodeInfoProvider nodeInfoProvider)
issuerKeys
is issuer private keys;ownerKeys
is owner public keys;nodeInfoProvider
is node provider info;returns
ready Slot contract.
Returns Slot contract has change_owner
, revoke
and modify_data
with special slot fields permissions. Sets issuerKeys
as issuer, ownerKeys
as owner.
UNS1 contract
Name Service provides operation of decentralized storage for records of unique names that allow you to identify keys, address and origin of the contract. UNS1 contract is used to manage and for payment of registration names in this distributed store.
The method creates ready simple UNS1 contract with need permissions and values:
UnsContract createUnsContract(Set<PrivateKey> issuerKeys, Set<PublicKey> ownerKeys, NSmartContract.NodeInfoProvider nodeInfoProvider)
issuerKeys
is issuer private keys;ownerKeys
is owner public keys;nodeInfoProvider
is node provider info;returns
ready UNS1 contract.
Returns UNS1 contract has change_owner
, revoke
and modify_data
with special fields permissions. Sets issuerKeys
as issuer, ownerKeys
as owner.
The method creates a UNS1 contract ready to register a unique contract name, with the necessary permissions and values:
UnsContract createUnsContractForRegisterContractName(Set<PrivateKey> issuerKeys, Set<PublicKey> ownerKeys, NSmartContract.NodeInfoProvider nodeInfoProvider, String name, String description, String URL, Contract namedContract)
issuerKeys
is issuer private keys.ownerKeys
is owner public keys.nodeInfoProvider
is node provider info;name
is name for registration.description
is description associated with name for registration.URL
is URL associated with name for registration.namedContract
is named contract.returns
ready UNS1 contract
Returns UNS1 contract has change_owner
, revoke
and modify_data
with special fields permissions. Sets issuerKeys
as issuer, ownerKeys
as owner.
Also added UNS name for registration associated with contract (by origin).
For example:
The method creates a UNS1 contract ready to register the unique name of the key (address), with the necessary permissions and values:
UnsContract createUnsContractForRegisterKeyName(Set<PrivateKey> issuerKeys, Set<PublicKey> ownerKeys, NSmartContract.NodeInfoProvider nodeInfoProvider, String name, String description, String URL, AbstractKey namedKey)
issuerKeys
is issuer private keys;ownerKeys
is owner public keys;nodeInfoProvider
is node provider info;name
is name for registration;description
is description associated with name for registration;URL
is URL associated with name for registration;namedKey
is is named key;returns
ready UNS1 contract.
Returns UNS1 contract has change_owner
, revoke
and modify_data
with special fields permissions. Sets issuerKeys
as issuer, ownerKeys
as owner.
Also added UNS name for registration associated with key (by addresses).
For example:
Follower contract
The “Follower contract” is one of several types of smart contracts that can be run on the node. Follower contract is a contract that tracks contract registrations in any chain of contracts in the network for payment, when a new event occurs, the contract sends a request to the URL specified by the user, which contains the body of the new registered revision.
The cost of servicing the Follower contract
The Follower contract works on the pre-paid basis.
When Follower contract is first created, it must be accompanying with a initial payment in the paying parcel, which should cover at least 100 origin-days, or cost 100 callbacks. For example, in the simplest case, at the moment the minimum cost will be 100 U, which corresponds to the cost of 100 OD or 100 callbacks.
After the registration of the Follower contract, the payment is spent on storage and on calling the callback.
If the balance on the account is less than the cost of the callback, then the contract will exist for some time. At this time you can replenish the account of the Follower contract. However, in this state, the contract will not cause a callback when registering a new revision of the tracked сontract.
Create Follower contract
Method createFollowerContract create and return ready FollowerContract contract with need permissions and values. FollowerContract is used for control and for payment for follow new revisions from some contract chains by origin.
FollowerContract createFollowerContract(Set
issuerKeys, Set ownerKeys, NSmartContract.NodeInfoProvider nodeInfoProvider)
issuerKeys
is issuer private keys;ownerKeys
is owner public keys;nodeInfoProvider
is node provider info.
Returns FollowerContract with need permissions and values.
Put tracking origin to Follower contract
Method putTrackingOrigin put new tracking origin
and his callback data (URL
and callback public key
) to the follower contract. If origin
already contained in follower contract, old callback data is replaced. If callback URL
already contained in follower contract, old callback key is replaced:
void putTrackingOrigin(HashId origin, String URL, PublicKey key)
origin
for tracking;URL
for callback if registered new revision with tracking origin;key
for checking receipt from callback by network.
Use the code:
FollowerContract followerContract = ContractsService.createFollowerContract(followerIssuerPrivateKeys, followerIssuerPublicKeys, nodeInfoProvider);
FollowerContract.putTrackingOrigin(simpleContract.getOrigin(), "http://localhost:7777/follow.callback", callbackKey.getPublicKey());
Revocation of contracts
In order to revoke the contract (let's name it a “source contract”), it is necessary to create an revocation contract. To revoke the contract it is necessary that it has "revoke" permission, and the party invoking the private key's matching the role(s) for this permission. That revocation contract should be sent to Universa, causing the “source” contract will be revoked. Method for creating a revocation contract:
Contract createRevocation(Contract sourceContract, PrivateKey... keys)
sourceContract
is a contract that must be revoked;keys
is one or more keys that together can play the role assigned to the revoke permission;returns
a ready sealed contract, that must be registered with Universa to complete the revocation contract procedure.
So, to revoke some contract:
- Call method
createRevocation(Contract c, PrivateKey... keys)
and get the revocation contract; - Register the revocation contract in the Universa network.
Upon the successful registration, the source contract will be revoked.
Use the code:
Contract revokeContract = ContractsService.createRevocation(sourceContract, privateKey);
ItemResult itemResult = client.register(revokeContract.getPackedTransaction(), 5000);
Exchanging the contracts
There is a thoroughly-defined and secure procedure when two parties want to exchange (swap) some contracts with each other; for example, Alice has 200 ABC tokens and want to receive 300 CDE tokens; and Bob has those 300 CDE tokens and want to receive 200 ABC tokens for them. This procedure makes it possible for them to execute such an exchange in an atomic way, so that neither of the two will may lose their tokens without receiving the new ones for them.
The procedure of such an exchange of contracts consists of three steps:
Step one
Methods prepares contracts with creating transactional section on the side of participant A, sign only one contract:
Contract startSwap(Contract contract1, Contract contract2, Set<PrivateKey> fromKeys, Set<PublicKey> toKeys)
Contract startSwap(List<Contract> contractsList1, List<Contract> contractsList2, Set<PrivateKey> fromKeys, Set<PublicKey> toKeys)
Contract startSwap(Contract contract1, Contract contract2, Set<PrivateKey> fromKeys, Set<PublicKey> toKeys, boolean createNewRevision)
Contract startSwap(List<Contract> contracts1, List<Contract> contracts2, Set<PrivateKey> fromKeys, Set<PublicKey> toKeys, boolean createNewRevision)
contract1
is own for calling part (participant A owned), existing or new revision of contract;contract2
is foreign for calling part (participant B owned), existing or new revision contract;contractsList1
is list of own for calling part (participant A owned), existing or new revision of contract;contractsList2
is list of foreign for calling part (participant B owned), existing or new revision contract;fromKeys
is own for calling part (participant A keys) private keys;toKeys
is foreign for calling part (participant B keys) public keys;createNewRevision
if true - create new revision of given contracts. If false - use them as new revisions;returns
swap contract including new revisions of old contracts swapping between.
Should be send to participant B and he should go to step two of the exchange procedure.
Step two
Method sign contracts on the side of participant B:
Contract signPresentedSwap(Contract swapContract, Set<PrivateKey> keys)
swapContract
is being processing swap contract, got from swapper1;keys
is own (belongs to participant B) private keys;returns
modified swapContract.
Participant B got swap contract from participant A and give it to service method.
Service signs the new contract where calling part was owner, store hashId of this contract.
Then added to reference of new contract, that will be own for calling part, contract_id and point it to contract that was own for calling part.
Then signs the second contract too.
Modified swapContract should be send back to participant A, and he should go to final step of the exchange procedure.
Final step
Method sign lost contracts on the side of participant A and finishing the exchange procedure:
Contract finishSwap(Contract swapContract, Set<PrivateKey> keys)
swapContract
is being processing swap contract, now got back from participant B;keys
is own (belongs to participant A) private keys;returns
ready and sealed swapContract that should be register in the Universa to finish of the exchange procedure.
Participant A got swap contract from participant B. Sends it to service method and service method signs contract (that is inside swap contract) that will be own for calling part.
In order to understand how to do this in practice, imagine that participant A has a contract Contract1 and wants to exchange it for participant B contract, let's call him Contract2:
As a result, we have a deal with the following properties:
- The contract1 and the contract2 are approved at the same time or none of them is approved (atomic transaction);
- There is a guarantee that Participant A has a valid copy of the Contract2, and Participant B has a valid copy of the contract1, that is, they exchanged contracts.
Use the code:
swapContract = ContractsService.startSwap(contractA, contractB, privateKeysA, publicKeysB);
mSwapContract = ContractsService.signPresentedSwap(swapContract, privateKeysB);
swapContract = ContractsService.finishSwap(mSwapContract, privateKeysA);
References
This is the method to add a reference and referenced contract to the base contract. That is, this method creates a contract with a reference, and the reference specified in a reference contract that must satisfy the reference conditions.
Contract addReferenceToContract(Contract baseContract, Contract refContract, String refName, int refType, Binder conditions)
Contract addReferenceToContract(Contract baseContract, Contract refContract, String refName, int refType, List <String> listConditions, boolean isAllOfConditions)
baseContract
is base contract for adding reference;refContract
is referenced contract (which must satisfy the conditions of the reference);refName
is name of reference;refType
is type of reference (section, may be TYPE_TRANSACTIONAL, TYPE_EXISTING_DEFINITION or TYPE_EXISTING_STATE;conditions
is conditions of the reference);listConditions
is list of strings with conditions of the reference;isAllOfConditions
is flag used if all conditions in list must be fulfilled (else - any of conditions);returns
ready and sealed contract.
When the returned contract is being unpacked, referenced contract verifies the compliance with the conditions of reference in the base contract.
For example:
- this.owner == ref.owner
- this.state.data.int <= ref.state.data.int
- ref.definition.created_at > "2018-04-12 19:03:00""]-->B["refContract"]
Use the code:
List <String> listConditions = new ArrayList<>();
listConditions.add("ref.definition.data.issuer == \"ApricoT\"");
listConditions.add("ref.definition.data.type == \"chief accountant assignment\"");
ContractsService.addReferenceToContract(llcProperty, jobCertificate, "certification_contract", Reference.TYPE_EXISTING_DEFINITION, listConditions, true);
Parcel and paying parcel
Most of all operations in the Universa network, such as contracts registration, should be paid. Payment carried out by special contract. To successfully registration of your contract you need to created paid transaction named as Parcel and send Parcel to the Universa network.
And also you can create paying parcel is an extension to the Parcel structure allowing include additional payment field that will not be registered if the transaction will fail.
Parcel
Methods created paid transaction named as Parcel, which consist from contract you want to register and payment contract that will be spend to process transaction:
Parcel createParcel(Contract payload, Contract payment, int amount, Set<PrivateKey> keys)
Parcel createParcel(Contract payload, Contract payment, int amount, Set<PrivateKey> keys, boolean withTestPayment)
payload
is prepared contract you want to register in the Universa;payment
is approved contract withU
belongs to you;amount
is number ofU
you want to spend to register payload contract;keys
is own private keys, which are set as owner of payment contract;param
withTestPayment if true Parcel will be created with test payment;returns
parcel, it ready to send to the Universa.
Methods create paid transaction named as Parcel, which consist from prepared TransactionPack you want to register and payment contract that will be spend to process transaction:
Parcel createParcel(TransactionPack payload, Contract payment, int amount, Set<PrivateKey> keys)
Parcel createParcel(TransactionPack payload, Contract payment, int amount, Set<PrivateKey> keys, boolean withTestPayment)
payload
is prepared TransactionPack you want to register in the Universa;payment
is approved contract withU
belongs to you;amount
is number ofU
you want to spend to register payload contract;keys
is own private keys, which are set as owner of payment contract;param
withTestPayment if true Parcel will be created with test payment;returns
parcel, it ready to send to the Universa.
Registration of the returned parcel is described in Java API.
Parcel structure:
Use the code:
Parcel parcel = ContractsService.createParcel(contract.getTransactionPack(), paymentContract, 1, privateKeys, false);
Paying Parcel
Method create Paying parcel is an extension to the parcel structure allowing include additional payment field that will not be registered if the transaction will fail:
Parcel createPayingParcel(TransactionPack payload, Contract payment, int amount, int amountSecond, Set<PrivateKey> keys, boolean withTestPayment)
payload
is prepared TransactionPack you want to register in the Universa;payment
is approved contract withU
belongs to you;amount
is number ofU
you want to spend to register payload contract;amountSecond
is number ofU
you want to spend from second payment;keys
is own private keys, which are set as owner of payment contract;withTestPayment
if true {@link Parcel} will be created with test payment;returns
parcel, it ready to send to the Universa.
Registration of the returned paying parcel is described in Java API.
Paying Parcel structure:
Use the code:
Parcel payingParcel = ContractsService.createPayingParcel(uns.getTransactionPack(), paymentContract, 1, nodeInfoProvider.getMinPayment("UNS1"), privateKeys, false);
Rate limit disabling contract
In the Universa network the limit of inquiries on a public key is established, you can make no more than 30 requests per minute, except for registration requests. However, if necessary, you can turn off the query limit for a time, for five minutes.The cost of five minute of unlimited use of the network is 5 U
.
In order to disable the limit of queries in the Universa network, you need to create a rate limit disabling contract using the createRateLimitDisablingContract method and register it on the Universa network.
If you need to extend disable the limit of queries in the Universa network, you must create a new contract and register it.
Method createRateLimitDisablingContract creates Special contract to disable request limit in the Universa network:
Contract createRateLimitDisablingContract(PublicKey key, Contract payment, int amount, Set
keys)
key
is key for setting unlimited requests;payment
is approved contract with "U" belongs to you;amount
is number of "U" you want to spend to set unlimited requests for key;keys
is own private keys, which are set as owner of payment contract.
Returns a rate limit disabling contract for the key.
A rate limit disabling contract is registered without additional payment, because it is a specialized contract.
Method getRateLimitDisablingPayment returns the cost to disable the limit of queries in the Universa network:
int getRateLimitDisablingPayment()
Use the code:
Contract contractForUnlimitKey = ContractsService.createRateLimitDisablingContract( publicKey, payment, Config.getRateLimitDisablingPayment(), paymentKeys);
Release notes
3.4.8 (08.05.2018)
- Added methods for payment parcel and slot contract creation
3.2.4b2 (27.03.2018)
- Added possibility for creation simple contract's templates such as token, share and notary
3.0.1 (27.02.2018)
- Collected and implemented methods for provide base contract's operations: revoke, split, join, swap, create parcel, create U