/// <summary> /// allow an administrator to request the unlocking of founder tokens /// </summary> /// <param name="address">founders script hash</param> /// <param name="roundNumber">1-7</param> /// <returns></returns> public static bool UnlockFoundersTokens(byte[] address, int roundNumber) { if (address.Length != 20) { Runtime.Log("UnlockFoundersTokens() invalid address supplied"); return(false); } byte[] roundKey = address.Concat(((BigInteger)roundNumber).AsByteArray()); StorageMap unlockedRounds = Storage.CurrentContext.CreateMap(StorageKeys.FounderTokenUnlockRound()); bool roundPreviouslyUnlocked = unlockedRounds.Get(roundKey).AsBigInteger() > 0; if (roundPreviouslyUnlocked) { Runtime.Log("UnlockFoundersTokens() round already unlocked"); return(false); } object[] foundersVestingPeriod = GetCoreTeamVestingSchedule(); uint currentTimestamp = Helpers.GetBlockTimestamp(); int roundIndex = (roundNumber * 2) - 2; int roundValueIndex = roundIndex + 1; if (roundIndex < 0) { Runtime.Log("UnlockFoundersTokens() invalid round index (<0)"); return(false); } uint roundReleaseDate = (uint)foundersVestingPeriod[roundIndex]; BigInteger roundReleaseAmount = (BigInteger)foundersVestingPeriod[roundValueIndex]; if (currentTimestamp < roundReleaseDate) { Runtime.Log("UnlockFoundersTokens() not scheduled for release"); return(false); } object[] founderKeys = ICOContract.MoonlightFounderKeys(); for (int i = 0; i < founderKeys.Length; i++) { byte[] founderKey = (byte[])founderKeys[i]; if (founderKey == address) { Runtime.Notify("UnlockFoundersTokens() releasing funds. currentTimestamp / roundReleaseDate / roundReleaseAmount", currentTimestamp, roundReleaseDate, roundReleaseAmount); Helpers.SetBalanceOf(founderKey, NEP5.BalanceOf(founderKey) + roundReleaseAmount); // set new balance for destination account unlockedRounds.Put(roundKey, "1"); return(true); } } return(false); }