bam-ticketing-sdk
Version:
SDK for B.A.M Ticketing API
147 lines (131 loc) • 3.94 kB
text/typescript
import { AxiosInstance } from 'axios'
import {
Digest,
KeyPair,
TxStatus,
SignedDigest,
TransactionProposalPayload,
BlockchainFunctionParams,
} from './types'
import { signDigest } from './signer'
import { HealthStatus } from '../common/types'
import { toSnakeCase } from '../common/converter'
/**
* Service class for blockchain transactions.
*/
export class BlockchainService {
constructor(readonly client: AxiosInstance, readonly version: string) {}
/**
* Returns true if the service is reachable
*
* @returns Services' online status
*/
async health(): Promise<HealthStatus> {
try {
const res = await this.client.get(`event/health`)
if (res.data.status === 'ok') {
return { online: true }
}
} catch (e) {
// Do nothing
}
return { online: false }
}
/**
* This is the first step in committing data to the blockchain.
* Creates a new proposal which need to be signed with the private key.
*
* @param proposal New proposal data
* @returns Digest hash of the proposal
*/
async createProposal(proposal: TransactionProposalPayload): Promise<Digest> {
// The payload is snake cased because chaincode consumes it
const res = await this.client.post(
`blockchain/${this.version}/transaction/proposal`,
{
...proposal,
args: [JSON.stringify(toSnakeCase(proposal.args))],
}
)
return res.data.data
}
/**
* This is the second step in committing data to the blockchain.
* Submits the proposal signature so that it can be endorsed.
* It is signed with the user's private key.
*
* @param proposal Proposal's digest and signature
* @returns Transaction (tx) digest, used in the commit transaction step
*/
async createTransaction(proposal: SignedDigest): Promise<Digest> {
const res = await this.client.post(
`blockchain/${this.version}/transaction/proposal/${proposal.digest}`,
{ signature: proposal.signature }
)
return res.data.data
}
/**
* Third and final step in creating a transaction.
* Commits a transaction. Once a proposal is submitted,
* signed and endorsed it can be committed as a transaction to the blockchain.
*
* @param tx Signed transaction
* @returns Status of the transaction
*/
async commitTransaction(tx: SignedDigest): Promise<TxStatus> {
const res = await this.client.post(
`blockchain/${this.version}/transaction/${tx.digest}`,
{ signature: tx.signature }
)
return res.data.data
}
/**
* Creates a proposal, signs it and commits it to the blockchain.
*
* @param proposal Transaction proposal containing the bc function and arguments
* @param keys Private key and certificate to sign the intermediate steps
* @returns Transaction commit status
*/
async sendTransaction(
proposal: BlockchainFunctionParams,
keys: KeyPair
): Promise<TxStatus> {
const proposalDigest = await this.createProposal({
fcn: proposal.fcn,
certificate: keys.certificate,
args: proposal.args,
})
const proposalSignature = signDigest(keys.privateKey, proposalDigest.digest)
const txDigest = await this.createTransaction({
digest: proposalDigest.digest,
signature: proposalSignature,
})
const txSignature = signDigest(keys.privateKey, txDigest.digest)
return this.commitTransaction({
digest: txDigest.digest,
signature: txSignature,
})
}
/**
* Sends online transaction to the blockchain service.
*
* @param proposal Transaction proposal containing the bc function and arguments
* @param keys Private key and certificate for which the transaction should be invoked.
* @returns Response from the chaincode.
*/
async sendOnlineTransaction(
proposal: BlockchainFunctionParams,
keys: KeyPair
): Promise<any> {
const body = {
...proposal,
...keys,
args: [JSON.stringify(toSnakeCase(proposal.args))],
}
const res = await this.client.post(
`blockchain/${this.version}/transaction`,
body
)
return res.data.data
}
}