// 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)));
        }
Example #2
0
        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)));
        }
 public SignedTransactionData(TransactionBuilder builder) : base(builder)
 {
     Signatures = builder.Signatures;
 }