-
Notifications
You must be signed in to change notification settings - Fork 33
Deploy smart contract using truffle
npm install -g truffle
- Create a new directory for our Truffle project:
mkdir FsnExample
cd FsnExample
- Create a bare Truffle project with no smart contracts included, use
truffle init
Once this operation is completed, we'll now have a project structure with the following items:
- contracts/: Directory for Solidity contracts
- migrations/: Directory for scriptable deployment files
- test/: Directory for test files for testing your application and contracts
- truffle-config.js: Truffle configuration file
we use fusion private chain
as example in this doc. we want to start a private chain locally and make truffle connect to our running priavte chain. If you want deploy contract on testnet
or mainnet
, please start chain and modify truffle-config.js
according to the actual blockchain.
reference to Deploy-private-chain for more information.
start Fusion private chain with RPC port 12001
./efsn --devnet --datadir node1 --port 12341 --rpc --rpcport 12001 --rpcapi web3,eth,net,db,personal,fsn,fsntx --rpcaddr 0.0.0.0 --rpccorsdomain "*" --ws --wsport 13001 --wsapi web3,eth,net,db,personal,fsn,fsntx --wsaddr 0.0.0.0 --wsorigins "*" --unlock 0x0122bf3930c1201a21133937ad5c83eb4ded1b08 --password passwd --miner.etherbase 0x0122bf3930c1201a21133937ad5c83eb4ded1b08 --networkid 55555 --mine --autobt --gcmode archive 2>&1 | tee -a node1.log
In our example, we should have at least three accounts:
accounts[0]: coinbase for mining, and contract creator
accounts[1]: deposit timelock and asset from this account to contract, test `receiveAsset`method
accounts[2]: withdraw timelock or asset from contract to this account, test `sendAsset`method
If not, we can create some new accounts:
./efsn account new --datadir node1
and save the corresponding password in file passwd
We should unlock at least two accounts to make transactions:
./efsn attach node1/efsn.ipc
> personal.unlockAccount(eth.accounts[1],null,0)
add development
in networks
, please ensure the host, port and network_id is same to our private chain. The fusion private chain network id is 55555, testnet is 46688, mainnet is 32659.
development: {
host: "127.0.0.1",
port: 12001,
network_id: 55555,
gas: 4700000,
gasPrice: 1000000000,
},
and specify solc version to "0.5.4" (higher version may not support)
compilers: {
solc: {
version: "0.5.4",
}
}
truffle console
after enter into truffle console, we can input the following commands
web3.currentProvider.host
web3.eth.net.getId()
to verify if we have connected to our private chain successfully.
Let's create a solidity smart contract named as FSNExample.sol in our contracts/ directory.
FSNExample.sol
pragma solidity <=0.5.10;
contract FSNContract {
address constant precompile = address(0x9999999999999999999999999999999999999999);
// these events will be generated by the low level impl.
event LogFusionAssetReceived(bytes32 indexed _asset, address indexed _from, uint256 _value, uint64 _start, uint64 _end, SendAssetFlag _flag);
event LogFusionAssetSent(bytes32 indexed _asset, address indexed _to, uint256 _value, uint64 _start, uint64 _end, SendAssetFlag _flag);
enum SendAssetFlag {
UseAny, // 0
UseAnyToTimeLock, // 1
UseTimeLock, // 2
UseTimeLockToTimeLock, // 3
UseAsset, // 4
UseAssetToTimeLock // 5
}
function _sendAsset(bytes32 asset, address to, uint256 value, uint64 start, uint64 end, SendAssetFlag flag) internal returns (bool, bytes memory) {
bytes memory input = abi.encode(1, asset, to, value, start, end, flag);
return precompile.call(input);
}
}
contract FSNExample is FSNContract {
address owner;
modifier onlyOwner {
require(msg.sender == owner, "only owner");
_;
}
constructor() public {
owner = msg.sender;
}
// If a contract want to receive Fusion Asset and TimeLock from an EOA,
// the contract must impl the following 'receiveAsset' interface.
function receiveAsset(bytes32 assetID, uint64 startTime, uint64 endTime, SendAssetFlag flag, uint256[] memory extraInfo) payable public returns (bool success) {
(assetID, startTime, endTime, flag, extraInfo); // silence warning of Unused function parameter
return true;
}
// impl by calling a precompiled contract '0x9999999999999999999999999999999999999999'
// which support send out Fusion Asset and TimeLock from the calling contract.
function sendAsset(bytes32 asset, address to, uint256 value, uint64 start, uint64 end, SendAssetFlag flag) onlyOwner public returns (bool success) {
(success,) = _sendAsset(asset, to, value, start, end, flag);
require(success, "call sendAsset failed");
return true;
}
}
run truffle console
to enter into truffle console, and input compile
command
compile
the compiling process is like the following:
truffle(development)> compile
Compiling your contracts...
===========================
✔ Fetching solc version list from solc-bin. Attempt #1
✔ Downloading compiler. Attempt #3.
> Compiling ./contracts/FSNExample.sol
> Compiling ./contracts/Migrations.sol
> Artifacts written to /home/jowen/projects/contracts/FsnExample/build/contracts
Once you compiled your smart contract class, it’s time to create a migration file. Create a migration file 2_deploy_contracts.js in /migrations folder.
> Compiled successfully using:
- solc: 0.5.4+commit.9549d8ff.Emscripten.clang
Once we compiled our smart contract class, it's time to create a migration file. Create a migration file 2_deploy_contracts.js in migrations/
directory.
2_deploy_contracts.js
var FSNExample = artifacts.require("./FSNExample.sol");
module.exports = function(deployer) {
deployer.deploy(FSNExample);
};
Once you created the contract migration file, it is time to migrate it using truffle development cli. Let's get back to the terminal window again and type this command there.
migrate
It will start from migrating 1_initial_migration.js file and it will show various migration details like transaction hash, contract address, and total cost, etc.
truffle(development)> migrate
Compiling your contracts...
===========================
> Everything is up to date, there is nothing to compile.
Starting migrations...
======================
> Network name: 'development'
> Network id: 55555
> Block gas limit: 0x60f45e
1_initial_migration.js
======================
Deploying 'Migrations'
----------------------
> transaction hash: 0xa5f33ef3befe1bd2e206a48b7dfa4487f2fbad6937162c534e3cc742f121a0e4
> Blocks: 1 Seconds: 12
> contract address: 0xE5Ab4cb9340Ff5a25885FE5f703F69c29152Dff0
> block number: 310
> block timestamp: 1583132601
> account: 0x0122BF3930c1201A21133937Ad5C83Eb4dEd1b08
> balance: 99975775
> gas used: 192057
> gas price: 1 gwei
> value sent: 0 ETH
> total cost: 0.000192057 ETH
> Saving migration to chain.
> Saving artifacts
-------------------------------------
> Total cost: 0.000192057 ETH
Then it will migrate our contract file 2_deploy_contract.js and all migration details.
2_deploy_contracts.js
=====================
Deploying 'FSNExample'
----------------------
> transaction hash: 0x46e89673e55f64dcb2e9a6512bad6a7d21410d96f2246ef44331ce72c186769d
> Blocks: 0 Seconds: 12
> contract address: 0x751387409a378ab28a7421F99892F6D063943E67
> block number: 312
> block timestamp: 1583132627
> account: 0x0122BF3930c1201A21133937Ad5C83Eb4dEd1b08
> balance: 99975780
> gas used: 428304
> gas price: 1 gwei
> value sent: 0 ETH
> total cost: 0.000428304 ETH
> Saving migration to chain.
> Saving artifacts
-------------------------------------
> Total cost: 0.000428304 ETH
Summary
=======
> Total deployments: 2
> Final cost: 0.000620361 ETH
Now, we can get our contract's address by the following command.
FSNExample.address
Once our smart contract deployed to a blockchain, now it's time to interact with it. We are going to use our truffle console to interact with it.
FSNExample.deployed().then(function(instance){ app = instance; })
Once we have created an app
instance of our smart contract class, we can get complete details of FSNExample smart contract.
app
Let's assign all our available accounts to a variable for preparation.
web3.eth.getAccounts().then(function(result){ accounts = result })
Now, we can check this accounts array variable. Just type accounts
in our terminal window.
first, let remember its interface:
function receiveAsset(bytes32 assetID, uint64 startTime, uint64 endTime, SendAssetFlag flag, uint256[] memory extraInfo) payable public returns (bool success)
then, use call
method to check our calling first. Notice the way of giving value
parameter. If value
is not given, then nothing will be received.
app.receiveAsset.call("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",0,1614671636,0,[],{from:accounts[1],value:web3.utils.toWei("10")})
And replace call
with sendTransaction
when call
returns true
.
app.receiveAsset.sendTransaction("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",0,1614671636,0,[],{from:accounts[1],value:web3.utils.toWei("10")})
Once this command executes successfully, it will show the transaction details.
truffle(development)> app.receiveAsset.sendTransaction("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",0,1614671636,0,[],{from:accounts[1],value:web3.utils.toWei("10")})
{ tx:
'0x765e17c22cc729fbed3b46ba28cf0b8008c75f9ca1d067c71382d936c2a8a211',
receipt:
{ blockHash:
'0x4355c525916c10a7a3511f974bc81056b20f3520b1a163a53f157dd2ddf337ef',
blockNumber: 733,
contractAddress: null,
cumulativeGasUsed: 47097,
from: '0x37a200388caa75edcc53a2bd329f7e9563c6acb6',
gasUsed: 25145,
logs: [ [Object] ],
logsBloom:
'0x00000000800000000000000400000000000100080000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000100000000000000000000000010000000000000000000000000200000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000',
status: true,
to: '0x751387409a378ab28a7421f99892f6d063943e67',
transactionHash:
'0x765e17c22cc729fbed3b46ba28cf0b8008c75f9ca1d067c71382d936c2a8a211',
transactionIndex: 1,
rawLogs: [ [Object] ] },
logs:
[ { address: '0x751387409a378ab28a7421F99892F6D063943E67',
blockNumber: 733,
transactionHash:
'0x765e17c22cc729fbed3b46ba28cf0b8008c75f9ca1d067c71382d936c2a8a211',
transactionIndex: 1,
blockHash:
'0x4355c525916c10a7a3511f974bc81056b20f3520b1a163a53f157dd2ddf337ef',
logIndex: 1,
removed: false,
id: 'log_5529e6b3',
event: 'LogFusionAssetReceived',
args: [Result] } ] }
To check whether our message is updated in our smart contract or not, we could first check the above transaction's status and logs, then query our asset and timelock balance of our contact address and the sender address in our private blockchain.
first, let remember its interface:
function sendAsset(bytes32 asset, address to, uint256 value, uint64 start, uint64 end, SendAssetFlag flag) onlyOwner public returns (bool success)
then, use call
method to check our calling first.
app.sendAsset.call("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",accounts[2],web3.utils.toWei("1"),0,1614671636,0,{from:accounts[0]})
And replace call
with sendTransaction
when call
returns true
.
app.sendAsset.sendTransaction("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",accounts[2],web3.utils.toWei("1"),0,1614671636,0,{from:accounts[0]})
Once this command executes successfully, it will show the transaction details.
truffle(development)> app.sendAsset.sendTransaction("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",accounts[2],web3.utils.toWei("1"),0,1614671636,0,{from:accounts[0]})
{ tx:
'0x7bed61043c9dd5f4d4e3d34d7c6f8fcfbd76272db2a3f60d47d96d39e424077b',
receipt:
{ blockHash:
'0xa391b9e6a1f5fb4fc6235bbd46e18d590a2585a7cb0436fab3c82cfb7d8896c0',
blockNumber: 750,
contractAddress: null,
cumulativeGasUsed: 60870,
from: '0x0122bf3930c1201a21133937ad5c83eb4ded1b08',
gasUsed: 38918,
logs: [ [Object] ],
logsBloom:
'0x00000000800000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000010000000000000000000000000600000000000000000020000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000080200000000000',
status: true,
to: '0x751387409a378ab28a7421f99892f6d063943e67',
transactionHash:
'0x7bed61043c9dd5f4d4e3d34d7c6f8fcfbd76272db2a3f60d47d96d39e424077b',
transactionIndex: 1,
rawLogs: [ [Object] ] },
logs:
[ { address: '0x751387409a378ab28a7421F99892F6D063943E67',
blockNumber: 750,
transactionHash:
'0x7bed61043c9dd5f4d4e3d34d7c6f8fcfbd76272db2a3f60d47d96d39e424077b',
transactionIndex: 1,
blockHash:
'0xa391b9e6a1f5fb4fc6235bbd46e18d590a2585a7cb0436fab3c82cfb7d8896c0',
logIndex: 1,
removed: false,
id: 'log_b88c6352',
event: 'LogFusionAssetSent',
args: [Result] } ] }
To check whether our message is updated in our smart contract or not, we could first check the above transaction's status and logs, then query our asset and timelock balance of our contact address and the receiver address in our private blockchain.