Istanbul Byzantine Fault Tolerance (IBFT) is a proof-of-authority blockchain consensus protocol that ensures immediate finality. IBFT Consensus is inspired by Castro-Liskov 99 PBFT paper.
Imagine you and your friends are building an NFT marketplace. You are the CEO and your friend works as a Solidity engineer who writes the smart contract. The NFT marketplace becomes popular, and your revenue builds from the market fee of every NFT sale transaction. You store your profit inside a smart contract, and boast to the media about your company that has enough money to buy a private island. Then, the Solidity engineer disappears and withdraws all the funds from the treasury. You watch in horror.
Now, you vow not to fall into the same trap again. From now on, every sensitive transaction in a smart contract needs approval from a certain number of people. For example, withdrawing funds from your treasury requires at least 60 percent approval from certain key people. If there are five key people, at least three approvals are needed.
Luckily, you don’t need to build this mechanism from scratch; you can use Gnosis Safe to interact with your NFT marketplace. You put the funds inside the Gnosis Safe smart contracts, and withdrawing the funds now requires at least a certain number of signatures. A rogue agent cannot steal the funds anymore, and you’re back to saving up for a private island!
Gnosis Safe is a project from Gnosis. Gnosis started as a prediction markets platform where people can trade information freely. As part of the project, the team behind Gnosis created Gnosis Safe to secure funds for multiple participants. Today, it’s the most popular multisig wallet smart contract on Ethereum. Search “multisig wallet Ethereum” on Google and you will find Gnosis in the top results.
In this article, you will learn how to set up a treasury wallet with Gnosis Safe, so you can protect your funds on the Ethereum blockchain.
Setting up Gnosis Safe smart contracts
You can clone the Gnosis Safe smart contract from their GitHub repo like so:
Use a specific version so you can follow this tutorial:
1 2
$ cd safe-contracts $ git checkout v1.3.0-libs.0
With this specific version, the deployed addresses of Gnosis Safe will be deterministic.
Let’s deploy Gnosis Safe to the Hardhat development network. But first, you must install Hardhat inside the safe-contracts directory:
1
$ yarn add hardhat
Then, run the Hardhat development network and deploy the Gnosis Safe smart contracts:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
$ npx hardhat node Nothing to compile sending eth to create2 contract deployer address (0x3fab184622dc19b6109349b94811493bf2a45362) (tx: 0x076c3e6eb9678931c92e0322885f48ebdc064226483a9bae4866f99c7f8aa8bb)... deploying create2 deployer contract (at 0x4e59b44847b379578588920ca78fbf26c0b4956c) using deterministic deployment (https://github.com/Arachnid/deterministic-deployment-proxy) (tx: 0xeddf9e61fb9d8f5111840daef55e5fde0041f5702856532cdbb5a02998033d26)... deploying "SimulateTxAccessor" (tx: 0xfc6d7c491688840e79ed7d8f0fc73494be305250f0d5f62d04c41bc4467e8603)...: deployed at 0x59AD6735bCd8152B84860Cb256dD9e96b85F69Da with 237871 gas deploying "GnosisSafeProxyFactory" (tx: 0x6fff529768b3c5660234fcd53d5d04918aadc935a90ec05aca1796649bf4f699)...: deployed at 0xa6B71E26C5e0845f74c812102Ca7114b6a896AB2 with 867594 gas deploying "DefaultCallbackHandler" (tx: 0x406498f13d684b2db11ac78d1b06c2b38657f02e729ecebc677b7ea28a30e712)...: deployed at 0x1AC114C2099aFAf5261731655Dc6c306bFcd4Dbd with 542473 gas deploying "CompatibilityFallbackHandler" (tx: 0xe7426790ce3fed5ba2083b5e5b911b561a306d3f26fbd5c0d0d6c0c1d5847e3f)...: deployed at 0xf48f2B2d2a534e402487b3ee7C18c33Aec0Fe5e4 with 1238095 gas deploying "CreateCall" (tx: 0xa602d00962fa8de99f84dbefd62f831f179d12e549863bd305607bbb775f5c81)...: deployed at 0x7cbB62EaA69F79e6873cD1ecB2392971036cFAa4 with 294718 gas deploying "MultiSend" (tx: 0x8790b4413d0b4336586897f0bf40a72cdcfcb8fd06aed8a164fac5ecf662e0f6)...: deployed at 0xA238CBeb142c10Ef7Ad8442C6D1f9E89e07e7761 with 190004 gas deploying "MultiSendCallOnly" (tx: 0xb4ccc0ce8099412d505d0ab131ce9fffb1915a5053906875fc301528ebe79f1a)...: deployed at 0x40A2aCCbd92BCA938b02010E17A5b8929b49130D with 142122 gas deploying "SignMessageLib" (tx: 0xdf0d113415ea15354de8e816b793ca89e5a9a7d4ad7b48e1344872d0f4aacdbf)...: deployed at 0xA65387F16B013cf2Af4605Ad8aA5ec25a2cbA3a2 with 262353 gas deploying "GnosisSafeL2" (tx: 0x83b42dd66a2e282b3e76cb10fb4ab93da970b0454010faef142ab8c6a5c4233d)...: deployed at 0x3E5c63644E683549055b9Be8653de26E0B4CD36E with 5200241 gas deploying "GnosisSafe" (tx: 0xea94214f16af5e66646518db2403a6e24b17973d6bbb0208fc40f01343b0225f)...: deployed at 0xd9Db270c1B5E3Bd161E8c8503c55cEABeE709552 with 5017833 gas Started HTTP and WebSocket JSON-RPC server at http://127.0.0.1:8545/
The Gnosis Safe smart contracts are not just one smart contract; they are many. But you need to pay attention to three smart contracts in particular: MultiSend, GnosisSafe, and GnosisSafeProxyFactory. You need their addresses when you use the Gnosis Safe SDK later.
So what are these three smart contracts?
GnosisSafe is the core safe smart contract, and everyone only needs one. Your startup and your business competitors can use the same deployed GnosisSafe, so you don’t need to deploy it separately if it has been deployed already.
You don’t interact directly with GnosisSafe. You use a proxy, called GnosisSafeProxy. Because of this, your startup and your business competitor need to use different GnosisSafeProxys. To create your own GnosisSafeProxy, you can use GnosisSafeProxyFactory.
MultiSend is a helper smart contract to batch multiple transactions into one. You may want to buy a yacht as your startup office, pay salary to a meme artist, and pay taxes to the country where your startup resides. Instead of executing these transactions one by one, you can batch them into one with this helper smart contract, then execute them in one go.
There are other smart contracts as part of the Gnosis Safe, but you don’t touch them directly. You only deal with the three smart contracts mentioned previously. That’s why the Gnosis Safe SDK requires you to provide their addresses.
If you use Gnosis Safe in other networks like Ethereum mainnet or Rinkeby, you don’t need to deploy the Gnosis Safe smart contracts because the team behind Gnosis Safe already deployed these core ones. You just need to find their addresses and write them down. But since you are using the Hardhat development network, you need to do this step.
Let the process run peacefully. You can open a new terminal and create your project that interacts with these smart contracts in the new terminal.
Installing the Gnosis Safe SDK libraries
The Gnosis Safe SDK libraries are Node.js libraries. To use them, you need to create a Node project. Let’s create one by creating an empty directory and initialize it with yarn:
1 2 3 4 5 6 7 8 9
$ mkdir our-treasury $ cd our-treasury $ yarn init -y yarn init v1.22.11 warning The yes flag has been set. This will automatically answer yes to all questions, which may have security implications. success Saved package.json Done in 0.02s. $ ls package.json
To interact with Ethereum in Node, you have two choices: web3.js and ethers.js. In this tutorial, you’ll use the ethers.js library. Install the library with yarn like so:
1
$ yarn add ethers
You will put the Ethereum addresses on the .env file instead of hard-coding them, so you need the dotenv library:
These are the core libraries that you’re going to learn how to use in this tutorial to interface with the Gnosis Safe smart contracts.
Setting up the .env file
Instead of hard-coding the Ethereum addresses, you can store them as environment variables. But setting up environment variables in a terminal before executing a script is a hassle:
It’s better if you use the .env file. Basically, you use the dotenv library to load the environment variables from the .env file. That way, you only need to set up the environment variables once.
In the code above, you can see that the addresses for MULTI_SEND_ADDRESS, SAFE_MASTER_COPY_ADDRESS, SAFE_PROXY_FACTORY_ADDRESS are the same as the ones in the first terminal. As a reminder, the first terminal is the terminal where you’ve deployed the Gnosis Safe smart contracts on the Hardhat development network. Later, in your client code, you will load these smart contracts’ addresses from the .env file to interact with the deployed smart contracts on the Hardhat development network.
The ACCOUNT_1 and other accounts are the sample Ethereum addresses provided by the Hardhat development node. If you run npx hardhat node in a new Hardhat project, you will get 20 sample Ethereum addresses with their private keys for development. Each account has 10,000ETH. In this .env file, you just took the first seven addresses.
Creating the treasury
Let’s create the index.js file. This is where you will write the code to build the treasury with Gnosis Safe:
1
$ edit index.js # replace edit with vim or code or your favorite editor
First things first, you want to be able to read the variables you put in the .env file. So add this line:
To make things clearer, imagine that you’re creating a web3 startup to disrupt traditional banks. There are five people who are building this startup, with you acting as the CEO. The other people on the team are the CTO, a Solidity engineer, a meme artist, and an advisor.
An angel investor sends money to your startup. The money is put inside the safe smart contract. It takes three of five signatures from your team to approve any transactions related to this smart contract. You, as the CEO, decide to buy a yacht for your startup office. You will need two other signatures from your team to approve this transaction. Let’s do it!
Setting up multisignature authorization in Gnosis Safe wallet
To protect your company’s treasury from being emptied by a single member, you have to make sure that three out of your five team members approve of the yacht purchase. Let’s add this functionality now.
Still in the same file, index.js, add these lines below the const Safe = require… line:
The Gnosis Safe smart contracts work with the ethers.js library and the web3.js library. In this tutorial, you are using ethers.js. So you need the adapter that works with ethers.js:
As explained in the beginning of the tutorial, the only way to create a safe is from the safe factory that is shared with everyone. So first, you need to create a safe factory object connecting to the safe factory smart contract, GnosisSafeProxyFactory:
In the code above, you first received the chain ID. Then, you created an object containing three smart contracts with which you safe will interact. Finally, you created a safe factory.
Next, create a safe from this safe factory like so:
The safe needs the addresses of the members and the minimum amount of signatures required to approve transactions for this safe. In the code above, you put all members of the startup and 3 as the threshold. To deploy a safe, you can use the deploySafe method from the safe factory.
Now that you have a safe already, an investor sends money to your startup, which would look like this:
The transaction is sending 3ETH to the yacht shop. Since the transaction is transferring ETH, you can fill empty data, 0x, in the data field of the transaction. However, if you create a smart contract transaction, such as minting NFTs or selling tokens, you will need to fill the data field.
After doing that, create the safe transaction using the createTransaction method. Then, get the hash with the getTransactionHash method.
Finally, your job as CEO is to approve the transaction:
But your job is not done yet. You call your co-founder, the CTO of your startup, and persuade her to approve the transaction of buying a yacht. “Wouldn’t it be nice if you could code in the vast ocean?”
The CTO needs a different Safe object. But you don’t need to create it with the safe factory; you can create it with the create method of the Safe object. Because your safe smart contract is live already on the blockchain, you just passed the treasury address when you created the Safe object.
Next, you pass the transaction to your CTO either by chatting or via email. What the transaction means in this context is the transaction object in the code. Remember, you’ve already created this object:
Your CTO created a safe transaction from this one and got its hash. Then, she approves the transaction using the approveTransactionHash method, which accepts the hash argument.
Your job is still not done yet; you need another signature. But this time, you don’t need to convince your advisor because he gives you full support to buy a yacht. He approves the transaction:
The code is the same as the CTO’s approval transaction, but instead of the approveTransactionHash method, the advisor used the executeTransaction method. This method approves the transaction as well behind the scenes. But most importantly, this method executes the safe transaction, which is buying a yacht!
Finally, let’s check your treasury balance:
1 2
const afterBalance = await safeSdk_ceo.getBalance(); console.log(`The final balance of the treasury: ${ethers.utils.formatUnits(afterBalance, "ether")} ETH`);
The script is finished. You can execute the script like so:
1 2 3 4 5
$ node index.js Fundraising. Initial balance of the treasury: 10.0 ETH Buying a yacht. The final balance of the treasury: 7.0 ETH
Now, you can work in a yacht with your team building a DAO to disrupt banks!
Conclusion
In this article, you learned how to create a Gnosis Safe that can be configured to require multiple signatures to approve transactions. You launched the Gnosis Safe smart contracts in the Hardhat development network, then, using the Gnosis safe SDK, created a safe to hold the treasury. Using multiple addresses, you created and approved the transaction of sending ETH.
This article only explains the SDK of interacting with the Gnosis Safe smart contracts. If you want to learn the ins and outs of the smart contract themselves, you can check their GitHub repository! The SDK also has other methods like signing a transaction off-chain. Check their GitHub repository to learn more. The code for this article is available on this GitHub repository.
To help with the FireFly evaluation, especially how it makes digital assets management easy by supporting token standards (ERC20, ERC721, ERC1155, and other standard contracts or your custom implementations via extensions) with REST APIs and event streams, we have a minimal tutorial that you can set up locally on your laptop. Please give it a try and let us know if you have any questions.
initialize the FireFly stack using Ethereum as the underlying blockchain, and load the ERC20/ERC721 token connector:
1
$ ff init -t erc20_erc721
start the stack named “digital-assets”
1
$ ff start digital-assets
deploy the token contract. the easiest way is using Truffle. The Hyperledger implementation of the token connector has sample ERC20 and ERC721 contracts you can use to deploy to Ethereum:
1 2 3 4 5 6 7 8 9
$ git clone [git@github.com:hyperledger/firefly-tokens-erc20-erc721.git](mailto:git@github.com:hyperledger/firefly-tokens-erc20-erc721.git) $ cd firefly-tokens-erc20-erc721 $ cd solidity $ npm install $ truffle migrate
copy the contract address for the deployed ERC20 token contract (highlighted below in the sample output), to use in the next step
Deploying 'Migrations' \---------------------- ⠋ Blocks: 0 Seconds: 0 > transaction hash: 0xb81c60fd920bf28775bd8610271c60a40380e278af97ccd18458efafe852dc99 \> Blocks: 0 Seconds: 0 \> contract address: 0x0C2c9222835692912b3999D6DAE955a9d306393d \> block number: 6 \> block timestamp: 1648585628 \> account: 0x1eAecAb9D796Ee765865f47a78De13735619c914 \> balance: 904625697166532776746648320380374280103671755200316906558.262375061821325312 \> gas used: 272788 (0x42994) \> gas price: 0 gwei \> value sent: 0 ETH \> total cost: 0 ETH
\> Saving migration to chain. \> Saving artifacts \------------------------------------- \> Total cost: 0 ETH
2_deploy_contracts.js
Deploying 'ERC20WithData' \------------------------- ⠋ Blocks: 0 Seconds: 0 > transaction hash: 0x748a60953ceacda47431210752c2a9991f77b552d19397827500feef086fc3cf \> Blocks: 0 Seconds: 0 \> contract address: **0xB6728020f998f32afb4936f9CEcE04B1d3951895** \> block number: 8 \> block timestamp: 1648585628 \> account: 0x1eAecAb9D796Ee765865f47a78De13735619c914 \> balance: 904625697166532776746648320380374280103671755200316906558.262375061821325312 \> gas used: 1948804 (0x1dbc84) \> gas price: 0 gwei \> value sent: 0 ETH \> total cost: 0 ETH
\> Saving migration to chain. \> Saving artifacts \------------------------------------- \> Total cost: 0 ETH
Summary
> Total deployments: 2 > Final cost: 0 ETH
teach FireFly about the token contract so that it can start tracking transactions on the contract. For this step you can use the Swagger UI that comes with FireFly. Open http://localhost:5000/api, and expand the request entry POST /namespaces/{ns}/tokens/pools. Plugin the values as shown below (you can delete all the other optional properties in the payload):
Now you can start using FireFly APIs to manage the new token contract: mint/transfer/burn.
You can use the following JSON RPC command to create additional Ethereum addresses in the go-ethereum node’s built-in wallet:
Try the minting API using the POST /namespaces/{ns}/tokens/mint endpoint:
check the result of the minting transaction in the FireFly UI at http://localhost:5000/ui (for org0) and http//localhost:5001/ui (for org1):
That’s it! Now you have a local setup to explore the many features of FireFly.
connect with metamask as below. by the way, the para when you add a network for firefly , please refer the info at ~/.firefly/stacks/oh/blockchain/genesis.json, here you can cat genesis block info.
Consider n parties, where n ≥ 3, and where one of the parties is designated as a sender. The sender has a bit b ∈ {0, 1}. A broadcast protocol is a protocol where the parties send messages to one another, and eventually every party outputs a bit bi , for i = 1, . . . , n, or outputs nothing.
We say that the protocol has consistency if for every two honest parties, if one party outputs b and the other outputs b’ , then b = b’ .
We say that the protocol has validity if when the sender is honest, the output of all honest parties is equal to the sender’s input bit b.
We say that the protocol has totality if whenever some honest party outputs a bit, then eventually all honest parties output a bit.
A reliable broadcast protocol (RBC) is a broadcast protocol that satisfies all three properties. Let us assume that there is a public key infrastructure (PKI), meaning that every party has a secret signing key, and every party knows the correct public signature verification key for every other party.
In a synchronous network, consider the following broadcast protocol:
step 0: The sender sends its input bit b (along with its signature) to all other parties. The sender then outputs its bit b and terminates.
step 1: Every non-sender party i echoes what it heard from the sender to all the other non-sender parties (with i’s signature added). If the party heard nothing from the sender, it does nothing in this step. Similarly, the party does nothing in this step if the sender’s message is malformed: for example, if the sender’s signature is invalid, or the message is not a single bit.
step 2: Every non-sender party collects all the messages it received (up to n−1 messages, with at most one from the sender in step 0 and at most one from each non-sender party in step 1). If some two of the received messages contain a valid signature by the sender, but for opposite bits (i.e., in one signed message the bit is 0 and in the other signed message the bit is 1) then the sender is dishonest and the party outputs 0 and terminates. Otherwise, all the properly signed bits from the sender are the same, and the party outputs that bit. If the non-sender received no messages, it outputs nothing.
For each of the following questions, describe an attack or explain why there is no attack.
A) If there is at most one dishonest party, does the protocol have consistency?
answer - a dishonest party have options as below in step 1 & 2 to cheat a honest part:
don’t answer / response;
broke sender’s signature but cannot make a fake/wrong bit b, because broken signature cannot verify correct.
broke node’s signature itself.
If the sender is a dishonest party, in step 0, dishonest part can send b to some parties, and send a different b’ to other parties. Then it don’t have consistency. If the sender is a honest part, the dishonest party don’t response, so other nodes can’t accumulate “all the properly signed bits from the sender are the same, and the party outputs that bit”, then other nodes have no response. Then it still don’t have consistency.
B) If there is at most one dishonest party, does the protocol have validity?
answer - dishonest party don’t response any message , and make other nodes cannot reach “all the properly signed bits from the sender are the same, and the party outputs that bit.” So this protocol don’t have validity.
C) If there are at most two dishonest parties, show that the protocol does not have consistency.
answer - As answer A)
D) If there are at most two dishonest parties, does the protocol have validity?
answer - two dishonest parties can send out the same dishonest message or they don’t response, and make other nodes cannot reach “all the properly signed bits from the sender are the same, and the party outputs that bit.” So this protocol don’t have validity.
E) Does the protocol have totality (for any number of dishonest parties)?
answer - It assume that this protocol run in a reliable broadcast protocol (RBC). But the dishonest party can send a (or some) correct response to one (or some other) party, but don’t response any message to one (or some other) party in step 1. Dishonest party also can do the same in step 0. So these honest party cannot have the same result. Then this protocol don’t have totality.
A) Briefly explain why a Rollup system stores all transaction data on chain? What would go wrong if transaction data were discarded and not stored anywhere?
answer - The main goal of Rollup is to increase transaction speed (faster finality), and transaction throughput (high transactions per second), without sacrificing decentralization or security.
Some Rollup solutions are optimistic rollups, zero-knowledge rollups or state channels. Transactions are rolled up into a single transaction to Mainnet Ethereum, reducing gas fees for users making Ethereum more inclusive and accessible for people everywhere. Rollups perform transaction execution outside layer 1 and then the data is posted to layer 1 where consensus is reached. As transaction data is included in layer 1 blocks, this allows rollups to be secured by native Ethereum security. That is why Rollup system stores all transaction data.
So If Rollup system has only one single data storage and its transaction data were discarded, the transaction data before rollup will lose and can not get back. Usually, Rollup system is a blockchain and data saved in decentralized nodes, so original transaction data will not lose when one of blockchain nodes is down or broken.
Suppose this code is deployed in two contracts: a contract at address X and a contract at address Y . Which of the following can read the state of _balances in contract X? Circle the correct answer(s).
A Code in the _transfer() function in contract ERC20 at address X
B Code in the _transfer() function in contract ERC20 at address Y
C An enduser using etherscan.io
answer C is correct.
C) Continuing with part (B),
which of the following can read the log entry Transfer emitted when the function _transfer() is called? Circle the correct answer(s).
A Code in the function getBalance() defined in contract ERC20 at address X
B Code in the function getBalance() defined in contract ERC20 at address Y
C An enduser using etherscan.io
answer C is correct.
D) Two Ethereum transactions, tx1 and tx2, are submitted to the network at the same time. Transaction tx1 has maxPriorityFee set to y and transaction tx2 has maxPriorityFee set to 2y. Will tx2 necessarily be executed on chain before tx1? Justify your answer. You can assume that maxFee for both tx1 and tx2 is greater than baseFee + maxPriorityFee.
answer - Assume that maxFee (tx1 and tx2) is greater than baseFee + maxPriorityFee, tx1 and tx2 will mine by miner both, they will execute in the same block, that is the most possibility, because usually miner nodes are working for tx order base on gasFee from high to low. But still has other possibilities - 1) send tx1 in node 1, send tx2 in node2, the network of node 1 is bad, and all txs in txpool of node 1 maybe blocked , so the speed and status of network of node is very important for transaction success; 2) the other transactions’ maxPriorityFee, if they all very high than 2y, the block is full and cannot take tx2 in, then tx1 and tx2 will not execute, and their executed order will depends on the next block. Or they all very high than y, the block is full and cannot take tx1 in, but the block take tx2 in, so tx1 will not execute, tx2 will execute.
Catch up high Miner extractable value (MEV) may cause a miner to take priority of a lower fee transaction because it benefits them in some way, it is good for DeFi and application boom, but bad for UX, blockchain network congestion, even make blockchain block order re-organization and consensus instability.
E) Alice wants to buy a car from dealer Bob. She sends 1 BTC to Bob’s Bitcoin address. Bob waits for a transaction where (i) the input is from Alice’s address, and (ii) one of the outputs is a UTXO bound to Bob’s address with a value of 1 BTC. As soon as Bob sees this transaction on the Bitcoin blockchain, he gives Alice the keys, and she drives away. Is this safe? Could Alice get the car for free? If so, explain why. If not, explain what Bob should do to ensure that he gets paid.
answer - In bitcoin with PoW consensus protocol, the tx finality need to wait 6 blocks. so Bob should to wait 6 blocks after the block of tx.
F) Alice owns a brand new Tesla Model Y. Can she currently use her car as collateral for a loan in the Compound system? (without selling the car) If yes, explain how. If no, explain why not.
answer - no, physical car cannot come into digital Compound system yet, because the car maybe bad, maybe broken, maybe stole from somewhere illegally, the car loan needs many kinds of service to confirm its value and price. Compound now only provide cryptocurrencies as collateral for a loan.