public static IPromise <TransactionBuilder> SetRequiredFees(TransactionBuilder builder, SpaceTypeId assetId = null) { if (builder.IsFinalized) { throw new InvalidOperationException("SetRequiredFees... Already finalized"); } if (builder.operations.IsNullOrEmpty()) { throw new InvalidOperationException("SetRequiredFees... Add operation first"); } var ops = new OperationData[builder.operations.Count]; for (var i = 0; i < builder.operations.Count; i++) { ops[i] = builder.operations[i].Clone(); } var coreAssetId = SpaceTypeId.CreateOne(SpaceType.Asset); if (assetId.IsNull()) { var firstFee = ops.First().Fee; if (!firstFee.IsNull() && !firstFee.AssetId.IsNullOrEmpty()) { assetId = firstFee.AssetId; } else { assetId = coreAssetId; } } var isNotCoreAsset = !assetId.Equals(coreAssetId); var promises = new List <IPromise <object> >(); if (ops.Contains(op => op.Type.Equals(ChainTypes.Operation.ContractCall))) { promises.Add(EchoApiManager.Instance.Database.GetRequiredFees <FeeForCallContractData>(ops, assetId.ToUintId).Then <object>(feesData => feesData.Cast <IFeeAsset>())); if (isNotCoreAsset) { promises.Add(EchoApiManager.Instance.Database.GetRequiredFees <FeeForCallContractData>(ops, coreAssetId.ToUintId).Then <object>(coreFeesData => coreFeesData.Cast <IFeeAsset>())); } } else if (ops.Contains(op => op.Type.Equals(ChainTypes.Operation.ContractCreate))) { promises.Add(EchoApiManager.Instance.Database.GetRequiredFees <FeeForCreateContractData>(ops, assetId.ToUintId).Then <object>(feesData => feesData.Cast <IFeeAsset>())); if (isNotCoreAsset) { promises.Add(EchoApiManager.Instance.Database.GetRequiredFees <FeeForCreateContractData>(ops, coreAssetId.ToUintId).Then <object>(coreFeesData => coreFeesData.Cast <IFeeAsset>())); } } else { promises.Add(EchoApiManager.Instance.Database.GetRequiredFees <AssetData>(ops, assetId.ToUintId).Then <object>(feesData => feesData.Cast <IFeeAsset>())); if (isNotCoreAsset) { promises.Add(EchoApiManager.Instance.Database.GetRequiredFees <AssetData>(ops, coreAssetId.ToUintId).Then <object>(coreFeesData => coreFeesData.Cast <IFeeAsset>())); } } if (isNotCoreAsset) { promises.Add(Repository.GetInPromise(assetId, () => EchoApiManager.Instance.Database.GetAsset(assetId.ToUintId)).Then <object>(assetObject => assetObject)); } return(Promise <object> .All(promises.ToArray()).Then(results => { var list = new List <object>(results).ToArray(); var feesData = list.First() as IFeeAsset[]; var coreFeesData = (list.Length > 1) ? (list[1] as IFeeAsset[]) : null; var assetObject = (list.Length > 2) ? (list[2] as AssetObject) : null; var dynamicPromise = isNotCoreAsset ? EchoApiManager.Instance.Database.GetObject <AssetDynamicDataObject>(assetObject.DynamicAssetData) : Promise <AssetDynamicDataObject> .Resolved(null); return dynamicPromise.Then(dynamicObject => { if (isNotCoreAsset) { var totalFees = 0L; for (var j = 0; j < coreFeesData.Length; j++) { totalFees += coreFeesData[j].FeeAsset.Amount; } var feePool = dynamicObject.IsNull() ? 0L : dynamicObject.FeePool; if (totalFees > feePool) { feesData = coreFeesData; } } var flatAssets = GetFee(feesData.OrEmpty(), new List <AssetData>()); var assetIndex = 0; for (var i = 0; i < builder.operations.Count; i++) { SetFee(builder.operations[i], ref assetIndex, flatAssets); } }); }).Then(() => Promise <TransactionBuilder> .Resolved(builder))); }
// Optional: the fees can be obtained from the witness node public static IPromise <TransactionBuilder> SetRequiredFees(TransactionBuilder builder, SpaceTypeId asset = null) { var feePool = 0L; if (builder.IsFinalized) { throw new InvalidOperationException("SetRequiredFees... Already finalized"); } if (builder.operations.IsNullOrEmpty()) { throw new InvalidOperationException("SetRequiredFees... Add operation first"); } var ops = new OperationData[builder.operations.Count]; for (var i = 0; i < builder.operations.Count; i++) { ops[i] = builder.operations[i].Clone(); } var zeroAsset = SpaceTypeId.CreateOne(SpaceType.Asset); if (asset.IsNull()) { var firstFee = ops[0].Fee; if (!firstFee.IsNull() && !firstFee.Asset.IsNullOrEmpty()) { asset = firstFee.Asset; } else { asset = zeroAsset; } } var promises = new List <IPromise <object> >(); promises.Add(ApiManager.Instance.Database.GetRequiredFees(ops, asset.Id).Then <object>(feesData => feesData)); if (!asset.Equals(zeroAsset)) { // This handles the fallback to paying fees in BTS if the fee pool is empty. promises.Add(ApiManager.Instance.Database.GetRequiredFees(ops, zeroAsset.Id).Then <object>(coreFeesData => coreFeesData)); promises.Add(Repository.GetInPromise(asset, () => ApiManager.Instance.Database.GetAsset(asset.Id)).Then <object>(assetObject => assetObject)); } return(Promise <object> .All(promises.ToArray()).Then(results => { var list = new List <object>(results).ToArray(); var feesData = list[0] as AssetData[]; var coreFeesData = (list.Length > 1) ? (list[1] as AssetData[]) : null; var assetObject = (list.Length > 2) ? (list[2] as AssetObject) : null; var dynamicPromise = (!asset.Equals(zeroAsset) && !asset.IsNull()) ? ApiManager.Instance.Database.GetObject <AssetDynamicDataObject>(assetObject.DynamicAssetData) : Promise <AssetDynamicDataObject> .Resolved(null); return dynamicPromise.Then(dynamicObject => { if (!asset.Equals(zeroAsset)) { feePool = !dynamicObject.IsNull() ? dynamicObject.FeePool : 0L; var totalFees = 0L; for (var j = 0; j < coreFeesData.Length; j++) { totalFees += coreFeesData[j].Amount; } if (totalFees > feePool) { feesData = coreFeesData; asset = zeroAsset; } } // Proposed transactions need to be flattened var flatAssets = new List <AssetData>(); Action <object> flatten = null; flatten = obj => { if (obj.IsArray()) { var array = obj as IList; for (var k = 0; k < array.Count; k++) { flatten(array[k]); } } else { flatAssets.Add(( AssetData )obj); } }; flatten(feesData.OrEmpty()); var assetIndex = 0; Action <OperationData> setFee = null; setFee = operation => { if (operation.Fee.IsNull() || operation.Fee.Amount == 0L) { operation.Fee = flatAssets[assetIndex]; } assetIndex++; if (operation.Type.Equals(ChainTypes.Operation.ProposalCreate)) { var proposedOperations = (operation as ProposalCreateOperationData).ProposedOperations; for (var y = 0; y < proposedOperations.Length; y++) { setFee(proposedOperations[y].Operation); } } }; for (var i = 0; i < builder.operations.Count; i++) { setFee(builder.operations[i]); } }); }).Then(results => Promise <TransactionBuilder> .Resolved(builder))); }