public async Task TransferGold() { NineChroniclesNodeService service = StandaloneContextFx.NineChroniclesNodeService !; Currency goldCurrency = new GoldCurrencyState( (Dictionary)BlockChain.GetState(GoldCurrencyState.Address) ).Currency; Address senderAddress = service.MinerPrivateKey !.ToAddress(); var store = service.Store; await BlockChain.MineBlock(service.MinerPrivateKey); await BlockChain.MineBlock(service.MinerPrivateKey); // 10 + 10 (mining rewards) Assert.Equal( 20 * goldCurrency, BlockChain.GetBalance(senderAddress, goldCurrency) ); var recipientKey = new PrivateKey(); Address recipient = recipientKey.ToAddress(); var query = $"mutation {{ transferGold(recipient: \"{recipient}\", amount: \"17.5\") }}"; ExecutionResult result = await ExecuteQueryAsync(query); var stagedTxIds = BlockChain.GetStagedTransactionIds().ToImmutableList(); Assert.Single(stagedTxIds); var expectedResult = new Dictionary <string, object> { ["transferGold"] = stagedTxIds.Single().ToString(), }; Assert.Null(result.Errors); Assert.Equal(expectedResult, result.Data); await BlockChain.MineBlock(recipientKey); // 10 + 10 - 17.5(transfer) Assert.Equal( FungibleAssetValue.Parse(goldCurrency, "2.5"), BlockChain.GetBalance(senderAddress, goldCurrency) ); // 0 + 17.5(transfer) + 10(mining reward) Assert.Equal( FungibleAssetValue.Parse(goldCurrency, "27.5"), BlockChain.GetBalance(recipient, goldCurrency) ); }
public int TransferAsset( [Argument("SENDER-ADDRESS", Description = "A hex-encoded sender address.")] string senderAddress, [Argument("RECIPIENT-ADDRESS", Description = "A hex-encoded recipient address.")] string recipientAddress, [Argument("AMOUNT", Description = "The amount of asset to transfer.")] string amount, [Argument("PATH", Description = "A file path of base64 encoded action.")] string?filePath = null, [Argument("MEMO", Description = "A memo of asset transfer")] string?memo = null ) { try { filePath ??= Path.Combine(Path.GetTempPath(), Path.GetTempFileName()); // Minter for 9c-mainnet var currency = new Currency("NCG", 2, minter: new Address("47d082a115c63e7b58b1532d20e631538eafadde")); FungibleAssetValue amountFungibleAssetValue = FungibleAssetValue.Parse(currency, amount); Address sender = new Address(ByteUtil.ParseHex(senderAddress)); Address recipient = new Address(ByteUtil.ParseHex(recipientAddress)); Nekoyume.Action.TransferAsset action = new TransferAsset( sender, recipient, amountFungibleAssetValue, memo); var encoded = new List( new[] { (Text)nameof(Nekoyume.Action.TransferAsset), action.PlainValue } ); byte[] raw = Codec.Encode(encoded); File.WriteAllText(filePath, Convert.ToBase64String(raw)); Console.Write(Convert.ToBase64String(raw)); return(0); } catch (Exception e) { _console.Error.WriteLine(e); return(-1); } }
public IAccountStateDelta MinerReward(IActionContext ctx, IAccountStateDelta states) { // 마이닝 보상 // https://www.notion.so/planetarium/Mining-Reward-b7024ef463c24ebca40a2623027d497d Currency currency = states.GetGoldCurrency(); FungibleAssetValue defaultMiningReward = currency * 10; var countOfHalfLife = (int)Math.Pow(2, Convert.ToInt64((ctx.BlockIndex - 1) / 12614400)); FungibleAssetValue miningReward = defaultMiningReward.DivRem(countOfHalfLife, out FungibleAssetValue _); if (miningReward >= FungibleAssetValue.Parse(currency, "1.25")) { states = states.TransferAsset( GoldCurrencyState.Address, ctx.Miner, miningReward ); } return(states); }
public async Task Transfer(string?memo, bool error) { NineChroniclesNodeService service = StandaloneContextFx.NineChroniclesNodeService !; Currency goldCurrency = new GoldCurrencyState( (Dictionary)BlockChain.GetState(GoldCurrencyState.Address) ).Currency; Address senderAddress = service.MinerPrivateKey !.ToAddress(); var store = service.Store; await BlockChain.MineBlock(senderAddress); await BlockChain.MineBlock(senderAddress); // 10 + 10 (mining rewards) Assert.Equal( 20 * goldCurrency, BlockChain.GetBalance(senderAddress, goldCurrency) ); Address recipient = new PrivateKey().ToAddress(); long txNonce = BlockChain.GetNextTxNonce(senderAddress); var args = $"recipient: \"{recipient}\", txNonce: {txNonce}, amount: \"17.5\""; if (!(memo is null)) { args += $"memo: \"{memo}\""; } var query = $"mutation {{ transfer({args}) }}"; ExecutionResult result = await ExecuteQueryAsync(query); if (error) { Assert.NotNull(result.Errors); } else { Assert.Null(result.Errors); var stagedTxIds = BlockChain.GetStagedTransactionIds().ToImmutableList(); Assert.Single(stagedTxIds); string transferTxIdString = stagedTxIds.Single().ToString(); TxId transferTxId = new TxId(ByteUtil.ParseHex(transferTxIdString)); Transaction <NCAction>?tx = BlockChain.StagePolicy.Get(BlockChain, transferTxId, false); Assert.NotNull(tx); Assert.IsType <TransferAsset>(tx !.Actions.Single().InnerAction); TransferAsset transferAsset = (TransferAsset)tx.Actions.Single().InnerAction; Assert.Equal(memo, transferAsset.Memo); var expectedResult = new Dictionary <string, object> { ["transfer"] = transferTxIdString, }; Assert.Equal(expectedResult, result.Data); await BlockChain.MineBlock(recipient); // 10 + 10 - 17.5(transfer) Assert.Equal( FungibleAssetValue.Parse(goldCurrency, "2.5"), BlockChain.GetBalance(senderAddress, goldCurrency) ); // 0 + 17.5(transfer) + 10(mining reward) Assert.Equal( FungibleAssetValue.Parse(goldCurrency, "27.5"), BlockChain.GetBalance(recipient, goldCurrency) ); } }
public void Parse() { Currency baz = new Currency("BAZ", 1, minter: null); FormatException e; e = Assert.Throws <FormatException>(() => FungibleAssetValue.Parse(FOO, "abc")); Assert.StartsWith("The value string must consist of digits", e.Message); const string signError = "Plus (+) or minus (-) sign can be appeared only at"; e = Assert.Throws <FormatException>(() => FungibleAssetValue.Parse(FOO, "++123")); Assert.StartsWith(signError, e.Message); e = Assert.Throws <FormatException>(() => FungibleAssetValue.Parse(FOO, "--123")); Assert.StartsWith(signError, e.Message); e = Assert.Throws <FormatException>(() => FungibleAssetValue.Parse(FOO, "++123.45")); Assert.StartsWith(signError, e.Message); e = Assert.Throws <FormatException>(() => FungibleAssetValue.Parse(FOO, "--123.45")); Assert.StartsWith(signError, e.Message); e = Assert.Throws <FormatException>(() => FungibleAssetValue.Parse(FOO, "23.4-5")); Assert.StartsWith(signError, e.Message); e = Assert.Throws <FormatException>(() => FungibleAssetValue.Parse(FOO, "45.6+7")); Assert.StartsWith(signError, e.Message); e = Assert.Throws <FormatException>(() => FungibleAssetValue.Parse(FOO, "2-3")); Assert.StartsWith(signError, e.Message); e = Assert.Throws <FormatException>(() => FungibleAssetValue.Parse(FOO, "45+6")); Assert.StartsWith(signError, e.Message); e = Assert.Throws <FormatException>(() => FungibleAssetValue.Parse(FOO, "+12-3")); Assert.StartsWith(signError, e.Message); e = Assert.Throws <FormatException>(() => FungibleAssetValue.Parse(FOO, "-45+6")); Assert.StartsWith(signError, e.Message); const string decimalSeparatorError = "The decimal separator (.) cannot be appeared"; e = Assert.Throws <FormatException>(() => FungibleAssetValue.Parse(FOO, "123..4")); Assert.Contains(decimalSeparatorError, e.Message); e = Assert.Throws <FormatException>(() => FungibleAssetValue.Parse(FOO, "123.4.5")); Assert.Contains(decimalSeparatorError, e.Message); const string decimalsError = "does not allow more than"; e = Assert.Throws <FormatException>(() => FungibleAssetValue.Parse(FOO, "123.456")); Assert.Contains(decimalsError, e.Message); e = Assert.Throws <FormatException>(() => FungibleAssetValue.Parse(BAR, "123.0")); Assert.Contains(decimalsError, e.Message); e = Assert.Throws <FormatException>(() => FungibleAssetValue.Parse(baz, "123.12")); Assert.Contains(decimalsError, e.Message); Assert.Equal( new FungibleAssetValue(FOO, 123, 45), FungibleAssetValue.Parse(FOO, "123.45") ); Assert.Equal( new FungibleAssetValue(FOO, 123, 45), FungibleAssetValue.Parse(FOO, "+123.45") ); Assert.Equal( new FungibleAssetValue(FOO, -123, 45), FungibleAssetValue.Parse(FOO, "-123.45") ); Assert.Equal( new FungibleAssetValue(FOO, 123, 40), FungibleAssetValue.Parse(FOO, "123.4") ); Assert.Equal( new FungibleAssetValue(FOO, 123, 40), FungibleAssetValue.Parse(FOO, "+123.4") ); Assert.Equal( new FungibleAssetValue(FOO, -123, 40), FungibleAssetValue.Parse(FOO, "-123.4") ); Assert.Equal(new FungibleAssetValue(FOO, 123, 0), FungibleAssetValue.Parse(FOO, "123")); Assert.Equal(new FungibleAssetValue(FOO, 12, 0), FungibleAssetValue.Parse(FOO, "+12")); Assert.Equal(new FungibleAssetValue(FOO, -12, 0), FungibleAssetValue.Parse(FOO, "-12")); }
public StandaloneMutation(StandaloneContext standaloneContext) { Field <KeyStoreMutation>( name: "keyStore", resolve: context => standaloneContext.KeyStore); Field <ActivationStatusMutation>( name: "activationStatus", resolve: context => standaloneContext.NineChroniclesNodeService); Field <ActionMutation>( name: "action", resolve: context => standaloneContext.NineChroniclesNodeService); Field <NonNullGraphType <BooleanGraphType> >( name: "stageTx", description: "Add a new transaction to staging", arguments: new QueryArguments( new QueryArgument <NonNullGraphType <StringGraphType> > { Name = "payload", Description = "Hex-encoded bytes for new transaction." } ), resolve: context => { try { byte[] bytes = ByteUtil.ParseHex(context.GetArgument <string>("payload")); Transaction <NCAction> tx = Transaction <NCAction> .Deserialize(bytes); NineChroniclesNodeService service = standaloneContext.NineChroniclesNodeService; BlockChain <NCAction> blockChain = service.Swarm.BlockChain; if (blockChain.Policy.DoesTransactionFollowsPolicy(tx, blockChain)) { blockChain.StageTransaction(tx); return(true); } else { context.Errors.Add(new ExecutionError("The given transaction is invalid.")); return(false); } } catch (Exception e) { context.Errors.Add(new ExecutionError("An unexpected exception occurred.", e)); return(false); } } ); Field <TxIdType>( name: "transferGold", arguments: new QueryArguments( new QueryArgument <NonNullGraphType <AddressType> > { Name = "recipient", }, new QueryArgument <NonNullGraphType <StringGraphType> > { Name = "amount" } ), resolve: context => { NineChroniclesNodeService service = standaloneContext.NineChroniclesNodeService; PrivateKey privateKey = service.PrivateKey; if (privateKey is null) { // FIXME We should cover this case on unittest. var msg = "No private key was loaded."; context.Errors.Add(new ExecutionError(msg)); Log.Error(msg); return(null); } BlockChain <NCAction> blockChain = service.BlockChain; var currency = new GoldCurrencyState( (Dictionary)blockChain.GetState(GoldCurrencyState.Address) ).Currency; FungibleAssetValue amount = FungibleAssetValue.Parse(currency, context.GetArgument <string>("amount")); Address recipient = context.GetArgument <Address>("recipient"); Transaction <NCAction> tx = blockChain.MakeTransaction( privateKey, new NCAction[] { new TransferAsset( privateKey.ToAddress(), recipient, amount ), } ); return(tx.Id); } ); }
public ActionMutation() { Field <NonNullGraphType <BooleanGraphType> >("createAvatar", resolve: context => { try { NineChroniclesNodeService service = context.Source; PrivateKey privatekey = service.PrivateKey; BlockChain <NineChroniclesActionType> blockChain = service.Swarm.BlockChain; Address userAddress = privatekey.PublicKey.ToAddress(); Address avatarAddress = userAddress.Derive("avatar_0"); var action = new CreateAvatar { avatarAddress = avatarAddress, index = 0, hair = 0, lens = 0, ear = 0, tail = 0, name = "createbymutation", }; var actions = new PolymorphicAction <ActionBase>[] { action }; blockChain.MakeTransaction(privatekey, actions); } catch (Exception e) { var msg = $"Unexpected exception occurred during {typeof(ActionMutation)}: {e}"; context.Errors.Add(new ExecutionError(msg, e)); Log.Error(msg, e); return(false); } return(true); }); Field <NonNullGraphType <BooleanGraphType> >("hackAndSlash", arguments: new QueryArguments( new QueryArgument <NonNullGraphType <StringGraphType> > { Name = "weeklyArenaAddress", }, new QueryArgument <NonNullGraphType <StringGraphType> > { Name = "rankingArenaAddress", }), resolve: context => { try { NineChroniclesNodeService service = context.Source; PrivateKey privatekey = service.PrivateKey; BlockChain <NineChroniclesActionType> blockChain = service.Swarm.BlockChain; Address userAddress = privatekey.PublicKey.ToAddress(); Address avatarAddress = userAddress.Derive("avatar_0"); Address weeklyArenaAddress = new Address(context.GetArgument <string>("weeklyArenaAddress")); Address rankingArenaAddress = new Address(context.GetArgument <string>("rankingArenaAddress")); var action = new HackAndSlash { avatarAddress = avatarAddress, worldId = 1, stageId = 1, WeeklyArenaAddress = weeklyArenaAddress, RankingMapAddress = rankingArenaAddress, costumes = new List <int>(), equipments = new List <Guid>(), foods = new List <Guid>(), }; var actions = new PolymorphicAction <ActionBase>[] { action }; blockChain.MakeTransaction(privatekey, actions); } catch (Exception e) { var msg = $"Unexpected exception occurred during {typeof(ActionMutation)}: {e}"; context.Errors.Add(new ExecutionError(msg, e)); Log.Error(msg, e); return(false); } return(true); }); Field <NonNullGraphType <BooleanGraphType> >("combinationEquipment", arguments: new QueryArguments( new QueryArgument <NonNullGraphType <DecimalGraphType> > { Name = "recipeId", }, new QueryArgument <NonNullGraphType <DecimalGraphType> > { Name = "slotIndex", }, new QueryArgument <DecimalGraphType> { Name = "subRecipeId", }), resolve: context => { try { NineChroniclesNodeService service = context.Source; PrivateKey privatekey = service.PrivateKey; BlockChain <NineChroniclesActionType> blockChain = service.Swarm.BlockChain; Address userAddress = privatekey.PublicKey.ToAddress(); Address avatarAddress = userAddress.Derive("avatar_0"); int recipeId = context.GetArgument <int>("recipeId"); int slotIndex = context.GetArgument <int>("slotIndex"); int?subRecipeId = context.GetArgument <int>("subRecipeId"); var action = new CombinationEquipment { AvatarAddress = avatarAddress, RecipeId = recipeId, SlotIndex = slotIndex, SubRecipeId = subRecipeId }; var actions = new PolymorphicAction <ActionBase>[] { action }; blockChain.MakeTransaction(privatekey, actions); } catch (Exception e) { var msg = $"Unexpected exception occurred during {typeof(ActionMutation)}: {e}"; context.Errors.Add(new ExecutionError(msg, e)); Log.Error(msg, e); return(false); } return(true); }); Field <NonNullGraphType <BooleanGraphType> >("itemEnhancement", arguments: new QueryArguments( new QueryArgument <NonNullGraphType <StringGraphType> > { Name = "itemId", }, new QueryArgument <NonNullGraphType <StringGraphType> > { Name = "materialIds", }), resolve: context => { try { NineChroniclesNodeService service = context.Source; PrivateKey privatekey = service.PrivateKey; BlockChain <NineChroniclesActionType> blockChain = service.Swarm.BlockChain; Address userAddress = privatekey.PublicKey.ToAddress(); Address avatarAddress = userAddress.Derive("avatar_0"); Guid itemId = Guid.Parse(context.GetArgument <string>("itemId")); Guid materialId = Guid.Parse(context.GetArgument <string>("materialIds")); var action = new ItemEnhancement { avatarAddress = avatarAddress, slotIndex = 0, itemId = itemId, materialIds = new[] { materialId } }; var actions = new PolymorphicAction <ActionBase>[] { action }; blockChain.MakeTransaction(privatekey, actions); } catch (Exception e) { var msg = $"Unexpected exception occurred during {typeof(ActionMutation)}: {e}"; context.Errors.Add(new ExecutionError(msg, e)); Log.Error(msg, e); return(false); } return(true); }); Field <NonNullGraphType <BooleanGraphType> >("buy", arguments: new QueryArguments( new QueryArgument <NonNullGraphType <StringGraphType> > { Name = "sellerAgentAddress", }, new QueryArgument <NonNullGraphType <StringGraphType> > { Name = "sellerAvatarAddress", }, new QueryArgument <NonNullGraphType <StringGraphType> > { Name = "productId", }), resolve: context => { try { NineChroniclesNodeService service = context.Source; PrivateKey privatekey = service.PrivateKey; BlockChain <NineChroniclesActionType> blockChain = service.Swarm.BlockChain; Address userAddress = privatekey.PublicKey.ToAddress(); Address avatarAddress = userAddress.Derive("avatar_0"); Address sellerAgentAddress = new Address(context.GetArgument <string>("sellerAgentAddress")); Address sellerAvatarAddress = new Address(context.GetArgument <string>("sellerAvatarAddress")); Guid productId = Guid.Parse(context.GetArgument <string>("productId")); var action = new Buy { buyerAvatarAddress = avatarAddress, sellerAgentAddress = sellerAgentAddress, sellerAvatarAddress = sellerAvatarAddress, productId = productId, }; var actions = new PolymorphicAction <ActionBase>[] { action }; blockChain.MakeTransaction(privatekey, actions); } catch (Exception e) { var msg = $"Unexpected exception occurred during {typeof(ActionMutation)}: {e}"; context.Errors.Add(new ExecutionError(msg, e)); Log.Error(msg, e); return(false); } return(true); }); Field <NonNullGraphType <BooleanGraphType> >("sell", arguments: new QueryArguments( new QueryArgument <NonNullGraphType <StringGraphType> > { Name = "sellerAvatarAddress", }, new QueryArgument <NonNullGraphType <StringGraphType> > { Name = "productId", }, new QueryArgument <NonNullGraphType <StringGraphType> > { Name = "itemId", }, new QueryArgument <NonNullGraphType <StringGraphType> > { Name = "price", }), resolve: context => { try { NineChroniclesNodeService service = context.Source; PrivateKey privatekey = service.PrivateKey; BlockChain <NineChroniclesActionType> blockChain = service.Swarm.BlockChain; Address sellerAvatarAddress = new Address(context.GetArgument <string>("sellerAvatarAddress")); Guid itemId = Guid.Parse(context.GetArgument <string>("itemId")); var currency = new GoldCurrencyState( (Dictionary)blockChain.GetState(GoldCurrencyState.Address) ).Currency; FungibleAssetValue price = FungibleAssetValue.Parse(currency, context.GetArgument <string>("price")); var action = new Sell { sellerAvatarAddress = sellerAvatarAddress, itemId = itemId, price = price }; var actions = new PolymorphicAction <ActionBase>[] { action }; blockChain.MakeTransaction(privatekey, actions); } catch (Exception e) { var msg = $"Unexpected exception occurred during {typeof(ActionMutation)}: {e}"; context.Errors.Add(new ExecutionError(msg, e)); Log.Error(msg, e); return(false); } return(true); }); Field <NonNullGraphType <BooleanGraphType> >("dailyReward", resolve: context => { try { NineChroniclesNodeService service = context.Source; PrivateKey privatekey = service.PrivateKey; BlockChain <NineChroniclesActionType> blockChain = service.Swarm.BlockChain; Address userAddress = privatekey.PublicKey.ToAddress(); Address avatarAddress = userAddress.Derive("avatar_0"); var action = new DailyReward { avatarAddress = avatarAddress }; var actions = new PolymorphicAction <ActionBase>[] { action }; blockChain.MakeTransaction(privatekey, actions); } catch (Exception e) { var msg = $"Unexpected exception occurred during {typeof(ActionMutation)}: {e}"; context.Errors.Add(new ExecutionError(msg, e)); Log.Error(msg, e); return(false); } return(true); }); }