generated from ConsenSys-Academy/supply-chain-exercise
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit 4d85f9b
Showing
12 changed files
with
779 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
# This workflow will do a clean install of node dependencies, build the source code and run tests across different versions of node | ||
# For more information see: https://help.github.com/actions/language-and-framework-guides/using-nodejs-with-github-actions | ||
|
||
name: Node.js CI | ||
|
||
on: | ||
push: | ||
branches: | ||
- master | ||
- final-updates | ||
pull_request: | ||
branches: | ||
-master | ||
|
||
jobs: | ||
build: | ||
|
||
runs-on: ubuntu-latest | ||
|
||
strategy: | ||
matrix: | ||
node-version: [12.x] | ||
# See supported Node.js release schedule at https://nodejs.org/en/about/releases/ | ||
|
||
steps: | ||
- uses: actions/checkout@v2 | ||
with: | ||
fetch-depth: 0 | ||
- name: Use Node.js ${{ matrix.node-version }} | ||
uses: actions/setup-node@v2 | ||
with: | ||
node-version: ${{ matrix.node-version }} | ||
|
||
- name: Install latest truffle | ||
run: npm -g install truffle | ||
|
||
- name: Setup for Consensys Academy | ||
if: ${{ github.repository_owner == 'Consensys-Academy' }} | ||
run: git checkout cea0c82a1a36991ea5943f8e315af30dde903b89 test/supply_chain.test.js | ||
|
||
- name: Setup for student grading | ||
if: ${{ github.repository_owner != 'Consensys-Academy' }} | ||
# get initial commit. this will be the first commit for repos created from template | ||
run: git checkout $(git rev-list --max-parents=0 master) test/supply_chain.test.js | ||
|
||
- name: Run tests | ||
run: truffle test test/supply_chain.test.js |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
build | ||
node_modules |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,121 @@ | ||
# Supply Chain Exercise | ||
|
||
The Supply Chain directory is a truffle project that contains the required | ||
contract, migration and test files. In this exercise you are going to implement | ||
the SupplyChain.sol contract and write some tests in Solidity. | ||
|
||
Clone this repo to your local machine. | ||
|
||
Follow the comments outlined in SupplyChain.sol (in the contracts directory) to | ||
implement its functions. We have written a set of tests (in javascript) to | ||
determine if your implementation is correct. As an additional challenge, try | ||
writing some Solidity tests in TestSupplyChain.sol. | ||
|
||
To test your implementation run `$ truffle test` from the terminal in the | ||
project directory. There are **23 pending tests** that you must pass to complete | ||
this exercise. | ||
|
||
## Instructions | ||
|
||
Check out the test file to see the tests that define the behavior of the | ||
SupplyChain smart contract. Notice the tests are in `it` blocks and have a | ||
`skip` modifier, which disables the test. To enable the test, remove the | ||
`.skip` modifier. Tests can have two modifiers: `skip` which skips the test, | ||
and `only` which runs only that test. But what if more than one test have the | ||
`only` modifier you may ask? Well only those test marked such will be executed. | ||
|
||
### State variables | ||
|
||
- [ ] should have an owner | ||
<details><summary>:book:</summary> | ||
|
||
The contract should have an owner, of type address that is public. | ||
**hint:** define a public variable `owner` of type address | ||
|
||
</details> | ||
|
||
- [ ] should have an skuCount | ||
<details><summary>:book:</summary> | ||
|
||
The contract will keep track of the | ||
[sku](https://en.wikipedia.org/wiki/Stock_keeping_unit)s in our supply | ||
chain. Each item for sale will have a unique sku number. | ||
|
||
**hint**: define a public variable called `skuCounter` of type uint | ||
|
||
</details> | ||
|
||
### enum State | ||
|
||
Items can exist in our Supply chain domain in a few states. In Solidity an | ||
`enum` can be used to represent these different states. Remove the `skip` | ||
annotation from the enum tests to proceed. | ||
|
||
- [ ] should define `ForSale` for when an item is put on sale | ||
- [ ] should define `Sold` for when an item has been purchased | ||
- [ ] should define `Shipped` for when an item has been shippd to the buyer | ||
- [ ] should define `Received` for when the shipped item has been received by the buyer | ||
|
||
### Item struct | ||
|
||
How do we describe an item in our supply chain? It is a union of properties: | ||
`name`, `sku`, `price`, `state`, `seller` and `buyer`. We can use a Solidity | ||
`struct` to model this Item. Remove the `skip` annotation from the `Item | ||
struct` tests and proceed. | ||
|
||
- [ ] should have a `name` | ||
- [ ] should have a `sku` | ||
- [ ] should have a `price` | ||
- [ ] should have a `state` | ||
- [ ] should have a `seller` | ||
- [ ] should have a `buyer` | ||
|
||
### SupplyChain Use cases | ||
|
||
**NOTE** Before proceeding, you should un-comment the `fetchItem` function in the contract. This function is necessary to validate the remaining tests. | ||
|
||
- [ ] should add an item with the provided name and price | ||
<details><summary>:book:</summary> | ||
use case: As a seller, I want to add an item for sale. I should | ||
</details> | ||
- [ ] should emit a LogForSale event when an item is added | ||
<details><summary>:book:</summary> | ||
use case: Whenever an item is added (placed for sale), the contract should | ||
emit a `LogForSale` event | ||
</details> | ||
- [ ] should allow someone to purchase an item and update state accordingly | ||
<details><summary>:book:</summary> | ||
use case: As a buyer, I want to purchase an item that is for sale. | ||
</details> | ||
- [ ] should error when not enough value is sent when purchasing an item | ||
<details><summary>:book:</summary> | ||
use case: A buyer will be notified when they do not have enough funds for the purchase | ||
</details> | ||
- [ ] should emit LogSold event when and item is purchased | ||
<details><summary>:book:</summary> | ||
use case: Whenever an item is bought (sold), the contract should emit a "LogSold" event | ||
</details> | ||
- [ ] should revert when someone that is not the seller tries to call shipItem() | ||
<details><summary>:book:</summary> | ||
use case: As a seller, only I can ship a bought item | ||
</details> | ||
- [ ] should allow the seller to mark the item as shipped | ||
<details><summary>:book:</summary> | ||
use case : Whenever an item is shipped, the seller should be able to mark the item as shipped | ||
</details> | ||
- [ ] should emit a LogShipped event when an item is shipped | ||
<details><summary>:book:</summary> | ||
use case: Whenever the item is shipped, the contract should emit a "LogShipped" event | ||
</details> | ||
- [ ] should allow the buyer to mark the item as received | ||
<details><summary>:book:</summary> | ||
use case: Whenever an item is recieved, the buyer should be able to mark the item as received | ||
</details> | ||
- [ ] should revert if an address other than the buyer calls receiveItem() | ||
<details><summary>:book:</summary> | ||
use case: As a buyer, only I can mark the item as received | ||
</details> | ||
- [ ] should emit a LogReceived event when an item is received | ||
<details><summary>:book:</summary> | ||
use case: Whenever an item is received, the contract should emit a "LogReceived" event | ||
</details> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
// SPDX-License-Identifier: MIT | ||
pragma solidity >=0.5.16 <0.9.0; | ||
|
||
contract Migrations { | ||
address public owner = msg.sender; | ||
uint public last_completed_migration; | ||
|
||
modifier restricted() { | ||
require( | ||
msg.sender == owner, | ||
"This function is restricted to the contract's owner" | ||
); | ||
_; | ||
} | ||
|
||
function setCompleted(uint completed) public restricted { | ||
last_completed_migration = completed; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,133 @@ | ||
// SPDX-License-Identifier: MIT | ||
pragma solidity >=0.5.16 <0.9.0; | ||
|
||
contract SupplyChain { | ||
|
||
// <owner> | ||
|
||
// <skuCount> | ||
|
||
// <items mapping> | ||
|
||
// <enum State: ForSale, Sold, Shipped, Received> | ||
|
||
// <struct Item: name, sku, price, state, seller, and buyer> | ||
|
||
/* | ||
* Events | ||
*/ | ||
|
||
// <LogForSale event: sku arg> | ||
|
||
// <LogSold event: sku arg> | ||
|
||
// <LogShipped event: sku arg> | ||
|
||
// <LogReceived event: sku arg> | ||
|
||
|
||
/* | ||
* Modifiers | ||
*/ | ||
|
||
// Create a modifer, `isOwner` that checks if the msg.sender is the owner of the contract | ||
|
||
// <modifier: isOwner | ||
|
||
modifier verifyCaller (address _address) { | ||
// require (msg.sender == _address); | ||
_; | ||
} | ||
|
||
modifier paidEnough(uint _price) { | ||
// require(msg.value >= _price); | ||
_; | ||
} | ||
|
||
modifier checkValue(uint _sku) { | ||
//refund them after pay for item (why it is before, _ checks for logic before func) | ||
_; | ||
// uint _price = items[_sku].price; | ||
// uint amountToRefund = msg.value - _price; | ||
// items[_sku].buyer.transfer(amountToRefund); | ||
} | ||
|
||
// For each of the following modifiers, use what you learned about modifiers | ||
// to give them functionality. For example, the forSale modifier should | ||
// require that the item with the given sku has the state ForSale. Note that | ||
// the uninitialized Item.State is 0, which is also the index of the ForSale | ||
// value, so checking that Item.State == ForSale is not sufficient to check | ||
// that an Item is for sale. Hint: What item properties will be non-zero when | ||
// an Item has been added? | ||
|
||
// modifier forSale | ||
// modifier sold(uint _sku) | ||
// modifier shipped(uint _sku) | ||
// modifier received(uint _sku) | ||
|
||
constructor() public { | ||
// 1. Set the owner to the transaction sender | ||
// 2. Initialize the sku count to 0. Question, is this necessary? | ||
} | ||
|
||
function addItem(string memory _name, uint _price) public returns (bool) { | ||
// 1. Create a new item and put in array | ||
// 2. Increment the skuCount by one | ||
// 3. Emit the appropriate event | ||
// 4. return true | ||
|
||
// hint: | ||
// items[skuCount] = Item({ | ||
// name: _name, | ||
// sku: skuCount, | ||
// price: _price, | ||
// state: State.ForSale, | ||
// seller: msg.sender, | ||
// buyer: address(0) | ||
//}); | ||
// | ||
//skuCount = skuCount + 1; | ||
// emit LogForSale(skuCount); | ||
// return true; | ||
} | ||
|
||
// Implement this buyItem function. | ||
// 1. it should be payable in order to receive refunds | ||
// 2. this should transfer money to the seller, | ||
// 3. set the buyer as the person who called this transaction, | ||
// 4. set the state to Sold. | ||
// 5. this function should use 3 modifiers to check | ||
// - if the item is for sale, | ||
// - if the buyer paid enough, | ||
// - check the value after the function is called to make | ||
// sure the buyer is refunded any excess ether sent. | ||
// 6. call the event associated with this function! | ||
function buyItem(uint sku) public {} | ||
|
||
// 1. Add modifiers to check: | ||
// - the item is sold already | ||
// - the person calling this function is the seller. | ||
// 2. Change the state of the item to shipped. | ||
// 3. call the event associated with this function! | ||
function shipItem(uint sku) public {} | ||
|
||
// 1. Add modifiers to check | ||
// - the item is shipped already | ||
// - the person calling this function is the buyer. | ||
// 2. Change the state of the item to received. | ||
// 3. Call the event associated with this function! | ||
function receiveItem(uint sku) public {} | ||
|
||
// Uncomment the following code block. it is needed to run tests | ||
/* function fetchItem(uint _sku) public view */ | ||
/* returns (string memory name, uint sku, uint price, uint state, address seller, address buyer) */ | ||
/* { */ | ||
/* name = items[_sku].name; */ | ||
/* sku = items[_sku].sku; */ | ||
/* price = items[_sku].price; */ | ||
/* state = uint(items[_sku].state); */ | ||
/* seller = items[_sku].seller; */ | ||
/* buyer = items[_sku].buyer; */ | ||
/* return (name, sku, price, state, seller, buyer); */ | ||
/* } */ | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
var Migrations = artifacts.require("./Migrations.sol"); | ||
|
||
module.exports = function(deployer) { | ||
deployer.deploy(Migrations); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
//var SimpleBank = artifacts.require("./SimpleBank.sol"); | ||
var SupplyChain = artifacts.require("./SupplyChain.sol"); | ||
|
||
module.exports = function(deployer) { | ||
//deployer.deploy(SimpleBank); | ||
deployer.deploy(SupplyChain); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
pragma solidity ^0.5.0; | ||
|
||
import "truffle/Assert.sol"; | ||
import "truffle/DeployedAddresses.sol"; | ||
import "../contracts/SupplyChain.sol"; | ||
|
||
contract TestSupplyChain { | ||
|
||
// Test for failing conditions in this contracts: | ||
// https://truffleframework.com/tutorials/testing-for-throws-in-solidity-tests | ||
|
||
// buyItem | ||
|
||
// test for failure if user does not send enough funds | ||
// test for purchasing an item that is not for Sale | ||
|
||
// shipItem | ||
|
||
// test for calls that are made by not the seller | ||
// test for trying to ship an item that is not marked Sold | ||
|
||
// receiveItem | ||
|
||
// test calling the function from an address that is not the buyer | ||
// test calling the function on an item not marked Shipped | ||
|
||
} |
Oops, something went wrong.