Smart contracts are basically pieces of code that are attached to an address. They get called every time someone create a transaction pointing to their contract address. Remember that smart contracts can only be deployed once with each address, bringing immutability.
Jelscript is basically a small low-level language used to create smart contracts on JeChain.
For every instructions, you will lose 10000000 Jem, preventing infinite loops.
There is no "real" data type in JeChain, values are represented as dynamic hex strings.
"Memory" means that data is only stored in one contract execution, in RAM, or more specifically just in a map.
Set a value for a memory slot at a position provided:
set mem_key, value
You can reference a value from a memory slot
set 0x1, 0x100
set 0x2, $0x1
The example above set 0x100
to memory position 0x1
, then assigned the value of that position (which is 0x100
) to memory slot position 0x2
.
- Addition:
add mem_key, value
- Subtraction:
sub mem_key, value
- Multiplication:
mul mem_key, value
- Division:
div mem_key, value
- Modulo:
mod mem_key, value
- And:
and mem_key, value
- Or:
or mem_key, value
- Xor:
xor mem_key, value
- Left shift:
ls mem_key, value
- Right shift:
rs mem_key, value
For conditions, you can use these instructions:
- Greater than -
gtr mem_key, value
. - Less than -
lss mem_key, value
. - Greater or equal to -
geq mem_key, value
. - Less or equal to -
leq mem_key, value
. - Equal to -
equ mem_key, value
. - Not equal to -
neq mem_key, value
.
Note that all of these will store 0x1
to the memory slot if the condition is true, 0x0
otherwise.
For loops, you can use labels and the jump
instruction:
Labels:
label label_name
...
...
...
Jump:
jump value, label_name
If value
is evaluated to be 0x1
, it will jump to label_name
.
Before we dig in, we need to know that a contract's storage is a key-value database. The difference with memory is that data will be kept on your computer and can be reused in the future.
- Store into storage:
store storage_key, value
. - Pull from storage and store it into a memory slot:
pull mem_key, storage_key
.
External arguments that users pass into the contract call can be represented as %0
, %1
, %2
,..., %n
.
- Store block's timestamp into a memory slot:
timestamp mem_key
. - Store block's number into a memory slot:
blocknumber mem_key
. - Store block's hash into a memory slot:
blockhash mem_key
. - Store block's difficulty into a memory slot:
difficulty mem_key
.
- Store transaction's amount into a memory slot:
txvalue mem_key
. - Store transaction's sender address into a memory slot:
txsender mem_key
. - Store transaction's gas into a memory slot:
txgas mem_key
. - Store transaction's contract execution gas into a memory slot:
txexecgas mem_key
.
- Store contract's address into a memory slot:
address mem_key
. - Store contract's balance into a memory slot:
selfbalance mem_key
.
- Store address's balance into a memory slot:
balance mem_key, address
. - Send Jem to an address:
send address, amount
.
- Print out a value:
log value
. - Generate SHA256 hash of a value and store into a memory slot:
sha256 mem_key, value
. - Store remaining gas into a memory slot:
gas mem_key
. - Stop execution:
stop
(will not cost gas). - Stop execution and revert all changes:
revert
(will not cost gas).
A contract is attached to a transaction when deployed, so to deploy a contract, simply create a transaction, paste the contract's code into <tx>.additionalData.scBody
, and then broadcast the transaction away.
const myContract = `
...
...
...
`;
const transaction = new Transaction("contract address", amount, gas, {
scBody: myContract;
});
Transaction.sign(transaction, keyPair);
sendTransaction(transaction);
Just simply send a transaction to the contract address, also adding the contract execution gas in Transaction.additionalData.contractGas
:
const transaction = new Transaction("some contract address", amount, gas, {
contractGas: someAmount
});
Transaction.sign(transaction, keyPair);
sendTransaction(transaction);
You can call the contract with arguments by passing in an additional array to Transaction.additionalData.args
:
const transaction = new Transaction("some contract address", amount, gas, {
contractGas: someAmount,
args: [args, go, into, here]
});
Note that all args should be strings that either represent a hex string or a decimal number, and they will be converted to hex strings in execution.
This ís a sample contract with the functionality of calculating the fibonacci number and store it into storage until its balance wears off.
set 0x1, 0x0
set 0x2, 0x1
store 0x3, 0x1
label 0x10
set 0x4, 0x0
add 0x4, $0x1
add 0x4, $0x2
set 0x1, $0x2
set 0x2, $0x4
store 0x3, $0x4
jump 0x1, 0x10
This is an example of a simple token. It will release 297297297
tokens, and people can send tokens to each others.
pull 0x1, insert_contract_address_here
equ 0x1, 0
jump $0x1, 0x10
jump 0x1, 0x20
label 0x10
store insert_some_address_here, 297297297
label 0x20
address 0x2
pull 0x3, $0x2
lss 0x3, %0
jump $0x3, 0x30
pull 0x4, %1
pull 0x3, $0x2
add 0x4, %0
sub 0x3, %0
store $0x2, $0x3
store %1, $0x4
label 0x30
Note that this is built just to be an example, a good token would follow some standards like ERC-20.