@0xcert/ethereum-value-ledger
Version:
Value ledger module for currency management on the Ethereum blockchain.
203 lines (180 loc) • 6.56 kB
text/typescript
import { GenericProvider, Mutation, MutationEventSignature, MutationEventTypeKind } from '@0xcert/ethereum-generic-provider';
import { bigNumberify } from '@0xcert/ethereum-utils';
import { ProviderError, ProviderIssue, ValueLedgerBase,
ValueLedgerDeployRecipe, ValueLedgerInfo, ValueLedgerTransferRecipe } from '@0xcert/scaffold';
import approveAccount from '../mutations/approve-account';
import deploy from '../mutations/deploy';
import transfer from '../mutations/transfer';
import transferFrom from '../mutations/transfer-from';
import getAllowance from '../queries/get-allowance';
import getBalance from '../queries/get-balance';
import getInfo from '../queries/get-info';
/**
* Ethereum value ledger implementation.
*/
export class ValueLedger implements ValueLedgerBase {
/**
* Value ledger Id. Address pointing at the smartcontract.
*/
protected _id: string;
/**
* Provider instance.
*/
protected _provider: GenericProvider;
/**
* Initialize value ledger.
* @param provider Provider class with which we communicate with blockchain.
* @param id Address of the erc20 smart contract.
*/
public constructor(provider: GenericProvider, id: string) {
this._provider = provider;
this._id = this._provider.encoder.normalizeAddress(id);
}
/**
* Deploys a new smart contract representing value ledger to the blockchain.
* @param provider Provider class with which we communicate with blockchain.
* @param recipe Data needed to deploy a new value ledger.
*/
public static async deploy(provider: GenericProvider, recipe: ValueLedgerDeployRecipe) {
return deploy(provider, recipe);
}
/**
* Gets an instance of already deployed value ledger.
* @param provider Provider class with which we communicate with blockchain.
* @param id Address of the erc20 smart contract.
*/
public static getInstance(provider: GenericProvider, id: string): ValueLedger {
return new this(provider, id);
}
/**
* Gets the address of the smart contract that represents this value ledger.
*/
public get id() {
return this._id;
}
/**
* Gets the provider that is used to communicate with blockchain.
*/
public get provider() {
return this._provider;
}
/**
* Gets the amount of value that another account id approved for.
* @param accountId Account id.
* @param spenderId Account id of the spender.
*/
public async getApprovedValue(accountId: string, spenderId: string): Promise<string> {
accountId = this._provider.encoder.normalizeAddress(accountId);
spenderId = this._provider.encoder.normalizeAddress(spenderId as string);
return getAllowance(this, accountId, spenderId);
}
/**
* Gets the amount of value a specific account owns.
* @param accountId Account id.
*/
public async getBalance(accountId: string): Promise<string> {
accountId = this._provider.encoder.normalizeAddress(accountId);
return getBalance(this, accountId);
}
/**
* Gets information(name, symbol, total supply, decimals) about the value ledger.
*/
public async getInfo(): Promise<ValueLedgerInfo> {
return getInfo(this);
}
/**
* Checks if spender is approved for the specific values.
* @param accountId Account id.
* @param spenderId Account id of spender.
* @param value Value amount we are checking against.
*/
public async isApprovedValue(value: string, accountId: string, spenderId: string): Promise<boolean> {
accountId = this._provider.encoder.normalizeAddress(accountId);
spenderId = this._provider.encoder.normalizeAddress(spenderId as string);
const approved = await getAllowance(this, accountId, spenderId);
return bigNumberify(approved).gte(bigNumberify(value));
}
/**
* Approves another account to operate with a specified amount of value.
* @param accountId Account id.
* @param value Value amount.
*/
public async approveValue(value: string, accountId: string): Promise<Mutation> {
accountId = this._provider.encoder.normalizeAddress(accountId as string);
const approvedValue = await this.getApprovedValue(this.provider.accountId, accountId);
if (!bigNumberify(value).isZero() && !bigNumberify(approvedValue).isZero()) {
throw new ProviderError(ProviderIssue.ERC20_APPROVAL_RACE_CONDITION);
}
return approveAccount(this, accountId, value);
}
/**
* Disapproves account for operating with your value.
* @param accountId Account id.
*/
public async disapproveValue(accountId: string): Promise<Mutation> {
accountId = this._provider.encoder.normalizeAddress(accountId as string);
return approveAccount(this, accountId, '0');
}
/**
* Transfer value to another account.
* @param recipe Data needed for the transfer.
*/
public async transferValue(recipe: ValueLedgerTransferRecipe): Promise<Mutation> {
const senderId = this._provider.encoder.normalizeAddress(recipe.senderId);
const receiverId = this._provider.encoder.normalizeAddress(recipe.receiverId);
return recipe.senderId
? transferFrom(this, senderId, receiverId, recipe.value)
: transfer(this, receiverId, recipe.value);
}
/**
* Gets context for mutation event parsing.
* This are event definitions for Value Ledger smart contract event parsing. This method is used
* by the Mutation class to provide log information.
*/
public getContext(): MutationEventSignature[] {
return [
{
name: 'Transfer',
topic: '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef',
types: [
{
kind: MutationEventTypeKind.INDEXED,
name: 'from',
type: 'address',
},
{
kind: MutationEventTypeKind.INDEXED,
name: 'to',
type: 'address',
},
{
kind: MutationEventTypeKind.NORMAL,
name: 'value',
type: 'uint256',
},
],
},
{
name: 'Approval',
topic: '0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925',
types: [
{
kind: MutationEventTypeKind.INDEXED,
name: 'owner',
type: 'address',
},
{
kind: MutationEventTypeKind.INDEXED,
name: 'spender',
type: 'address',
},
{
kind: MutationEventTypeKind.NORMAL,
name: 'value',
type: 'uint256',
},
],
},
];
}
}