Skip to content

Commit

Permalink
Initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
github-classroom[bot] committed Sep 23, 2021
0 parents commit 4d85f9b
Show file tree
Hide file tree
Showing 12 changed files with 779 additions and 0 deletions.
47 changes: 47 additions & 0 deletions .github/workflows/node.js.yml
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
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
build
node_modules
121 changes: 121 additions & 0 deletions README.md
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>
19 changes: 19 additions & 0 deletions contracts/Migrations.sol
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;
}
}
133 changes: 133 additions & 0 deletions contracts/SupplyChain.sol
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); */
/* } */
}
5 changes: 5 additions & 0 deletions migrations/1_initial_migration.js
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);
};
7 changes: 7 additions & 0 deletions migrations/2_deploy_contracts.js
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);
};
27 changes: 27 additions & 0 deletions test/TestSupplyChain.sol
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

}
Loading

0 comments on commit 4d85f9b

Please sign in to comment.