From b9947837c249be1bf076b34b5d1f1961ed7c4913 Mon Sep 17 00:00:00 2001 From: Kellan Wampler Date: Tue, 27 Feb 2024 09:25:23 -0500 Subject: [PATCH 01/17] Adding stats and leaderboard queries for Sepolia. --- api/queries/sepolia/home_run_leaderboard.sql | 55 ++++++++ api/queries/sepolia/pitch_distribution.sql | 50 +++++++ api/queries/sepolia/player_stats_atbat.sql | 122 ++++++++++++++++++ api/queries/sepolia/strikeout_leaderboard.sql | 55 ++++++++ api/queries/sepolia/swing_distribution.sql | 50 +++++++ .../{ => wyrm}/home_run_leaderboard.sql | 0 api/queries/wyrm/pitch_distribution.sql | 52 ++++++++ api/queries/{ => wyrm}/player_stats_atbat.sql | 0 .../{ => wyrm}/strikeout_leaderboard.sql | 0 api/queries/{ => wyrm}/swing_distribution.sql | 0 10 files changed, 384 insertions(+) create mode 100644 api/queries/sepolia/home_run_leaderboard.sql create mode 100644 api/queries/sepolia/pitch_distribution.sql create mode 100644 api/queries/sepolia/player_stats_atbat.sql create mode 100644 api/queries/sepolia/strikeout_leaderboard.sql create mode 100644 api/queries/sepolia/swing_distribution.sql rename api/queries/{ => wyrm}/home_run_leaderboard.sql (100%) create mode 100644 api/queries/wyrm/pitch_distribution.sql rename api/queries/{ => wyrm}/player_stats_atbat.sql (100%) rename api/queries/{ => wyrm}/strikeout_leaderboard.sql (100%) rename api/queries/{ => wyrm}/swing_distribution.sql (100%) diff --git a/api/queries/sepolia/home_run_leaderboard.sql b/api/queries/sepolia/home_run_leaderboard.sql new file mode 100644 index 00000000..0c288b4f --- /dev/null +++ b/api/queries/sepolia/home_run_leaderboard.sql @@ -0,0 +1,55 @@ +with dedup_events as ( + SELECT + DISTINCT ON(transaction_hash, log_index) * + FROM arbitrum_sepolia_labels + WHERE label='moonworm-alpha' + AND address='0x3a1Ad54d12b1f39805Ea77aFe7DeeFf2F32C97f5' + AND log_index IS NOT NULL +), AtBats as ( + SELECT + label_data->'args'->>'sessionID' as session_id, + label_data->'args'->>'outcome' as outcome, + label_data->'args'->>'batterAddress' as batter_address, + label_data->'args'->>'batterTokenID' as batter_token_id, + label_data->'args'->>'pitcherAddress' as pitcher_address, + label_data->'args'->>'pitcherTokenID' as pitcher_token_id, + log_index + FROM dedup_events + WHERE label_data->>'name'='AtBatProgress' AND label_data->'args'->>'outcome'!='0' +), batter_stats as ( + SELECT + SUM(CASE + WHEN outcome = '1' THEN 1 ELSE 0 + END) as strikeouts, + SUM(CASE + WHEN outcome = '2' THEN 1 ELSE 0 + END) as walks, + SUM(CASE + WHEN outcome = '3' THEN 1 ELSE 0 + END) as singles, + SUM(CASE + WHEN outcome = '4' THEN 1 ELSE 0 + END) as doubles, + SUM(CASE + WHEN outcome = '5' THEN 1 ELSE 0 + END) as triples, + SUM(CASE + WHEN outcome = '6' THEN 1 ELSE 0 + END) as home_runs, + SUM(CASE + WHEN outcome = '7' THEN 1 ELSE 0 + END) as in_play_outs, + count(*) as total_batter_events, + batter_address as batter_address, + batter_token_id as batter_token_id + FROM AtBats + GROUP BY batter_address, batter_token_id + ORDER BY home_runs DESC +) +select + batter_address || '_' || batter_token_id as address, + home_runs as score, + json_build_object( + 'home_runs', home_runs + ) as points_data +from batter_stats \ No newline at end of file diff --git a/api/queries/sepolia/pitch_distribution.sql b/api/queries/sepolia/pitch_distribution.sql new file mode 100644 index 00000000..bd27806d --- /dev/null +++ b/api/queries/sepolia/pitch_distribution.sql @@ -0,0 +1,50 @@ +with dedup_events as ( + SELECT + DISTINCT ON(transaction_hash, log_index) * + FROM arbitrum_sepolia_labels + WHERE label='moonworm-alpha' + AND address='0x3a1Ad54d12b1f39805Ea77aFe7DeeFf2F32C97f5' + AND log_index IS NOT NULL +), SessionResolved as ( + SELECT + address as contract_address, + label_data->'args'->>'sessionID' as session_id, + label_data->'args'->>'outcome' as outcome, + label_data->'args'->>'batterAddress' as batter_address, + label_data->'args'->>'batterTokenID' as batter_token_id, + label_data->'args'->>'pitcherAddress' as pitcher_address, + label_data->'args'->>'pitcherTokenID' as pitcher_token_id, + log_index + FROM dedup_events + WHERE label_data->>'name'='SessionResolved' +), PitchRevealed as ( + SELECT + address as contract_address, + label_data->'args'->>'sessionID' as session_id, + label_data->'args'->'pitch'-> 1 as pitch_speed, + label_data->'args'->'pitch'-> 2 as pitch_vertical, + label_data->'args'->'pitch'-> 3 as pitch_horizontal, + log_index + FROM dedup_events + WHERE label_data->>'name'='PitchRevealed' +), PitchDistribution as ( + SELECT + pitcher_address || '_' || pitcher_token_id as address, + pitch_speed, + pitch_vertical, + pitch_horizontal, + count(*) as pitch_count + FROM SessionResolved LEFT JOIN PitchRevealed ON (SessionResolved.contract_address=PitchRevealed.contract_address AND SessionResolved.session_id = PitchRevealed.session_id) + GROUP BY pitcher_address, pitcher_token_id, pitch_speed, pitch_vertical, pitch_horizontal + ORDER BY pitch_speed, pitch_vertical, pitch_horizontal +) +SELECT + address, + json_agg(json_build_object( + 'pitch_speed', pitch_speed, + 'pitch_vertical', pitch_vertical, + 'pitch_horizontal', pitch_horizontal, + 'count', pitch_count + )) as pitch_distribution +FROM PitchDistribution +GROUP BY address \ No newline at end of file diff --git a/api/queries/sepolia/player_stats_atbat.sql b/api/queries/sepolia/player_stats_atbat.sql new file mode 100644 index 00000000..f1e2741d --- /dev/null +++ b/api/queries/sepolia/player_stats_atbat.sql @@ -0,0 +1,122 @@ +with dedup_events as ( + SELECT + DISTINCT ON(transaction_hash, log_index) * + FROM arbitrum_sepolia_labels + WHERE label='moonworm-alpha' + AND address='0x3a1Ad54d12b1f39805Ea77aFe7DeeFf2F32C97f5' + AND log_index IS NOT NULL +), AtBats as ( + SELECT + label_data->'args'->>'sessionID' as session_id, + label_data->'args'->>'outcome' as outcome, + label_data->'args'->>'batterAddress' as batter_address, + label_data->'args'->>'batterTokenID' as batter_token_id, + label_data->'args'->>'pitcherAddress' as pitcher_address, + label_data->'args'->>'pitcherTokenID' as pitcher_token_id, + log_index + FROM dedup_events + WHERE label_data->>'name'='AtBatProgress' AND label_data->'args'->>'outcome'!='0' +), batter_stats as ( + SELECT + SUM(CASE + WHEN outcome = '1' THEN 1 ELSE 0 + END) as strikeouts, + SUM(CASE + WHEN outcome = '2' THEN 1 ELSE 0 + END) as walks, + SUM(CASE + WHEN outcome = '3' THEN 1 ELSE 0 + END) as singles, + SUM(CASE + WHEN outcome = '4' THEN 1 ELSE 0 + END) as doubles, + SUM(CASE + WHEN outcome = '5' THEN 1 ELSE 0 + END) as triples, + SUM(CASE + WHEN outcome = '6' THEN 1 ELSE 0 + END) as home_runs, + SUM(CASE + WHEN outcome = '7' THEN 1 ELSE 0 + END) as in_play_outs, + count(*) as total_batter_events, + batter_address as batter_address, + batter_token_id as batter_token_id + FROM AtBats + GROUP BY batter_address, batter_token_id +), pitcher_stats as ( + SELECT + SUM(CASE + WHEN outcome = '1' THEN 1 ELSE 0 + END) as strikeouts, + SUM(CASE + WHEN outcome = '2' THEN 1 ELSE 0 + END) as walks, + SUM(CASE + WHEN outcome = '3' THEN 1 ELSE 0 + END) as singles, + SUM(CASE + WHEN outcome = '4' THEN 1 ELSE 0 + END) as doubles, + SUM(CASE + WHEN outcome = '5' THEN 1 ELSE 0 + END) as triples, + SUM(CASE + WHEN outcome = '6' THEN 1 ELSE 0 + END) as home_runs, + SUM(CASE + WHEN outcome = '7' THEN 1 ELSE 0 + END) as in_play_outs, + count(*) as total_pitcher_events, + pitcher_address, + pitcher_token_id + FROM AtBats + GROUP BY pitcher_address, pitcher_token_id +), pitcher_data as ( + select + pitcher_address || '_' || pitcher_token_id as address, + json_build_object( + 'strikeouts', strikeouts, + 'walks', walks, + 'singles', singles, + 'doubles', doubles, + 'triples', triples, + 'home_runs', home_runs, + 'in_play_outs', in_play_outs, + 'innings', (strikeouts + in_play_outs) / 3.0, + 'earned_runs', 1.5 * singles + 2.5 * doubles + 3 * triples + 4 * home_runs, + 'earned_run_average', 9.0 * (1.5 * singles + 2.5 * doubles + 3 * triples + 4 * home_runs) / NULLIF((strikeouts + in_play_outs) / 3.0, 0), + 'whip', (walks + singles + doubles + triples + home_runs) / NULLIF((strikeouts + in_play_outs) / 3.0, 0), + 'batting_average_against', 1.0 * (singles + doubles + triples + home_runs) / NULLIF(total_pitcher_events - walks, 0) + ) as points_data + from pitcher_stats +), batter_data as ( + select + batter_address || '_' || batter_token_id as address, + json_build_object( + 'strikeouts', strikeouts, + 'walks', walks, + 'singles', singles, + 'doubles', doubles, + 'triples', triples, + 'home_runs', home_runs, + 'in_play_outs', in_play_outs, + 'at_bats', total_batter_events - walks, + 'hits', singles + doubles + triples + home_runs, + 'runs_batted_in', walks + 1.5 * singles + 2.5 * doubles + 3 * triples + 4 * home_runs, + 'batting_average', 1.0 * (singles + doubles + triples + home_runs) / NULLIF(total_batter_events - walks, 0), + 'on-base', 1.0 * (walks + singles + doubles + triples + home_runs) / NULLIF(total_batter_events, 0), + 'slugging', (1.0 * singles + 2.0 * doubles + 3.0 * triples + 4.0 * home_runs) / NULLIF(total_batter_events - walks, 0), + 'ops', COALESCE(1.0 * (walks + singles + doubles + triples + home_runs) / NULLIF(total_batter_events, 0), 0) + + COALESCE((1.0 * singles + 2.0 * doubles + 3.0 * triples + 4.0 * home_runs) / NULLIF(total_batter_events - walks, 0), 0) + ) as points_data + from batter_stats +) +select + COALESCE(batter_data.address, pitcher_data.address) as address, + 0 as score, + json_build_object( + 'batting_data', batter_data.points_data, + 'pitching_data', pitcher_data.points_data + ) as points_data +from batter_data full outer join pitcher_data on batter_data.address = pitcher_data.address \ No newline at end of file diff --git a/api/queries/sepolia/strikeout_leaderboard.sql b/api/queries/sepolia/strikeout_leaderboard.sql new file mode 100644 index 00000000..8aa43a44 --- /dev/null +++ b/api/queries/sepolia/strikeout_leaderboard.sql @@ -0,0 +1,55 @@ +with dedup_events as ( + SELECT + DISTINCT ON(transaction_hash, log_index) * + FROM arbitrum_sepolia_labels + WHERE label='moonworm-alpha' + AND address='0x3a1Ad54d12b1f39805Ea77aFe7DeeFf2F32C97f5' + AND log_index IS NOT NULL +), AtBats as ( + SELECT + label_data->'args'->>'sessionID' as session_id, + label_data->'args'->>'outcome' as outcome, + label_data->'args'->>'batterAddress' as batter_address, + label_data->'args'->>'batterTokenID' as batter_token_id, + label_data->'args'->>'pitcherAddress' as pitcher_address, + label_data->'args'->>'pitcherTokenID' as pitcher_token_id, + log_index + FROM dedup_events + WHERE label_data->>'name'='AtBatProgress' AND label_data->'args'->>'outcome'!='0' +), pitcher_stats as ( + SELECT + SUM(CASE + WHEN outcome = '1' THEN 1 ELSE 0 + END) as strikeouts, + SUM(CASE + WHEN outcome = '2' THEN 1 ELSE 0 + END) as walks, + SUM(CASE + WHEN outcome = '3' THEN 1 ELSE 0 + END) as singles, + SUM(CASE + WHEN outcome = '4' THEN 1 ELSE 0 + END) as doubles, + SUM(CASE + WHEN outcome = '5' THEN 1 ELSE 0 + END) as triples, + SUM(CASE + WHEN outcome = '6' THEN 1 ELSE 0 + END) as home_runs, + SUM(CASE + WHEN outcome = '7' THEN 1 ELSE 0 + END) as in_play_outs, + count(*) as total_pitcher_events, + pitcher_address, + pitcher_token_id + FROM AtBats + GROUP BY pitcher_address, pitcher_token_id + ORDER BY strikeouts DESC +) +select + pitcher_address || '_' || pitcher_token_id as address, + strikeouts as score, + json_build_object( + 'strikeouts', strikeouts + ) as points_data +from pitcher_stats \ No newline at end of file diff --git a/api/queries/sepolia/swing_distribution.sql b/api/queries/sepolia/swing_distribution.sql new file mode 100644 index 00000000..bc4d915f --- /dev/null +++ b/api/queries/sepolia/swing_distribution.sql @@ -0,0 +1,50 @@ +with dedup_events as ( + SELECT + DISTINCT ON(transaction_hash, log_index) * + FROM arbitrum_sepolia_labels + WHERE label='moonworm-alpha' + AND address='0x3a1Ad54d12b1f39805Ea77aFe7DeeFf2F32C97f5' + AND log_index IS NOT NULL +), SessionResolved as ( + SELECT + address as contract_address, + label_data->'args'->>'sessionID' as session_id, + label_data->'args'->>'outcome' as outcome, + label_data->'args'->>'batterAddress' as batter_address, + label_data->'args'->>'batterTokenID' as batter_token_id, + label_data->'args'->>'pitcherAddress' as pitcher_address, + label_data->'args'->>'pitcherTokenID' as pitcher_token_id, + log_index + FROM dedup_events + WHERE label_data->>'name'='SessionResolved' +), SwingRevealed as ( + SELECT + address as contract_address, + label_data->'args'->>'sessionID' as session_id, + label_data->'args'->'swing'-> 1 as swing_type, + label_data->'args'->'swing'-> 2 as swing_vertical, + label_data->'args'->'swing'-> 3 as swing_horizontal, + log_index + FROM dedup_events + WHERE label_data->>'name'='SwingRevealed' +), SwingDistribution as ( + SELECT + batter_address || '_' || batter_token_id as address, + swing_type, + swing_vertical, + swing_horizontal, + count(*) as swing_count + FROM SessionResolved LEFT JOIN SwingRevealed ON (SessionResolved.contract_address=SwingRevealed.contract_address AND SessionResolved.session_id = SwingRevealed.session_id) + GROUP BY batter_address, batter_token_id, swing_type, swing_vertical, swing_horizontal + ORDER BY swing_type, swing_vertical, swing_horizontal +) +SELECT + address, + json_agg(json_build_object( + 'swing_type', swing_type, + 'swing_vertical', swing_vertical, + 'swing_horizontal', swing_horizontal, + 'count', swing_count + )) as swing_distribution +FROM SwingDistribution +GROUP BY address \ No newline at end of file diff --git a/api/queries/home_run_leaderboard.sql b/api/queries/wyrm/home_run_leaderboard.sql similarity index 100% rename from api/queries/home_run_leaderboard.sql rename to api/queries/wyrm/home_run_leaderboard.sql diff --git a/api/queries/wyrm/pitch_distribution.sql b/api/queries/wyrm/pitch_distribution.sql new file mode 100644 index 00000000..bbfa97ae --- /dev/null +++ b/api/queries/wyrm/pitch_distribution.sql @@ -0,0 +1,52 @@ +with dedup_events as ( + SELECT + DISTINCT ON(transaction_hash, log_index) * + FROM wyrm_labels + WHERE label='moonworm-alpha' + AND (address='0xde191e8c352BA59F95cf19f0931cCbBcc7B60934' + OR address='0x9270df8d907A99E5024dc3532657a5cF9C7A4889' + OR address='0xC90F37D09f2f8fB2e9D1Aa9a9d5142f5aE100d84') + AND log_index IS NOT NULL +), SessionResolved as ( + SELECT + address as contract_address, + label_data->'args'->>'sessionID' as session_id, + label_data->'args'->>'outcome' as outcome, + label_data->'args'->>'batterAddress' as batter_address, + label_data->'args'->>'batterTokenID' as batter_token_id, + label_data->'args'->>'pitcherAddress' as pitcher_address, + label_data->'args'->>'pitcherTokenID' as pitcher_token_id, + log_index + FROM dedup_events + WHERE label_data->>'name'='SessionResolved' +), PitchRevealed as ( + SELECT + address as contract_address, + label_data->'args'->>'sessionID' as session_id, + label_data->'args'->'pitch'-> 1 as pitch_speed, + label_data->'args'->'pitch'-> 2 as pitch_vertical, + label_data->'args'->'pitch'-> 3 as pitch_horizontal, + log_index + FROM dedup_events + WHERE label_data->>'name'='PitchRevealed' +), PitchDistribution as ( + SELECT + pitcher_address || '_' || pitcher_token_id as address, + pitch_speed, + pitch_vertical, + pitch_horizontal, + count(*) as pitch_count + FROM SessionResolved LEFT JOIN PitchRevealed ON (SessionResolved.contract_address=PitchRevealed.contract_address AND SessionResolved.session_id = PitchRevealed.session_id) + GROUP BY pitcher_address, pitcher_token_id, pitch_speed, pitch_vertical, pitch_horizontal + ORDER BY pitch_speed, pitch_vertical, pitch_horizontal +) +SELECT + address, + json_agg(json_build_object( + 'pitch_speed', pitch_speed, + 'pitch_vertical', pitch_vertical, + 'pitch_horizontal', pitch_horizontal, + 'count', pitch_count + )) as pitch_distribution +FROM PitchDistribution +GROUP BY address \ No newline at end of file diff --git a/api/queries/player_stats_atbat.sql b/api/queries/wyrm/player_stats_atbat.sql similarity index 100% rename from api/queries/player_stats_atbat.sql rename to api/queries/wyrm/player_stats_atbat.sql diff --git a/api/queries/strikeout_leaderboard.sql b/api/queries/wyrm/strikeout_leaderboard.sql similarity index 100% rename from api/queries/strikeout_leaderboard.sql rename to api/queries/wyrm/strikeout_leaderboard.sql diff --git a/api/queries/swing_distribution.sql b/api/queries/wyrm/swing_distribution.sql similarity index 100% rename from api/queries/swing_distribution.sql rename to api/queries/wyrm/swing_distribution.sql From 6049504596c322e471a4d86134b94df22da28590 Mon Sep 17 00:00:00 2001 From: Kellan Wampler Date: Wed, 13 Mar 2024 10:27:06 -0400 Subject: [PATCH 02/17] First pass at adding profile images. --- src/Players.sol | 49 ++++++++++++++++---------- test/Players.t.sol | 88 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 119 insertions(+), 18 deletions(-) create mode 100644 test/Players.t.sol diff --git a/src/Players.sol b/src/Players.sol index a3e741f1..7c71b03e 100644 --- a/src/Players.sol +++ b/src/Players.sol @@ -6,9 +6,10 @@ import { ERC721 } from "../lib/openzeppelin-contracts/contracts/token/ERC721/ERC import { ERC721Enumerable } from "../lib/openzeppelin-contracts/contracts/token/ERC721/extensions/ERC721Enumerable.sol"; import { Base64 } from "../lib/openzeppelin-contracts/contracts/utils/Base64.sol"; import { Strings } from "../lib/openzeppelin-contracts/contracts/utils/Strings.sol"; +import { ITerminus } from "lib/web3/contracts/interfaces/Iterminus.sol"; contract BeerLeagueBallers is ERC721Enumerable { - string[24] public ProfileImages = [ + string[] public ProfileImages = [ "https://badges.moonstream.to/blb/p0.png", "https://badges.moonstream.to/blb/p1.png", "https://badges.moonstream.to/blb/p2.png", @@ -17,28 +18,40 @@ contract BeerLeagueBallers is ERC721Enumerable { "https://badges.moonstream.to/blb/p5.png", "https://badges.moonstream.to/blb/p6.png", "https://badges.moonstream.to/blb/p7.png", - "https://badges.moonstream.to/blb/p8.png", - "https://badges.moonstream.to/blb/p9.png", - "https://badges.moonstream.to/blb/p10.png", - "https://badges.moonstream.to/blb/p11.png", - "https://badges.moonstream.to/blb/p12.png", - "https://badges.moonstream.to/blb/p13.png", - "https://badges.moonstream.to/blb/p14.png", - "https://badges.moonstream.to/blb/p15.png", - "https://badges.moonstream.to/blb/p16.png", - "https://badges.moonstream.to/blb/p17.png", - "https://badges.moonstream.to/blb/p18.png", - "https://badges.moonstream.to/blb/p19.png", - "https://badges.moonstream.to/blb/p20.png", - "https://badges.moonstream.to/blb/p21.png", - "https://badges.moonstream.to/blb/p22.png", - "https://badges.moonstream.to/blb/p23.png" + "https://badges.moonstream.to/blb/p8.png" ]; mapping(uint256 => string) public Name; mapping(uint256 => uint256) public ImageIndex; - constructor() ERC721("Beer League Ballers", "BLB") { } + address adminTerminus; + uint256 adminPoolID; + + constructor(address _adminTerminus, uint256 _adminPoolID) ERC721("Beer League Ballers", "BLB") { + adminTerminus = _adminTerminus; + adminPoolID = _adminPoolID; + } + + function _enforceIsAdmin() internal view { + ITerminus terminus = ITerminus(address(adminTerminus)); + require(terminus.balanceOf(msg.sender, adminPoolID) > 0, "BeerLeagueBallers._enforceIsAdmin: not admin"); + } + + function getProfileImageCount() external view returns (uint256) { + return ProfileImages.length; + } + + function addProfileImage(string memory newImage) public { + _enforceIsAdmin(); + + ProfileImages.push(newImage); + } + + function setProfileImage(uint256 index, string memory newImage) public { + _enforceIsAdmin(); + + ProfileImages[index] = newImage; + } function mint(string memory name, uint256 imageIndex) public returns (uint256) { require(imageIndex < ProfileImages.length, "BLB.mint: invalid image index"); diff --git a/test/Players.t.sol b/test/Players.t.sol new file mode 100644 index 00000000..9c46adc6 --- /dev/null +++ b/test/Players.t.sol @@ -0,0 +1,88 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.8.13; + +import { Test } from "../lib/forge-std/src/Test.sol"; +import { console2 as console } from "../lib/forge-std/src/console2.sol"; +import { BeerLeagueBallers } from "../src/Players.sol"; +// import { TerminusFacet } from "../lib/web3/contracts/terminus/TerminusFacet.sol"; +import "@openzeppelin-contracts/contracts/token/ERC1155/extensions/ERC1155Burnable.sol"; + +contract MockERC1155 is ERC1155Burnable { + constructor() ERC1155("lol://lol") { } + + function mint(address to, uint256 id, uint256 amount, bytes memory data) public virtual { + _mint(to, id, amount, data); + } + + function mintBatch(address to, uint256[] memory ids, uint256[] memory amounts, bytes memory data) public virtual { + _mintBatch(to, ids, amounts, data); + } +} + +// contract MockTerminus is TerminusFacet { +// constructor() { } +// } + +contract PlayersTestBase is Test { + BeerLeagueBallers players; + MockERC1155 terminus; + + uint256 adminPrivateKey = 0x1; + uint256 randomPersonPrivateKey = 0x77; + + address admin = vm.addr(adminPrivateKey); + address randomPerson = vm.addr(randomPersonPrivateKey); + + uint256 adminPoolID = 1; + + function setUp() public virtual { + terminus = new MockERC1155(); + terminus.mint(address(admin), adminPoolID, 1, ""); + + players = new BeerLeagueBallers(address(terminus), 1); + } +} + +contract PlayersTestAdmin is PlayersTestBase { + function test_admin_can_add_profile_image() public { + uint256 initialImageCount = players.getProfileImageCount(); + + vm.prank(admin); + players.addProfileImage("http://www.example.com"); + + assertEq(players.getProfileImageCount(), initialImageCount + 1); + } + + function test_non_admin_cannot_add_profile_image() public { + uint256 initialImageCount = players.getProfileImageCount(); + + vm.prank(randomPerson); + vm.expectRevert("BeerLeagueBallers._enforceIsAdmin: not admin"); + players.addProfileImage("http://www.example.com"); + + assertEq(players.getProfileImageCount(), initialImageCount); + } + + function test_admin_can_set_profile_image() public { + uint256 index = 1; + string memory initialImage = players.ProfileImages(index); + + vm.prank(admin); + players.setProfileImage(index, "http://www.example.com"); + + assertEq(players.ProfileImages(index), "http://www.example.com"); + assertNotEq(players.ProfileImages(index), initialImage); + } + + function test_non_admin_cannot_set_profile_image() public { + uint256 index = 1; + string memory initialImage = players.ProfileImages(index); + + vm.prank(randomPerson); + vm.expectRevert("BeerLeagueBallers._enforceIsAdmin: not admin"); + players.setProfileImage(index, "http://www.example.com"); + + assertEq(players.ProfileImages(index), initialImage); + assertNotEq(players.ProfileImages(index), "http://www.example.com"); + } +} From 9311ca671cbc376cfd5dcdb6ae7d859f7bfdaa56 Mon Sep 17 00:00:00 2001 From: Kellan Wampler Date: Sun, 17 Mar 2024 22:17:52 -0400 Subject: [PATCH 03/17] Cli to calculate distance frequencies and average distance from location to a uniform random location. --- python/fullcount/cli.py | 18 +++++++++++++----- python/fullcount/data.py | 12 ++++++++---- 2 files changed, 21 insertions(+), 9 deletions(-) diff --git a/python/fullcount/cli.py b/python/fullcount/cli.py index 15b35d38..fe31d79e 100644 --- a/python/fullcount/cli.py +++ b/python/fullcount/cli.py @@ -1,6 +1,6 @@ import argparse -from . import BeerLeagueBallers, Fullcount, generation_1, randomness, generators, signatures +from . import BeerLeagueBallers, Fullcount, generation_1, randomness, generators, signatures, tuning def generate_cli() -> argparse.ArgumentParser: @@ -14,22 +14,30 @@ def generate_cli() -> argparse.ArgumentParser: subparsers = parser.add_subparsers() contract_parser = Fullcount.generate_cli() - subparsers.add_parser("contract", parents=[contract_parser], add_help=False) + subparsers.add_parser("contract", parents=[ + contract_parser], add_help=False) generation_1_parser = generation_1.generate_cli() - subparsers.add_parser("gen-1", parents=[generation_1_parser], add_help=False) + subparsers.add_parser( + "gen-1", parents=[generation_1_parser], add_help=False) blb_parser = BeerLeagueBallers.generate_cli() subparsers.add_parser("blb", parents=[blb_parser], add_help=False) randomness_parser = randomness.generate_cli() - subparsers.add_parser("randomness", parents=[randomness_parser], add_help=False) + subparsers.add_parser("randomness", parents=[ + randomness_parser], add_help=False) codegen_parser = generators.generate_cli() subparsers.add_parser("codegen", parents=[codegen_parser], add_help=False) signatures_parser = signatures.generate_cli() - subparsers.add_parser("signatures", parents=[signatures_parser], add_help=False) + subparsers.add_parser("signatures", parents=[ + signatures_parser], add_help=False) + + tuning_parser = tuning.generate_cli() + subparsers.add_parser("tuning", parents=[ + tuning_parser], add_help=False) return parser diff --git a/python/fullcount/data.py b/python/fullcount/data.py index ac40d0b2..8a5eab10 100644 --- a/python/fullcount/data.py +++ b/python/fullcount/data.py @@ -130,14 +130,16 @@ def l1_distance( assert swing_type != SwingType.Take, "Distance not used when batter chooses Take" return ( abs(pitch_horizontal_location.value - swing_horizontal_location.value) - + abs(pitch_vertical_location.value - swing_vertical_location.value) + + 2 * abs(pitch_vertical_location.value - + swing_vertical_location.value) + abs(pitch_type.value - swing_type.value) ) def sample(distribution: OutcomeDistribution) -> Outcome: roll = random.randint(0, 9999) - outcome_index = min(i for i in range(8) if sum(distribution[: i + 1]) > roll) + outcome_index = min(i for i in range( + 8) if sum(distribution[: i + 1]) > roll) return Outcome(outcome_index) @@ -146,7 +148,9 @@ def configure_move_type_handler( ) -> None: parser.add_argument("--pitch-type", "-t", type=int, required=required) parser.add_argument("--pitch-vertical", "-v", type=int, required=required) - parser.add_argument("--pitch-horizontal", "-z", type=int, required=required) + parser.add_argument("--pitch-horizontal", "-z", + type=int, required=required) parser.add_argument("--swing-type", "-T", type=int, required=required) parser.add_argument("--swing-vertical", "-V", type=int, required=required) - parser.add_argument("--swing-horizontal", "-Z", type=int, required=required) + parser.add_argument("--swing-horizontal", "-Z", + type=int, required=required) From 2794236b7db0f604eacfa996c8831b1f4b2dab55 Mon Sep 17 00:00:00 2001 From: Kellan Wampler Date: Sun, 17 Mar 2024 22:44:39 -0400 Subject: [PATCH 04/17] Removing session expiration when no one has joined. --- src/Fullcount.sol | 11 +++++---- test/Fullcount.t.sol | 55 ++++++++++++++++++++++++++++++++++---------- 2 files changed, 50 insertions(+), 16 deletions(-) diff --git a/src/Fullcount.sol b/src/Fullcount.sol index 6c2d85e2..4e78a657 100644 --- a/src/Fullcount.sol +++ b/src/Fullcount.sol @@ -186,7 +186,7 @@ contract Fullcount is EIP712 { if (session.didPitcherReveal && session.didBatterReveal) { return 5; - } else if (session.phaseStartTimestamp + SecondsPerPhase < block.timestamp) { + } else if (session.phaseStartTimestamp > 0 && session.phaseStartTimestamp + SecondsPerPhase < block.timestamp) { return 6; } else if (session.pitcherNFT.nftAddress == address(0) || session.batterNFT.nftAddress == address(0)) { if (session.pitcherLeftSession || session.batterLeftSession) { @@ -243,7 +243,7 @@ contract Fullcount is EIP712 { StakedSession[nftAddress][tokenID] = NumSessions; - SessionState[NumSessions].phaseStartTimestamp = block.timestamp; + // SessionState[NumSessions].phaseStartTimestamp = block.timestamp; SessionRequiresSignature[NumSessions] = requireSignature; @@ -474,7 +474,7 @@ contract Fullcount is EIP712 { SessionAtBat[nextSessionID] = atBatID; } - // TODO Change name of function as tokens are no longer staked? + // Possibly change name of function as tokens are no longer staked? function _unstakeNFT(address nftAddress, uint256 tokenID) internal { require(_isTokenOwner(nftAddress, tokenID), "Fullcount._unstakeNFT: msg.sender is not NFT owner"); @@ -500,7 +500,10 @@ contract Fullcount is EIP712 { function unstakeNFT(address nftAddress, uint256 tokenID) external { uint256 progress = _sessionProgress(StakedSession[nftAddress][tokenID]); - require(progress == 5 || progress == 6, "Fullcount.unstakeNFT: cannot unstake from session in this state"); + require( + progress == 2 || progress == 5 || progress == 6, + "Fullcount.unstakeNFT: cannot unstake from session in this state" + ); _unstakeNFT(nftAddress, tokenID); } diff --git a/test/Fullcount.t.sol b/test/Fullcount.t.sol index 97779e2f..c9eb979e 100644 --- a/test/Fullcount.t.sol +++ b/test/Fullcount.t.sol @@ -245,7 +245,7 @@ contract FullcountTest_startSession is FullcountTestBase { assertEq(terminalNumSessions, initialNumSessions + 1); Session memory session = game.getSession(sessionID); - assertEq(session.phaseStartTimestamp, block.timestamp); + assertEq(session.phaseStartTimestamp, 0); assertEq(session.pitcherNFT.nftAddress, address(characterNFTs)); assertEq(session.pitcherNFT.tokenID, tokenID); assertEq(session.batterNFT.nftAddress, address(0)); @@ -274,7 +274,7 @@ contract FullcountTest_startSession is FullcountTestBase { assertEq(terminalNumSessions, initialNumSessions + 1); Session memory session = game.getSession(sessionID); - assertEq(session.phaseStartTimestamp, block.timestamp); + assertEq(session.phaseStartTimestamp, 0); assertEq(session.batterNFT.nftAddress, address(characterNFTs)); assertEq(session.batterNFT.tokenID, tokenID); assertEq(session.pitcherNFT.nftAddress, address(0)); @@ -314,6 +314,45 @@ contract FullcountTest_startSession is FullcountTestBase { vm.stopPrank(); } + + function test_session_with_only_starter_does_not_expire() public { + charactersMinted++; + uint256 tokenID = charactersMinted; + characterNFTs.mint(player1, tokenID); + + uint256 initialNumSessions = game.NumSessions(); + + vm.startPrank(player1); + + vm.expectEmit(address(game)); + emit SessionStarted(initialNumSessions + 1, address(characterNFTs), tokenID, PlayerType.Pitcher); + uint256 sessionID = game.startSession(address(characterNFTs), tokenID, PlayerType.Pitcher, false); + + vm.stopPrank(); + + uint256 startTimestamp = block.timestamp; + + uint256 terminalNumSessions = game.NumSessions(); + assertEq(sessionID, terminalNumSessions); + assertEq(terminalNumSessions, initialNumSessions + 1); + + Session memory session = game.getSession(sessionID); + assertEq(session.phaseStartTimestamp, 0); + assertEq(session.pitcherNFT.nftAddress, address(characterNFTs)); + assertEq(session.pitcherNFT.tokenID, tokenID); + assertEq(session.batterNFT.nftAddress, address(0)); + assertEq(session.batterNFT.tokenID, 0); + + assertEq(game.StakedSession(address(characterNFTs), tokenID), sessionID); + + uint256 sessionProgress = game.sessionProgress(sessionID); + assertEq(sessionProgress, 2); + + vm.warp(startTimestamp + game.SecondsPerPhase() + 1); + + sessionProgress = game.sessionProgress(sessionID); + assertEq(sessionProgress, 2); + } } /** @@ -1440,7 +1479,7 @@ contract FullcountTest_unstake is FullcountTestBase { vm.stopPrank(); } - function test_pitcher_can_unstake_when_session_expired_in_phase_2() public { + function test_pitcher_can_unstake_in_phase_2() public { PitcherTokenID = charactersMinted + 1; characterNFTs.mint(player1, PitcherTokenID); @@ -1449,7 +1488,6 @@ contract FullcountTest_unstake is FullcountTestBase { vm.startPrank(player1); - uint256 startTimestamp = block.timestamp; uint256 newSessionID = game.startSession(PitcherNFTAddress, PitcherTokenID, PlayerType.Pitcher, false); Session memory session = game.getSession(newSessionID); @@ -1459,9 +1497,6 @@ contract FullcountTest_unstake is FullcountTestBase { assertEq(game.sessionProgress(newSessionID), 2); - vm.warp(startTimestamp + game.SecondsPerPhase() + 1); - - assertEq(game.sessionProgress(newSessionID), 6); game.unstakeNFT(PitcherNFTAddress, PitcherTokenID); session = game.getSession(newSessionID); @@ -1472,7 +1507,7 @@ contract FullcountTest_unstake is FullcountTestBase { vm.stopPrank(); } - function test_batter_can_unstake_when_session_expired_in_phase_2() public { + function test_batter_can_unstake_in_phase_2() public { PitcherTokenID = charactersMinted + 1; characterNFTs.mint(player1, PitcherTokenID); @@ -1481,7 +1516,6 @@ contract FullcountTest_unstake is FullcountTestBase { vm.startPrank(player2); - uint256 startTimestamp = block.timestamp; uint256 newSessionID = game.startSession(BatterNFTAddress, BatterTokenID, PlayerType.Batter, false); Session memory session = game.getSession(newSessionID); @@ -1491,9 +1525,6 @@ contract FullcountTest_unstake is FullcountTestBase { assertEq(game.sessionProgress(newSessionID), 2); - vm.warp(startTimestamp + game.SecondsPerPhase() + 1); - - assertEq(game.sessionProgress(newSessionID), 6); game.unstakeNFT(BatterNFTAddress, BatterTokenID); session = game.getSession(newSessionID); From 7752ddbe1a9d09e108873ff9eb5ec959262d9755 Mon Sep 17 00:00:00 2001 From: Kellan Wampler Date: Mon, 18 Mar 2024 10:17:10 -0400 Subject: [PATCH 05/17] Changing fullcount distance calculation. Specifically vertical discrepancies should have a doubled effect on distance. --- python/fullcount/generation_1.py | 11 +- python/fullcount/test_generation_1.py | 4 +- python/fullcount/tuning.py | 77 +++++ src/Fullcount.sol | 25 +- test/AtBats.t.sol | 17 +- test/Resolution.t.sol | 395 +++++++++++++------------- 6 files changed, 301 insertions(+), 228 deletions(-) create mode 100644 python/fullcount/tuning.py diff --git a/python/fullcount/generation_1.py b/python/fullcount/generation_1.py index db7a6482..09ae902b 100644 --- a/python/fullcount/generation_1.py +++ b/python/fullcount/generation_1.py @@ -4,16 +4,15 @@ from . import data -Distance0: data.OutcomeDistribution = (0, 0, 0, 1000, 3000, 1000, 5000, 0) +Distance0: data.OutcomeDistribution = (0, 0, 0, 0, 2500, 1500, 6000, 0) -Distance1: data.OutcomeDistribution = (0, 0, 2500, 2500, 2000, 500, 2500, 0) +Distance1: data.OutcomeDistribution = (0, 0, 2500, 2500, 2500, 500, 2000, 0) -Distance2: data.OutcomeDistribution = ( - 1000, 0, 3200, 3200, 1100, 200, 800, 500) +Distance2: data.OutcomeDistribution = (0, 0, 4000, 3700, 1400, 200, 700, 0) -Distance3: data.OutcomeDistribution = (4000, 0, 3000, 1500, 250, 0, 0, 1250) +Distance3: data.OutcomeDistribution = (3200, 0, 4500, 1500, 500, 0, 0, 300) -Distance4: data.OutcomeDistribution = (7000, 0, 2000, 0, 0, 0, 0, 1000) +Distance4: data.OutcomeDistribution = (7100, 0, 2000, 0, 0, 0, 0, 900) DistanceGT4: data.OutcomeDistribution = (10_000, 0, 0, 0, 0, 0, 0, 0) diff --git a/python/fullcount/test_generation_1.py b/python/fullcount/test_generation_1.py index 3217a53e..2883263e 100644 --- a/python/fullcount/test_generation_1.py +++ b/python/fullcount/test_generation_1.py @@ -9,7 +9,9 @@ def test_outcome_weights(self): "Distance0": generation_1.Distance0, "Distance1": generation_1.Distance1, "Distance2": generation_1.Distance2, - "DistanceGT2": generation_1.DistanceGT2, + "Distance3": generation_1.Distance3, + "Distance4": generation_1.Distance4, + "DistanceGT4": generation_1.DistanceGT4, } for name, outcome_type in outcome_types.items(): diff --git a/python/fullcount/tuning.py b/python/fullcount/tuning.py new file mode 100644 index 00000000..36340db4 --- /dev/null +++ b/python/fullcount/tuning.py @@ -0,0 +1,77 @@ +""" +Inspect randomness specified by Fullcount nonces +""" + +import argparse +import random +from typing import Optional, List, Tuple +from collections import defaultdict + +from . import data + + +def distance_frequencies(vertical: int, horizontal: int) -> None: + print(("Calculating frequencies for ({}, {}).").format(vertical, horizontal)) + pitch_type = data.PitchType(0) + pitch_vertical = data.VerticalLocation(vertical) + pitch_horizontal = data.HorizontalLocation(horizontal) + distance_frequencies = defaultdict(int) + total_distance = 0 + for v in range(0, 5): + for h in range(0, 5): + swing_type = data.SwingType(0) + swing_vertical = data.VerticalLocation(v) + swing_horizontal = data.HorizontalLocation(h) + distance = data.l1_distance( + pitch_type, pitch_vertical, pitch_horizontal, swing_type, swing_vertical, swing_horizontal) + total_distance += distance + distance_frequencies[distance] = distance_frequencies[distance] + 1 + + # Print the entire dictionary + for key, value in distance_frequencies.items(): + print(f"Distance {key} has frequency {value}.") + + avg_dist = total_distance/25 + + print(f"Average distance is {avg_dist}") + + +def handle_average_distance(args: argparse.Namespace) -> None: + distance_frequencies(args.vertical, args.horizontal) + result = [] + # result = grind(args.nonce_1, args.nonce_2, args.denominator, args.target) + print(result) + + +def generate_cli() -> argparse.ArgumentParser: + parser = argparse.ArgumentParser( + description="Calculate distances for fullcount." + ) + parser.set_defaults(func=lambda _: parser.print_help()) + + subparsers = parser.add_subparsers() + + average_distance_parser = subparsers.add_parser( + "distance", + help="Calculate average distance of a random square from specified location. Also show number of squares at each distance.", + ) + average_distance_parser.add_argument( + "-V", + "--vertical", + required=True, + type=int, + default=0, + help="Vertical location", + ) + average_distance_parser.add_argument( + "-H", + "--horizontal", + required=True, + type=int, + default=0, + help="Horizontal location", + ) + + average_distance_parser.set_defaults(func=handle_average_distance) + + return parser diff --git a/src/Fullcount.sol b/src/Fullcount.sol index 4e78a657..2ea8bef5 100644 --- a/src/Fullcount.sol +++ b/src/Fullcount.sol @@ -63,22 +63,21 @@ contract Fullcount is EIP712 { uint256 public NumSessions; // We want to strongly reward distance 0 swings. - // 10% chance of single, 30% chance of double, 10% chance of triple, 50% chance of home run - uint256[8] public Distance0Distribution = [0, 0, 0, 1000, 3000, 1000, 5000, 0]; + // 10% chance of single, 25% chance of double, 15% chance of triple, 60% chance of home run + uint256[8] public Distance0Distribution = [0, 0, 0, 0, 2500, 1500, 6000, 0]; // Distance 1 swings should also be mostly postive outcomes and have no negative outsomes (for batter) // but considerably lower chances at big hits. - // 25% chamce of foul, 25% chance of single, 20% chance of double, 5% chance of triple, 25% chance of home run - uint256[8] public Distance1Distribution = [0, 0, 2500, 2500, 2000, 500, 2500, 0]; + // 25% chamce of foul, 25% chance of single, 25% chance of double, 5% chance of triple, 20% chance of home run + uint256[8] public Distance1Distribution = [0, 0, 2500, 2500, 2500, 500, 2000, 0]; // Distance 2 swings should be half hits (mostly weaker) with some neutral and few negative outcomes - // 10% chance of strike, 32% chance of foul, 32% chance of single, 11% chance of double, 2% chance of triple, - // 8% chance of home run, 5% chance of out - uint256[8] public Distance2Distribution = [1000, 0, 3200, 3200, 1100, 200, 800, 500]; + // 40% chance of foul, 37% chance of single, 14% chance of double, 2% chance of triple, 7% chance of home run + uint256[8] public Distance2Distribution = [0, 0, 4000, 3700, 1400, 200, 700, 0]; // Distance 3 swings should be mostly negative outcomes and little chance of big hits - // 40% chance of strike, 30% chance of foul, 15% chance of single, 2.5% chance of double, 12.5% chance of out - uint256[8] public Distance3Distribution = [4000, 0, 3000, 1500, 250, 0, 0, 1250]; + // 32% chance of strike, 45% chance of foul, 15% chance of single, 5% chance of double, 3% chance of out + uint256[8] public Distance3Distribution = [3200, 0, 4500, 1500, 500, 0, 0, 300]; // Distance 4 swings should be mostly strikes and have no positive outcomes (for batter) - // 70% chance of strike, 20% chance of foul, 10% chance of out - uint256[8] public Distance4Distribution = [7000, 0, 2000, 0, 0, 0, 0, 1000]; + // 71% chance of strike, 21% chance of foul, 9% chance of out + uint256[8] public Distance4Distribution = [7100, 0, 2000, 0, 0, 0, 0, 900]; // Distance 5+ swings should all be strikes uint256[8] public DistanceGT4Distribution = [10_000, 0, 0, 0, 0, 0, 0, 0]; @@ -729,9 +728,9 @@ contract Fullcount is EIP712 { pitchParam = uint256(pitch.vertical); swingParam = uint256(swing.vertical); if (pitchParam <= swingParam) { - dist += (swingParam - pitchParam); + dist += 2 * (swingParam - pitchParam); } else { - dist += (pitchParam - swingParam); + dist += 2 * (pitchParam - swingParam); } pitchParam = uint256(pitch.horizontal); diff --git a/test/AtBats.t.sol b/test/AtBats.t.sol index 71d7e076..8d94b261 100644 --- a/test/AtBats.t.sol +++ b/test/AtBats.t.sol @@ -797,13 +797,13 @@ contract FullcountTest_ballsAndStrikes is FullcountAtBatTest { // Generates a double Pitch memory pitch = Pitch( - 115_501_419_915_073_027_201_528_450_984_807_047_638_958_490_173_387_813_223_494_386_604_734_350_200_751, - PitchSpeed.Fast, + 111_226_050_657_822_924_597_491_446_253_991_213_025_840_145_394_201_015_488_938_793_738_637_304_727_056, + PitchSpeed.Slow, VerticalLocation.Middle, - HorizontalLocation.Middle + HorizontalLocation.InsideStrike ); - Swing memory swing = Swing(4574, SwingType.Contact, VerticalLocation.HighBall, HorizontalLocation.OutsideStrike); + Swing memory swing = Swing(5682, SwingType.Power, VerticalLocation.Middle, HorizontalLocation.OutsideStrike); _commitPitch(sixthSessionID, player1, player1PrivateKey, pitch); _commitSwing(sixthSessionID, player2, player2PrivateKey, swing); @@ -1031,14 +1031,13 @@ contract FullcountTest_ballsAndStrikes is FullcountAtBatTest { // Generates a home run Pitch memory hrPitch = Pitch( - 80_491_828_288_466_500_398_500_201_838_979_874_564_536_822_010_908_142_391_208_468_039_821_070_678_148, + 70_742_784_270_056_657_581_884_307_797_108_841_089_344_138_257_779_225_355_304_684_713_507_588_495_343, PitchSpeed.Fast, - VerticalLocation.Middle, - HorizontalLocation.InsideStrike + VerticalLocation.HighBall, + HorizontalLocation.OutsideStrike ); - Swing memory hrSwing = - Swing(32_155, SwingType.Power, VerticalLocation.LowStrike, HorizontalLocation.InsideStrike); + Swing memory hrSwing = Swing(6874, SwingType.Power, VerticalLocation.HighBall, HorizontalLocation.OutsideStrike); _commitPitch(nextSessionID, player1, player1PrivateKey, hrPitch); diff --git a/test/Resolution.t.sol b/test/Resolution.t.sol index 75e9e1b3..617c9b9f 100644 --- a/test/Resolution.t.sol +++ b/test/Resolution.t.sol @@ -64,30 +64,30 @@ contract ResolutionTest is FullcountTestBase { /** * To generate boundary and interior condition tests for this test case: - * $ fullcount codegen outcome-tests --desired-outcome 0 --pitch-type 0 --pitch-vert 1 --pitch-hor 0 --swing-type 0 - * --swing-vert 0 --swing-hor 3 + * $ fullcount codegen outcome-tests --desired-outcome 0 --pitch-type 0 --pitch-vert 0 --pitch-hor 1 --swing-type 1 + * --swing-vert 2 --swing-hor 2 */ - function test_53636414796787111351049665755288371011221745379470127565060084802567310083887_Fast_HighStrike_InsideBall_2449_Contact_HighBall_OutsideStrike_Strike( + function test_65686237749379525263138999652126209949201934271010366394849630801988942131313_Fast_HighBall_InsideStrike_2930_Power_Middle_Middle_Strike( ) public { - // Nonces 53636414796787111351049665755288371011221745379470127565060084802567310083887 and 2449 generate + // Nonces 65686237749379525263138999652126209949201934271010366394849630801988942131313 and 2930 generate // random number 0 which maps to Outcome.Strike. assertEq(game.sessionProgress(SessionID), 3); Pitch memory pitch = Pitch( - 53_636_414_796_787_111_351_049_665_755_288_371_011_221_745_379_470_127_565_060_084_802_567_310_083_887, + 65_686_237_749_379_525_263_138_999_652_126_209_949_201_934_271_010_366_394_849_630_801_988_942_131_313, PitchSpeed.Fast, - VerticalLocation.HighStrike, - HorizontalLocation.InsideBall + VerticalLocation.HighBall, + HorizontalLocation.InsideStrike ); _commitPitch(SessionID, player1, player1PrivateKey, pitch); assertEq(game.sessionProgress(SessionID), 3); - Swing memory swing = Swing(2449, SwingType.Contact, VerticalLocation.HighBall, HorizontalLocation.OutsideStrike); + Swing memory swing = Swing(2930, SwingType.Power, VerticalLocation.Middle, HorizontalLocation.Middle); _commitSwing(SessionID, player2, player2PrivateKey, swing); @@ -122,30 +122,30 @@ contract ResolutionTest is FullcountTestBase { /** * To generate boundary and interior condition tests for this test case: - * $ fullcount codegen outcome-tests --desired-outcome 0 --pitch-type 0 --pitch-vert 1 --pitch-hor 0 --swing-type 0 - * --swing-vert 0 --swing-hor 3 + * $ fullcount codegen outcome-tests --desired-outcome 0 --pitch-type 0 --pitch-vert 0 --pitch-hor 1 --swing-type 1 + * --swing-vert 2 --swing-hor 2 */ - function test_53636414796787111351049665755288371011221745379470127565060084802567310083887_Fast_HighStrike_InsideBall_7457_Contact_HighBall_OutsideStrike_Strike( + function test_65686237749379525263138999652126209949201934271010366394849630801988942131313_Fast_HighBall_InsideStrike_23804_Power_Middle_Middle_Strike( ) public { - // Nonces 53636414796787111351049665755288371011221745379470127565060084802567310083887 and 7457 generate - // random number 3499 which maps to Outcome.Strike. + // Nonces 65686237749379525263138999652126209949201934271010366394849630801988942131313 and 23804 generate + // random number 4999 which maps to Outcome.Strike. assertEq(game.sessionProgress(SessionID), 3); Pitch memory pitch = Pitch( - 53_636_414_796_787_111_351_049_665_755_288_371_011_221_745_379_470_127_565_060_084_802_567_310_083_887, + 65_686_237_749_379_525_263_138_999_652_126_209_949_201_934_271_010_366_394_849_630_801_988_942_131_313, PitchSpeed.Fast, - VerticalLocation.HighStrike, - HorizontalLocation.InsideBall + VerticalLocation.HighBall, + HorizontalLocation.InsideStrike ); _commitPitch(SessionID, player1, player1PrivateKey, pitch); assertEq(game.sessionProgress(SessionID), 3); - Swing memory swing = Swing(7457, SwingType.Contact, VerticalLocation.HighBall, HorizontalLocation.OutsideStrike); + Swing memory swing = Swing(23_804, SwingType.Power, VerticalLocation.Middle, HorizontalLocation.Middle); _commitSwing(SessionID, player2, player2PrivateKey, swing); @@ -180,30 +180,30 @@ contract ResolutionTest is FullcountTestBase { /** * To generate boundary and interior condition tests for this test case: - * $ fullcount codegen outcome-tests --desired-outcome 0 --pitch-type 0 --pitch-vert 1 --pitch-hor 0 --swing-type 0 - * --swing-vert 0 --swing-hor 3 + * $ fullcount codegen outcome-tests --desired-outcome 0 --pitch-type 0 --pitch-vert 0 --pitch-hor 1 --swing-type 1 + * --swing-vert 2 --swing-hor 2 */ - function test_53636414796787111351049665755288371011221745379470127565060084802567310083887_Fast_HighStrike_InsideBall_8639_Contact_HighBall_OutsideStrike_Strike( + function test_65686237749379525263138999652126209949201934271010366394849630801988942131313_Fast_HighBall_InsideStrike_4683_Power_Middle_Middle_Strike( ) public { - // Nonces 53636414796787111351049665755288371011221745379470127565060084802567310083887 and 8639 generate - // random number 6999 which maps to Outcome.Strike. + // Nonces 65686237749379525263138999652126209949201934271010366394849630801988942131313 and 4683 generate + // random number 9999 which maps to Outcome.Strike. assertEq(game.sessionProgress(SessionID), 3); Pitch memory pitch = Pitch( - 53_636_414_796_787_111_351_049_665_755_288_371_011_221_745_379_470_127_565_060_084_802_567_310_083_887, + 65_686_237_749_379_525_263_138_999_652_126_209_949_201_934_271_010_366_394_849_630_801_988_942_131_313, PitchSpeed.Fast, - VerticalLocation.HighStrike, - HorizontalLocation.InsideBall + VerticalLocation.HighBall, + HorizontalLocation.InsideStrike ); _commitPitch(SessionID, player1, player1PrivateKey, pitch); assertEq(game.sessionProgress(SessionID), 3); - Swing memory swing = Swing(8639, SwingType.Contact, VerticalLocation.HighBall, HorizontalLocation.OutsideStrike); + Swing memory swing = Swing(4683, SwingType.Power, VerticalLocation.Middle, HorizontalLocation.Middle); _commitSwing(SessionID, player2, player2PrivateKey, swing); @@ -238,30 +238,30 @@ contract ResolutionTest is FullcountTestBase { /** * To generate boundary and interior condition tests for this test case: - * $ fullcount codegen outcome-tests --desired-outcome 2 --pitch-type 1 --pitch-vert 0 --pitch-hor 3 --swing-type 0 - * --swing-vert 0 --swing-hor 3 + * $ fullcount codegen outcome-tests --desired-outcome 2 --pitch-type 0 --pitch-vert 2 --pitch-hor 1 --swing-type 1 + * --swing-vert 2 --swing-hor 2 */ - function test_76272677889733487807869088975394561199007238211299295369669345782657832457462_Slow_HighBall_OutsideStrike_6060_Contact_HighBall_OutsideStrike_Foul( + function test_99040106910354088664340605326131809105991529673177939176246891022451497110668_Fast_Middle_InsideStrike_2627_Power_Middle_Middle_Foul( ) public { - // Nonces 76272677889733487807869088975394561199007238211299295369669345782657832457462 and 6060 generate + // Nonces 99040106910354088664340605326131809105991529673177939176246891022451497110668 and 2627 generate // random number 0 which maps to Outcome.Foul. assertEq(game.sessionProgress(SessionID), 3); Pitch memory pitch = Pitch( - 76_272_677_889_733_487_807_869_088_975_394_561_199_007_238_211_299_295_369_669_345_782_657_832_457_462, - PitchSpeed.Slow, - VerticalLocation.HighBall, - HorizontalLocation.OutsideStrike + 99_040_106_910_354_088_664_340_605_326_131_809_105_991_529_673_177_939_176_246_891_022_451_497_110_668, + PitchSpeed.Fast, + VerticalLocation.Middle, + HorizontalLocation.InsideStrike ); _commitPitch(SessionID, player1, player1PrivateKey, pitch); assertEq(game.sessionProgress(SessionID), 3); - Swing memory swing = Swing(6060, SwingType.Contact, VerticalLocation.HighBall, HorizontalLocation.OutsideStrike); + Swing memory swing = Swing(2627, SwingType.Power, VerticalLocation.Middle, HorizontalLocation.Middle); _commitSwing(SessionID, player2, player2PrivateKey, swing); @@ -296,30 +296,30 @@ contract ResolutionTest is FullcountTestBase { /** * To generate boundary and interior condition tests for this test case: - * $ fullcount codegen outcome-tests --desired-outcome 2 --pitch-type 1 --pitch-vert 0 --pitch-hor 3 --swing-type 0 - * --swing-vert 0 --swing-hor 3 + * $ fullcount codegen outcome-tests --desired-outcome 2 --pitch-type 0 --pitch-vert 2 --pitch-hor 1 --swing-type 1 + * --swing-vert 2 --swing-hor 2 */ - function test_76272677889733487807869088975394561199007238211299295369669345782657832457462_Slow_HighBall_OutsideStrike_5027_Contact_HighBall_OutsideStrike_Foul( + function test_99040106910354088664340605326131809105991529673177939176246891022451497110668_Fast_Middle_InsideStrike_6054_Power_Middle_Middle_Foul( ) public { - // Nonces 76272677889733487807869088975394561199007238211299295369669345782657832457462 and 5027 generate - // random number 1249 which maps to Outcome.Foul. + // Nonces 99040106910354088664340605326131809105991529673177939176246891022451497110668 and 6054 generate + // random number 1999 which maps to Outcome.Foul. assertEq(game.sessionProgress(SessionID), 3); Pitch memory pitch = Pitch( - 76_272_677_889_733_487_807_869_088_975_394_561_199_007_238_211_299_295_369_669_345_782_657_832_457_462, - PitchSpeed.Slow, - VerticalLocation.HighBall, - HorizontalLocation.OutsideStrike + 99_040_106_910_354_088_664_340_605_326_131_809_105_991_529_673_177_939_176_246_891_022_451_497_110_668, + PitchSpeed.Fast, + VerticalLocation.Middle, + HorizontalLocation.InsideStrike ); _commitPitch(SessionID, player1, player1PrivateKey, pitch); assertEq(game.sessionProgress(SessionID), 3); - Swing memory swing = Swing(5027, SwingType.Contact, VerticalLocation.HighBall, HorizontalLocation.OutsideStrike); + Swing memory swing = Swing(6054, SwingType.Power, VerticalLocation.Middle, HorizontalLocation.Middle); _commitSwing(SessionID, player2, player2PrivateKey, swing); @@ -354,30 +354,30 @@ contract ResolutionTest is FullcountTestBase { /** * To generate boundary and interior condition tests for this test case: - * $ fullcount codegen outcome-tests --desired-outcome 2 --pitch-type 1 --pitch-vert 0 --pitch-hor 3 --swing-type 0 - * --swing-vert 0 --swing-hor 3 + * $ fullcount codegen outcome-tests --desired-outcome 2 --pitch-type 0 --pitch-vert 2 --pitch-hor 1 --swing-type 1 + * --swing-vert 2 --swing-hor 2 */ - function test_76272677889733487807869088975394561199007238211299295369669345782657832457462_Slow_HighBall_OutsideStrike_6004_Contact_HighBall_OutsideStrike_Foul( + function test_99040106910354088664340605326131809105991529673177939176246891022451497110668_Fast_Middle_InsideStrike_15938_Power_Middle_Middle_Foul( ) public { - // Nonces 76272677889733487807869088975394561199007238211299295369669345782657832457462 and 6004 generate - // random number 2499 which maps to Outcome.Foul. + // Nonces 99040106910354088664340605326131809105991529673177939176246891022451497110668 and 15938 generate + // random number 3999 which maps to Outcome.Foul. assertEq(game.sessionProgress(SessionID), 3); Pitch memory pitch = Pitch( - 76_272_677_889_733_487_807_869_088_975_394_561_199_007_238_211_299_295_369_669_345_782_657_832_457_462, - PitchSpeed.Slow, - VerticalLocation.HighBall, - HorizontalLocation.OutsideStrike + 99_040_106_910_354_088_664_340_605_326_131_809_105_991_529_673_177_939_176_246_891_022_451_497_110_668, + PitchSpeed.Fast, + VerticalLocation.Middle, + HorizontalLocation.InsideStrike ); _commitPitch(SessionID, player1, player1PrivateKey, pitch); assertEq(game.sessionProgress(SessionID), 3); - Swing memory swing = Swing(6004, SwingType.Contact, VerticalLocation.HighBall, HorizontalLocation.OutsideStrike); + Swing memory swing = Swing(15_938, SwingType.Power, VerticalLocation.Middle, HorizontalLocation.Middle); _commitSwing(SessionID, player2, player2PrivateKey, swing); @@ -412,22 +412,22 @@ contract ResolutionTest is FullcountTestBase { /** * To generate boundary and interior condition tests for this test case: - * $ fullcount codegen outcome-tests --desired-outcome 3 --pitch-type 1 --pitch-vert 4 --pitch-hor 4 --swing-type 1 - * --swing-vert 2 --swing-hor 3 + * $ fullcount codegen outcome-tests --desired-outcome 3 --pitch-type 0 --pitch-vert 3 --pitch-hor 4 --swing-type 1 + * --swing-vert 3 --swing-hor 3 */ - function test_33362354671537370654190716892156555408700188156617020216245752358008161499558_Slow_LowBall_OutsideBall_24524_Power_Middle_OutsideStrike_Single( + function test_32061386110044083800252479881904741175752556045021122783415455594732640393917_Fast_LowStrike_OutsideBall_8309_Power_LowStrike_OutsideStrike_Single( ) public { - // Nonces 33362354671537370654190716892156555408700188156617020216245752358008161499558 and 24524 generate - // random number 7000 which maps to Outcome.Single. + // Nonces 32061386110044083800252479881904741175752556045021122783415455594732640393917 and 8309 generate + // random number 4000 which maps to Outcome.Single. assertEq(game.sessionProgress(SessionID), 3); Pitch memory pitch = Pitch( - 33_362_354_671_537_370_654_190_716_892_156_555_408_700_188_156_617_020_216_245_752_358_008_161_499_558, - PitchSpeed.Slow, - VerticalLocation.LowBall, + 32_061_386_110_044_083_800_252_479_881_904_741_175_752_556_045_021_122_783_415_455_594_732_640_393_917, + PitchSpeed.Fast, + VerticalLocation.LowStrike, HorizontalLocation.OutsideBall ); @@ -435,7 +435,7 @@ contract ResolutionTest is FullcountTestBase { assertEq(game.sessionProgress(SessionID), 3); - Swing memory swing = Swing(24_524, SwingType.Power, VerticalLocation.Middle, HorizontalLocation.OutsideStrike); + Swing memory swing = Swing(8309, SwingType.Power, VerticalLocation.LowStrike, HorizontalLocation.OutsideStrike); _commitSwing(SessionID, player2, player2PrivateKey, swing); @@ -470,22 +470,22 @@ contract ResolutionTest is FullcountTestBase { /** * To generate boundary and interior condition tests for this test case: - * $ fullcount codegen outcome-tests --desired-outcome 3 --pitch-type 1 --pitch-vert 4 --pitch-hor 4 --swing-type 1 - * --swing-vert 2 --swing-hor 3 + * $ fullcount codegen outcome-tests --desired-outcome 3 --pitch-type 0 --pitch-vert 3 --pitch-hor 4 --swing-type 1 + * --swing-vert 3 --swing-hor 3 */ - function test_33362354671537370654190716892156555408700188156617020216245752358008161499558_Slow_LowBall_OutsideBall_2623_Power_Middle_OutsideStrike_Single( + function test_32061386110044083800252479881904741175752556045021122783415455594732640393917_Fast_LowStrike_OutsideBall_49935_Power_LowStrike_OutsideStrike_Single( ) public { - // Nonces 33362354671537370654190716892156555408700188156617020216245752358008161499558 and 2623 generate - // random number 8499 which maps to Outcome.Single. + // Nonces 32061386110044083800252479881904741175752556045021122783415455594732640393917 and 49935 generate + // random number 5849 which maps to Outcome.Single. assertEq(game.sessionProgress(SessionID), 3); Pitch memory pitch = Pitch( - 33_362_354_671_537_370_654_190_716_892_156_555_408_700_188_156_617_020_216_245_752_358_008_161_499_558, - PitchSpeed.Slow, - VerticalLocation.LowBall, + 32_061_386_110_044_083_800_252_479_881_904_741_175_752_556_045_021_122_783_415_455_594_732_640_393_917, + PitchSpeed.Fast, + VerticalLocation.LowStrike, HorizontalLocation.OutsideBall ); @@ -493,7 +493,8 @@ contract ResolutionTest is FullcountTestBase { assertEq(game.sessionProgress(SessionID), 3); - Swing memory swing = Swing(2623, SwingType.Power, VerticalLocation.Middle, HorizontalLocation.OutsideStrike); + Swing memory swing = + Swing(49_935, SwingType.Power, VerticalLocation.LowStrike, HorizontalLocation.OutsideStrike); _commitSwing(SessionID, player2, player2PrivateKey, swing); @@ -528,22 +529,22 @@ contract ResolutionTest is FullcountTestBase { /** * To generate boundary and interior condition tests for this test case: - * $ fullcount codegen outcome-tests --desired-outcome 3 --pitch-type 1 --pitch-vert 4 --pitch-hor 4 --swing-type 1 - * --swing-vert 2 --swing-hor 3 + * $ fullcount codegen outcome-tests --desired-outcome 3 --pitch-type 0 --pitch-vert 3 --pitch-hor 4 --swing-type 1 + * --swing-vert 3 --swing-hor 3 */ - function test_33362354671537370654190716892156555408700188156617020216245752358008161499558_Slow_LowBall_OutsideBall_5469_Power_Middle_OutsideStrike_Single( + function test_32061386110044083800252479881904741175752556045021122783415455594732640393917_Fast_LowStrike_OutsideBall_2878_Power_LowStrike_OutsideStrike_Single( ) public { - // Nonces 33362354671537370654190716892156555408700188156617020216245752358008161499558 and 5469 generate - // random number 7749 which maps to Outcome.Single. + // Nonces 32061386110044083800252479881904741175752556045021122783415455594732640393917 and 2878 generate + // random number 7699 which maps to Outcome.Single. assertEq(game.sessionProgress(SessionID), 3); Pitch memory pitch = Pitch( - 33_362_354_671_537_370_654_190_716_892_156_555_408_700_188_156_617_020_216_245_752_358_008_161_499_558, - PitchSpeed.Slow, - VerticalLocation.LowBall, + 32_061_386_110_044_083_800_252_479_881_904_741_175_752_556_045_021_122_783_415_455_594_732_640_393_917, + PitchSpeed.Fast, + VerticalLocation.LowStrike, HorizontalLocation.OutsideBall ); @@ -551,7 +552,7 @@ contract ResolutionTest is FullcountTestBase { assertEq(game.sessionProgress(SessionID), 3); - Swing memory swing = Swing(5469, SwingType.Power, VerticalLocation.Middle, HorizontalLocation.OutsideStrike); + Swing memory swing = Swing(2878, SwingType.Power, VerticalLocation.LowStrike, HorizontalLocation.OutsideStrike); _commitSwing(SessionID, player2, player2PrivateKey, swing); @@ -586,30 +587,30 @@ contract ResolutionTest is FullcountTestBase { /** * To generate boundary and interior condition tests for this test case: - * $ fullcount codegen outcome-tests --desired-outcome 4 --pitch-type 0 --pitch-vert 2 --pitch-hor 2 --swing-type 0 - * --swing-vert 0 --swing-hor 3 + * $ fullcount codegen outcome-tests --desired-outcome 4 --pitch-type 1 --pitch-vert 2 --pitch-hor 1 --swing-type 1 + * --swing-vert 2 --swing-hor 3 */ - function test_115501419915073027201528450984807047638958490173387813223494386604734350200751_Fast_Middle_Middle_222_Contact_HighBall_OutsideStrike_Double( + function test_111226050657822924597491446253991213025840145394201015488938793738637304727056_Slow_Middle_InsideStrike_11505_Power_Middle_OutsideStrike_Double( ) public { - // Nonces 115501419915073027201528450984807047638958490173387813223494386604734350200751 and 222 generate - // random number 8624 which maps to Outcome.Double. + // Nonces 111226050657822924597491446253991213025840145394201015488938793738637304727056 and 11505 generate + // random number 9099 which maps to Outcome.Double. assertEq(game.sessionProgress(SessionID), 3); Pitch memory pitch = Pitch( - 115_501_419_915_073_027_201_528_450_984_807_047_638_958_490_173_387_813_223_494_386_604_734_350_200_751, - PitchSpeed.Fast, + 111_226_050_657_822_924_597_491_446_253_991_213_025_840_145_394_201_015_488_938_793_738_637_304_727_056, + PitchSpeed.Slow, VerticalLocation.Middle, - HorizontalLocation.Middle + HorizontalLocation.InsideStrike ); _commitPitch(SessionID, player1, player1PrivateKey, pitch); assertEq(game.sessionProgress(SessionID), 3); - Swing memory swing = Swing(222, SwingType.Contact, VerticalLocation.HighBall, HorizontalLocation.OutsideStrike); + Swing memory swing = Swing(11_505, SwingType.Power, VerticalLocation.Middle, HorizontalLocation.OutsideStrike); _commitSwing(SessionID, player2, player2PrivateKey, swing); @@ -644,30 +645,30 @@ contract ResolutionTest is FullcountTestBase { /** * To generate boundary and interior condition tests for this test case: - * $ fullcount codegen outcome-tests --desired-outcome 4 --pitch-type 0 --pitch-vert 2 --pitch-hor 2 --swing-type 0 - * --swing-vert 0 --swing-hor 3 + * $ fullcount codegen outcome-tests --desired-outcome 4 --pitch-type 1 --pitch-vert 2 --pitch-hor 1 --swing-type 1 + * --swing-vert 2 --swing-hor 3 */ - function test_115501419915073027201528450984807047638958490173387813223494386604734350200751_Fast_Middle_Middle_4574_Contact_HighBall_OutsideStrike_Double( + function test_111226050657822924597491446253991213025840145394201015488938793738637304727056_Slow_Middle_InsideStrike_5682_Power_Middle_OutsideStrike_Double( ) public { - // Nonces 115501419915073027201528450984807047638958490173387813223494386604734350200751 and 4574 generate - // random number 8500 which maps to Outcome.Double. + // Nonces 111226050657822924597491446253991213025840145394201015488938793738637304727056 and 5682 generate + // random number 7700 which maps to Outcome.Double. assertEq(game.sessionProgress(SessionID), 3); Pitch memory pitch = Pitch( - 115_501_419_915_073_027_201_528_450_984_807_047_638_958_490_173_387_813_223_494_386_604_734_350_200_751, - PitchSpeed.Fast, + 111_226_050_657_822_924_597_491_446_253_991_213_025_840_145_394_201_015_488_938_793_738_637_304_727_056, + PitchSpeed.Slow, VerticalLocation.Middle, - HorizontalLocation.Middle + HorizontalLocation.InsideStrike ); _commitPitch(SessionID, player1, player1PrivateKey, pitch); assertEq(game.sessionProgress(SessionID), 3); - Swing memory swing = Swing(4574, SwingType.Contact, VerticalLocation.HighBall, HorizontalLocation.OutsideStrike); + Swing memory swing = Swing(5682, SwingType.Power, VerticalLocation.Middle, HorizontalLocation.OutsideStrike); _commitSwing(SessionID, player2, player2PrivateKey, swing); @@ -702,31 +703,30 @@ contract ResolutionTest is FullcountTestBase { /** * To generate boundary and interior condition tests for this test case: - * $ fullcount codegen outcome-tests --desired-outcome 4 --pitch-type 0 --pitch-vert 2 --pitch-hor 2 --swing-type 0 - * --swing-vert 0 --swing-hor 3 + * $ fullcount codegen outcome-tests --desired-outcome 4 --pitch-type 1 --pitch-vert 2 --pitch-hor 1 --swing-type 1 + * --swing-vert 2 --swing-hor 3 */ - function test_115501419915073027201528450984807047638958490173387813223494386604734350200751_Fast_Middle_Middle_28812_Contact_HighBall_OutsideStrike_Double( + function test_111226050657822924597491446253991213025840145394201015488938793738637304727056_Slow_Middle_InsideStrike_9624_Power_Middle_OutsideStrike_Double( ) public { - // Nonces 115501419915073027201528450984807047638958490173387813223494386604734350200751 and 28812 generate - // random number 8749 which maps to Outcome.Double. + // Nonces 111226050657822924597491446253991213025840145394201015488938793738637304727056 and 9624 generate + // random number 8399 which maps to Outcome.Double. assertEq(game.sessionProgress(SessionID), 3); Pitch memory pitch = Pitch( - 115_501_419_915_073_027_201_528_450_984_807_047_638_958_490_173_387_813_223_494_386_604_734_350_200_751, - PitchSpeed.Fast, + 111_226_050_657_822_924_597_491_446_253_991_213_025_840_145_394_201_015_488_938_793_738_637_304_727_056, + PitchSpeed.Slow, VerticalLocation.Middle, - HorizontalLocation.Middle + HorizontalLocation.InsideStrike ); _commitPitch(SessionID, player1, player1PrivateKey, pitch); assertEq(game.sessionProgress(SessionID), 3); - Swing memory swing = - Swing(28_812, SwingType.Contact, VerticalLocation.HighBall, HorizontalLocation.OutsideStrike); + Swing memory swing = Swing(9624, SwingType.Power, VerticalLocation.Middle, HorizontalLocation.OutsideStrike); _commitSwing(SessionID, player2, player2PrivateKey, swing); @@ -761,30 +761,30 @@ contract ResolutionTest is FullcountTestBase { /** * To generate boundary and interior condition tests for this test case: - * $ fullcount codegen outcome-tests --desired-outcome 5 --pitch-type 1 --pitch-vert 2 --pitch-hor 4 --swing-type 1 - * --swing-vert 2 --swing-hor 3 + * $ fullcount codegen outcome-tests --desired-outcome 5 --pitch-type 0 --pitch-vert 0 --pitch-hor 2 --swing-type 1 + * --swing-vert 0 --swing-hor 2 */ - function test_30878253991008052489834351670334743750262955920015606602786415223606657291215_Slow_Middle_OutsideBall_543_Power_Middle_OutsideStrike_Triple( + function test_110272984089120695342144296309024110718048875277997935968562678835896684431432_Fast_HighBall_Middle_14585_Power_HighBall_Middle_Triple( ) public { - // Nonces 30878253991008052489834351670334743750262955920015606602786415223606657291215 and 543 generate random - // number 7000 which maps to Outcome.Triple. + // Nonces 110272984089120695342144296309024110718048875277997935968562678835896684431432 and 14585 generate + // random number 7500 which maps to Outcome.Triple. assertEq(game.sessionProgress(SessionID), 3); Pitch memory pitch = Pitch( - 30_878_253_991_008_052_489_834_351_670_334_743_750_262_955_920_015_606_602_786_415_223_606_657_291_215, - PitchSpeed.Slow, - VerticalLocation.Middle, - HorizontalLocation.OutsideBall + 110_272_984_089_120_695_342_144_296_309_024_110_718_048_875_277_997_935_968_562_678_835_896_684_431_432, + PitchSpeed.Fast, + VerticalLocation.HighBall, + HorizontalLocation.Middle ); _commitPitch(SessionID, player1, player1PrivateKey, pitch); assertEq(game.sessionProgress(SessionID), 3); - Swing memory swing = Swing(543, SwingType.Power, VerticalLocation.Middle, HorizontalLocation.OutsideStrike); + Swing memory swing = Swing(14_585, SwingType.Power, VerticalLocation.HighBall, HorizontalLocation.Middle); _commitSwing(SessionID, player2, player2PrivateKey, swing); @@ -819,30 +819,30 @@ contract ResolutionTest is FullcountTestBase { /** * To generate boundary and interior condition tests for this test case: - * $ fullcount codegen outcome-tests --desired-outcome 5 --pitch-type 1 --pitch-vert 2 --pitch-hor 4 --swing-type 1 - * --swing-vert 2 --swing-hor 3 + * $ fullcount codegen outcome-tests --desired-outcome 5 --pitch-type 0 --pitch-vert 0 --pitch-hor 2 --swing-type 1 + * --swing-vert 0 --swing-hor 2 */ - function test_30878253991008052489834351670334743750262955920015606602786415223606657291215_Slow_Middle_OutsideBall_17257_Power_Middle_OutsideStrike_Triple( + function test_110272984089120695342144296309024110718048875277997935968562678835896684431432_Fast_HighBall_Middle_15406_Power_HighBall_Middle_Triple( ) public { - // Nonces 30878253991008052489834351670334743750262955920015606602786415223606657291215 and 17257 generate - // random number 7249 which maps to Outcome.Triple. + // Nonces 110272984089120695342144296309024110718048875277997935968562678835896684431432 and 15406 generate + // random number 7749 which maps to Outcome.Triple. assertEq(game.sessionProgress(SessionID), 3); Pitch memory pitch = Pitch( - 30_878_253_991_008_052_489_834_351_670_334_743_750_262_955_920_015_606_602_786_415_223_606_657_291_215, - PitchSpeed.Slow, - VerticalLocation.Middle, - HorizontalLocation.OutsideBall + 110_272_984_089_120_695_342_144_296_309_024_110_718_048_875_277_997_935_968_562_678_835_896_684_431_432, + PitchSpeed.Fast, + VerticalLocation.HighBall, + HorizontalLocation.Middle ); _commitPitch(SessionID, player1, player1PrivateKey, pitch); assertEq(game.sessionProgress(SessionID), 3); - Swing memory swing = Swing(17_257, SwingType.Power, VerticalLocation.Middle, HorizontalLocation.OutsideStrike); + Swing memory swing = Swing(15_406, SwingType.Power, VerticalLocation.HighBall, HorizontalLocation.Middle); _commitSwing(SessionID, player2, player2PrivateKey, swing); @@ -877,30 +877,30 @@ contract ResolutionTest is FullcountTestBase { /** * To generate boundary and interior condition tests for this test case: - * $ fullcount codegen outcome-tests --desired-outcome 5 --pitch-type 1 --pitch-vert 2 --pitch-hor 4 --swing-type 1 - * --swing-vert 2 --swing-hor 3 + * $ fullcount codegen outcome-tests --desired-outcome 5 --pitch-type 0 --pitch-vert 0 --pitch-hor 2 --swing-type 1 + * --swing-vert 0 --swing-hor 2 */ - function test_30878253991008052489834351670334743750262955920015606602786415223606657291215_Slow_Middle_OutsideBall_11518_Power_Middle_OutsideStrike_Triple( + function test_110272984089120695342144296309024110718048875277997935968562678835896684431432_Fast_HighBall_Middle_17179_Power_HighBall_Middle_Triple( ) public { - // Nonces 30878253991008052489834351670334743750262955920015606602786415223606657291215 and 11518 generate - // random number 7499 which maps to Outcome.Triple. + // Nonces 110272984089120695342144296309024110718048875277997935968562678835896684431432 and 17179 generate + // random number 7999 which maps to Outcome.Triple. assertEq(game.sessionProgress(SessionID), 3); Pitch memory pitch = Pitch( - 30_878_253_991_008_052_489_834_351_670_334_743_750_262_955_920_015_606_602_786_415_223_606_657_291_215, - PitchSpeed.Slow, - VerticalLocation.Middle, - HorizontalLocation.OutsideBall + 110_272_984_089_120_695_342_144_296_309_024_110_718_048_875_277_997_935_968_562_678_835_896_684_431_432, + PitchSpeed.Fast, + VerticalLocation.HighBall, + HorizontalLocation.Middle ); _commitPitch(SessionID, player1, player1PrivateKey, pitch); assertEq(game.sessionProgress(SessionID), 3); - Swing memory swing = Swing(11_518, SwingType.Power, VerticalLocation.Middle, HorizontalLocation.OutsideStrike); + Swing memory swing = Swing(17_179, SwingType.Power, VerticalLocation.HighBall, HorizontalLocation.Middle); _commitSwing(SessionID, player2, player2PrivateKey, swing); @@ -935,30 +935,30 @@ contract ResolutionTest is FullcountTestBase { /** * To generate boundary and interior condition tests for this test case: - * $ fullcount codegen outcome-tests --desired-outcome 6 --pitch-type 0 --pitch-vert 2 --pitch-hor 1 --swing-type 1 - * --swing-vert 3 --swing-hor 1 + * $ fullcount codegen outcome-tests --desired-outcome 6 --pitch-type 0 --pitch-vert 0 --pitch-hor 3 --swing-type 1 + * --swing-vert 0 --swing-hor 3 */ - function test_80491828288466500398500201838979874564536822010908142391208468039821070678148_Fast_Middle_InsideStrike_6323_Power_LowStrike_InsideStrike_HomeRun( + function test_70742784270056657581884307797108841089344138257779225355304684713507588495343_Fast_HighBall_OutsideStrike_11687_Power_HighBall_OutsideStrike_HomeRun( ) public { - // Nonces 80491828288466500398500201838979874564536822010908142391208468039821070678148 and 6323 generate - // random number 9499 which maps to Outcome.HomeRun. + // Nonces 70742784270056657581884307797108841089344138257779225355304684713507588495343 and 11687 generate + // random number 8000 which maps to Outcome.HomeRun. assertEq(game.sessionProgress(SessionID), 3); Pitch memory pitch = Pitch( - 80_491_828_288_466_500_398_500_201_838_979_874_564_536_822_010_908_142_391_208_468_039_821_070_678_148, + 70_742_784_270_056_657_581_884_307_797_108_841_089_344_138_257_779_225_355_304_684_713_507_588_495_343, PitchSpeed.Fast, - VerticalLocation.Middle, - HorizontalLocation.InsideStrike + VerticalLocation.HighBall, + HorizontalLocation.OutsideStrike ); _commitPitch(SessionID, player1, player1PrivateKey, pitch); assertEq(game.sessionProgress(SessionID), 3); - Swing memory swing = Swing(6323, SwingType.Power, VerticalLocation.LowStrike, HorizontalLocation.InsideStrike); + Swing memory swing = Swing(11_687, SwingType.Power, VerticalLocation.HighBall, HorizontalLocation.OutsideStrike); _commitSwing(SessionID, player2, player2PrivateKey, swing); @@ -993,30 +993,30 @@ contract ResolutionTest is FullcountTestBase { /** * To generate boundary and interior condition tests for this test case: - * $ fullcount codegen outcome-tests --desired-outcome 6 --pitch-type 0 --pitch-vert 2 --pitch-hor 1 --swing-type 1 - * --swing-vert 3 --swing-hor 1 + * $ fullcount codegen outcome-tests --desired-outcome 6 --pitch-type 0 --pitch-vert 0 --pitch-hor 3 --swing-type 1 + * --swing-vert 0 --swing-hor 3 */ - function test_80491828288466500398500201838979874564536822010908142391208468039821070678148_Fast_Middle_InsideStrike_32155_Power_LowStrike_InsideStrike_HomeRun( + function test_70742784270056657581884307797108841089344138257779225355304684713507588495343_Fast_HighBall_OutsideStrike_6874_Power_HighBall_OutsideStrike_HomeRun( ) public { - // Nonces 80491828288466500398500201838979874564536822010908142391208468039821070678148 and 32155 generate - // random number 8700 which maps to Outcome.HomeRun. + // Nonces 70742784270056657581884307797108841089344138257779225355304684713507588495343 and 6874 generate + // random number 8999 which maps to Outcome.HomeRun. assertEq(game.sessionProgress(SessionID), 3); Pitch memory pitch = Pitch( - 80_491_828_288_466_500_398_500_201_838_979_874_564_536_822_010_908_142_391_208_468_039_821_070_678_148, + 70_742_784_270_056_657_581_884_307_797_108_841_089_344_138_257_779_225_355_304_684_713_507_588_495_343, PitchSpeed.Fast, - VerticalLocation.Middle, - HorizontalLocation.InsideStrike + VerticalLocation.HighBall, + HorizontalLocation.OutsideStrike ); _commitPitch(SessionID, player1, player1PrivateKey, pitch); assertEq(game.sessionProgress(SessionID), 3); - Swing memory swing = Swing(32_155, SwingType.Power, VerticalLocation.LowStrike, HorizontalLocation.InsideStrike); + Swing memory swing = Swing(6874, SwingType.Power, VerticalLocation.HighBall, HorizontalLocation.OutsideStrike); _commitSwing(SessionID, player2, player2PrivateKey, swing); @@ -1051,30 +1051,30 @@ contract ResolutionTest is FullcountTestBase { /** * To generate boundary and interior condition tests for this test case: - * $ fullcount codegen outcome-tests --desired-outcome 6 --pitch-type 0 --pitch-vert 2 --pitch-hor 1 --swing-type 1 - * --swing-vert 3 --swing-hor 1 + * $ fullcount codegen outcome-tests --desired-outcome 6 --pitch-type 0 --pitch-vert 0 --pitch-hor 3 --swing-type 1 + * --swing-vert 0 --swing-hor 3 */ - function test_80491828288466500398500201838979874564536822010908142391208468039821070678148_Fast_Middle_InsideStrike_101_Power_LowStrike_InsideStrike_HomeRun( + function test_70742784270056657581884307797108841089344138257779225355304684713507588495343_Fast_HighBall_OutsideStrike_7560_Power_HighBall_OutsideStrike_HomeRun( ) public { - // Nonces 80491828288466500398500201838979874564536822010908142391208468039821070678148 and 101 generate random - // number 9099 which maps to Outcome.HomeRun. + // Nonces 70742784270056657581884307797108841089344138257779225355304684713507588495343 and 7560 generate + // random number 9999 which maps to Outcome.HomeRun. assertEq(game.sessionProgress(SessionID), 3); Pitch memory pitch = Pitch( - 80_491_828_288_466_500_398_500_201_838_979_874_564_536_822_010_908_142_391_208_468_039_821_070_678_148, + 70_742_784_270_056_657_581_884_307_797_108_841_089_344_138_257_779_225_355_304_684_713_507_588_495_343, PitchSpeed.Fast, - VerticalLocation.Middle, - HorizontalLocation.InsideStrike + VerticalLocation.HighBall, + HorizontalLocation.OutsideStrike ); _commitPitch(SessionID, player1, player1PrivateKey, pitch); assertEq(game.sessionProgress(SessionID), 3); - Swing memory swing = Swing(101, SwingType.Power, VerticalLocation.LowStrike, HorizontalLocation.InsideStrike); + Swing memory swing = Swing(7560, SwingType.Power, VerticalLocation.HighBall, HorizontalLocation.OutsideStrike); _commitSwing(SessionID, player2, player2PrivateKey, swing); @@ -1109,31 +1109,30 @@ contract ResolutionTest is FullcountTestBase { /** * To generate boundary and interior condition tests for this test case: - * $ fullcount codegen outcome-tests --desired-outcome 7 --pitch-type 1 --pitch-vert 0 --pitch-hor 4 --swing-type 0 - * --swing-vert 1 --swing-hor 3 + * $ fullcount codegen outcome-tests --desired-outcome 7 --pitch-type 0 --pitch-vert 2 --pitch-hor 0 --swing-type 0 + * --swing-vert 4 --swing-hor 0 */ - function test_26552784285933202465540785509845637871737540752676713985038719979779669496190_Slow_HighBall_OutsideBall_9442_Contact_HighStrike_OutsideStrike_InPlayOut( + function test_50854314433890071022989996820635348696297975617722869624891647074907967575707_Fast_Middle_InsideBall_475_Contact_LowBall_InsideBall_InPlayOut( ) public { - // Nonces 26552784285933202465540785509845637871737540752676713985038719979779669496190 and 9442 generate - // random number 9374 which maps to Outcome.InPlayOut. + // Nonces 50854314433890071022989996820635348696297975617722869624891647074907967575707 and 475 generate random + // number 9100 which maps to Outcome.InPlayOut. assertEq(game.sessionProgress(SessionID), 3); Pitch memory pitch = Pitch( - 26_552_784_285_933_202_465_540_785_509_845_637_871_737_540_752_676_713_985_038_719_979_779_669_496_190, - PitchSpeed.Slow, - VerticalLocation.HighBall, - HorizontalLocation.OutsideBall + 50_854_314_433_890_071_022_989_996_820_635_348_696_297_975_617_722_869_624_891_647_074_907_967_575_707, + PitchSpeed.Fast, + VerticalLocation.Middle, + HorizontalLocation.InsideBall ); _commitPitch(SessionID, player1, player1PrivateKey, pitch); assertEq(game.sessionProgress(SessionID), 3); - Swing memory swing = - Swing(9442, SwingType.Contact, VerticalLocation.HighStrike, HorizontalLocation.OutsideStrike); + Swing memory swing = Swing(475, SwingType.Contact, VerticalLocation.LowBall, HorizontalLocation.InsideBall); _commitSwing(SessionID, player2, player2PrivateKey, swing); @@ -1168,31 +1167,30 @@ contract ResolutionTest is FullcountTestBase { /** * To generate boundary and interior condition tests for this test case: - * $ fullcount codegen outcome-tests --desired-outcome 7 --pitch-type 1 --pitch-vert 0 --pitch-hor 4 --swing-type 0 - * --swing-vert 1 --swing-hor 3 + * $ fullcount codegen outcome-tests --desired-outcome 7 --pitch-type 0 --pitch-vert 2 --pitch-hor 0 --swing-type 0 + * --swing-vert 4 --swing-hor 0 */ - function test_26552784285933202465540785509845637871737540752676713985038719979779669496190_Slow_HighBall_OutsideBall_1374_Contact_HighStrike_OutsideStrike_InPlayOut( + function test_50854314433890071022989996820635348696297975617722869624891647074907967575707_Fast_Middle_InsideBall_19544_Contact_LowBall_InsideBall_InPlayOut( ) public { - // Nonces 26552784285933202465540785509845637871737540752676713985038719979779669496190 and 1374 generate - // random number 8750 which maps to Outcome.InPlayOut. + // Nonces 50854314433890071022989996820635348696297975617722869624891647074907967575707 and 19544 generate + // random number 9549 which maps to Outcome.InPlayOut. assertEq(game.sessionProgress(SessionID), 3); Pitch memory pitch = Pitch( - 26_552_784_285_933_202_465_540_785_509_845_637_871_737_540_752_676_713_985_038_719_979_779_669_496_190, - PitchSpeed.Slow, - VerticalLocation.HighBall, - HorizontalLocation.OutsideBall + 50_854_314_433_890_071_022_989_996_820_635_348_696_297_975_617_722_869_624_891_647_074_907_967_575_707, + PitchSpeed.Fast, + VerticalLocation.Middle, + HorizontalLocation.InsideBall ); _commitPitch(SessionID, player1, player1PrivateKey, pitch); assertEq(game.sessionProgress(SessionID), 3); - Swing memory swing = - Swing(1374, SwingType.Contact, VerticalLocation.HighStrike, HorizontalLocation.OutsideStrike); + Swing memory swing = Swing(19_544, SwingType.Contact, VerticalLocation.LowBall, HorizontalLocation.InsideBall); _commitSwing(SessionID, player2, player2PrivateKey, swing); @@ -1227,31 +1225,30 @@ contract ResolutionTest is FullcountTestBase { /** * To generate boundary and interior condition tests for this test case: - * $ fullcount codegen outcome-tests --desired-outcome 7 --pitch-type 1 --pitch-vert 0 --pitch-hor 4 --swing-type 0 - * --swing-vert 1 --swing-hor 3 + * $ fullcount codegen outcome-tests --desired-outcome 7 --pitch-type 0 --pitch-vert 2 --pitch-hor 0 --swing-type 0 + * --swing-vert 4 --swing-hor 0 */ - function test_26552784285933202465540785509845637871737540752676713985038719979779669496190_Slow_HighBall_OutsideBall_27290_Contact_HighStrike_OutsideStrike_InPlayOut( + function test_50854314433890071022989996820635348696297975617722869624891647074907967575707_Fast_Middle_InsideBall_7551_Contact_LowBall_InsideBall_InPlayOut( ) public { - // Nonces 26552784285933202465540785509845637871737540752676713985038719979779669496190 and 27290 generate + // Nonces 50854314433890071022989996820635348696297975617722869624891647074907967575707 and 7551 generate // random number 9999 which maps to Outcome.InPlayOut. assertEq(game.sessionProgress(SessionID), 3); Pitch memory pitch = Pitch( - 26_552_784_285_933_202_465_540_785_509_845_637_871_737_540_752_676_713_985_038_719_979_779_669_496_190, - PitchSpeed.Slow, - VerticalLocation.HighBall, - HorizontalLocation.OutsideBall + 50_854_314_433_890_071_022_989_996_820_635_348_696_297_975_617_722_869_624_891_647_074_907_967_575_707, + PitchSpeed.Fast, + VerticalLocation.Middle, + HorizontalLocation.InsideBall ); _commitPitch(SessionID, player1, player1PrivateKey, pitch); assertEq(game.sessionProgress(SessionID), 3); - Swing memory swing = - Swing(27_290, SwingType.Contact, VerticalLocation.HighStrike, HorizontalLocation.OutsideStrike); + Swing memory swing = Swing(7551, SwingType.Contact, VerticalLocation.LowBall, HorizontalLocation.InsideBall); _commitSwing(SessionID, player2, player2PrivateKey, swing); From 39b2b26b67dfcdf7ff480fa2877d5108e0983d50 Mon Sep 17 00:00:00 2001 From: Kellan Wampler Date: Mon, 18 Mar 2024 14:24:58 -0400 Subject: [PATCH 06/17] Set token name method for BLB admins. --- src/Players.sol | 6 ++++++ test/Players.t.sol | 35 +++++++++++++++++++++++++++++++++++ 2 files changed, 41 insertions(+) diff --git a/src/Players.sol b/src/Players.sol index 7c71b03e..e84dba01 100644 --- a/src/Players.sol +++ b/src/Players.sol @@ -53,6 +53,12 @@ contract BeerLeagueBallers is ERC721Enumerable { ProfileImages[index] = newImage; } + function setTokenName(uint256 tokenID, string memory newName) public { + _enforceIsAdmin(); + + Name[tokenID] = newName; + } + function mint(string memory name, uint256 imageIndex) public returns (uint256) { require(imageIndex < ProfileImages.length, "BLB.mint: invalid image index"); uint256 tokenId = totalSupply() + 1; diff --git a/test/Players.t.sol b/test/Players.t.sol index 9c46adc6..c8c6c4c5 100644 --- a/test/Players.t.sol +++ b/test/Players.t.sol @@ -28,9 +28,11 @@ contract PlayersTestBase is Test { MockERC1155 terminus; uint256 adminPrivateKey = 0x1; + uint256 playerPrivateKey = 0x2; uint256 randomPersonPrivateKey = 0x77; address admin = vm.addr(adminPrivateKey); + address player = vm.addr(playerPrivateKey); address randomPerson = vm.addr(randomPersonPrivateKey); uint256 adminPoolID = 1; @@ -85,4 +87,37 @@ contract PlayersTestAdmin is PlayersTestBase { assertEq(players.ProfileImages(index), initialImage); assertNotEq(players.ProfileImages(index), "http://www.example.com"); } + + function test_admin_can_set_token_name() public { + string memory playerName = "Offensive Bunny"; + + vm.prank(player); + uint256 tokenID = players.mint(playerName, 0); + + assertEq(players.Name(tokenID), playerName); + + string memory adminName = "Fluffy Bunny"; + + vm.prank(admin); + players.setTokenName(tokenID, adminName); + + assertEq(players.Name(tokenID), adminName); + } + + function test_non_admin_cannot_set_token_name() public { + string memory playerName = "Offensive Bunny"; + + vm.prank(player); + uint256 tokenID = players.mint(playerName, 0); + + assertEq(players.Name(tokenID), playerName); + + string memory randomName = "Random Bunny"; + + vm.prank(randomPerson); + vm.expectRevert("BeerLeagueBallers._enforceIsAdmin: not admin"); + players.setTokenName(tokenID, randomName); + + assertEq(players.Name(tokenID), playerName); + } } From eaa8f3c02d6005cb08baf84da4328ff8d1e6e4d6 Mon Sep 17 00:00:00 2001 From: Kellan Wampler Date: Mon, 18 Mar 2024 14:35:54 -0400 Subject: [PATCH 07/17] Updating web3 dependency. --- lib/web3 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/web3 b/lib/web3 index ec4e44c5..f2d6bed4 160000 --- a/lib/web3 +++ b/lib/web3 @@ -1 +1 @@ -Subproject commit ec4e44c536cdcc88fbcddd4628955bf607bbad82 +Subproject commit f2d6bed4d0ff8b29fd9f5b6ad8652edc27e96b97 From 507826033a94838e6db57c43f5c8dff04ff8dc0d Mon Sep 17 00:00:00 2001 From: Kellan Wampler Date: Mon, 18 Mar 2024 14:38:16 -0400 Subject: [PATCH 08/17] Using relative path in solidity import. --- src/Players.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Players.sol b/src/Players.sol index e84dba01..db7634ae 100644 --- a/src/Players.sol +++ b/src/Players.sol @@ -6,7 +6,7 @@ import { ERC721 } from "../lib/openzeppelin-contracts/contracts/token/ERC721/ERC import { ERC721Enumerable } from "../lib/openzeppelin-contracts/contracts/token/ERC721/extensions/ERC721Enumerable.sol"; import { Base64 } from "../lib/openzeppelin-contracts/contracts/utils/Base64.sol"; import { Strings } from "../lib/openzeppelin-contracts/contracts/utils/Strings.sol"; -import { ITerminus } from "lib/web3/contracts/interfaces/Iterminus.sol"; +import { ITerminus } from "../lib/web3/contracts/interfaces/Iterminus.sol"; contract BeerLeagueBallers is ERC721Enumerable { string[] public ProfileImages = [ From d7b6e77560f4bdab77ed8902f3d37fc0af0bd097 Mon Sep 17 00:00:00 2001 From: Kellan Wampler Date: Mon, 18 Mar 2024 14:41:58 -0400 Subject: [PATCH 09/17] Fixing web3 path. --- src/Players.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Players.sol b/src/Players.sol index db7634ae..a17b4e3c 100644 --- a/src/Players.sol +++ b/src/Players.sol @@ -6,7 +6,7 @@ import { ERC721 } from "../lib/openzeppelin-contracts/contracts/token/ERC721/ERC import { ERC721Enumerable } from "../lib/openzeppelin-contracts/contracts/token/ERC721/extensions/ERC721Enumerable.sol"; import { Base64 } from "../lib/openzeppelin-contracts/contracts/utils/Base64.sol"; import { Strings } from "../lib/openzeppelin-contracts/contracts/utils/Strings.sol"; -import { ITerminus } from "../lib/web3/contracts/interfaces/Iterminus.sol"; +import { ITerminus } from "web3/interfaces/Iterminus.sol"; contract BeerLeagueBallers is ERC721Enumerable { string[] public ProfileImages = [ From 5bac81e8040185f13a850e9564ac64badc9c2b9b Mon Sep 17 00:00:00 2001 From: Kellan Wampler Date: Mon, 18 Mar 2024 14:52:37 -0400 Subject: [PATCH 10/17] Casing issue in ITerminus import. --- src/Players.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Players.sol b/src/Players.sol index a17b4e3c..eaaf8018 100644 --- a/src/Players.sol +++ b/src/Players.sol @@ -6,7 +6,7 @@ import { ERC721 } from "../lib/openzeppelin-contracts/contracts/token/ERC721/ERC import { ERC721Enumerable } from "../lib/openzeppelin-contracts/contracts/token/ERC721/extensions/ERC721Enumerable.sol"; import { Base64 } from "../lib/openzeppelin-contracts/contracts/utils/Base64.sol"; import { Strings } from "../lib/openzeppelin-contracts/contracts/utils/Strings.sol"; -import { ITerminus } from "web3/interfaces/Iterminus.sol"; +import { ITerminus } from "../lib/web3/contracts/interfaces/ITerminus.sol"; contract BeerLeagueBallers is ERC721Enumerable { string[] public ProfileImages = [ From b59cebd11cba536f00d3385e345ed106dd8fa118 Mon Sep 17 00:00:00 2001 From: Kellan Wampler Date: Mon, 18 Mar 2024 19:01:45 -0400 Subject: [PATCH 11/17] Updating BLB cli. --- python/fullcount/BeerLeagueBallers.py | 116 +++++++++++++++++++++++++- 1 file changed, 113 insertions(+), 3 deletions(-) diff --git a/python/fullcount/BeerLeagueBallers.py b/python/fullcount/BeerLeagueBallers.py index e0d62a8d..92c75bd5 100644 --- a/python/fullcount/BeerLeagueBallers.py +++ b/python/fullcount/BeerLeagueBallers.py @@ -96,9 +96,13 @@ def __init__(self, contract_address: Optional[ChecksumAddress]): self.contract_name, self.address, self.abi ) - def deploy(self, transaction_config): + def deploy( + self, _admin_terminus: ChecksumAddress, _admin_pool_id: int, transaction_config + ): contract_class = contract_from_build(self.contract_name) - deployed_contract = contract_class.deploy(transaction_config) + deployed_contract = contract_class.deploy( + _admin_terminus, _admin_pool_id, transaction_config + ) self.address = deployed_contract.address self.contract = deployed_contract return deployed_contract.tx @@ -130,6 +134,10 @@ def profile_images( self.assert_contract_is_instantiated() return self.contract.ProfileImages.call(arg1, block_identifier=block_number) + def add_profile_image(self, new_image: str, transaction_config) -> Any: + self.assert_contract_is_instantiated() + return self.contract.addProfileImage(new_image, transaction_config) + def approve(self, to: ChecksumAddress, token_id: int, transaction_config) -> Any: self.assert_contract_is_instantiated() return self.contract.approve(to, token_id, transaction_config) @@ -150,6 +158,12 @@ def get_approved( self.assert_contract_is_instantiated() return self.contract.getApproved.call(token_id, block_identifier=block_number) + def get_profile_image_count( + self, block_number: Optional[Union[str, int]] = "latest" + ) -> Any: + self.assert_contract_is_instantiated() + return self.contract.getProfileImageCount.call(block_identifier=block_number) + def is_approved_for_all( self, owner: ChecksumAddress, @@ -210,6 +224,14 @@ def set_approval_for_all( self.assert_contract_is_instantiated() return self.contract.setApprovalForAll(operator, approved, transaction_config) + def set_profile_image(self, index: int, new_image: str, transaction_config) -> Any: + self.assert_contract_is_instantiated() + return self.contract.setProfileImage(index, new_image, transaction_config) + + def set_token_name(self, token_id: int, new_name: str, transaction_config) -> Any: + self.assert_contract_is_instantiated() + return self.contract.setTokenName(token_id, new_name, transaction_config) + def supports_interface( self, interface_id: bytes, block_number: Optional[Union[str, int]] = "latest" ) -> Any: @@ -331,7 +353,11 @@ def handle_deploy(args: argparse.Namespace) -> None: network.connect(args.network) transaction_config = get_transaction_config(args) contract = BeerLeagueBallers(None) - result = contract.deploy(transaction_config=transaction_config) + result = contract.deploy( + _admin_terminus=args.admin_terminus_arg, + _admin_pool_id=args.admin_pool_id_arg, + transaction_config=transaction_config, + ) print(result) if args.verbose: print(result.info()) @@ -365,6 +391,18 @@ def handle_profile_images(args: argparse.Namespace) -> None: print(result) +def handle_add_profile_image(args: argparse.Namespace) -> None: + network.connect(args.network) + contract = BeerLeagueBallers(args.address) + transaction_config = get_transaction_config(args) + result = contract.add_profile_image( + new_image=args.new_image, transaction_config=transaction_config + ) + print(result) + if args.verbose: + print(result.info()) + + def handle_approve(args: argparse.Namespace) -> None: network.connect(args.network) contract = BeerLeagueBallers(args.address) @@ -405,6 +443,13 @@ def handle_get_approved(args: argparse.Namespace) -> None: print(result) +def handle_get_profile_image_count(args: argparse.Namespace) -> None: + network.connect(args.network) + contract = BeerLeagueBallers(args.address) + result = contract.get_profile_image_count(block_number=args.block_number) + print(result) + + def handle_is_approved_for_all(args: argparse.Namespace) -> None: network.connect(args.network) contract = BeerLeagueBallers(args.address) @@ -496,6 +541,34 @@ def handle_set_approval_for_all(args: argparse.Namespace) -> None: print(result.info()) +def handle_set_profile_image(args: argparse.Namespace) -> None: + network.connect(args.network) + contract = BeerLeagueBallers(args.address) + transaction_config = get_transaction_config(args) + result = contract.set_profile_image( + index=args.index, + new_image=args.new_image, + transaction_config=transaction_config, + ) + print(result) + if args.verbose: + print(result.info()) + + +def handle_set_token_name(args: argparse.Namespace) -> None: + network.connect(args.network) + contract = BeerLeagueBallers(args.address) + transaction_config = get_transaction_config(args) + result = contract.set_token_name( + token_id=args.token_id, + new_name=args.new_name, + transaction_config=transaction_config, + ) + print(result) + if args.verbose: + print(result.info()) + + def handle_supports_interface(args: argparse.Namespace) -> None: network.connect(args.network) contract = BeerLeagueBallers(args.address) @@ -564,6 +637,12 @@ def generate_cli() -> argparse.ArgumentParser: deploy_parser = subcommands.add_parser("deploy") add_default_arguments(deploy_parser, True) + deploy_parser.add_argument( + "--admin-terminus-arg", required=True, help="Type: address" + ) + deploy_parser.add_argument( + "--admin-pool-id-arg", required=True, help="Type: uint256", type=int + ) deploy_parser.set_defaults(func=handle_deploy) verify_contract_parser = subcommands.add_parser("verify-contract") @@ -589,6 +668,13 @@ def generate_cli() -> argparse.ArgumentParser: ) profile_images_parser.set_defaults(func=handle_profile_images) + add_profile_image_parser = subcommands.add_parser("add-profile-image") + add_default_arguments(add_profile_image_parser, True) + add_profile_image_parser.add_argument( + "--new-image", required=True, help="Type: string", type=str + ) + add_profile_image_parser.set_defaults(func=handle_add_profile_image) + approve_parser = subcommands.add_parser("approve") add_default_arguments(approve_parser, True) approve_parser.add_argument("--to", required=True, help="Type: address") @@ -616,6 +702,10 @@ def generate_cli() -> argparse.ArgumentParser: ) get_approved_parser.set_defaults(func=handle_get_approved) + get_profile_image_count_parser = subcommands.add_parser("get-profile-image-count") + add_default_arguments(get_profile_image_count_parser, False) + get_profile_image_count_parser.set_defaults(func=handle_get_profile_image_count) + is_approved_for_all_parser = subcommands.add_parser("is-approved-for-all") add_default_arguments(is_approved_for_all_parser, False) is_approved_for_all_parser.add_argument( @@ -699,6 +789,26 @@ def generate_cli() -> argparse.ArgumentParser: ) set_approval_for_all_parser.set_defaults(func=handle_set_approval_for_all) + set_profile_image_parser = subcommands.add_parser("set-profile-image") + add_default_arguments(set_profile_image_parser, True) + set_profile_image_parser.add_argument( + "--index", required=True, help="Type: uint256", type=int + ) + set_profile_image_parser.add_argument( + "--new-image", required=True, help="Type: string", type=str + ) + set_profile_image_parser.set_defaults(func=handle_set_profile_image) + + set_token_name_parser = subcommands.add_parser("set-token-name") + add_default_arguments(set_token_name_parser, True) + set_token_name_parser.add_argument( + "--token-id", required=True, help="Type: uint256", type=int + ) + set_token_name_parser.add_argument( + "--new-name", required=True, help="Type: string", type=str + ) + set_token_name_parser.set_defaults(func=handle_set_token_name) + supports_interface_parser = subcommands.add_parser("supports-interface") add_default_arguments(supports_interface_parser, False) supports_interface_parser.add_argument( From 3d3160c30217d30c11eb2578a8aa80f9c1007af8 Mon Sep 17 00:00:00 2001 From: Kellan Wampler Date: Tue, 19 Mar 2024 13:47:15 -0400 Subject: [PATCH 12/17] Adding TODO back to "unstake" rename comment. --- src/Fullcount.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Fullcount.sol b/src/Fullcount.sol index 2ea8bef5..975a20dd 100644 --- a/src/Fullcount.sol +++ b/src/Fullcount.sol @@ -473,7 +473,7 @@ contract Fullcount is EIP712 { SessionAtBat[nextSessionID] = atBatID; } - // Possibly change name of function as tokens are no longer staked? + // TODO change name of function as tokens are no longer staked? function _unstakeNFT(address nftAddress, uint256 tokenID) internal { require(_isTokenOwner(nftAddress, tokenID), "Fullcount._unstakeNFT: msg.sender is not NFT owner"); From 5ab8f8e89537bde6b432deba38787a9176ede0f9 Mon Sep 17 00:00:00 2001 From: Kellan Wampler Date: Tue, 19 Mar 2024 16:52:28 -0400 Subject: [PATCH 13/17] Updating Fullcount version. --- src/Fullcount.sol | 2 +- src/Players.sol | 17 +---------------- test/Fullcount.t.sol | 4 ++-- 3 files changed, 4 insertions(+), 19 deletions(-) diff --git a/src/Fullcount.sol b/src/Fullcount.sol index 975a20dd..0c10f354 100644 --- a/src/Fullcount.sol +++ b/src/Fullcount.sol @@ -56,7 +56,7 @@ Functionality: second commit, then the session is cancelled and both players may unstake their NFTs. */ contract Fullcount is EIP712 { - string public constant FullcountVersion = "0.1.0"; + string public constant FullcountVersion = "0.1.1"; uint256 public SecondsPerPhase; diff --git a/src/Players.sol b/src/Players.sol index a3e741f1..068882e2 100644 --- a/src/Players.sol +++ b/src/Players.sol @@ -17,22 +17,7 @@ contract BeerLeagueBallers is ERC721Enumerable { "https://badges.moonstream.to/blb/p5.png", "https://badges.moonstream.to/blb/p6.png", "https://badges.moonstream.to/blb/p7.png", - "https://badges.moonstream.to/blb/p8.png", - "https://badges.moonstream.to/blb/p9.png", - "https://badges.moonstream.to/blb/p10.png", - "https://badges.moonstream.to/blb/p11.png", - "https://badges.moonstream.to/blb/p12.png", - "https://badges.moonstream.to/blb/p13.png", - "https://badges.moonstream.to/blb/p14.png", - "https://badges.moonstream.to/blb/p15.png", - "https://badges.moonstream.to/blb/p16.png", - "https://badges.moonstream.to/blb/p17.png", - "https://badges.moonstream.to/blb/p18.png", - "https://badges.moonstream.to/blb/p19.png", - "https://badges.moonstream.to/blb/p20.png", - "https://badges.moonstream.to/blb/p21.png", - "https://badges.moonstream.to/blb/p22.png", - "https://badges.moonstream.to/blb/p23.png" + "https://badges.moonstream.to/blb/p8.png" ]; mapping(uint256 => string) public Name; diff --git a/test/Fullcount.t.sol b/test/Fullcount.t.sol index c9eb979e..c378d231 100644 --- a/test/Fullcount.t.sol +++ b/test/Fullcount.t.sol @@ -207,9 +207,9 @@ contract FullcountTestBase is Test { contract FullcountTestDeployment is FullcountTestBase { function test_Deployment() public { vm.expectEmit(); - emit FullcountDeployed("0.1.0", secondsPerPhase); + emit FullcountDeployed("0.1.1", secondsPerPhase); Fullcount newGame = new Fullcount(secondsPerPhase); - assertEq(newGame.FullcountVersion(), "0.1.0"); + assertEq(newGame.FullcountVersion(), "0.1.1"); assertEq(newGame.SecondsPerPhase(), secondsPerPhase); assertEq(newGame.NumSessions(), 0); } From ee092ce3956d8316a894d30bf7df638eaecfd5de Mon Sep 17 00:00:00 2001 From: Kellan Wampler Date: Tue, 19 Mar 2024 16:53:44 -0400 Subject: [PATCH 14/17] Removing extra images. --- src/Players.sol | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/Players.sol b/src/Players.sol index 068882e2..01a96350 100644 --- a/src/Players.sol +++ b/src/Players.sol @@ -16,8 +16,7 @@ contract BeerLeagueBallers is ERC721Enumerable { "https://badges.moonstream.to/blb/p4.png", "https://badges.moonstream.to/blb/p5.png", "https://badges.moonstream.to/blb/p6.png", - "https://badges.moonstream.to/blb/p7.png", - "https://badges.moonstream.to/blb/p8.png" + "https://badges.moonstream.to/blb/p7.png" ]; mapping(uint256 => string) public Name; From e6df7446fe3e923091ec77947162c436c517c27d Mon Sep 17 00:00:00 2001 From: Kellan Wampler Date: Wed, 20 Mar 2024 09:01:39 -0400 Subject: [PATCH 15/17] Updating images. --- src/Players.sol | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/Players.sol b/src/Players.sol index bb8d1089..82bbb098 100644 --- a/src/Players.sol +++ b/src/Players.sol @@ -10,14 +10,14 @@ import { ITerminus } from "../lib/web3/contracts/interfaces/ITerminus.sol"; contract BeerLeagueBallers is ERC721Enumerable { string[] public ProfileImages = [ - "https://badges.moonstream.to/blb/p0.png", - "https://badges.moonstream.to/blb/p1.png", - "https://badges.moonstream.to/blb/p2.png", - "https://badges.moonstream.to/blb/p3.png", - "https://badges.moonstream.to/blb/p4.png", - "https://badges.moonstream.to/blb/p5.png", - "https://badges.moonstream.to/blb/p6.png", - "https://badges.moonstream.to/blb/p7.png" + "https://s3.amazonaws.com/static.fullcount.xyz/Beer_League_Ballers/p0.png", + "https://s3.amazonaws.com/static.fullcount.xyz/Beer_League_Ballers/p1.png", + "https://s3.amazonaws.com/static.fullcount.xyz/Beer_League_Ballers/p2.png", + "https://s3.amazonaws.com/static.fullcount.xyz/Beer_League_Ballers/p3.png", + "https://s3.amazonaws.com/static.fullcount.xyz/Beer_League_Ballers/p4.png", + "https://s3.amazonaws.com/static.fullcount.xyz/Beer_League_Ballers/p5.png", + "https://s3.amazonaws.com/static.fullcount.xyz/Beer_League_Ballers/p6.png", + "https://s3.amazonaws.com/static.fullcount.xyz/Beer_League_Ballers/p7.png" ]; mapping(uint256 => string) public Name; From 9d91e4156beb1dbd97f24bd3c2ed65d8f27e6e02 Mon Sep 17 00:00:00 2001 From: Kellan Wampler Date: Thu, 21 Mar 2024 15:06:14 -0400 Subject: [PATCH 16/17] Changing array of images to mapping. Batching setTokenNames method. Adding setTokenImages method (also batched). --- python/fullcount/BeerLeagueBallers.py | 124 +++++++++++++++++--------- src/Players.sol | 57 ++++++++---- test/Players.t.sol | 119 +++++++++++++++++------- 3 files changed, 207 insertions(+), 93 deletions(-) diff --git a/python/fullcount/BeerLeagueBallers.py b/python/fullcount/BeerLeagueBallers.py index 92c75bd5..7469e66e 100644 --- a/python/fullcount/BeerLeagueBallers.py +++ b/python/fullcount/BeerLeagueBallers.py @@ -128,6 +128,12 @@ def name( self.assert_contract_is_instantiated() return self.contract.Name.call(arg1, block_identifier=block_number) + def num_profile_images( + self, block_number: Optional[Union[str, int]] = "latest" + ) -> Any: + self.assert_contract_is_instantiated() + return self.contract.NumProfileImages.call(block_identifier=block_number) + def profile_images( self, arg1: int, block_number: Optional[Union[str, int]] = "latest" ) -> Any: @@ -158,12 +164,6 @@ def get_approved( self.assert_contract_is_instantiated() return self.contract.getApproved.call(token_id, block_identifier=block_number) - def get_profile_image_count( - self, block_number: Optional[Union[str, int]] = "latest" - ) -> Any: - self.assert_contract_is_instantiated() - return self.contract.getProfileImageCount.call(block_identifier=block_number) - def is_approved_for_all( self, owner: ChecksumAddress, @@ -224,13 +224,21 @@ def set_approval_for_all( self.assert_contract_is_instantiated() return self.contract.setApprovalForAll(operator, approved, transaction_config) - def set_profile_image(self, index: int, new_image: str, transaction_config) -> Any: + def set_token_images( + self, token_id_list: List, image_index_list: List, transaction_config + ) -> Any: self.assert_contract_is_instantiated() - return self.contract.setProfileImage(index, new_image, transaction_config) + return self.contract.setTokenImages( + token_id_list, image_index_list, transaction_config + ) - def set_token_name(self, token_id: int, new_name: str, transaction_config) -> Any: + def set_token_names( + self, token_id_list: List, new_name_list: List, transaction_config + ) -> Any: self.assert_contract_is_instantiated() - return self.contract.setTokenName(token_id, new_name, transaction_config) + return self.contract.setTokenNames( + token_id_list, new_name_list, transaction_config + ) def supports_interface( self, interface_id: bytes, block_number: Optional[Union[str, int]] = "latest" @@ -281,6 +289,12 @@ def transfer_from( self.assert_contract_is_instantiated() return self.contract.transferFrom(from_, to, token_id, transaction_config) + def update_profile_image( + self, index: int, new_image: str, transaction_config + ) -> Any: + self.assert_contract_is_instantiated() + return self.contract.updateProfileImage(index, new_image, transaction_config) + def get_transaction_config(args: argparse.Namespace) -> Dict[str, Any]: signer = network.accounts.load(args.sender, args.password) @@ -384,6 +398,13 @@ def handle_name(args: argparse.Namespace) -> None: print(result) +def handle_num_profile_images(args: argparse.Namespace) -> None: + network.connect(args.network) + contract = BeerLeagueBallers(args.address) + result = contract.num_profile_images(block_number=args.block_number) + print(result) + + def handle_profile_images(args: argparse.Namespace) -> None: network.connect(args.network) contract = BeerLeagueBallers(args.address) @@ -443,13 +464,6 @@ def handle_get_approved(args: argparse.Namespace) -> None: print(result) -def handle_get_profile_image_count(args: argparse.Namespace) -> None: - network.connect(args.network) - contract = BeerLeagueBallers(args.address) - result = contract.get_profile_image_count(block_number=args.block_number) - print(result) - - def handle_is_approved_for_all(args: argparse.Namespace) -> None: network.connect(args.network) contract = BeerLeagueBallers(args.address) @@ -541,13 +555,13 @@ def handle_set_approval_for_all(args: argparse.Namespace) -> None: print(result.info()) -def handle_set_profile_image(args: argparse.Namespace) -> None: +def handle_set_token_images(args: argparse.Namespace) -> None: network.connect(args.network) contract = BeerLeagueBallers(args.address) transaction_config = get_transaction_config(args) - result = contract.set_profile_image( - index=args.index, - new_image=args.new_image, + result = contract.set_token_images( + token_id_list=args.token_id_list, + image_index_list=args.image_index_list, transaction_config=transaction_config, ) print(result) @@ -555,13 +569,13 @@ def handle_set_profile_image(args: argparse.Namespace) -> None: print(result.info()) -def handle_set_token_name(args: argparse.Namespace) -> None: +def handle_set_token_names(args: argparse.Namespace) -> None: network.connect(args.network) contract = BeerLeagueBallers(args.address) transaction_config = get_transaction_config(args) - result = contract.set_token_name( - token_id=args.token_id, - new_name=args.new_name, + result = contract.set_token_names( + token_id_list=args.token_id_list, + new_name_list=args.new_name_list, transaction_config=transaction_config, ) print(result) @@ -630,6 +644,20 @@ def handle_transfer_from(args: argparse.Namespace) -> None: print(result.info()) +def handle_update_profile_image(args: argparse.Namespace) -> None: + network.connect(args.network) + contract = BeerLeagueBallers(args.address) + transaction_config = get_transaction_config(args) + result = contract.update_profile_image( + index=args.index, + new_image=args.new_image, + transaction_config=transaction_config, + ) + print(result) + if args.verbose: + print(result.info()) + + def generate_cli() -> argparse.ArgumentParser: parser = argparse.ArgumentParser(description="CLI for BeerLeagueBallers") parser.set_defaults(func=lambda _: parser.print_help()) @@ -661,6 +689,10 @@ def generate_cli() -> argparse.ArgumentParser: name_parser.add_argument("--arg1", required=True, help="Type: uint256", type=int) name_parser.set_defaults(func=handle_name) + num_profile_images_parser = subcommands.add_parser("num-profile-images") + add_default_arguments(num_profile_images_parser, False) + num_profile_images_parser.set_defaults(func=handle_num_profile_images) + profile_images_parser = subcommands.add_parser("profile-images") add_default_arguments(profile_images_parser, False) profile_images_parser.add_argument( @@ -702,10 +734,6 @@ def generate_cli() -> argparse.ArgumentParser: ) get_approved_parser.set_defaults(func=handle_get_approved) - get_profile_image_count_parser = subcommands.add_parser("get-profile-image-count") - add_default_arguments(get_profile_image_count_parser, False) - get_profile_image_count_parser.set_defaults(func=handle_get_profile_image_count) - is_approved_for_all_parser = subcommands.add_parser("is-approved-for-all") add_default_arguments(is_approved_for_all_parser, False) is_approved_for_all_parser.add_argument( @@ -789,25 +817,25 @@ def generate_cli() -> argparse.ArgumentParser: ) set_approval_for_all_parser.set_defaults(func=handle_set_approval_for_all) - set_profile_image_parser = subcommands.add_parser("set-profile-image") - add_default_arguments(set_profile_image_parser, True) - set_profile_image_parser.add_argument( - "--index", required=True, help="Type: uint256", type=int + set_token_images_parser = subcommands.add_parser("set-token-images") + add_default_arguments(set_token_images_parser, True) + set_token_images_parser.add_argument( + "--token-id-list", required=True, help="Type: uint256[]", nargs="+" ) - set_profile_image_parser.add_argument( - "--new-image", required=True, help="Type: string", type=str + set_token_images_parser.add_argument( + "--image-index-list", required=True, help="Type: uint256[]", nargs="+" ) - set_profile_image_parser.set_defaults(func=handle_set_profile_image) + set_token_images_parser.set_defaults(func=handle_set_token_images) - set_token_name_parser = subcommands.add_parser("set-token-name") - add_default_arguments(set_token_name_parser, True) - set_token_name_parser.add_argument( - "--token-id", required=True, help="Type: uint256", type=int + set_token_names_parser = subcommands.add_parser("set-token-names") + add_default_arguments(set_token_names_parser, True) + set_token_names_parser.add_argument( + "--token-id-list", required=True, help="Type: uint256[]", nargs="+" ) - set_token_name_parser.add_argument( - "--new-name", required=True, help="Type: string", type=str + set_token_names_parser.add_argument( + "--new-name-list", required=True, help="Type: string[]", nargs="+" ) - set_token_name_parser.set_defaults(func=handle_set_token_name) + set_token_names_parser.set_defaults(func=handle_set_token_names) supports_interface_parser = subcommands.add_parser("supports-interface") add_default_arguments(supports_interface_parser, False) @@ -857,6 +885,16 @@ def generate_cli() -> argparse.ArgumentParser: ) transfer_from_parser.set_defaults(func=handle_transfer_from) + update_profile_image_parser = subcommands.add_parser("update-profile-image") + add_default_arguments(update_profile_image_parser, True) + update_profile_image_parser.add_argument( + "--index", required=True, help="Type: uint256", type=int + ) + update_profile_image_parser.add_argument( + "--new-image", required=True, help="Type: string", type=str + ) + update_profile_image_parser.set_defaults(func=handle_update_profile_image) + return parser diff --git a/src/Players.sol b/src/Players.sol index 82bbb098..23e75a97 100644 --- a/src/Players.sol +++ b/src/Players.sol @@ -9,16 +9,8 @@ import { Strings } from "../lib/openzeppelin-contracts/contracts/utils/Strings.s import { ITerminus } from "../lib/web3/contracts/interfaces/ITerminus.sol"; contract BeerLeagueBallers is ERC721Enumerable { - string[] public ProfileImages = [ - "https://s3.amazonaws.com/static.fullcount.xyz/Beer_League_Ballers/p0.png", - "https://s3.amazonaws.com/static.fullcount.xyz/Beer_League_Ballers/p1.png", - "https://s3.amazonaws.com/static.fullcount.xyz/Beer_League_Ballers/p2.png", - "https://s3.amazonaws.com/static.fullcount.xyz/Beer_League_Ballers/p3.png", - "https://s3.amazonaws.com/static.fullcount.xyz/Beer_League_Ballers/p4.png", - "https://s3.amazonaws.com/static.fullcount.xyz/Beer_League_Ballers/p5.png", - "https://s3.amazonaws.com/static.fullcount.xyz/Beer_League_Ballers/p6.png", - "https://s3.amazonaws.com/static.fullcount.xyz/Beer_League_Ballers/p7.png" - ]; + mapping(uint256 => string) public ProfileImages; + uint256 public NumProfileImages; mapping(uint256 => string) public Name; mapping(uint256 => uint256) public ImageIndex; @@ -29,6 +21,16 @@ contract BeerLeagueBallers is ERC721Enumerable { constructor(address _adminTerminus, uint256 _adminPoolID) ERC721("Beer League Ballers", "BLB") { adminTerminus = _adminTerminus; adminPoolID = _adminPoolID; + + ProfileImages[0] = "https://s3.amazonaws.com/static.fullcount.xyz/Beer_League_Ballers/p0.png"; + ProfileImages[1] = "https://s3.amazonaws.com/static.fullcount.xyz/Beer_League_Ballers/p1.png"; + ProfileImages[2] = "https://s3.amazonaws.com/static.fullcount.xyz/Beer_League_Ballers/p2.png"; + ProfileImages[3] = "https://s3.amazonaws.com/static.fullcount.xyz/Beer_League_Ballers/p3.png"; + ProfileImages[4] = "https://s3.amazonaws.com/static.fullcount.xyz/Beer_League_Ballers/p4.png"; + ProfileImages[5] = "https://s3.amazonaws.com/static.fullcount.xyz/Beer_League_Ballers/p5.png"; + ProfileImages[6] = "https://s3.amazonaws.com/static.fullcount.xyz/Beer_League_Ballers/p6.png"; + ProfileImages[7] = "https://s3.amazonaws.com/static.fullcount.xyz/Beer_League_Ballers/p7.png"; + NumProfileImages = 8; } function _enforceIsAdmin() internal view { @@ -36,30 +38,47 @@ contract BeerLeagueBallers is ERC721Enumerable { require(terminus.balanceOf(msg.sender, adminPoolID) > 0, "BeerLeagueBallers._enforceIsAdmin: not admin"); } - function getProfileImageCount() external view returns (uint256) { - return ProfileImages.length; - } - function addProfileImage(string memory newImage) public { _enforceIsAdmin(); - ProfileImages.push(newImage); + ProfileImages[NumProfileImages] = newImage; + NumProfileImages++; } - function setProfileImage(uint256 index, string memory newImage) public { + function updateProfileImage(uint256 index, string memory newImage) public { _enforceIsAdmin(); ProfileImages[index] = newImage; } - function setTokenName(uint256 tokenID, string memory newName) public { + function setTokenNames(uint256[] memory tokenIDList, string[] memory newNameList) public { _enforceIsAdmin(); - Name[tokenID] = newName; + require( + tokenIDList.length == newNameList.length, + "BeerLeagueBallers.setTokenNames: tokenIDList and newNameList length mismatch" + ); + + for (uint256 i = 0; i < tokenIDList.length; i++) { + Name[tokenIDList[i]] = newNameList[i]; + } + } + + function setTokenImages(uint256[] memory tokenIDList, uint256[] memory imageIndexList) public { + _enforceIsAdmin(); + + require( + tokenIDList.length == imageIndexList.length, + "BeerLeagueBallers.setTokenImages: tokenIDList and imageIndexList length mismatch" + ); + + for (uint256 i = 0; i < tokenIDList.length; i++) { + ImageIndex[tokenIDList[i]] = imageIndexList[i]; + } } function mint(string memory name, uint256 imageIndex) public returns (uint256) { - require(imageIndex < ProfileImages.length, "BLB.mint: invalid image index"); + require(imageIndex < NumProfileImages, "BLB.mint: invalid image index"); uint256 tokenId = totalSupply() + 1; Name[tokenId] = name; ImageIndex[tokenId] = imageIndex; diff --git a/test/Players.t.sol b/test/Players.t.sol index c8c6c4c5..761b9839 100644 --- a/test/Players.t.sol +++ b/test/Players.t.sol @@ -2,9 +2,7 @@ pragma solidity ^0.8.13; import { Test } from "../lib/forge-std/src/Test.sol"; -import { console2 as console } from "../lib/forge-std/src/console2.sol"; import { BeerLeagueBallers } from "../src/Players.sol"; -// import { TerminusFacet } from "../lib/web3/contracts/terminus/TerminusFacet.sol"; import "@openzeppelin-contracts/contracts/token/ERC1155/extensions/ERC1155Burnable.sol"; contract MockERC1155 is ERC1155Burnable { @@ -19,20 +17,18 @@ contract MockERC1155 is ERC1155Burnable { } } -// contract MockTerminus is TerminusFacet { -// constructor() { } -// } - contract PlayersTestBase is Test { BeerLeagueBallers players; MockERC1155 terminus; uint256 adminPrivateKey = 0x1; - uint256 playerPrivateKey = 0x2; - uint256 randomPersonPrivateKey = 0x77; + uint256 player1PrivateKey = 0x101; + uint256 player2PrivateKey = 0x102; + uint256 randomPersonPrivateKey = 0x201; address admin = vm.addr(adminPrivateKey); - address player = vm.addr(playerPrivateKey); + address player1 = vm.addr(player1PrivateKey); + address player2 = vm.addr(player2PrivateKey); address randomPerson = vm.addr(randomPersonPrivateKey); uint256 adminPoolID = 1; @@ -47,22 +43,22 @@ contract PlayersTestBase is Test { contract PlayersTestAdmin is PlayersTestBase { function test_admin_can_add_profile_image() public { - uint256 initialImageCount = players.getProfileImageCount(); + uint256 initialImageCount = players.NumProfileImages(); vm.prank(admin); players.addProfileImage("http://www.example.com"); - assertEq(players.getProfileImageCount(), initialImageCount + 1); + assertEq(players.NumProfileImages(), initialImageCount + 1); } function test_non_admin_cannot_add_profile_image() public { - uint256 initialImageCount = players.getProfileImageCount(); + uint256 initialImageCount = players.NumProfileImages(); vm.prank(randomPerson); vm.expectRevert("BeerLeagueBallers._enforceIsAdmin: not admin"); players.addProfileImage("http://www.example.com"); - assertEq(players.getProfileImageCount(), initialImageCount); + assertEq(players.NumProfileImages(), initialImageCount); } function test_admin_can_set_profile_image() public { @@ -70,7 +66,7 @@ contract PlayersTestAdmin is PlayersTestBase { string memory initialImage = players.ProfileImages(index); vm.prank(admin); - players.setProfileImage(index, "http://www.example.com"); + players.updateProfileImage(index, "http://www.example.com"); assertEq(players.ProfileImages(index), "http://www.example.com"); assertNotEq(players.ProfileImages(index), initialImage); @@ -82,42 +78,103 @@ contract PlayersTestAdmin is PlayersTestBase { vm.prank(randomPerson); vm.expectRevert("BeerLeagueBallers._enforceIsAdmin: not admin"); - players.setProfileImage(index, "http://www.example.com"); + players.updateProfileImage(index, "http://www.example.com"); assertEq(players.ProfileImages(index), initialImage); assertNotEq(players.ProfileImages(index), "http://www.example.com"); } - function test_admin_can_set_token_name() public { - string memory playerName = "Offensive Bunny"; + function test_admin_can_set_token_name_and_images() public { + string memory firstOffensiveName = "Offensive Bunny"; + string memory secondOffensiveName = "Explitive Bunny"; + uint256 firstTokenImageIndex = 0; + uint256 secondTokenImageIndex = 5; + + vm.prank(player1); + uint256 firstTokenID = players.mint(firstOffensiveName, firstTokenImageIndex); - vm.prank(player); - uint256 tokenID = players.mint(playerName, 0); + vm.prank(player2); + uint256 secondTokenID = players.mint(secondOffensiveName, secondTokenImageIndex); - assertEq(players.Name(tokenID), playerName); + assertEq(players.Name(firstTokenID), firstOffensiveName); + assertEq(players.Name(secondTokenID), secondOffensiveName); + assertEq(players.ImageIndex(firstTokenID), firstTokenImageIndex); + assertEq(players.ImageIndex(secondTokenID), secondTokenImageIndex); string memory adminName = "Fluffy Bunny"; + uint256 adminImageIndex = 2; - vm.prank(admin); - players.setTokenName(tokenID, adminName); + uint256[] memory tokenList = new uint256[](2); + tokenList[0] = firstTokenID; + tokenList[1] = secondTokenID; + + string[] memory nameList = new string[](2); + nameList[0] = adminName; + nameList[1] = adminName; + + uint256[] memory imageIndexList = new uint256[](2); + imageIndexList[0] = adminImageIndex; + imageIndexList[1] = adminImageIndex; + + vm.startPrank(admin); + + players.setTokenNames(tokenList, nameList); + + players.setTokenImages(tokenList, imageIndexList); + + vm.stopPrank(); - assertEq(players.Name(tokenID), adminName); + assertEq(players.Name(firstTokenID), adminName); + assertEq(players.Name(secondTokenID), adminName); + assertEq(players.ImageIndex(firstTokenID), adminImageIndex); + assertEq(players.ImageIndex(secondTokenID), adminImageIndex); } - function test_non_admin_cannot_set_token_name() public { - string memory playerName = "Offensive Bunny"; + function test_non_admin_cannot_set_token_name_or_images() public { + string memory firstOffensiveName = "Offensive Bunny"; + string memory secondOffensiveName = "Explitive Bunny"; + uint256 firstTokenImageIndex = 1; + uint256 secondTokenImageIndex = 3; - vm.prank(player); - uint256 tokenID = players.mint(playerName, 0); + vm.prank(player1); + uint256 firstTokenID = players.mint(firstOffensiveName, firstTokenImageIndex); - assertEq(players.Name(tokenID), playerName); + vm.prank(player2); + uint256 secondTokenID = players.mint(secondOffensiveName, secondTokenImageIndex); + + assertEq(players.Name(firstTokenID), firstOffensiveName); + assertEq(players.Name(secondTokenID), secondOffensiveName); + assertEq(players.ImageIndex(firstTokenID), firstTokenImageIndex); + assertEq(players.ImageIndex(secondTokenID), secondTokenImageIndex); string memory randomName = "Random Bunny"; + uint256 randomImageIndex = 7; + + uint256[] memory tokenList = new uint256[](2); + tokenList[0] = firstTokenID; + tokenList[1] = secondTokenID; + + string[] memory nameList = new string[](2); + nameList[0] = randomName; + nameList[1] = randomName; + + uint256[] memory imageIndexList = new uint256[](2); + imageIndexList[0] = randomImageIndex; + imageIndexList[1] = randomImageIndex; + + vm.startPrank(randomPerson); + + vm.expectRevert("BeerLeagueBallers._enforceIsAdmin: not admin"); + players.setTokenNames(tokenList, nameList); - vm.prank(randomPerson); vm.expectRevert("BeerLeagueBallers._enforceIsAdmin: not admin"); - players.setTokenName(tokenID, randomName); + players.setTokenImages(tokenList, imageIndexList); + + vm.stopPrank(); - assertEq(players.Name(tokenID), playerName); + assertEq(players.Name(firstTokenID), firstOffensiveName); + assertEq(players.Name(secondTokenID), secondOffensiveName); + assertEq(players.ImageIndex(firstTokenID), firstTokenImageIndex); + assertEq(players.ImageIndex(secondTokenID), secondTokenImageIndex); } } From 24c40c966b057854736a9e5dbb344a2437e8cb62 Mon Sep 17 00:00:00 2001 From: Kellan Wampler Date: Fri, 22 Mar 2024 13:31:23 -0400 Subject: [PATCH 17/17] Using cdn urls for metadata. Updating tests per PR. --- src/Players.sol | 16 ++++++++-------- test/Players.t.sol | 18 ++++++++++++------ 2 files changed, 20 insertions(+), 14 deletions(-) diff --git a/src/Players.sol b/src/Players.sol index 23e75a97..29273451 100644 --- a/src/Players.sol +++ b/src/Players.sol @@ -22,14 +22,14 @@ contract BeerLeagueBallers is ERC721Enumerable { adminTerminus = _adminTerminus; adminPoolID = _adminPoolID; - ProfileImages[0] = "https://s3.amazonaws.com/static.fullcount.xyz/Beer_League_Ballers/p0.png"; - ProfileImages[1] = "https://s3.amazonaws.com/static.fullcount.xyz/Beer_League_Ballers/p1.png"; - ProfileImages[2] = "https://s3.amazonaws.com/static.fullcount.xyz/Beer_League_Ballers/p2.png"; - ProfileImages[3] = "https://s3.amazonaws.com/static.fullcount.xyz/Beer_League_Ballers/p3.png"; - ProfileImages[4] = "https://s3.amazonaws.com/static.fullcount.xyz/Beer_League_Ballers/p4.png"; - ProfileImages[5] = "https://s3.amazonaws.com/static.fullcount.xyz/Beer_League_Ballers/p5.png"; - ProfileImages[6] = "https://s3.amazonaws.com/static.fullcount.xyz/Beer_League_Ballers/p6.png"; - ProfileImages[7] = "https://s3.amazonaws.com/static.fullcount.xyz/Beer_League_Ballers/p7.png"; + ProfileImages[0] = "https://static.fullcount.xyz/Beer_League_Ballers/p0.png"; + ProfileImages[1] = "https://static.fullcount.xyz/Beer_League_Ballers/p1.png"; + ProfileImages[2] = "https://static.fullcount.xyz/Beer_League_Ballers/p2.png"; + ProfileImages[3] = "https://static.fullcount.xyz/Beer_League_Ballers/p3.png"; + ProfileImages[4] = "https://static.fullcount.xyz/Beer_League_Ballers/p4.png"; + ProfileImages[5] = "https://static.fullcount.xyz/Beer_League_Ballers/p5.png"; + ProfileImages[6] = "https://static.fullcount.xyz/Beer_League_Ballers/p6.png"; + ProfileImages[7] = "https://static.fullcount.xyz/Beer_League_Ballers/p7.png"; NumProfileImages = 8; } diff --git a/test/Players.t.sol b/test/Players.t.sol index 761b9839..02e1dfab 100644 --- a/test/Players.t.sol +++ b/test/Players.t.sol @@ -46,7 +46,7 @@ contract PlayersTestAdmin is PlayersTestBase { uint256 initialImageCount = players.NumProfileImages(); vm.prank(admin); - players.addProfileImage("http://www.example.com"); + players.addProfileImage("http://www.example.com/test_admin_can_add_profile_image"); assertEq(players.NumProfileImages(), initialImageCount + 1); } @@ -56,7 +56,7 @@ contract PlayersTestAdmin is PlayersTestBase { vm.prank(randomPerson); vm.expectRevert("BeerLeagueBallers._enforceIsAdmin: not admin"); - players.addProfileImage("http://www.example.com"); + players.addProfileImage("http://www.example.com/test_non_admin_cannot_add_profile_image"); assertEq(players.NumProfileImages(), initialImageCount); } @@ -64,24 +64,30 @@ contract PlayersTestAdmin is PlayersTestBase { function test_admin_can_set_profile_image() public { uint256 index = 1; string memory initialImage = players.ProfileImages(index); + string memory newImage = "http://www.example.com/test_admin_can_set_profile_image"; + + assertNotEq(players.ProfileImages(index), newImage); vm.prank(admin); - players.updateProfileImage(index, "http://www.example.com"); + players.updateProfileImage(index, newImage); - assertEq(players.ProfileImages(index), "http://www.example.com"); + assertEq(players.ProfileImages(index), newImage); assertNotEq(players.ProfileImages(index), initialImage); } function test_non_admin_cannot_set_profile_image() public { uint256 index = 1; string memory initialImage = players.ProfileImages(index); + string memory newImage = "http://www.example.com/test_non_admin_cannot_set_profile_image"; + + assertNotEq(players.ProfileImages(index), newImage); vm.prank(randomPerson); vm.expectRevert("BeerLeagueBallers._enforceIsAdmin: not admin"); - players.updateProfileImage(index, "http://www.example.com"); + players.updateProfileImage(index, newImage); assertEq(players.ProfileImages(index), initialImage); - assertNotEq(players.ProfileImages(index), "http://www.example.com"); + assertNotEq(players.ProfileImages(index), newImage); } function test_admin_can_set_token_name_and_images() public {