Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Mainnet] Hashbattle Gaming Contract #84

Open
wants to merge 7 commits into
base: master
Choose a base branch
from

Conversation

mksmanish79
Copy link
Contributor

@mksmanish79 mksmanish79 commented Oct 26, 2022

Hashbattle Smart Contract

Description

Smart contract for running a game battle where owner will start the battle and maximum 4 users can enter a battle

Compiler Version

v2.0.0

Contract Hash

07e52e71a4ce2afa30d03280b15a205b53eb7131c5fae709031fdf570d4a80b2

Contract Byte Code

4D5A90000300000004000000FFFF0000B800000000000000400000000000000000000000000000000000000000000000000000000000000000000000800000000E1FBA0E00B409CD21B8014CCD21546869732070726F6772616D2063616E6E6F742062652072756E20696E20444F53206D6F64652E0D0D0A2400000000000000504500004C010200E6EB4ACA0000000000000000E00022200B013000001A000000020000000000001E380000002000000040000000000010002000000002000004000000000000000400000000000000006000000002000000000000030040850000100000100000000010000010000000000000100000000000000000000000CC3700004F000000000000000000000000000000000000000000000000000000004000000C000000B03700001C0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000080000000000000000000000082000004800000000000000000000002E746578740000002418000000200000001A000000020000000000000000000000000000200000602E72656C6F6300000C0000000040000000020000001C0000000000000000000000000000400000420000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003800000000000048000000020005000C270000A410000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007602280500000A7201000070038C0B000001280600000A046F0100002B2A7202280500000A7201000070038C0B000001280600000A6F0200002B2A8E02280500000A7217000070038C0B000001048C06000001280900000A056F0300002B2A8A02280500000A7217000070038C0B000001048C06000001280900000A6F0400002B2A7602280500000A7231000070038C0B000001280600000A046F0500002B2A7202280500000A7231000070038C0B000001280600000A6F0600002B2A7602280500000A7247000070038C0B000001280600000A046F0A00000A2A7202280500000A7247000070038C0B000001280600000A6F0B00000A2A7602280500000A7259000070038C0B000001280600000A046F0A00000A2A7202280500000A7259000070038C0B000001280600000A6F0B00000A2A4602280500000A72790000706F0C00000A2A4A02280500000A7279000070036F0D00000A2A4602280500000A72850000706F0C00000A2A4A02280500000A7285000070036F0D00000A2A4602280500000A729F0000706F0B00000A2A4A02280500000A729F000070036F0A00000A2A4602280500000A72B10000706F0E00000A2A4A02280500000A72B1000070036F0F00000A2AA20203281000000A0202281100000A6F1200000A280C0000060204281000000602176A28120000062A13300300320000000100001102281D0000060203280E000006021200FE1507000002120002280B0000067D0C0000041200037D0D00000406280700002B2A0000133003005C0000000200001102280D0000060A020602281100000A6F1200000A281400000A72CB000070281500000A02280B0000060B0206280C000006027E1600000A280E000006021202FE15060000021202077D0A0000041202067D0B00000408280800002B2A13300400A9000000030000110202281100000A6F1200000A02280B000006281400000A723D010070281500000A0203156A02280F0000066E5CFE057281010070281500000A0228110000060A0206176AD728120000061202FE15030000021202067D010000041202037D04000004120202280F0000068D060000017D03000004080B0206072801000006021203FE15080000021203067D0E000004120302281100000A6F1200000A7D0F00000409280900002B062A00000013300400F300000004000011020328020000060A02067B020000047E1600000A281400000A72A1010070281500000A02067B0400000402281100000A6F1700000AFE0172C5010070281500000A020302281100000A6F1200000A28040000060B02077B0600000416FE017225020070281500000A020302281100000A6F1200000A072803000006020328080000060C020802280F000006FE0116FE017269020070281500000A067B0300000402281100000A6F1200000A8C06000001086E6F1800000A02030817D728070000060203062801000006021203FE15090000021203037D10000004120302281100000A6F1200000A7D1100000409280A00002B2A001330040045010000050000110202281100000A6F1200000A02280B000006281400000A72AD020070281500000A0204280A0000060A020602280F000006FE0572ED020070281500000A020428020000060B02077B020000047E1600000A281400000A72A1010070281500000A02040328040000060C02087B0600000416FE017225020070281500000A1202177D060000040204030828030000060617D70A0204062809000006020428060000060D05097B0700000436221203057D070000041203037D090000041203177D0800000402040928050000062B1D05097B07000004331412037C08000004254B17D75402040928050000060602280F0000063327020428060000060D097B080000041736090207281C0000062B0D0207097B09000004281A000006021204FE150A0000021204047D12000004120402281100000A6F1200000A7D130000041104280B00002B2A36020328020000067B020000042A760F01047D0200000402037B010000040328010000060203281B0000062A000000133003003300000006000011037B0400000402280F00000617DB6ED90A02037B0200000406281900000A260202280B000006037B04000004281900000A262A00133003007A000000000000000F01177D0500000402037B0100000403280100000602037B0300000416A306000001037B04000004281900000A2602037B0300000417A306000001037B04000004281900000A2602037B0300000418A306000001037B04000004281900000A2602037B0300000419A306000001037B04000004281900000A262A8A0202281100000A6F1200000A02280B000006281400000A7233030070281500000A2A00000042534A4201000100000000000C00000076342E302E33303331390000000005006C000000EC050000237E0000580600001C05000023537472696E677300000000740B00006803000023555300DC0E0000100000002347554944000000EC0E0000B801000023426C6F6200000000000000020000015715A201090A000000FA01330016000001000000100000000A000000130000001D00000022000000190000000D000000060000000100000004000000080000000100000002000000080000000B00000000004902010000000000060068019D03060097019D03060054018A030F00BD0300000A00450427040A00170427040A001C0127040600FC005B020A00880127040A0043012704060022005B020600DB015B02060053045B020A009D0027040600FA045B020A006E042704000000002900000000000100010001001000320000001500010001000A01100062020000210001001E000A01100064030000210006001E000A01100020030000210007001E000A0110000202000021000A001E000A0110002B02000021000C001E000A0110001A02000021000E001E000A011000F1010000210010001E000A011000E2010000210012001E0006006800F2000600A6029B000600E903F50006009500F20006007A00FA0006008600FA0006000601FD000600AC04FD00060048039B000600F3029B0006000E039B00060001039B000600E6029B0006006800F200060017049B0006006800F200060017049B0006006800F200060017049B005020000000008100DF00000101006E20000000008600D500070103008B2000000000810077030D010400AF200000000086006F0316010700D22000000000810045031E010900F020000000008600340325010B000D21000000008100E3042B010C002B21000000008100D60431010E00482100000000810095042B010F0066210000000081007E04310111008321000000008608AD026E0012009521000000008108B70236011200A821000000008608C1026E001300BA21000000008108D20236011300CD21000000008608CC033C011400DF21000000008108D90340011400F2210000000086084F00BD0015000422000000008108600045011500172200000000861884034A0116004022000000008600E302360118008022000000008600720206001900E822000000008600E90051011900A023000000008600C90045011A00A024000000008600B20056011B00F125000000008600A3025E011E00FF25000000008100950264011F002026000000008100CE016C0121006026000000008100BC006C012200E62600000000810000050600230000000100710000000200F500000001007100000001007100000002001F04000003007F03000001007100000002001F0400000100710000000200560300000100710000000100710000000200F00400000100710000000100710000000200BE0400000100710000000100C80100000100C80100000100C80100000100C80100000100300100000200E60300000100170300000100990000000100710000000100FD03000002007100000003000C0100000100710000000100F50000000200EF0300000100F50000000100F500090084030100110084030600190084030A0049008403060029001201100061003E041500510064041B0051005A04280061003E042F0051000B004000510001004600510009044B0051001404510051001500580051001F005D002900840363002900A6006900710081026E00290045027800310010058D002900CF04950031006D029B007100B501BD007900BF01C10029008C02E1002E000B007F012E00130088012E001B00A70141012300B00161012300B00181012300B001A1012300B001C1012300B001E1012300B00101022300B00121022300B00141022300B00161022300B00173008400A400B300CC00DD000200010000001A0372010000E60272010000DD037701000064007B0102000B00030001000C00030002000D00050001000E00050002000F00070001001000070002001100090001001200090004800000000000000000000000000000000045040000040000000000000000000000E9003800000000000200000000000000000000000000270400000000030002000400020005000200060002000700020008000200090002000A0002000F002300110023000F003600110036000F003B0011003B0027007F0027009F002700AE002700C7002700D800000000000047657455496E7433320053657455496E7433320047657455496E7436340053657455496E743634003C4D6F64756C653E004172656E610053797374656D2E507269766174652E436F72654C6962006765745F4E657874426174746C654964007365745F4E657874426174746C65496400626174746C65496400497343616E63656C6C65640053636F72655375626D6974746564004665650066656500494D657373616765006765745F4D65737361676500456E64426174746C650043616E63656C426174746C6500456E746572426174746C6500476574426174746C6500536574426174746C65005374617274426174746C6500626174746C650056616C7565547970650053636F72650073636F7265006765745F53746174650049536D617274436F6E7472616374537461746500736D617274436F6E74726163745374617465004950657273697374656E7453746174650044656275676761626C6541747472696275746500436F6D70696C6174696F6E52656C61786174696F6E7341747472696275746500496E6465784174747269627574650052756E74696D65436F6D7061746962696C697479417474726962757465006765745F56616C75650053657456616C75650076616C75650050726F636573735072697A6500537472696E6700426174746C65456E6465644C6F6700426174746C65456E74657265644C6F67004F776E6572736869705472616E736665727265644C6F6700426174746C65537461727465644C6F67004F776E6572736869705472616E736665725265717565737465644C6F6700536D617274436F6E74726163742E646C6C0053797374656D00426174746C654D61696E005A65726F00436C61696D4F776E657273686970006765745F53656E646572005472616E736665720050726F6365737357696E6E65720047657457696E6E6572006765745F4F776E6572007365745F4F776E6572006765745F50656E64696E674F776E6572007365745F50656E64696E674F776E65720053657450656E64696E674F776E65720050726576696F75734F776E65720043757272656E744F776E6572004E65774F776E6572006E65774F776E657200426174746C654869676865737453636F726572004765744869676865737453636F726572005365744869676865737453636F726572006869676865737453636F72657200426174746C6555736572004765745573657200536574557365720075736572002E63746F720053797374656D2E446961676E6F73746963730053797374656D2E52756E74696D652E436F6D70696C6572536572766963657300446562756767696E674D6F646573006765745F4D61785573657273007365745F4D61785573657273006D617855736572730077696E6E65724164647265737300757365724164647265737300476574416464726573730053657441646472657373006164647265737300537472617469732E536D617274436F6E74726163747300466F726D617400536D617274436F6E7472616374004F626A656374004765745374727563740053657453747275637400495472616E73666572526573756C740047657453636F72655375626D6974746564436F756E740053657453636F72655375626D6974746564436F756E74004869676865737453636F7265436F756E740073636F72657375626D6974636F756E74004173736572740047657455736572496E6465780053657455736572496E6465780075736572696E64657800417272617900456E737572654F776E65724F6E6C79006F705F457175616C69747900001562006100740074006C0065003A007B0030007D00001975007300650072003A007B0030007D003A007B0031007D000015730063006F007200650072003A007B0030007D00001175007300650072003A007B0030007D00001F730063006F00720065007300750062006D00690074003A007B0030007D00000B4F0077006E00650072000019500065006E00640069006E0067004F0077006E006500720000114D00610078005500730065007200730000194E0065007800740042006100740074006C00650049006400007143006C00610069006D004F0077006E0065007200730068006900700020006D007500730074002000620065002000630061006C006C0065006400200062007900200074006800650020006E00650077002800700065006E00640069006E006700290020006F0077006E00650072002E0000434F006E006C007900200062006100740074006C00650020006F0077006E00650072002000630061006E002000730074006100720074002000670061006D0065002E00001F460065006500200069007300200074006F006F0020006800690067006800002342006100740074006C00650020006E006F007400200066006F0075006E0064002E00005F42006100740074006C006500200066006500650020006900730020006E006F00740020006D00610074006300680069006E00670020007700690074006800200065006E007400720079002000660065006500200070006100690064002E00004354006800650020007500730065007200200061006C007200650061006400790020007300750062006D00690074007400650064002000730063006F00720065002E0000434D00610078002000750073006500720020007200650061006300680065006400200066006F00720020007400680069007300200062006100740074006C0065002E00003F4F006E006C007900200062006100740074006C00650020006F0077006E00650072002000630061006E00200065006E0064002000670061006D0065002E00004541006C006C00200075007300650072007300200061006C007200650061006400790020007300750062006D00690074007400650064002000730063006F00720065002E00003354006800650020006D006500740068006F00640020006900730020006F0077006E006500720020006F006E006C0079002E000000F641A50CB4EA5F4D9C24BB4EACC176CA0004200101080320000105200101111104200012290500020E0E1C07300102010E1E00040A01110C063001011E000E0600030E0E1C1C040A011110040A011114052002010E09042001090E05200111190E062002010E11190420010B0E052002010E0B05200101121D04200012390420001119040701111C06300101011E00040A01111C080703111911191118070002021119111905200201020E03061119040A0111180907040B110C110C1120040A011120090704110C11100911240320000B052002011C0A040A0111240B070509110C111011141128040A0111280307010B072002124111190B087CEC85D7BEA7798E02060B04061D1119020602020609062002010B110C052001110C0B082003010B1119111007200211100B1119062002010B111405200111140B052002010B09042001090B052001011119032000090420010109042001010B06200201121D090420010B0B0720030111190B0905200111190B07200201110C111905200101110C0428001119032800090328000B0801000800000000001E01000100540216577261704E6F6E457863657074696F6E5468726F777301080100020000000000040100000000000000000000000000000000000010000000000000000000000000000000F437000000000000000000000E38000000200000000000000000000000000000000000000000000000380000000000000000000000005F436F72446C6C4D61696E006D73636F7265652E646C6C0000000000FF25002000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003000000C000000203800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000

Comment on lines 28 to 41
public bool StartBattle(ulong battleId, ulong fee)
{
Assert(Message.Sender == BattleOwner, "Only battle owner can start game.");

var battle = new BattleMain();
battle.BattleId = battleId;
battle.MaxUsers = 4;
battle.Fee = fee;
battle.Users = new Address[battle.MaxUsers];
SetBattle(battleId, battle);

Log(battle);
return true;
}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider storing battle id as an incremental state value, otherwise the battle owner can overwrite the result of a battle by calling StartBattle. As an example, see NextProposalId in the Opdex vault contract.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for your review. I have added all suggested changes. Please review the pull request again.

SetBattle(battleId, battle);

Log(battle);
return true;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The return value of the methods returning bool has no purpose and they can return void instead.

public ulong BattleId;
public Address Winner;
public Address[] Users;
public uint MaxUsers;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Max users appears to be constant, so consider declaring it as a constant instead and exclude it from the struct.

/// <summary>
/// 4 different user will enter the battle
/// </summary>
public bool EnterBattle(ulong battleId, uint userindex)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

User index/count should be stored in state on the battle struct and incremented, otherwise anyone can take the place of another user in an ongoing battle, by calling EnterBattle with the index of an existing entrant. It's also possible for a user to enter the same battle multiple times by calling EnterBattle twice with a different index each time.

battle.Users.SetValue(user.Address, userindex);
SetBattle(battleId, battle);

Log(battle);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You may want to consider logging events rather than the battle details. For example, you could define an event like so:

public struct HashBattleEnteredEvent
{
    public ulong BattleId;
    public Address Address;
}

Then here you would call

Log(new HashBattleEnteredEvent { BattleId = battleId, Address = Message.Sender }

This way it'd be easier to index and process the logs on your dApp. You're able to search the full node for specific events rather than having to analyze the entire sequence of events to determine which action happened at a point in time.

Comment on lines 111 to 112
if (battle.Users.Length <= 4)
{

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This if statement is redundant and can be removed to save gas


SetUser(battleId, userAddress, user);

if (IsBattleOver)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Appears that if all scores are submitted, yet IsBattleOver is false, then the fees will never be paid out to the winner or battle owner. Instead you should determine within the method whether all scores have been submitted and then process the winner accordingly.

Another way to go about it would be to submit all of the scores in a single method call, which would save a lot of gas fees for the battle owner.

foreach (Address userAddress in battle.Users)
{
var user = GetUser(battle.BattleId, userAddress);
if (!user.ScoreSubmitted)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This if statement is redundant as it is impossible for the winner to be processed if not all scores are submitted. Remove to save gas.

}
}
uint winnerIndex = GetWinnerIndex(battle.BattleId, battle.Users);
if (battle.Winner == Address.Zero)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This if statement appears to be redundant also

public Address GetWinner(ulong battleId)
{
var battle = GetBattle(battleId);
Log(battle);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This log serves no purpose and should be removed. Logs should only be used for events, or in other words logging state changes, otherwise you're wasting gas and making it a lot harder to determine what happened on chain.

/// <summary>
/// Set the address deploying the contract as battle owner
/// </summary>
private Address BattleOwner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider adding the ability to migrate the battle owner address to a new address. This way, if the battle owner ever needs to migrate wallets, they can change the owner address of the contract and continue to retrieve battle fees. See this example of how to implement it.

@StratisIain StratisIain changed the title Added hashbattle contract on mainnet [Mainnet] Hashbattle Gaming Contract Dec 21, 2022
@mksmanish79 mksmanish79 requested a review from drmathias April 22, 2023 01:31
Copy link
Member

@YakupIpek YakupIpek left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These are my initial review. I will look again after code is updated.

<LangVersion>8.0</LangVersion>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Stratis.SmartContracts" Version="1.2.1" />
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
<PackageReference Include="Stratis.SmartContracts" Version="1.2.1" />
<PackageReference Include="Stratis.SmartContracts" Version="2.0.0" />

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Version is not upgraded. Also C#8 may not be supported fully.

/// </summary>
private Address BattleOwner
{
get => PersistentState.GetAddress(nameof(BattleOwner));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

After upgrading package to 2.0.0 then you have to use State

Suggested change
get => PersistentState.GetAddress(nameof(BattleOwner));
get => State.GetAddress(nameof(BattleOwner));

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is not done.

private set => PersistentState.SetAddress(nameof(PendingBattleOwner), value);
}

public void SetPendingBattleOwnership(Address pendingBattleOwner)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

/// </summary>
public ulong NextBattleId
{
get => PersistentState.GetUInt64(ArenaStateKeys.NextBattleId);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Keep naming consistent for keys.

Suggested change
get => PersistentState.GetUInt64(ArenaStateKeys.NextBattleId);
get => PersistentState.GetUInt64(nameof(NextBattleId));

Comment on lines 74 to 77
var battle = new BattleMain();
battle.BattleId = battleId;
battle.Fee = fee;
battle.Users = new Address[MaxUsers];
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
var battle = new BattleMain();
battle.BattleId = battleId;
battle.Fee = fee;
battle.Users = new Address[MaxUsers];
var battle = new BattleMain
{
BattleId = battleId,
Fee = fee,
Users = new Address[MaxUsers]
};

{
uint winningScore = 0;
uint winningScoreIndex = 0;
for (uint i = 0; i < users.Length; i++)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Iterations are not recommended for contracts as general design guidelines.

My recommendation is on EndBattle method keep track of highest one in the state. Then you can remove Battle.Users property fully.

Comment on lines 132 to 146
private uint GetWinnerIndex(ulong battleid, Address[] users)
{
uint winningScore = 0;
uint winningScoreIndex = 0;
for (uint i = 0; i < users.Length; i++)
{
var user = GetUser(battleid, users[i]);
if (user.Score > winningScore)
{
winningScore = user.Score;
winningScoreIndex = i;
}
}
return winningScoreIndex;
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Last indexed user will be winner in this case if users have same score. Just fyi

/// </summary>
private uint GetWinnerIndex(ulong battleid, Address[] users)
{
uint winningScore = 0;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

var always

uint winnerIndex = GetWinnerIndex(battle.BattleId, battle.Users);
battle.Winner = battle.Users[winnerIndex];
SetBattle(battle.BattleId, battle);
ProcessPrize(battle.BattleId);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why dont you send battle as paramter instead of battleId ?

Suggested change
ProcessPrize(battle.BattleId);
ProcessPrize(battle);

/// </summary>
public ulong StartBattle(ulong fee)
{
Assert(Message.Sender == BattleOwner, "Only battle owner can start game.");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Avoid overflows when you process price at the end.

Suggested change
Assert(Message.Sender == BattleOwner, "Only battle owner can start game.");
Assert(fee < ulong.MaxValue / MaxUsers, "Fee is too high");

Comment on lines 71 to 72
ulong battleId = NextBattleId;
NextBattleId += 1;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I recommend this syntax. Also use var or type consistently in the code. i recommend var

Suggested change
ulong battleId = NextBattleId;
NextBattleId += 1;
var battleId = NextBattleId++;

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this will assign next id to battleId instead of current.

Copy link
Member

@YakupIpek YakupIpek Jun 12, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will not change current behaviour.
But this statement would change it if it is var battleId = ++NextBattleId;

{
var battle = GetBattle(battleid);
ulong prize = battle.Fee * (MaxUsers - 1);
Transfer(battle.Winner, prize);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If winner address is a contract address then this transfer has possibility to fail. So you can use withdrawal pattern(pull) in here. It will transfer funds immediately if destination is not a contract address and if it is then it will fallback to withdrawal pattern.

private bool SafeTransfer(Address to, ulong amount)

private bool SafeTransfer(Address to, ulong amount)
{
    if (State.IsContract(to))
    {
        var balance = GetBalance(to) + amount;

        SetBalance(to, balance);

        return true;
    }

    var result = Transfer(to, amount);

    return result.Success;
}

public bool Withdraw()
{
    EnsureNotPayable();

    var amount = GetBalance(Message.Sender);

    Assert(amount > 0);

    SetBalance(Message.Sender, 0);

    var transfer = Transfer(Message.Sender, amount);

    Assert(transfer.Success, "Transfer failed.");

    Log(new BalanceRefundedLog { To = Message.Sender, Amount = amount });

    return transfer.Success;
}

public ulong GetBalance(Address address)
{
    return State.GetUInt64($"Balance:{address}");
}

private void SetBalance(Address address, ulong balance)
{
    State.SetUInt64($"Balance:{address}", balance);
}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Winner address will not be a contract address. 4 players will play the game with their wallet address.

Copy link
Member

@YakupIpek YakupIpek Jun 12, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

how do you ensure that user addresses will not belong to a another contract ?

Copy link
Member

@YakupIpek YakupIpek left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please move all get/set methods, fields and properties to top of constructor. Just keep methods under constructor.

@mksmanish79 mksmanish79 requested a review from YakupIpek June 1, 2023 05:09
@mksmanish79
Copy link
Contributor Author

Added changes as suggested

Copy link
Member

@YakupIpek YakupIpek left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am done on review. I will quickly review new changes you can push them quickly

SetHighestScorer(battleId, new BattleHighestScorer { Scorers = scorers, Score = score });
}

if (ScoreSubmittedCount == MaxUsers)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You have to assert ScoreSubmittedCount > MaxUsers case at the beginning of the method ?

/// </summary>
public class Arena : SmartContract
{
private const uint MaxUsers = 4;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If there is possibility in future that MaxUsers can be higher than 4 than you can make it constructor parameter.

public uint Score;
public Address[] Scorers;
}
public struct ClaimPendingDeployerOwnershipLog
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This log type name should be not changed. It should stays as in original.

[Index] public Address From;
[Index] public Address To;
}
public struct SetPendingDeployerOwnershipLog
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This log type name should be not changed. It should stays as in original.

else if (score == highestScorer.Score)
{
var scorers = highestScorer.Scorers;
Array.Resize(ref scorers, scorers.Length + 1);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This allocate new array actually and iterate it by copying fully. We should avoid it. What you need to is highest score and how many times same highest score counted and highest user. You can keep last highest one always whenever equal score submited. So you can do something like this

    public struct BattleHighestScorer
    {
        public uint Score;
        public uint HighestScoreCount;
        public Address HighestScorer;
    }
      if (score > highestScorer.Score)
        {
            highestScorer.Score = score;
            highestScorer.HighestScorer = userAddress;
            highestScorer.HighestScoreCount = 1;

            SetHighestScorer(battleId, highestScorer);
        }
        else if (score == highestScorer.Score)
        {
            highestScorer.HighestScoreCount++;
            SetHighestScorer(battleId, highestScorer);
        }

        if (ScoreSubmittedCount == MaxUsers)
        {
            highestScorer = GetHighestScorer(battleId);
            if (highestScorer.HighestScoreCount > 1)
                CancelBattle(battle);
            else
                ProcessWinner(battle, highestScorer.HighestScorer);
        }


SetBattle(battleId, battle);

Log(new BattleEventLog { Event = "Enter", BattleId = battleId, Address = Message.Sender });
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Log(new BattleEventLog { Event = "Enter", BattleId = battleId, Address = Message.Sender });
Log(new BattleStartedLog { BattleId = battleId, Address = Message.Sender });

var userindex = GetUserIndex(battleId);
Assert(userindex != MaxUsers, "Max user reached for this battle.");
battle.Users.SetValue(Message.Sender, userindex);
SetUserIndex(battleId, (userindex + 1));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
SetUserIndex(battleId, (userindex + 1));
SetUserIndex(battleId, userindex + 1);

}
private void SetUser(ulong battleId, Address address, BattleUser user)
{
State.SetStruct($"user:{battleId}-{address}", user);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Always use : for multiple key seperator and do this for others.

Suggested change
State.SetStruct($"user:{battleId}-{address}", user);
State.SetStruct($"user:{battleId}:{address}", user);

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also these are getters and setters method over State so please move them to top of constructor.


Assert(!user.ScoreSubmitted, "The user already submitted score.");

user.Score = score;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What for we save Score on user ? It seems there is no use case for it.

public class Arena : SmartContract
{
private const uint MaxUsers = 4;
public struct BattleMain
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All struct definitions should go to bottom of the class.

@mksmanish79 mksmanish79 requested a review from YakupIpek June 19, 2023 04:51
@mksmanish79
Copy link
Contributor Author

Added changes as suggested

Copy link
Member

@YakupIpek YakupIpek left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I approved pr with 1-2 change request. You have to update hash info on pr and copy files to testnet.

Assert(fee < ulong.MaxValue / MaxUsers, "Fee is too high");

var battleId = NextBattleId;
NextBattleId += 1;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You access value of NextBattleId twice in this code so please follow my recommandation.

Assert(fee < ulong.MaxValue / MaxUsers, "Fee is too high");

var battleId = NextBattleId;
NextBattleId += 1;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Or alternatively you can use below code.

Suggested change
NextBattleId += 1;
NextBattleId = battleId + 1;

public uint HighestScoreCount;
public Address HighestScorer;
}
public struct OwnershipTransferedLog
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Typo

Suggested change
public struct OwnershipTransferedLog
public struct OwnershipTransferredLog

@mksmanish79 mksmanish79 reopened this Jun 20, 2023
@mksmanish79 mksmanish79 requested a review from YakupIpek June 20, 2023 03:30
@mksmanish79
Copy link
Contributor Author

@YakupIpek Added the additional feedback changes. Please merge the pull request.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants