Skip to content

Commit c970342

Browse files
authored
Merge pull request #110 from yashrajdesai/iroha-js-smart-contract
feat: Add smart-contract example
2 parents 8b79bb0 + 4bf0c1c commit c970342

File tree

4 files changed

+241
-0
lines changed

4 files changed

+241
-0
lines changed
Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
/* eslint-disable no-console */
2+
3+
import grpc from 'grpc'
4+
import {
5+
QueryService_v1Client as QueryService,
6+
CommandService_v1Client as CommandService
7+
} from '../../lib/proto/endpoint_grpc_pb'
8+
9+
import queries from '../../lib/queries'
10+
import commands from '../../lib/commands'
11+
import { leftPaddedAddressOfParam, getFirstFourBytesOfKeccak, argumentEncoding, hexToAscii } from './integrationHelpers'
12+
13+
const IROHA_ADDRESS = 'localhost:50051'
14+
const ADMIN_ACCOUNT_ID = 'admin@test'
15+
16+
const adminPriv =
17+
'f101537e319568c765b2cc89698325604991dca57b9716b58016b253506cab70'
18+
19+
const commandService = new CommandService(
20+
IROHA_ADDRESS,
21+
grpc.credentials.createInsecure()
22+
)
23+
24+
const queryService = new QueryService(
25+
IROHA_ADDRESS,
26+
grpc.credentials.createInsecure()
27+
)
28+
29+
queries.fetchCommits(
30+
{
31+
privateKey: adminPriv,
32+
creatorAccountId: ADMIN_ACCOUNT_ID,
33+
queryService,
34+
timeoutLimit: 5000
35+
},
36+
(block) => console.log('fetchCommits new block:', JSON.stringify(block)),
37+
(error) => console.error('fetchCommits failed:', error.stack)
38+
)
39+
40+
async function getAccountTransactions () {
41+
try {
42+
const bytecode = '608060405234801561001057600080fd5b5073a6abc17819738299b3b2c1ce46d55c74f04e290c6000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506111dd806100746000396000f3fe608060405234801561001057600080fd5b50600436106100575760003560e01c806353b676e71461005c578063ae44f0c21461008c578063bf010d56146100bc578063d4e804ab146100ec578063d8f7441a1461010a575b600080fd5b610076600480360381019061007191906107b7565b61013a565b6040516100839190610d6a565b60405180910390f35b6100a660048036038101906100a19190610800565b6102a6565b6040516100b39190610d6a565b60405180910390f35b6100d660048036038101906100d19190610907565b61041e565b6040516100e39190610d6a565b60405180910390f35b6100f461059f565b6040516101019190610d4f565b60405180910390f35b610124600480360381019061011f9190610a9d565b6105c3565b6040516101319190610d6a565b60405180910390f35b606060008260405160240161014f9190610d8c565b6040516020818303038152906040527f53b676e7000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8381831617835250505050905060008060008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16836040516102169190610d38565b600060405180830381855af49150503d8060008114610251576040519150601f19603f3d011682016040523d82523d6000602084013e610256565b606091505b50915091508161029b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161029290610fa6565b60405180910390fd5b809350505050919050565b6060600086868686866040516024016102c3959493929190610dae565b6040516020818303038152906040527fae44f0c2000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8381831617835250505050905060008060008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168360405161038a9190610d38565b600060405180830381855af49150503d80600081146103c5576040519150601f19603f3d011682016040523d82523d6000602084013e6103ca565b606091505b50915091508161040f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161040690610fa6565b60405180910390fd5b80935050505095945050505050565b606060008989898989898989604051602401610441989796959493929190610e24565b6040516020818303038152906040527fbf010d56000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8381831617835250505050905060008060008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16836040516105089190610d38565b600060405180830381855af49150503d8060008114610543576040519150601f19603f3d011682016040523d82523d6000602084013e610548565b606091505b50915091508161058d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161058490610fa6565b60405180910390fd5b80935050505098975050505050505050565b60008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b606060008a8a8a8a8a8a8a8a8a6040516024016105e899989796959493929190610eda565b6040516020818303038152906040527fd8f7441a000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8381831617835250505050905060008060008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16836040516106af9190610d38565b600060405180830381855af49150503d80600081146106ea576040519150601f19603f3d011682016040523d82523d6000602084013e6106ef565b606091505b509150915081610734576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161072b90610fa6565b60405180910390fd5b8093505050509998505050505050505050565b600061075a61075584610feb565b610fc6565b90508281526020810184848401111561077657610775611138565b5b610781848285611091565b509392505050565b600082601f83011261079e5761079d611133565b5b81356107ae848260208601610747565b91505092915050565b6000602082840312156107cd576107cc611142565b5b600082013567ffffffffffffffff8111156107eb576107ea61113d565b5b6107f784828501610789565b91505092915050565b600080600080600060a0868803121561081c5761081b611142565b5b600086013567ffffffffffffffff81111561083a5761083961113d565b5b61084688828901610789565b955050602086013567ffffffffffffffff8111156108675761086661113d565b5b61087388828901610789565b945050604086013567ffffffffffffffff8111156108945761089361113d565b5b6108a088828901610789565b935050606086013567ffffffffffffffff8111156108c1576108c061113d565b5b6108cd88828901610789565b925050608086013567ffffffffffffffff8111156108ee576108ed61113d565b5b6108fa88828901610789565b9150509295509295909350565b600080600080600080600080610100898b03121561092857610927611142565b5b600089013567ffffffffffffffff8111156109465761094561113d565b5b6109528b828c01610789565b985050602089013567ffffffffffffffff8111156109735761097261113d565b5b61097f8b828c01610789565b975050604089013567ffffffffffffffff8111156109a05761099f61113d565b5b6109ac8b828c01610789565b965050606089013567ffffffffffffffff8111156109cd576109cc61113d565b5b6109d98b828c01610789565b955050608089013567ffffffffffffffff8111156109fa576109f961113d565b5b610a068b828c01610789565b94505060a089013567ffffffffffffffff811115610a2757610a2661113d565b5b610a338b828c01610789565b93505060c089013567ffffffffffffffff811115610a5457610a5361113d565b5b610a608b828c01610789565b92505060e089013567ffffffffffffffff811115610a8157610a8061113d565b5b610a8d8b828c01610789565b9150509295985092959890939650565b60008060008060008060008060006101208a8c031215610ac057610abf611142565b5b60008a013567ffffffffffffffff811115610ade57610add61113d565b5b610aea8c828d01610789565b99505060208a013567ffffffffffffffff811115610b0b57610b0a61113d565b5b610b178c828d01610789565b98505060408a013567ffffffffffffffff811115610b3857610b3761113d565b5b610b448c828d01610789565b97505060608a013567ffffffffffffffff811115610b6557610b6461113d565b5b610b718c828d01610789565b96505060808a013567ffffffffffffffff811115610b9257610b9161113d565b5b610b9e8c828d01610789565b95505060a08a013567ffffffffffffffff811115610bbf57610bbe61113d565b5b610bcb8c828d01610789565b94505060c08a013567ffffffffffffffff811115610bec57610beb61113d565b5b610bf88c828d01610789565b93505060e08a013567ffffffffffffffff811115610c1957610c1861113d565b5b610c258c828d01610789565b9250506101008a013567ffffffffffffffff811115610c4757610c4661113d565b5b610c538c828d01610789565b9150509295985092959850929598565b610c6c8161105f565b82525050565b6000610c7d8261101c565b610c878185611032565b9350610c978185602086016110a0565b610ca081611147565b840191505092915050565b6000610cb68261101c565b610cc08185611043565b9350610cd08185602086016110a0565b80840191505092915050565b6000610ce782611027565b610cf1818561104e565b9350610d018185602086016110a0565b610d0a81611147565b840191505092915050565b6000610d2260278361104e565b9150610d2d82611158565b604082019050919050565b6000610d448284610cab565b915081905092915050565b6000602082019050610d646000830184610c63565b92915050565b60006020820190508181036000830152610d848184610c72565b905092915050565b60006020820190508181036000830152610da68184610cdc565b905092915050565b600060a0820190508181036000830152610dc88188610cdc565b90508181036020830152610ddc8187610cdc565b90508181036040830152610df08186610cdc565b90508181036060830152610e048185610cdc565b90508181036080830152610e188184610cdc565b90509695505050505050565b6000610100820190508181036000830152610e3f818b610cdc565b90508181036020830152610e53818a610cdc565b90508181036040830152610e678189610cdc565b90508181036060830152610e7b8188610cdc565b90508181036080830152610e8f8187610cdc565b905081810360a0830152610ea38186610cdc565b905081810360c0830152610eb78185610cdc565b905081810360e0830152610ecb8184610cdc565b90509998505050505050505050565b6000610120820190508181036000830152610ef5818c610cdc565b90508181036020830152610f09818b610cdc565b90508181036040830152610f1d818a610cdc565b90508181036060830152610f318189610cdc565b90508181036080830152610f458188610cdc565b905081810360a0830152610f598187610cdc565b905081810360c0830152610f6d8186610cdc565b905081810360e0830152610f818185610cdc565b9050818103610100830152610f968184610cdc565b90509a9950505050505050505050565b60006020820190508181036000830152610fbf81610d15565b9050919050565b6000610fd0610fe1565b9050610fdc82826110d3565b919050565b6000604051905090565b600067ffffffffffffffff82111561100657611005611104565b5b61100f82611147565b9050602081019050919050565b600081519050919050565b600081519050919050565b600082825260208201905092915050565b600081905092915050565b600082825260208201905092915050565b600061106a82611071565b9050919050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b82818337600083830152505050565b60005b838110156110be5780820151818401526020810190506110a3565b838111156110cd576000848401525b50505050565b6110dc82611147565b810181811067ffffffffffffffff821117156110fb576110fa611104565b5b80604052505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b600080fd5b600080fd5b600080fd5b600080fd5b6000601f19601f8301169050919050565b7f4572726f722063616c6c696e67207365727669636520636f6e7472616374206660008201527f756e6374696f6e0000000000000000000000000000000000000000000000000060208201525056fea26469706673582212205e584d5874226b894bcbcd685c22e9010a188385180559c526ec96dc806b313264736f6c63430008070033'
43+
const response: any = await commands.callEngine({
44+
privateKeys: [adminPriv],
45+
creatorAccountId: ADMIN_ACCOUNT_ID,
46+
quorum: 1,
47+
commandService,
48+
timeoutLimit: 5000
49+
}, {
50+
caller: ADMIN_ACCOUNT_ID,
51+
callee: null,
52+
input: bytecode
53+
})
54+
const hash: string = response.txHash[0]
55+
56+
const reciept: any = await queries.getEngineReceipts({
57+
privateKey: adminPriv,
58+
creatorAccountId: ADMIN_ACCOUNT_ID,
59+
queryService,
60+
timeoutLimit: 5000
61+
}, {
62+
txHash: hash
63+
})
64+
const address = reciept.array[0][0][3]
65+
66+
let params = getFirstFourBytesOfKeccak('getAccountTransactions(string,string,string,string,string,string,string,string)')
67+
68+
const noOfParam = 8
69+
70+
for (let index = 0; index < noOfParam; index++) {
71+
params = params + leftPaddedAddressOfParam(index, noOfParam)
72+
}
73+
74+
params = params + argumentEncoding(ADMIN_ACCOUNT_ID) // account id
75+
params = params + argumentEncoding('1') // page size
76+
params = params + argumentEncoding('') // first_tx_hash
77+
params = params + argumentEncoding('') // first_tx_time
78+
params = params + argumentEncoding('') // last_tx_time
79+
params = params + argumentEncoding('1') // first_tx_height
80+
params = params + argumentEncoding('2') // last_tx_height
81+
params = params + argumentEncoding('[{"Field": "kCreatedTime", "Direction": "kDescending"},{"Field": "kPosition", "Direction": "kDescending"}]')
82+
83+
const result: any = await commands.callEngine({
84+
privateKeys: [adminPriv],
85+
creatorAccountId: ADMIN_ACCOUNT_ID,
86+
quorum: 1,
87+
commandService,
88+
timeoutLimit: 5000
89+
}, {
90+
caller: ADMIN_ACCOUNT_ID,
91+
callee: address,
92+
input: params
93+
})
94+
95+
// Get engine reciepts result
96+
const res: any = await queries.getEngineReceipts({
97+
privateKey: adminPriv,
98+
creatorAccountId: ADMIN_ACCOUNT_ID,
99+
queryService,
100+
timeoutLimit: 5000
101+
}, {
102+
txHash: result.txHash[0]
103+
})
104+
105+
const resultData: string = res.array[0][0][2][1]
106+
const data = hexToAscii(resultData)
107+
108+
console.log(data)
109+
return data
110+
} catch (err) {
111+
console.log(err)
112+
return err
113+
}
114+
}
115+
116+
getAccountTransactions()
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
// SPDX-License-Identifier: Apache-2.0
2+
pragma solidity >=0.7.0 <0.9.0;
3+
4+
contract Transaction {
5+
address public serviceContractAddress;
6+
7+
// Initializing service contract address in constructor
8+
constructor() {
9+
serviceContractAddress = 0xA6Abc17819738299B3B2c1CE46d55c74f04E290C;
10+
}
11+
12+
// Queries the balance in _asset of an Iroha _account
13+
function getAccountTransactions(string memory _account, string memory _pageSize, string memory _firstTxHash, string memory _firstTxTime, string memory _lastTxTime, string memory _firstTxHeight, string memory _lastTxHeight, string memory _ordering) public returns (bytes memory result) {
14+
bytes memory payload = abi.encodeWithSignature(
15+
"getAccountTransactions(string,string,string,string,string,string,string,string)",
16+
_account,
17+
_pageSize,
18+
_firstTxHash,
19+
_firstTxTime,
20+
_lastTxTime,
21+
_firstTxHeight,
22+
_lastTxHeight,
23+
_ordering);
24+
(bool success, bytes memory ret) = address(serviceContractAddress).delegatecall(payload);
25+
require(success, "Error calling service contract function");
26+
result = ret;
27+
}
28+
29+
function getAccountAssetTransactions(string memory _account, string memory _asset, string memory _pageSize, string memory _firstTxHash, string memory _firstTxTime, string memory _lastTxTime, string memory _firstTxHeight, string memory _lastTxHeight, string memory _ordering) public returns (bytes memory result) {
30+
bytes memory payload = abi.encodeWithSignature(
31+
"getAccountAssetTransactions(string,string,string,string,string,string,string,string,string)",
32+
_account,
33+
_asset,
34+
_pageSize,
35+
_firstTxHash,
36+
_firstTxTime,
37+
_lastTxTime,
38+
_firstTxHeight,
39+
_lastTxHeight,
40+
_ordering);
41+
(bool success, bytes memory ret) = address(serviceContractAddress).delegatecall(payload);
42+
require(success, "Error calling service contract function");
43+
result = ret;
44+
}
45+
function getPendingTransactions(string memory _pageSize, string memory _firstTxHash, string memory _firstTxTime, string memory _lastTxTime, string memory _ordering) public returns (bytes memory result) {
46+
bytes memory payload = abi.encodeWithSignature(
47+
"getPendingTransactions(string,string,string,string,string)",
48+
_pageSize,
49+
_firstTxHash,
50+
_firstTxTime,
51+
_lastTxTime,
52+
_ordering);
53+
(bool success, bytes memory ret) = address(serviceContractAddress).delegatecall(payload);
54+
require(success, "Error calling service contract function");
55+
result = ret;
56+
}
57+
58+
function getTransactions(string memory hash) public returns (bytes memory result) {
59+
bytes memory payload = abi.encodeWithSignature(
60+
"getTransactions(string)",
61+
hash);
62+
(bool success, bytes memory ret) = address(serviceContractAddress).delegatecall(payload);
63+
require(success, "Error calling service contract function");
64+
result = ret;
65+
}
66+
}
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
import createKeccakHash from 'keccak'
2+
3+
function pad (num: string, size: number, dir: string) {
4+
while (num.length < size) {
5+
if (dir === 'left') {
6+
num = '0' + num
7+
} else if (dir === 'right') {
8+
num = num + '0'
9+
}
10+
}
11+
return num
12+
}
13+
14+
function hex (str: string) {
15+
const arr1: Array<string> = []
16+
for (let n = 0, l = str.length; n < l; n++) {
17+
const hex = Number(str.charCodeAt(n)).toString(16)
18+
arr1.push(hex)
19+
}
20+
return arr1.join('')
21+
}
22+
23+
function hexToAscii (str: string) {
24+
const hex = str.toString()
25+
let asciiStr = ''
26+
for (let n = 0; n < hex.length; n += 2) {
27+
asciiStr += String.fromCharCode(parseInt(hex.substr(n, 2), 16))
28+
}
29+
return asciiStr
30+
}
31+
32+
function makeNumberHexLeftPadded (number: number, width = 64) {
33+
const numberHex = number.toString(16)
34+
return pad(numberHex, width, 'left')
35+
}
36+
37+
function leftPaddedAddressOfParam (paramIndex: number, numberOfParams: number, width = 64) {
38+
/* Specifies the position of each argument according to Contract ABI specifications. */
39+
const bitsOffset = 32 * numberOfParams
40+
const bitsPerParam = 64
41+
const bitsForTheParam = bitsOffset + bitsPerParam * paramIndex
42+
return makeNumberHexLeftPadded(bitsForTheParam, width)
43+
}
44+
45+
function getFirstFourBytesOfKeccak (functionSignature: string) {
46+
return createKeccakHash('keccak256').update(functionSignature).digest('hex').slice(0, 8)
47+
}
48+
49+
function argumentEncoding (arg: string) {
50+
/* Encodes the argument according to Contract ABI specifications. */
51+
let encodedArgument: string = pad((arg.length).toString(16), 64, 'left')
52+
const encodedString = hex(Buffer.from(arg, 'utf-8').toString())
53+
encodedArgument = encodedArgument + pad(encodedString, 64, 'right').toUpperCase()
54+
return encodedArgument
55+
}
56+
57+
export { makeNumberHexLeftPadded, leftPaddedAddressOfParam, getFirstFourBytesOfKeccak, argumentEncoding, hexToAscii }

package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@
5151
"@types/node": "^12.7.2",
5252
"@typescript-eslint/eslint-plugin": "^2.0.0",
5353
"@typescript-eslint/parser": "^2.0.0",
54+
"@types/keccak": "^3.0.1",
5455
"eslint": "^6.1.0",
5556
"eslint-config-standard": "^13.0.1",
5657
"eslint-plugin-import": "^2.18.2",
@@ -59,6 +60,7 @@
5960
"eslint-plugin-standard": "^4.0.0",
6061
"grpc": "^1.22.2",
6162
"husky": "^3.0.3",
63+
"keccak": "^3.0.2",
6264
"shx": "^0.3.2",
6365
"ts-proto": "^1.41.1",
6466
"typescript": "^3.5.3"

0 commit comments

Comments
 (0)