You are on page 1of 102

Comprehensive Description of Aajtak Chain

SUHAS AGGARWAL
Main Strengths


Aajtak Chain is a multichain platform
interoperable with Ethereum, Bitcoin, Binance
Chain, Tron, and all major blockchains.

Deploy once to Aajtak Chain’s mainnet —
Basechain — and reach the largest user base
possible, so one can simply focus on Aajtak
development and business growth.

Enjoy having no gas fees for users, 5 second
confirmation times, and automatically get
connected to every major blockchain using any
kind of wallet.
Cool Features!!

Access the user base of multiple chains


1–3 second confirmation times


No gas fees for your users


Avoid mainnet transaction congestion


Fully compatible with MetaMask and other major Ethereum wallets
TRANSFER GATEWAY


The Transfer Gateway allows
tokens to be transferred between
Aajtak Chains and Ethereum
networks.

The Transfer Gateway consists
of four main components:

TRANSFER GATEWAY


The Transfer Gateway allows
tokens to be transferred between
AajtakChains and Ethereum
networks.

The Transfer Gateway consists
of four main components:


#Transferring a token from AajtakChain to
Ethereum

To get that same token back into their Ethereum
account the user must:

Transfer the token back to the AajtakChain
Gateway, which creates a pending withdrawal.

The pending withdrawal is picked up by the
Gateway Oracle, which signs the withdrawal,
and notifies the AajtakChain Gateway.

The AajtakChain Gateway emits an event to let
the user know they can withdraw their token
from the Mainnet Gateway to their Ethereum
account by providing the signed withdrawal
Role of oracle in transfer
gateway

Polls Ethereum
switch orc.gatewayType {

There are different gateways involved -


AajtakcoinGateway, Ethereum Gateway, Tron Gateway

For Aajtakcoin gateway -


Oracle fetches Aajtakcoin deposits and withdrawls from mainnet

For Ethereum gateway -


Oracle fetches Deposit and Withdrawl events for different currency types- ERC721,
ERC721X,ERC20, ETH Deposits from mainnet

For Tron gateway -


Oracle fetches TRC20 and TRX deposits and withdrawl events from mainnet.

case gwcontract.AajtakCoinGateway:

AajtakcoinDeposits, err = orc.fetchAajtakCoinDeposits(filterOpts)

if err != nil {

return nil, err

}

withdrawals, err = orc.fetchTokenWithdrawals(filterOpts)

if err != nil {

return nil, err

}


case
gwcontract.EthereumGate
way:

erc721Deposits, err =
orc.fetchERC721Deposits(filter
Opts)

if err != nil {


case gwcontract.TronGateway:

trxDeposits, err =
orc.fetchTRXDeposits(filterOpts)

if err != nil {

return nil, err

}

trc20Deposits, err =
orc.fetchTRC20Deposits(filterOpts)

if err != nil {

return nil, err

}
Batch Processing of events by
gateway contract

Event processing code does batch


processing of token deposits and
token withdrawls
func (gw *Gateway) ProcessEventBatch(ctx contract.Context, req
*ProcessEventBatchRequest) error {
switch payload := ev.Payload.(type) {
case *tgtypes.TransferGatewayMainnetEvent_Deposit:
// We need to pass ev here, as emitProcessEvent expects it.
if err := gw.handleDeposit(ctx, ev, checkTxHash); err != nil {
return err
}
case *tgtypes.TransferGatewayMainnetEvent_Withdrawal:
if !isTokenKindAllowed(gw.Type, payload.Withdrawal.TokenKind)
{
return ErrInvalidRequest
}

Polls Aajtakchain

1)Verify Contract Creators

2)Sign pending withdrawl receipts
Provision of claiming unclaimed contract tokens in
transfer gateway
func (gw *Gateway) GetUnclaimedContractTokens(
ctx contract.StaticContext, req *GetUnclaimedContractTokensRequest,
) (*GetUnclaimedContractTokensResponse, error) {
if req.TokenAddress == nil {
return nil, ErrInvalidRequest
}
ethTokenAddress := Aajtak.UnmarshalAddressPB(req.TokenAddress)
depositors, err := unclaimedTokenDepositorsByContract(ctx, ethTokenAddress)
if err != nil {
return nil, err
}
unclaimedAmount := Aajtak.NewBigUIntFromInt(0)
var unclaimedToken UnclaimedToken
amount := Aajtak.NewBigUIntFromInt(0)
for _, address := range depositors {
tokenKey := unclaimedTokenKey(address, ethTokenAddress)
err := ctx.Get(tokenKey, &unclaimedToken)
if err != nil && err != contract.ErrNotFound {
return nil, errors.Wrapf(err, "failed to load unclaimed token for %v", address)
}
switch unclaimedToken.TokenKind {
case TokenKind_ERC721:
unclaimedAmount = unclaimedAmount.Add(unclaimedAmount,
Aajtak.NewBigUIntFromInt(int64(len(unclaimedToken.Amounts))))
case TokenKind_ERC721X:
for _, a := range unclaimedToken.Amounts {
unclaimedAmount = unclaimedAmount.Add(unclaimedAmount,
Aajtak.NewBigUInt(a.TokenAmount.Value.Int))

}
case TokenKind_ERC20, TokenKind_ETH, TokenKind_AajtakCoin, TokenKind_BNBAajtakToken,
TokenKind_BEP2:
if len(unclaimedToken.Amounts) == 1 {
amount = Aajtak.NewBigUInt(unclaimedToken.Amounts[0].TokenAmount.Value.Int)
}
unclaimedAmount = unclaimedAmount.Add(unclaimedAmount, amount)

}
}
return &GetUnclaimedContractTokensResponse{
Workflow illustration of pending withdrawl receipt signing from multiple
Validators and simulation of token withdrawal from Ethereum Gateway to
clear out the pending withdrawal

calculatedHash :=
client.ToEthereumSignedMessage(gwHelper.Contract.calculateHashFromReceiptV2(Aajtak.RootAddress("eth").Mars
halPB(), withdrawalReceiptResp.Receipt))
aggregatedSignature := make([]byte, 0, 65*len(trustedValidatorDetails))
for _, validatorDetails := range trustedValidatorDetails {
sig, err := evmcompat.SoliditySign(calculatedHash, validatorDetails.EthPrivKey)
require.NoError(err)
aggregatedSignature = append(aggregatedSignature, sig...)
}

// Proper signature should work


err =
gwHelper.Contract.ConfirmWithdrawalReceiptV2(gwHelper.ContractCtx(fakeCtx.WithSender(ts.validatorsDetails[
2].AajtakAddress)), &ConfirmWithdrawalReceiptRequestV2{
TokenOwner: pendingWithdrawal.TokenOwner,
OracleSignature: aggregatedSignature,
MainnetGateway: Aajtak.RootAddress("eth").MarshalPB(),
})
require.NoError(err)

// Simulate token withdrawal from Ethereum Gateway to clear out the pending withdrawal
err = gwHelper.Contract.ProcessEventBatch(gwHelper.ContractCtx(fakeCtx),
&ProcessEventBatchRequest{
Events: []*MainnetEvent{
&MainnetEvent{
EthBlock: 5,
Payload: &MainnetWithdrawalEvent{
Withdrawal: &MainnetTokenWithdrawn{
TokenOwner: ts.ethAddr2.MarshalPB(),
TokenContract: etuhTokenAddr.MarshalPB(),
TokenKind: TokenKind_ERC721,
TokenID: &types.BigUInt{Value: *Aajtak.NewBigUInt(token1)},
},
},
},
},
. },
)
require.NoError(err)
Tron Integration


Aajtak’s PlasmaChain can be integrated with
TRON, which means TRON developers can
directly interact with all Aajtaks built on
PlasmaChain.
Binance Integration


Aajtak’s PlasmaChain can be integrated with
Binance Chain, users can easily deposit and
withdraw BNB between Binance Chain and
Aajtak.
Architecture
Smart contracts


It allows smart contracts written in Go, Solidity
or any language supporting GRPC.

Smart contracts can be embedded into the
chain, like DPoS, Coin or EthereumVM.

They can also be made as external processes,
that the blockchain communicates to via GRPC
Some of the important features of
Aajtakchain

Signing / Auth / Nonce Middleware

Built-in Coin

Indexing

Websockets and eventing

Solidity + Ethereum Virtual Machine

Transfer Gateway integration

Plasma integration

Rate limiting (early phases)
Some configurable parameters for
plasmachain


#RPCBindAddress

Options: "tcp://0.0.0.0:46658"

This is the primary interface for
binding RPC interface

#AajtakLogLevel

Options: debug, info, warn,

#config.toml

If you are using tendermint BFT engine, you can modify this file, otherwise leave it alone.

#ABCIAddress

Options: "http://127.0.0.1:45667"

Port for tendermint BFT engine

#ReceiptsVersion

Options: 1,2

Most users should set this to 1, and the EVM receipts will be stored in the application store. If the number is
set to 2, EVM receipts are stored in a seperate database. This is better for disk usage. However, it affects the
AppHashes, so the entire cluster must be initialized with the same version, and it must not be changed after
initialization.

#RegistryVersion

Options: 1,2

Most users should set this to 2. This is the latest version of the smart contract registry. The entire cluster
needs to be initialized with the same version, and it must not be changed after initialization.

#DPOSVersion

Options: 1,2,3
The entire cluster needs to be on same version, and it must not be changed after initialization.
#CreateEmptyBlocks
Boolean: true, false
Most clusters will want to disable empty blocks to save disk space.

#AppStore
AppStore:
CompactOnLoad: true
MaxVersions: 50
Configures how much history is retained in app.db. It should be enabled on production clusters, and dev clusters that don't get wiped often.
A new app.db version is created with each block, so without these settings nodes will consume significantly more disk space.

#CompactOnLoad
Will compact app.db when the node starts. This affects node start times, but ensures disk space that's taken up by old app.db versions
is freed.

#MaxVersions

Max versions stored in the app store. Each time a block is
committed a new version of the app state is stored in the
store.This doesn't affect how many blocks/transactions are
stored in the blockchain store.

#HSM

HsmConfig:

HsmEnabled: "true"

HsmDevType: "yubihsm"

HsmConnUrl: "localhost:12345"

HsmDevLogCred: "password"

HsmAuthKeyId: 1

HsmSignKeyId: 100

Please see HSM Page for more details

#Plasma


#Karma

The karma
module
provides a way

#Event Store

EventDispatcher:

# Available dispatcher: "db_indexer"
| "log" | "redis"

Dispatcher: "db_indexer"

# Redis will be use when Dispatcher
is "redis"

Redis:

URI:
"{{.EventDispatcher.Redis.URI}}"

Some sample JSON RPC endpoints
eth_accounts
Returns a list of addresses owned by the AajtakProvider

eth_blockNumber
Returns the number of the most recent completed block

eth_call
Executes a new message call immediately without creating a transaction on the blockchain.

eth_getBlockByNumber
Returns information about a block by block number.

eth_getBlockByHash
Returns information about a block by hash.

eth_getCode
Returns the code at a given address

eth_getFilterChanges
Polling method for a filter, which returns an array of logs which occurred since the last poll.

eth_getLogs

Returns an array of all logs matching a given filter object

eth_getTransactionReceipt

Returns the receipt of a transaction by transaction hash.

eth_newBlockFilter

Creates a filter, to notify when new pending transactions arrive

eth_newFilter

Creates a filter, to notify when new pending transactions arrive

eth_subscribe

It works by subscribing to particular events. The node will return a subscription id. For each event that matches the
subscription, a notification with relevant data is send together with the subscription id.

eth_uninstallFilter

Uninstalls a filter with the given id. It should always be called when watching is no longer needed

net_version

Returns the current network id.
Important go contracts and events
associated with it to indicate
workflow

Transfer gateway events

// Events

tokenWithdrawalSignedEventTopic =
"event:TokenWithdrawalSigned"

contractMappingConfirmedEventTopic =
"event:ContractMappingConfirmed"

withdrawETHTopic = "event:WithdrawETH"

withdrawAajtakCoinTopic = "event:WithdrawAajtakCoin"

withdrawTokenTopic = "event:WithdrawToken"

mainnetDepositEventTopic = "event:MainnetDepositEvent"

mainnetWithdrawalEventTopic =
"event:MainnetWithdrawalEvent"

mainnetProcessEventErrorTopic =
"event:MainnetProcessEventError"

reclaimErrorTopic = "event:ReclaimError"

withdrawETHErrorTopic = "event:WithdrawETHError"

withdrawAajtakCoinErrorTopic =
"event:WithdrawAajtakCoinError"

withdrawTokenErrorTopic = "event:WithdrawTokenError"

storeUnclaimedTokenTopic = "event:StoreUnclaimedToken"
Delegated proof of
stake go contract
events
ElectionEventTopic = "dposv3:election"
SlashEventTopic = "dposv3:slash"
JailEventTopic = "dposv3:jail"
UnjailEventTopic = "dposv3:unjail"
CandidateRegistersEventTopic = "dposv3:candidateregisters"
CandidateUnregistersEventTopic = "dposv3:candidateunregisters"
CandidateFeeChangeEventTopic = "dposv3:candidatefeechange"
UpdateCandidateInfoEventTopic = "dposv3:updatecandidateinfo"
DelegatorDelegatesEventTopic = "dposv3:delegatordelegates"
DelegatorRedelegatesEventTopic = "dposv3:delegatorredelegates"
DelegatorConsolidatesEventTopic = "dposv3:delegatorconsolidates"
DelegatorUnbondsEventTopic = "dposv3:delegatorunbonds"
ReferrerRegistersEventTopic = "dposv3:referrerregisters"
DelegatorClaimsRewardsEventTopic = "dposv3:delegatorclaimsrewards"
Aajtak Coin go based
smart contract
events

TransferEventTopic = "coin:transfer"

ApprovalEventTopic = "coin:approval"

Deployer whitelist + User deployer


whitelist smart contract events
Purpose of these go contracts is to whitelist keys to deploy evm
based contracts.
AddUserDeployer should be called by a third-party dev to authorize an
account to deploy EVM contracts on their behalf. In order to authorize an
account the caller must approve the contract to withdraw
the fee for whitelisting (charged in Aajtak coin) before calling this method, the
fee will be deducted from the caller if the requested account is successfuly
authorized.
Address mapper go smart
contract description

AddIdentityMapping adds a mapping between a AajtakChain
account and a Mainnet account.

The caller must provide proof of ownership of the Mainnet
account.

Chainconfig go based smart contract


description
FeatureEnablement – use to enable a specific feature in
Aajtakchain which means that it has been enabled by a
sufficient number of validators and has been activated.
Different stores
being used

Blockstore

type BlockStore interface {

// GetBlockByHeight retrieves block info at the specified
height,

// specify nil to retrieve the latest block info.

GetBlockByHeight(height *int64) (*ctypes.ResultBlock,
error)

// GetBlockRangeByHeight retrieves block info at the
specified height range,

// specify nil to retrieve the latest block info.

GetBlockRangeByHeight(minHeight, maxHeight int64)
(*ctypes.ResultBlockchainInfo, error)

// GetBlockResults retrieves the results of the txs
committed to the block at the specified height,

// specify nil to retrieve results from the latest block.

GetBlockResults(height *int64) (*ctypes.ResultBlockResults,
error)

// Get Transaction Results from Tendermint Tx Hash

GetTxResult(txHash []byte) (*ctypes.ResultTx, error)
}
Cache Wrapping and Advantages


Cache is wrapped on top of these blockstore
APIs. LRU and 2Q cache is used for the same.

Purpose is to reduce leveldb based disk seeks
and fetch block information from cache itself.

These APIs are extensively used in RPC calls
and reduce latencies of APIs.
Versioned Caching
Store
// KeyVersionTable keeps versions of a cached key
type KeyVersionTable map[int64]bool

type versionedBigCache struct {


cache *bigcache.BigCache
cacheLogger *Aajtak.Logger
keyTableMutex sync.RWMutex
keyTable map[string]KeyVersionTable
}
// versionedCachingStore wraps a write-through cache around a
VersionedKVStore.
// It is compatible with MultiWriterAppStore only.
type versionedCachingStore struct {
VersionedKVStore
cache *versionedBigCache
version int64
logger *Aajtak.Logger
}
Pruning IAVL store
PruningIAVLStore is a specialized IAVLStore that has a background
thread that periodically prunes old versions. It should only be
used to prune old clusters, on new clusters nodes will delete a
version each time they save a new one, so the background thread,
and all the extra locking is unnecessary.

type PruningIAVLStore struct {


store *IAVLStore
mutex *sync.RWMutex
oldestVer int64
maxVersions int64
batchSize int64
batchCount uint64
logger *Aajtak.Logger
}

NewPruningIAVLStore creates a new PruningIAVLStore.maxVersions can


be used to specify how many versions should be retained, if set to
zero then old versions will never been deleted.
RunWithRecovery should run in a goroutine, it will ensure the
given function keeps on running in a goroutine as long as it
doesn't panic due to a runtime error.

func (s *PruningIAVLStore) runWithRecovery(run func()) {


defer func() {
if r := recover(); r != nil {
s.logger.Error("Recovered from panic in PruningIAVLStore
goroutine", "r", r)
// Unless it's a runtime error restart the goroutine
if _, ok := r.(runtime.Error); !ok {
time.Sleep(30 * time.Second)
s.logger.Info("Restarting PruningIAVLStore
goroutine...\n")
go s.runWithRecovery(run)
}
}
}()
run()
}
EVM Store
EvmStore persists EVM state to a DB.

type EvmStore struct {


evmDB db.DBWrapper
cache map[string]cacheItem
rootHash []byte
lastSavedRoot []byte
rootCache *lru.Cache
version int64
}
MultiWriter AppStore
MultiWriterAppStore reads & writes keys that have the "vm" prefix
via both the IAVLStore and the EvmStore,or just the EvmStore,
depending on the evmStoreEnabled flag.

type MultiWriterAppStore struct {


appStore *IAVLStore
evmStore *EvmStore
lastSavedTree unsafe.Pointer
// *iavl.ImmutableTree
onlySaveEvmStateToEvmStore bool
}

Event Store

type EventStore interface {

// SaveEvent save a single event

// contractID, blockHeight, and eventIndex are required for
making a unique keys

SaveEvent(contractID uint64, blockHeight uint64, eventIndex
uint16, eventData *types.EventData) error

// BatchSaveEvents save series of events

BatchSaveEvents(events []*types.EventData) error

// FilterEvents filters events that match the given filter

FilterEvents(filter EventFilter) ([]*types.EventData,
error)

// ContractID mapping

GetContractID(pluginName string) uint64
}
The contract state


Each contract has access to a sandboxed state
for storage of data. The write actions on the
state are rolled back in case the contract
operation returns an error. If a transaction is
successfully committed, it contains the hash of
the state root so that any given state is
committed to the blockchain.

#Writing to the state

Use the Set operation on the contract context to
save to the state.
Contract Registry
// Registry stores contract meta data.

type Registry interface {


// Register stores the given contract meta data
Register(contractName string, contractAddr, ownerAddr
Aajtak.Address) error
// Resolve looks up the address of the contract matching the
given name
Resolve(contractName string) (Aajtak.Address, error)
// GetRecord looks up the meta data previously stored for the
given contract
GetRecord(contractAddr Aajtak.Address) (*Record, error)
}
Sample Protocol buffers used for messages -
Transfer gateway go smart contract

syntax = "proto3";

import "github.com/gogo/protobuf/gogoproto/gogo.proto";
import "github.com/Aajtaknetwork/go-Aajtak/types/types.proto";

enum TransferGatewayTokenKind {
ETH = 0;
ERC20 = 1;
ERC721 = 2;
ERC721X = 3;
AajtakCOIN = 4;
TRX = 5;
TRC20 = 6;
BNBAajtakToken = 7;
BEP2 = 8;
}

enum TransferGatewayTxStatus {
PENDING = 0;
PROCESSED = 1;
CONFIRMED = 2;
Aajtak Coin go smart
contract
syntax = "proto3";

import "github.com/Aajtaknetwork/go-Aajtak/types/types.proto";

message Economy {
BigUInt total_supply = 1;
}

message Account {
Address owner = 1;
BigUInt balance = 2;
}

message Allowance {
Address owner = 1;
Address spender = 2;
BigUInt amount = 3;
}

message InitialAccount {
Address owner = 1;
Delegated proof of stake
consensus go contract

syntax = "proto3";

package dposv3;

import "github.com/Aajtaknetwork/go-Aajtak/types/types.proto";

message Params {
uint64 validator_count = 1;
int64 election_cycle_length = 2;
Address coin_contract_address = 3;
Address oracle_address = 4;
BigUInt max_yearly_reward = 5;
BigUInt registration_requirement = 6;
BigUInt crash_slashing_percentage = 7;
BigUInt byzantine_slashing_percentage = 8;
uint64 min_candidate_fee = 9;
uint64 downtime_period = 10;
BigUInt max_downtime_percentage = 11;
bool jail_offline_validators = 12;
}
Plasma cash go smart
contract
syntax = "proto3";

import "github.com/gogo/protobuf/gogoproto/gogo.proto";
import "github.com/Aajtaknetwork/go-Aajtak/types/types.proto";

enum PlasmaCashCoinState {
DEPOSITED = 0;
EXITING = 1;
CHALLENGED = 2;
EXITED = 3;
}

// Plasma Cash coin holds a single ERC721 token


message PlasmaCashCoin {
// Unique ID
uint64 slot = 1 [jstype = JS_STRING];
PlasmaCashCoinState state = 2;
// ERC721 token ID
BigUInt token = 3;
// ERC721 token contract address
Address contract = 4;
Event Handling in
Aajtakchain

Emitting events

Events emitted from smart contracts and go
plugins. These events can be subscribed to in
two ways- via Redis or via web sockets.


#Event structure

The event JSON shown above is wrapped in
some transaction specific metadata before
being emitted to the event stream. The other
fields in the metadata include Called address,
the contract address, the contract name, and
Sample Event Data


{

"caller": {

"ChainID": "default",

"Local":
"2DiOmpX+kSRZK0jxEgxdGuPC0eo="

},

"address": {

"ChainID": "default",

"Local":
"4ojW7scVDWoi/eM/CqLYHgZZHE0="

},


Subscribing via Redis

By default, the Aajtak-sdk will only emit events
to the log. To configure it to send it to a Redis
sorted set, add the following line to the
Aajtak.yaml config file:

EventDispatcherURI: "redis://localhost:6379"

This will start emitting events to the Redis
server in a sorted set called Aajtakevents. Each
event is added to the sorted set with the score
being the blockchain height.

Subscribing via web sockets

The Aajtak SDK query endpoint can be used to
subscribe to the event stream as well. Here is a
sample subscription code using a command line and
the wscat nodejs cli.

$ cat command.json

{

"method": "subevents",

"jsonrpc": "2.0",

"params": [],

"id": "dontcare"

}

$ wscat -k ws://localhost:46658/queryws <
command.json

{
Virtual Machine
Implementation

type VM interface {
Create(caller Aajtak.Address, code []byte, value
*Aajtak.BigUInt) ([]byte, Aajtak.Address, error)
Call(caller, addr Aajtak.Address, input []byte, value
*Aajtak.BigUInt) ([]byte, error)
StaticCall(caller, addr Aajtak.Address, input []byte) ([]byte,
error)
GetCode(addr Aajtak.Address) ([]byte, error)
}
Aajtak virtual
machine description

Overview

Aajtak SideChains contain an Ethereum virtual
machine (EVM) and allow you to deploy and
run smart contracts that compile to EVM
bytecode.


#Ethereum virtual machine

An EVM consists of a database and the
interpreter for EVM bytecode.


The interpreter runs EVM bytecode and is

AajtakChains and EVM

There are currently several ways to interact with
the AajtakChain's EVM:


A smart contact can be deployed on the initial
startup of the blockchain.

The Aajtak command line tool allows deploying
a smart contract or calling a method on an
already deployed contract.

Another smart contract, either an EVM contract
or a plugin contract, can call methods on an
already deployed EVM contract.

In Go, you can use go-Aajtak's EvmContract

The Aajtak command line tool has three
commands for interacting with the chain's EVM

deploy This will deploy a smart contract in EVM
bytecode onto the chain's EVM.

call This will call a method that can mutate the
state on an already deployed EVM smart
contract.

static-call This will call a read-only method on
an already deployed EVM smart contract.

Smart contracts deployed on a AajtakChain's
EVM can be called from user created plugins.
The evm example in go-Aajtak shows how to
achieve this.

User application. This is the end user
application that initiates transactions on the
AajtakChain.

AajtakChain. Receives transactions from the
user application and forwards to the appropriate
contract to run. Also commits results to the
blockchain.
Transaction receipts


Transaction receipt

Details of each EVM call transaction are stored
on the Aajtakchain and can be accessed using
the transaction hash.

The Aajtak chain QueryService has the method
TxReceipt(txHash []byte) ([]byte, error) which
returns the receipt in a protobuf form. go-Aajtak
and Aajtak-js provide an API for this query.

go-Aajtak:func (c *AajtakChainRPCClient)
GetEvmTxReceipt(txHash []byte)
Prometheus metrics collection
Examples
var (
deliverTxLatency metrics.Histogram
checkTxLatency metrics.Histogram
commitBlockLatency metrics.Histogram
requestCount metrics.Counter
committedBlockCount metrics.Counter
validatorFuncLatency metrics.Histogram
)

func init() {
fieldKeys := []string{"method", "error"}
requestCount =
kitprometheus.NewCounterFrom(stdprometheus.CounterOpts{
Namespace: "Aajtakchain",
Subsystem: "application",
Name: "request_count",
Help: "Number of requests received.",
}, fieldKeys)
deliverTxLatency =
kitprometheus.NewSummaryFrom(stdprometheus.SummaryOpts{
Namespace: "Aajtakchain",
commitBlockLatency =
kitprometheus.NewSummaryFrom(stdprometheus.SummaryOpts{
Namespace: "Aajtakchain",
Subsystem: "application",
Name: "commit_block_latency_microseconds",
Help: "Total duration of commit block in
microseconds.",
Objectives: map[float64]float64{0.5: 0.05, 0.9: 0.01, 0.99:
0.001},
}, fieldKeys)

committedBlockCount =
kitprometheus.NewCounterFrom(stdprometheus.CounterOpts{
Namespace: "Aajtakchain",
Subsystem: "application",
Name: "block_count",
Help: "Number of committed blocks.",
}, fieldKeys)

validatorFuncLatency =
kitprometheus.NewSummaryFrom(stdprometheus.SummaryOpts{
Tx handlers


Three types of transaction

Deploy Tx

Call Tx

Migration Tx
deployTxHandler := &vm.DeployTxHandler{
Manager: vmManager,
CreateRegistry: createRegistry,
AllowNamedEVMContracts: cfg.AllowNamedEvmContracts,
}

callTxHandler := &vm.CallTxHandler{
Manager: vmManager,
}

migrationTxHandler := &tx_handler.MigrationTxHandler{
Manager: vmManager,
CreateRegistry: createRegistry,
Migrations: map[int32]tx_handler.MigrationFunc{
1: migrations.DPOSv3Migration,
},
}
var msg vm.MessageTx
err := proto.Unmarshal(txBytes, &msg)
if err != nil {
return false
}

switch txID {
case 1:
var tx vm.DeployTx
err = proto.Unmarshal(msg.Data, &tx)
if err != nil {

return false
}
return tx.VmType == vm.VMType_EVM
case 2:
var tx vm.CallTx
err = proto.Unmarshal(msg.Data, &tx)
if err != nil {

return false
Commit Tx - Broadcast
transaction asynchronously to
tendermint
CommitTx2 signs a tx with the given signer and sends it to the
chain, the from address is used to
query the chain for a tx nonce (this address may have a different
chain ID to the client).
func (c *AajtakChainRPCClient) CommitTx2(from Aajtak.Address,
signer auth.Signer, tx proto.Message) ([]byte, error) {
nonce, err := c.GetNonce2(from, signer)
if err != nil {
return nil, err
}
txBytes, err := proto.Marshal(tx)
if err != nil {
return nil, err
}
nonceTxBytes, err := proto.Marshal(&auth.NonceTx{
Inner: txBytes,
Sequence: nonce + 1,
})
if err != nil {
return nil, err
}
tx -Returns a transaction matching the
given transaction hash.

func (c *AajtakChainRPCClient) pollTx(hash string, shortPollLimit


int, shortPollDelay time.Duration) (*TxHandlerResult, error) {
var result TxQueryResult
var err error

decodedHash, err := hex.DecodeString(hash)


if err != nil {
return nil, errors.Wrapf(err, "error while polling for tx")
}
params := map[string]interface{}{
"hash": decodedHash,
}

for i := 0; i < shortPollLimit; i++ {


// Delaying in beginning of the loop, as immediate poll
will likely result in "not found"
time.Sleep(shortPollDelay)

if err = c.txClient.Call("tx", params,


c.getNextRequestID(), &result); err != nil {
if !strings.Contains(err.Error(), "not found") {
Tendermint Storage


Tendermint keeps multiple distinct databases in
the $TMROOT/data:

blockstore.db: Keeps the entire blockchain -
stores blocks, block commits, and block meta
data, each indexed by height. Used to sync new
peers.

evidence.db: Stores all verified evidence of
misbehaviour.

state.db: Stores the current blockchain state (ie.
height, validators, consensus params). Only
grows if consensus params or validators
Tx throttling
Sample Configuration

ContractTxLimiter:
Enabled: true
ContractDataRefreshInterval: 1
TierDataRefreshInterval: 10

TxLimiter:
SessionDuration: 10
MaxTxsPerSession: 2
type contractTxLimiter struct {
// contract_address to limiting parametres structure
contractToTierMap map[string]udw.TierID
inactiveDeployerContracts map[string]bool
contractDataLastUpdated int64
// track of no. of txns in previous blocks per contract
contractStatsMap map[string]*contractStats
tierMap map[udw.TierID]udw.Tier
tierDataLastUpdated int64
}

type contractStats struct {


txn int64
blockHeight int64
}
func (txl *contractTxLimiter) isAccountLimitReached(contractAddr Aajtak.Address, curBlockHeight int64)
bool {
blockTx, ok := txl.contractStatsMap[contractAddr.String()]
if !ok {
return false
}
// if execution reaches here => tierID and tier are valid
tierID := txl.contractToTierMap[contractAddr.String()]
tier := txl.tierMap[tierID]
if blockTx.blockHeight <= (curBlockHeight-int64(tier.BlockRange)) || int64(tier.MaxTxs) > blockTx.txn {
return false
}
return true
}

Caps the number of transactions for a contract in a particular blockrange.


Fixed block window is used for rate limiting i.e 1-5, 6-10, 11-15, 16-20

Rolling Block Window Algorithm can also be used for rate limiting.
In this algorithm, the block window is considered from the blockheight at which the request is made plus the
block window length.
Aajtak Coin go contract
CLI
[[TestCases]]
Dir = ""
RunCmd = "{{ $.AajtakPath }} coin balance {{index $.AccountAddressList 0}}"
Condition = "contains"
Expected = ["100000000000000000000"]

[[TestCases]]
Dir = ""
RunCmd = "{{ $.AajtakPath }} coin balance {{index $.AccountAddressList 1}}"
Condition = "contains"
Expected = ["100000000000000000000"]

[[TestCases]]
Dir = ""
RunCmd = "{{ $.AajtakPath }} coin balance {{index $.AccountAddressList 2}}"
Condition = "contains"
Expected = ["100000000000000000000"]

[[TestCases]]
Dir = ""
RunCmd = "{{ $.AajtakPath }} coin transfer {{index $.AccountAddressList 1}} 20000000 -k {{index
$.AccountPrivKeyPathList 2}}"
Condition = ""

[[TestCases]]
Dir = ""
RunCmd = "{{ $.AajtakPath }} coin balance {{index $.AccountAddressList 1}}"
Condition = "contains"
Expected = ["120000000000000000000"]

[[TestCases]]
Dir = ""
RunCmd = "{{ $.AajtakPath }} coin balance {{index $.AccountAddressList 2}}"
Condition = "contains"
DPOS Go contract CLI
[[TestCases]]
RunCmd = "check_validators"
Condition = "contains"
Expected = ["{{index $.NodePubKeyList 2}}"]

[[TestCases]]
RunCmd = "{{ $.AajtakPath }} dpos3 list-validators"
Condition = "excludes"
Excluded = ["Error"]

[[TestCases]]
RunCmd = "{{ $.AajtakPath }} coin approve dposV3 1250000 -k {{index $.NodePrivKeyPathList 1}}"
Condition = ""

# Note: Node1 registers with a 10% maximum referral fee


[[TestCases]]
RunCmd = "{{ $.AajtakPath }} dpos3 register-candidate {{index $.NodePubKeyList 1}} 100 0 1000 --
name numero-uno --website one.com --description the-number-one-validator-in-the-world -k {{index
$.NodePrivKeyPathList 1}}"
Condition = "excludes"
Excluded = ["Error"]

[[TestCases]]
RunCmd = "{{ $.AajtakPath }} coin approve dposV3 1250000 -k {{index $.NodePrivKeyPathList 2}}"
Condition = "excludes"
Excluded = ["Error"]

[[TestCases]]
RunCmd = "{{ $.AajtakPath }} dpos3 register-candidate {{index $.NodePubKeyList 2}} 50 0 600 --name
numero-dos -k {{index $.NodePrivKeyPathList 2}}"
[[TestCases]]
RunCmd = "{{ $.AajtakPath }} dpos3 change-fee 100 -k {{index $.NodePrivKeyPathList 2}}"
Condition = "excludes"
Excluded = ["Error"]

[[TestCases]]
RunCmd = "{{ $.AajtakPath }} dpos3 set-min-candidate-fee 900 -k {{index $.NodePrivKeyPathList
0}}"
Condition = "excludes"
Excluded = ["Error"]

[[TestCases]]
RunCmd = "{{ $.AajtakPath }} dpos3 change-fee 200 -k {{index $.NodePrivKeyPathList 2}}"
Condition = "contains"
Expected = ["Error"]

[[TestCases]]
RunCmd = "{{ $.AajtakPath }} dpos3 list-candidates"
Condition = "contains"
Expected = ["{{index $.NodePubKeyList 1}}", "{{index $.NodePubKeyList 2}}", "1000", "600"]

[[TestCases]]
RunCmd = "{{ $.AajtakPath }} coin approve dposV3 10 -k {{index $.NodePrivKeyPathList 1}}"
Condition = "excludes"
Excluded = ["Error"]

[[TestCases]]
RunCmd = "{{ $.AajtakPath }} coin approve dposV3 20 -k {{index $.NodePrivKeyPathList 2}}"
Condition = "excludes"
Excluded = ["Error"]

[[TestCases]]
RunCmd = "{{ $.AajtakPath }} dpos3 delegate {{index $.NodeAddressList 1}} 20 -k {{index
$.NodePrivKeyPathList 2}}"
Condition = "excludes"
Excluded = ["Error"]
User deployer whitelist go contract
CLI
[[TestCases]]
Dir = ""
RunCmd = "{{ $.AajtakPath }} coin balance {{index $.AccountAddressList 0}}"
Condition = "contains"
Expected = ["100000000000000000000"]

[[TestCases]]
RunCmd = "{{ $.AajtakPath }} coin approve user-deployer-whitelist 10000 -k {{index
$.AccountPrivKeyPathList 0}}"
Condition = "excludes"
Excluded = ['Error']

[[TestCases]]
RunCmd = "{{ $.AajtakPath }} dev add-deployer --tier 0 {{index $.AccountAddressList 1}} -k {{index
$.AccountPrivKeyPathList 0}}"
Condition = "excludes"
Excluded = ['Error']

[[TestCases]]
RunCmd = "{{ $.AajtakPath }} dev add-deployer --tier 0 {{index $.AccountAddressList 1}} -k {{index
$.AccountPrivKeyPathList 0}}"
Condition = "contains"
Expected = ['deployer already exists']

[[TestCases]]
RunCmd = "{{ $.AajtakPath }} dev add-deployer --tier 1 {{index $.AccountAddressList 2}} -k {{index
$.AccountPrivKeyPathList 0}}"
Condition = "excludes"
Excluded = ['Error']

[[TestCases]]
contracts CLI made using cobra command

Sample go contract CLI command code

github.com/spf13/cobra

const DPOSV3ContractName = "dposV3"

var (
candidateName string
candidateDescription string
candidateWebsite string
)

const unregisterCandidateCmdExample = dpos3 unregister-candidate --key path/to/private_key

func UnregisterCandidateCmdV3() *cobra.Command {


var flags cli.ContractCallFlags
cmd := &cobra.Command{
Use: "unregister-candidate",
Short: "Unregisters the candidate (only called if previously registered)",
Example: unregisterCandidateCmdExample,
RunE: func(cmd *cobra.Command, args []string) error {
return cli.CallContractWithFlags(
&flags, DPOSV3ContractName, "UnregisterCandidate",
&dposv3.UnregisterCandidateRequest{}, nil,
)
},
}
cli.AddContractCallFlags(cmd.Flags(), &flags)
return cmd
}
Load Testing - Blockchain

Sample Load Testing commands


# generate 10 keys
./bin/solidity-loadtest genkey -k 10

# Test deploying using 10 concurrent keys, each key set 10 accounts, all done in 200 iterations.

# This will use a default SimpleStore contract.


./bin/solidity-loadtest deploy -k 10 -m 10 -i 200

# You can use the -n or ContractName argumet to name the deployed contract.

# The -f argument allows you to use the compiled bytecode from a file.

# You can also use the -b argument to enter the bytecode on the command line.
./bin/solidity-loadtest deploy -k 10 -m 10 -i 200 -n "TestSimpleStore-Pass27" -f
Path/To/BinFile.bin

# deploy a single solidity contract on which the set and go test can be use
./bin/solidity-loadtest deployOnce

# set values using 10 concurrent keys, each key set 10 accounts, all done in 200 iterations.
./bin/solidity-loadtest set -k 10 -m 10 -i 200

# get values using 10 concurrent keys, each key get 10 accounts, all done in 10000 iterations

# Use -p to enter the ABI encoded input paramters, otherwise it uses a default SimpleStore get.
./bin/solidity-loadtest get -k 10 -m 100 -i 10000 -p 6d4ce63c

# run-all runs all the commands using 1000 keys for 60 seconds
To run load test, pass the following as environment variables. If not specified,
default will be used

NUM_KEYS defaults to 10
NUM_ACCOUNTS defaults to 10
ITERATIONS_CREATE defaults to 100
ITERATIONS_SET defaults to NUM_KEYS * NUM_ACCOUNTS * 4
ITERATIONS_GET defaults to NUM_KEYS * NUM_ACCOUNTS * 100
ITERATIONS_WS defaults to NUM_KEYS * NUM_ACCOUNTS * 1000
READ_PORT defaults to 46658
WRITE_PORT defaults to 46658
INFLUXDB_HOST defaults to 10.40.22.5
INFLUXDB_PORT defaults to 8086
Configuration for Load test

Readers_NUM: 100, //Number of readers for read rate control


Writers_NUM: 1, //Number of writers for write rate control
Listeners_NUM: 5, // Number of listeners denote Number of events subscribed for
ChainID: 'default',
WSURI: 'ws://test-z-us1.aajtakchains.com/websocket',
QueryWSURI: 'ws://test-z-us1.aajtakchains.com/queryws',
NumberofWebSockets: 20, //Number of WebSockets
Transaction_Period: 1, //Period of sending a tx to the contract
ConcurrencyLimit: 20, //Concurrency Limit for Limited Parallel Execution
ClientDelay: 1, //Delay with which websockets are initiated before concurrency limit
ClientDeltaDelay: 0, //Incremental Delay with which websockets are initiated after concurrency limit
Iterations: 100, //Number of Repeats per client for read write simulation
WriterWeight: 0.0, //Determine whether client is write only
ReaderWeight: 0.0, //Determine whether client is read only
ListenerWeight: 0.0, //Determine whether clients is listener only
WRWeight: 1.0, //Determine whether client both reads writes
LWWeight: 0.0, //Determine whether client is both writer and listener
LRWeight: 0.0, //Determine whether client is both listener and reader
LWRWeight: 0.0 //Determine whether client is reader,writer and listener

Create N WebSocket clients. Client can be reader,writer,listener or any permutation shown in configuration. Each client can
perform N write transactions on the SimpleStore contract every 'Y' seconds. Each client can perform X reads and can subscribe
to Z events. Number of iterations for load test simulation per client can be specified by Iterations parameter.
Enable CPU Profiling during Load Tests
Usage
# start cpu profiler on local node (must have unsafe set to true in config.toml)

# profileName is the name of the cpu profile file that will be written to the node working dir

yarn start-profiler local-node profileName

# start cpu profiler on test-z-us1

yarn start-profiler test-z-us1 profileName

# start test run

yarn test

# stop cpu profiler on local node

yarn stop-profiler local-node

# stop cpu profiler on test-z-us1

yarn stop-profiler test-z-us1

Command to start Default cpu profiling of Aajtak chain by node js by using rpc endpoint -

unsafe_start_cpu_profiler?filename=_
Cluster Maintenance
Tools
Maintenance tools for AajtakChain clusters

Description
Shrink app.db (by cloning latest IAVL store version to a new DB)

Each Aajtakchain node has an app.db, which is a LevelDB database that stores the persistent
app state. Every time a new block is executed by a node the resulting state changes are
persisted to app.db, previous state is pretty much never removed so app.db growth is
unbounded. The app-store clone command provides a way to clone the latest persisted app state
to a new app.db, while ignoring all the historical app state. Since historical app state is not copied
to the app.db clone it's impossible to rollbackthe clone to a previous state.

This cloning method is still experimental, and must not be used on PlasmaChain validator or
backup nodes.

Ensure that the node the app.db is being cloned from is not running, then execute the following
command:

clusterkit app-store clone <path/to/src/app.db> <path/to/dest/app.db> --log 1 --saves-per-commit 10000


path/to/dest/app.db can then be swapped in instead of path/to/src/app.db on the source node, or
used to spin up another node.
Prune blockstore.db

Tendermint stores block data in blockstore.db, this contains data for each block since genesis
and since Tendermint never deletes old data the growth of this DB is unbounded. The block data
is necessary to replay the chain from genesis, but at a certain point it becomes impractical to do
so due to the time requirements. It's also not necessary to have every node in the cluster with the
full blockstore.db as long as a jump-start archive is provided for spinning up new nodes. A full
backup of blockstore.db should be maintained, either offline or on archival nodes (which should
be non-validators with the sole purpose of storing blocks).

To remove old blocks from the blockstore.db first stop the node, then execute the following
command:
Extract EVM state from app.db to a new DB
The app-store extract-evm-state command will copy all the vm-prefixed keys from the IAVL store persisted to app.db to a new LevelDB.
clusterkit app-store extract-evm-state <path/to/src/app.db> <path/to/dest/evm.db> --log 1 --batch-size 10000

Index the block store by block hash


Tendermint doesn't index blocks by hash, only by height, this makes it difficult to look up blocks by hash in a reasonable amount of
time. Aajtakchain can use a block_index.db to speedup lookups by block hash, to bootstrap this DB on an existing node use the following
command.
clusterkit block-store index-by-hash <path/to/src/chaindata> <path/to/dest/db> --log 1 --batch-size 10000
Aajtak Website
Crypto kitty Solidity
Contract
contract KittyInterface {
function getKitty(uint256 ) external pure returns (
bool isGestating,
bool isReady,
uint256 cooldownIndex,
uint256 nextActionAt,
uint256 siringWithId,
uint256 generationTime,
uint256 matronId,
uint256 sireId,
uint256 generation,
uint256 genes
){
return (true, true,
3,4,5,6,7,8,9,7688748911342991);
}
}
contract ZombieFactory is Ownable {

using SafeMath for uint256;

event NewZombie(uint zombieId, string name, uint dna);

uint dnaDigits = 16;


uint dnaModulus = 10 ** dnaDigits;
uint cooldownTime = 0 days;

struct Zombie {
string name;
uint dna;
uint32 level;
uint32 readyTime;
uint16 winCount;
uint16 lossCount;
}

Zombie[] public zombies;

mapping (uint => address) public zombieToOwner;


mapping (address => uint) ownerZombieCount;

//Zombie creation
function _createZombie(string _name, uint _dna) internal {
uint id = zombies.push(Zombie(_name, _dna, 1, uint32(now + cooldownTime), 0, 0)) -
1;
zombieToOwner[id] = msg.sender;
ownerZombieCount[msg.sender]++;
NewZombie(id, _name, _dna);
}
function _generateRandomDna(string _str) private view returns (uint) {
uint rand = uint(keccak256(_str));
return rand % dnaModulus;
}

function createRandomZombie(string _name) public {


require(ownerZombieCount[msg.sender] == 0);
uint randDna = _generateRandomDna(_name);
randDna = randDna - randDna % 100;
_createZombie(_name, randDna);
}

}
contract ZombieFeeding is ZombieFactory {

KittyInterface kittyContract;

modifier onlyOwnerOf(uint _zombieId) {


require(msg.sender == zombieToOwner[_zombieId]);
_;
}

function setKittyContractAddress(address _address) external onlyOwner {


kittyContract = KittyInterface(_address);
}

function _triggerCooldown(Zombie storage _zombie) internal {


_zombie.readyTime = uint32(now + cooldownTime);
}

function _isReady(Zombie storage _zombie) internal view returns (bool) {


return (_zombie.readyTime <= now);
}
//Zombie feed and multiply
function feedAndMultiply(uint _zombieId, uint _targetDna, string _species) internal onlyOwnerOf(_zombieId) {
Zombie storage myZombie = zombies[_zombieId];
require(_isReady(myZombie));
_targetDna = _targetDna % dnaModulus;
uint newDna = (myZombie.dna + _targetDna) / 2;
if (keccak256(_species) == keccak256("kitty")) {
newDna = newDna - newDna % 100 + 99;
}
_createZombie("NoName", newDna);
_triggerCooldown(myZombie);
}
function feedOnKitty(uint _zombieId, uint _kittyId) public {
uint kittyDna;
(,,,,,,,,,kittyDna) = kittyContract.getKitty(_kittyId);
feedAndMultiply(_zombieId, kittyDna, "kitty");
Zombie Replication (User points
system)

Feed and multiply are determined by users
engagement time in different domains

1)Comments

2)IAB Segments Engagement

3)Topic Engagement

4)Emotion Persona

5)Impression/Click Activity

6)Geography

7)Device Type

Based on Frequency and time decay of above
parameters and engagement time threshold,
zombie growth and zombie feed is determined.
Block Explorer

This Block Explorer helps you to check the block data on your AajtakChain.
BlockScout
Fork for Aajtakchains, it has additional compatiblity with Plasmachain and other Aajtak SDK based
chains.

BlockScout provides a comprehensive, easy-to-use interface for users to view, confirm, and inspect
transactions on all EVM (Ethereum Virtual Machine) blockchains. This includes the Ethereum main
and test networks as well as Ethereum forks and sidechains. This version is customized for
Aajtakchain

Following is an overview of the project and instructions for getting started.

Features
Open source development: The code is community driven and available for anyone to use, explore
and improve.

Real time transaction tracking: Transactions are updated in real time - no page refresh required.
Infinite scrolling is also enabled.

Smart contract interaction: Users can read and verify Solidity smart contracts and access pre-
existing contracts to fast-track development. Support for Vyper, LLL, and Web Assembly contracts
is in progress.

Token support: ERC20 and ERC721 tokens are supported. Future releases will support additional
token types including ERC223 and ERC1155.

User customization: Users can easily deploy on a network and customize the Bootstrap interface.

Ethereum sidechain networks: BlockScout supports the Ethereum mainnet, Ethereum testnets,
Plasma cash briefing
Plasma is a design pattern that allows for off-chain messages to dictate the transfer of on-chain assets. It scales the root chain by offloading
transaction throughput to Plasma chains. You can think of it as a professor who needs to grade many exams in a short period of time. The
professor can delegate this work to the teaching assistants, who look through every question on the exam and tally up points, but report only a
grade back to the professor.
Each Plasma chain condenses messages about transaction ordering into a single hash stored on the root chain. Bitcoin and Ethereum are
examples of root chains — blockchains that have stronger security and decentralization guarantees (safety and liveness). In this post, we will use
Ethereum as the root chain throughout all of our examples.
1)Wannabe operator deploys Plasma contract to the
mainnet

One of the operator’s many roles is to aggregate and order transactions into blocks, then to commit a hash of the plasma block to the root chain.
There are many ways to implement Plasma. Different Plasma chains can have different governance rules, different tokens, methods of storing state, etc. but all Plasma
chains commit a hash periodically on to the root chain in order to inherit the security guarantees of the root chain.

.
2)Plasma operator creates a
block

One of the operator’s many roles is to aggregate and order transactions into blocks, then to commit a hash of the plasma block to the root chain.
There are many ways to implement Plasma. Different Plasma chains can have different governance rules, different tokens, methods of storing state, etc. but all Plasma
chains commit a hash periodically on to the root chain in order to inherit the security guarantees of the root chain.
3)Alice, who is a new user, deposits ETH into the Plasma contract and is assigned PETH in return

In both of the main Plasma designs you can deposit any token and receive that token on the
plasma chain. So if Alice deposits ETH, he’ll get PETH! If he deposits BTC he gets PBTC! (The
Plasma Cash spec better supports ERC721 assets like CryptoKitties, but not all Plasma specs will
support depositing any token).
4: Alice sends money to Bob, who is not part of the Plasma smart contract already
Alice isn’t limited to sending money only to those who are already members of the Plasma contract! He can
also send money to Donald, who is an Ethereum whale.In the Plasma Cash specification, each token you
deposit is assigned a unique ID. These unique IDs are stored in a sparse Merkle tree. The index of the leaf
that the coin is assigned to is the only place the coin can be transacted. Think of buying or selling a house —
the house doesn’t move when you transact it, but the person who owns the keys to the house will change,
and the house’s deed is a record of the parties involved and the frequency of the ownership changing hands
This makes it extremely easy to check the history of the token because you know where in the tree to look!
Here we zoom in on the index of the token that Alice sent Bob.Alice must include the history of the token when he sends a token. If a token gets
transacted many times, this history can get really large!. But for now, this is great for Bob who only has to download the histories of the tokens he
cares about

.
5: Bob has two choices: continue spending PETH or create an exit transaction to redeem for ETH on the root chain.
Bob doesn’t need to submit a message to the operator for membership in the Plasma contract in order to exit his PETH into
ETH. Bob wants to immediately tumble his tokens for anonymity, so he doesn’t want to continue transacting his PETH. He gets
a history of the token to prove ownership and includes it in an exit request to the Plasma contract. His exit transaction also
includes gas fees and a bond as a security deposit against lying. Everything checks out, nobody challenges Donald, and he
redeems his PETH for ETH on the root chain.
ERC 721 X Usecases

1)Transfers should cost very little gas, even if the player is


transferring a large quantity of items. For example, someone
might want to transfer a few hundred very cheap cards that are
worth little individually, but quite valuable in bulk.

2)One contract should contain multiple “classes” of items. In a


card game like Zombie Battleground, not every item is unique.
There may be thousands of identical copies of the same card
owned by different users, and the contract should be able to
recognize that these items are part of the same class.

3)Compatibility with marketplaces, wallets, and existing


infrastructure (e.g. Etherscan). Wallet and marketplace makers
provide a valuable service to the community, and it makes sense
to leverage their existing work.
Approach: Extending ERC721 with ERC1178

You might also like