diff --git a/client/public/imgs/BigLevel34.svg b/client/public/imgs/BigLevel34.svg
new file mode 100644
index 000000000..837f28fda
--- /dev/null
+++ b/client/public/imgs/BigLevel34.svg
@@ -0,0 +1,130 @@
+
+
\ No newline at end of file
diff --git a/client/public/imgs/Level34.svg b/client/public/imgs/Level34.svg
new file mode 100644
index 000000000..f05465993
--- /dev/null
+++ b/client/public/imgs/Level34.svg
@@ -0,0 +1,75 @@
+
+
+
\ No newline at end of file
diff --git a/client/src/gamedata/ar/descriptions/levels/timevault.md b/client/src/gamedata/ar/descriptions/levels/timevault.md
new file mode 100644
index 000000000..d556ce87c
--- /dev/null
+++ b/client/src/gamedata/ar/descriptions/levels/timevault.md
@@ -0,0 +1,7 @@
+يطبق عقد TimeVault أدناه تخزيناً آمناً مع آلية قفل زمني. تم تصميم الخزنة لتبقى مقفلة لفترة زمنية محددة (ساعة واحدة) قبل أن يتمكن أي شخص من الوصول إلى محتوياتها.
+
+تحتوي الخزنة على قيمة سرية يجب تعيينها إلى رقم محدد لإكمال هذا المستوى.
+
+هدفك هو تجاوز القفل الزمني وتعيين القيمة السرية إلى 42.
+
+الوقت وهم في عالم البلوك تشين. هل يمكنك التلاعب به لصالحك؟
\ No newline at end of file
diff --git a/client/src/gamedata/ar/descriptions/levels/timevault_complete.md b/client/src/gamedata/ar/descriptions/levels/timevault_complete.md
new file mode 100644
index 000000000..3cd908ece
--- /dev/null
+++ b/client/src/gamedata/ar/descriptions/levels/timevault_complete.md
@@ -0,0 +1,13 @@
+يوضح هذا المستوى ثغرة استخدام `block.timestamp` للتحكم في الوصول المبني على الوقت في العقود الذكية.
+
+يتضمن الحل فهم أن المعدنين لديهم بعض السيطرة على طوابع الوقت للكتل. بينما لا يمكنهم تعيين طوابع وقت عشوائية، يمكنهم التلاعب بها ضمن حدود معينة (عادة ±15 ثانية من الوقت الفعلي).
+
+في بيئات الاختبار مثل Foundry أو Hardhat، يمكنك استخدام دوال التلاعب بالوقت (`vm.warp()` أو `evm_increaseTime()`) لتسريع الوقت وتجاوز القفل الزمني فوراً.
+
+للحصول على تطبيقات آمنة للقفل الزمني، فكر في:
+- استخدام أرقام الكتل بدلاً من الطوابع الزمنية للحصول على توقيت أكثر قابلية للتنبؤ
+- تطبيق ضوابط وصول إضافية تتجاوز القيود المبنية على الوقت
+- استخدام أنماط القفل الزمني المعتمدة مثل TimelockController من OpenZeppelin
+- إدراك أن جميع البيانات على السلسلة عامة، بما في ذلك المتغيرات "الخاصة"
+
+راجع [أفضل ممارسات العقود الذكية من Consensys](https://consensys.github.io/smart-contract-best-practices/development-recommendations/general/timestamp-dependence/) لمزيد من المعلومات حول ثغرات الاعتماد على الطوابع الزمنية.
\ No newline at end of file
diff --git a/client/src/gamedata/authors.json b/client/src/gamedata/authors.json
index 220cf4294..3bdd32bb6 100644
--- a/client/src/gamedata/authors.json
+++ b/client/src/gamedata/authors.json
@@ -203,6 +203,15 @@
"www.x.com/carlitox477", "https://github.com/GianfrancoBazzani/"
],
"emails": ["carlitox477.auditor@gmail.com", "bazzanigianfranco@gmail.com"]
+ },
+ "Waiting-Chai": {
+ "name": [
+ "Waiting-Chai"
+ ],
+ "websites": [
+ "https://github.com/Waiting-Chai"
+ ],
+ "emails": []
}
}
}
\ No newline at end of file
diff --git a/client/src/gamedata/en/descriptions/levels/timevault.md b/client/src/gamedata/en/descriptions/levels/timevault.md
new file mode 100644
index 000000000..503d66164
--- /dev/null
+++ b/client/src/gamedata/en/descriptions/levels/timevault.md
@@ -0,0 +1,7 @@
+The TimeVault contract below implements a secure storage with a time lock mechanism. The vault is designed to remain locked for a specific time period (1 hour) before anyone can access its contents.
+
+The vault contains a secret value that must be set to a specific number to complete this level.
+
+Your goal is to bypass the time lock and set the secret value to 42.
+
+Time is an illusion in the blockchain world. Can you manipulate it to your advantage?
\ No newline at end of file
diff --git a/client/src/gamedata/en/descriptions/levels/timevault_complete.md b/client/src/gamedata/en/descriptions/levels/timevault_complete.md
new file mode 100644
index 000000000..683b89fad
--- /dev/null
+++ b/client/src/gamedata/en/descriptions/levels/timevault_complete.md
@@ -0,0 +1,13 @@
+This level demonstrates the vulnerability of using `block.timestamp` for time-based access controls in smart contracts.
+
+The solution involves understanding that miners have some control over block timestamps. While they cannot set arbitrary timestamps, they can manipulate them within certain bounds (typically ±15 seconds from the actual time).
+
+In testing environments like Foundry or Hardhat, you can use time manipulation functions (`vm.warp()` or `evm_increaseTime()`) to fast-forward time and bypass the timelock immediately.
+
+For secure timelock implementations, consider:
+- Using block numbers instead of timestamps for more predictable timing
+- Implementing additional access controls beyond time-based restrictions
+- Using established timelock patterns like OpenZeppelin's TimelockController
+- Being aware that all on-chain data is public, including "private" variables
+
+See [Consensys Smart Contract Best Practices](https://consensys.github.io/smart-contract-best-practices/development-recommendations/general/timestamp-dependence/) for more information about timestamp dependence vulnerabilities.
\ No newline at end of file
diff --git a/client/src/gamedata/es/descriptions/levels/timevault.md b/client/src/gamedata/es/descriptions/levels/timevault.md
new file mode 100644
index 000000000..dc4c0f8f2
--- /dev/null
+++ b/client/src/gamedata/es/descriptions/levels/timevault.md
@@ -0,0 +1,7 @@
+El contrato TimeVault a continuación implementa un almacenamiento seguro con un mecanismo de bloqueo temporal. La bóveda está diseñada para permanecer bloqueada durante un período de tiempo específico (1 hora) antes de que cualquiera pueda acceder a su contenido.
+
+La bóveda contiene un valor secreto que debe establecerse en un número específico para completar este nivel.
+
+Tu objetivo es eludir el bloqueo temporal y establecer el valor secreto en 42.
+
+El tiempo es una ilusión en el mundo blockchain. ¿Puedes manipularlo a tu favor?
\ No newline at end of file
diff --git a/client/src/gamedata/es/descriptions/levels/timevault_complete.md b/client/src/gamedata/es/descriptions/levels/timevault_complete.md
new file mode 100644
index 000000000..f0e5cdb47
--- /dev/null
+++ b/client/src/gamedata/es/descriptions/levels/timevault_complete.md
@@ -0,0 +1,13 @@
+Este nivel demuestra la vulnerabilidad de usar `block.timestamp` para controles de acceso basados en tiempo en contratos inteligentes.
+
+La solución implica entender que los mineros tienen cierto control sobre las marcas de tiempo de los bloques. Aunque no pueden establecer marcas de tiempo arbitrarias, pueden manipularlas dentro de ciertos límites (típicamente ±15 segundos del tiempo real).
+
+En entornos de prueba como Foundry o Hardhat, puedes usar funciones de manipulación de tiempo (`vm.warp()` o `evm_increaseTime()`) para acelerar el tiempo y eludir el bloqueo temporal inmediatamente.
+
+Para implementaciones seguras de bloqueo temporal, considera:
+- Usar números de bloque en lugar de marcas de tiempo para un tiempo más predecible
+- Implementar controles de acceso adicionales más allá de las restricciones basadas en tiempo
+- Usar patrones de bloqueo temporal establecidos como TimelockController de OpenZeppelin
+- Ser consciente de que todos los datos en cadena son públicos, incluyendo variables "privadas"
+
+Consulta [Mejores Prácticas de Contratos Inteligentes de Consensys](https://consensys.github.io/smart-contract-best-practices/development-recommendations/general/timestamp-dependence/) para más información sobre vulnerabilidades de dependencia de marcas de tiempo.
\ No newline at end of file
diff --git a/client/src/gamedata/fr/descriptions/levels/timevault.md b/client/src/gamedata/fr/descriptions/levels/timevault.md
new file mode 100644
index 000000000..6b7632942
--- /dev/null
+++ b/client/src/gamedata/fr/descriptions/levels/timevault.md
@@ -0,0 +1,7 @@
+Le contrat TimeVault ci-dessous implémente un stockage sécurisé avec un mécanisme de verrouillage temporel. Le coffre-fort est conçu pour rester verrouillé pendant une période de temps spécifique (1 heure) avant que quiconque puisse accéder à son contenu.
+
+Le coffre-fort contient une valeur secrète qui doit être définie sur un nombre spécifique pour compléter ce niveau.
+
+Votre objectif est de contourner le verrouillage temporel et de définir la valeur secrète à 42.
+
+Le temps est une illusion dans le monde de la blockchain. Pouvez-vous le manipuler à votre avantage ?
\ No newline at end of file
diff --git a/client/src/gamedata/fr/descriptions/levels/timevault_complete.md b/client/src/gamedata/fr/descriptions/levels/timevault_complete.md
new file mode 100644
index 000000000..6d02eac20
--- /dev/null
+++ b/client/src/gamedata/fr/descriptions/levels/timevault_complete.md
@@ -0,0 +1,13 @@
+Ce niveau démontre la vulnérabilité de l'utilisation de `block.timestamp` pour les contrôles d'accès basés sur le temps dans les contrats intelligents.
+
+La solution implique de comprendre que les mineurs ont un certain contrôle sur les horodatages des blocs. Bien qu'ils ne puissent pas définir des horodatages arbitraires, ils peuvent les manipuler dans certaines limites (généralement ±15 secondes par rapport au temps réel).
+
+Dans les environnements de test comme Foundry ou Hardhat, vous pouvez utiliser des fonctions de manipulation du temps (`vm.warp()` ou `evm_increaseTime()`) pour accélérer le temps et contourner le verrouillage temporel immédiatement.
+
+Pour des implémentations sécurisées de verrouillage temporel, considérez :
+- Utiliser les numéros de blocs au lieu des horodatages pour un timing plus prévisible
+- Implémenter des contrôles d'accès supplémentaires au-delà des restrictions basées sur le temps
+- Utiliser des modèles de verrouillage temporel établis comme TimelockController d'OpenZeppelin
+- Être conscient que toutes les données on-chain sont publiques, y compris les variables "privées"
+
+Consultez [Meilleures Pratiques des Contrats Intelligents de Consensys](https://consensys.github.io/smart-contract-best-practices/development-recommendations/general/timestamp-dependence/) pour plus d'informations sur les vulnérabilités de dépendance aux horodatages.
\ No newline at end of file
diff --git a/client/src/gamedata/gamedata.json b/client/src/gamedata/gamedata.json
index a90a5680e..0bc7f1eee 100644
--- a/client/src/gamedata/gamedata.json
+++ b/client/src/gamedata/gamedata.json
@@ -526,6 +526,21 @@
"deployId": "33",
"instanceGas": 750000,
"author": "Gianfranco&carlitox477"
+ },
+ {
+ "name": "TimeVault",
+ "created": "2025-08-18",
+ "difficulty": "5",
+ "description": "timevault.md",
+ "completedDescription": "timevault_complete.md",
+ "levelContract": "TimeVaultFactory.sol",
+ "instanceContract": "TimeVault.sol",
+ "revealCode": true,
+ "deployParams": [],
+ "deployFunds": 0,
+ "deployId": "34",
+ "instanceGas": 500000,
+ "author": "Waiting-Chai"
}
]
}
diff --git a/client/src/gamedata/ja/descriptions/levels/timevault.md b/client/src/gamedata/ja/descriptions/levels/timevault.md
new file mode 100644
index 000000000..457327e96
--- /dev/null
+++ b/client/src/gamedata/ja/descriptions/levels/timevault.md
@@ -0,0 +1,7 @@
+以下のTimeVaultコントラクトは、タイムロックメカニズムを備えた安全なストレージを実装しています。このボールトは、誰でもその内容にアクセスできるようになる前に、特定の時間(1時間)ロックされたままになるように設計されています。
+
+ボールトには秘密の値が含まれており、このレベルを完了するには特定の数値に設定する必要があります。
+
+あなたの目標は、タイムロックをバイパスして秘密の値を42に設定することです。
+
+ブロックチェーンの世界では、時間は幻想です。あなたはそれを有利に操作できますか?
\ No newline at end of file
diff --git a/client/src/gamedata/ja/descriptions/levels/timevault_complete.md b/client/src/gamedata/ja/descriptions/levels/timevault_complete.md
new file mode 100644
index 000000000..dad8aff00
--- /dev/null
+++ b/client/src/gamedata/ja/descriptions/levels/timevault_complete.md
@@ -0,0 +1,13 @@
+このレベルは、スマートコントラクトにおける時間ベースのアクセス制御に`block.timestamp`を使用することの脆弱性を実証しています。
+
+解決策は、マイナーがブロックのタイムスタンプに対してある程度の制御権を持っていることを理解することです。任意のタイムスタンプを設定することはできませんが、一定の範囲内(通常は実際の時間から±15秒)で操作することができます。
+
+FoundryやHardhatなどのテスト環境では、時間操作関数(`vm.warp()`または`evm_increaseTime()`)を使用して時間を早送りし、タイムロックを即座にバイパスできます。
+
+安全なタイムロック実装については、以下を検討してください:
+- より予測可能なタイミングのために、タイムスタンプの代わりにブロック番号を使用する
+- 時間ベースの制限を超えた追加のアクセス制御を実装する
+- OpenZeppelinのTimelockControllerなどの確立されたタイムロックパターンを使用する
+- 「プライベート」変数を含むすべてのオンチェーンデータが公開されていることを認識する
+
+タイムスタンプ依存の脆弱性について詳しくは、[Consensysスマートコントラクトベストプラクティス](https://consensys.github.io/smart-contract-best-practices/development-recommendations/general/timestamp-dependence/)を参照してください。
\ No newline at end of file
diff --git a/client/src/gamedata/pt_br/descriptions/levels/timevault.md b/client/src/gamedata/pt_br/descriptions/levels/timevault.md
new file mode 100644
index 000000000..c07d0b977
--- /dev/null
+++ b/client/src/gamedata/pt_br/descriptions/levels/timevault.md
@@ -0,0 +1,7 @@
+O contrato TimeVault abaixo implementa um armazenamento seguro com um mecanismo de bloqueio temporal. O cofre foi projetado para permanecer bloqueado por um período específico de tempo (1 hora) antes que qualquer pessoa possa acessar seu conteúdo.
+
+O cofre contém um valor secreto que deve ser definido para um número específico para completar este nível.
+
+Seu objetivo é contornar o bloqueio temporal e definir o valor secreto para 42.
+
+O tempo é uma ilusão no mundo blockchain. Você pode manipulá-lo a seu favor?
\ No newline at end of file
diff --git a/client/src/gamedata/pt_br/descriptions/levels/timevault_complete.md b/client/src/gamedata/pt_br/descriptions/levels/timevault_complete.md
new file mode 100644
index 000000000..c095ad6a2
--- /dev/null
+++ b/client/src/gamedata/pt_br/descriptions/levels/timevault_complete.md
@@ -0,0 +1,13 @@
+Este nível demonstra a vulnerabilidade de usar `block.timestamp` para controles de acesso baseados em tempo em contratos inteligentes.
+
+A solução envolve entender que os mineradores têm algum controle sobre os timestamps dos blocos. Embora não possam definir timestamps arbitrários, eles podem manipulá-los dentro de certos limites (tipicamente ±15 segundos do tempo real).
+
+Em ambientes de teste como Foundry ou Hardhat, você pode usar funções de manipulação de tempo (`vm.warp()` ou `evm_increaseTime()`) para avançar o tempo e contornar o bloqueio temporal imediatamente.
+
+Para implementações seguras de bloqueio temporal, considere:
+- Usar números de bloco em vez de timestamps para um tempo mais previsível
+- Implementar controles de acesso adicionais além das restrições baseadas em tempo
+- Usar padrões estabelecidos de bloqueio temporal como o TimelockController da OpenZeppelin
+- Estar ciente de que todos os dados on-chain são públicos, incluindo variáveis "privadas"
+
+Veja [Melhores Práticas de Contratos Inteligentes da Consensys](https://consensys.github.io/smart-contract-best-practices/development-recommendations/general/timestamp-dependence/) para mais informações sobre vulnerabilidades de dependência de timestamp.
\ No newline at end of file
diff --git a/client/src/gamedata/ru/descriptions/levels/timevault.md b/client/src/gamedata/ru/descriptions/levels/timevault.md
new file mode 100644
index 000000000..e0af96477
--- /dev/null
+++ b/client/src/gamedata/ru/descriptions/levels/timevault.md
@@ -0,0 +1,7 @@
+Контракт TimeVault ниже реализует безопасное хранилище с механизмом временной блокировки. Хранилище спроектировано так, чтобы оставаться заблокированным в течение определенного периода времени (1 час), прежде чем кто-либо сможет получить доступ к его содержимому.
+
+Хранилище содержит секретное значение, которое должно быть установлено на определенное число для завершения этого уровня.
+
+Ваша цель - обойти временную блокировку и установить секретное значение равным 42.
+
+Время - это иллюзия в мире блокчейна. Можете ли вы манипулировать им в свою польз
\ No newline at end of file
diff --git a/client/src/gamedata/ru/descriptions/levels/timevault_complete.md b/client/src/gamedata/ru/descriptions/levels/timevault_complete.md
new file mode 100644
index 000000000..f987c5207
--- /dev/null
+++ b/client/src/gamedata/ru/descriptions/levels/timevault_complete.md
@@ -0,0 +1,13 @@
+Этот уровень демонстрирует уязвимость использования `block.timestamp` для временного контроля доступа в смарт-контрактах.
+
+Решение включает понимание того, что майнеры имеют некоторый контроль над временными метками блоков. Хотя они не могут устанавливать произвольные временные метки, они могут манипулировать ими в определенных пределах (обычно ±15 секунд от реального времени).
+
+В тестовых средах, таких как Foundry или Hardhat, вы можете использовать функции манипуляции временем (`vm.warp()` или `evm_increaseTime()`), чтобы ускорить время и немедленно обойти временную блокировку.
+
+Для безопасных реализаций временной блокировки рассмотрите:
+- Использование номеров блоков вместо временных меток для более предсказуемого времени
+- Реализацию дополнительных контролей доступа помимо временных ограничений
+- Использование установленных паттернов временной блокировки, таких как TimelockController от OpenZeppelin
+- Осознание того, что все данные в блокчейне являются публичными, включая "приватные" переменные
+
+См. [Лучшие практики смарт-контрактов Consensys](https://consensys.github.io/smart-contract-best-practices/development-recommendations/general/timestamp-dependence/) для получения дополнительной информации об уязвимостях зависимости от временных меток.
\ No newline at end of file
diff --git a/client/src/gamedata/tr/descriptions/levels/timevault.md b/client/src/gamedata/tr/descriptions/levels/timevault.md
new file mode 100644
index 000000000..9d4b300f9
--- /dev/null
+++ b/client/src/gamedata/tr/descriptions/levels/timevault.md
@@ -0,0 +1,7 @@
+Aşağıdaki TimeVault kontratı, zaman kilidi mekanizması ile güvenli bir depolama sistemi uygular. Depo, herhangi birinin içeriğine erişebilmesi için belirli bir süre (1 saat) boyunca kilitli kalacak şekilde tasarlanmıştır.
+
+Depo, bu seviyeyi tamamlamak için belirli bir sayıya ayarlanması gereken gizli bir değer içerir.
+
+Amacınız zaman kilidini atlatmak ve gizli değeri 42'ye ayarlamaktır.
+
+Zaman, blockchain dünyasında bir illüzyondur. Onu kendi lehinize manipüle edebilir misiniz?
\ No newline at end of file
diff --git a/client/src/gamedata/tr/descriptions/levels/timevault_complete.md b/client/src/gamedata/tr/descriptions/levels/timevault_complete.md
new file mode 100644
index 000000000..a5d11b5b0
--- /dev/null
+++ b/client/src/gamedata/tr/descriptions/levels/timevault_complete.md
@@ -0,0 +1,13 @@
+Bu seviye, akıllı kontratlarında zamana dayalı erişim kontrolü için `block.timestamp` kullanmanın güvenlik açığını gösterir.
+
+Çözüm, madencilerin blok zaman damgaları üzerinde bir miktar kontrole sahip olduğunu anlamayı içerir. Keyfi zaman damgaları belirleyemeseler de, bunları belirli sınırlar içinde (genellikle gerçek zamandan ±15 saniye) manipüle edebilirler.
+
+Foundry veya Hardhat gibi test ortamlarında, zaman manipülasyon fonksiyonlarını (`vm.warp()` veya `evm_increaseTime()`) kullanarak zamanı hızlandırabilir ve zaman kilidini anında atlayabilirsiniz.
+
+Güvenli zaman kilidi uygulamaları için şunları düşünün:
+- Daha öngörülebilir zamanlama için zaman damgaları yerine blok numaralarını kullanma
+- Zaman kısıtlamalarının yanı sıra ek erişim kontrolleri uygulama
+- OpenZeppelin'in TimelockController'ı gibi yerleşik zaman kilidi desenlerini kullanma
+- "Özel" değişkenler dahil olmak üzere blockchain'deki tüm verilerin herkese açık olduğunu fark etme
+
+Zaman damgası bağımlılığı güvenlik açıkları hakkında daha fazla bilgi için [Consensys Akıllı Kontrat En İyi Uygulamaları](https://consensys.github.io/smart-contract-best-practices/development-recommendations/general/timestamp-dependence/)'na bakın.
\ No newline at end of file
diff --git a/client/src/gamedata/zh_cn/descriptions/levels/timevault.md b/client/src/gamedata/zh_cn/descriptions/levels/timevault.md
new file mode 100644
index 000000000..e59aaa942
--- /dev/null
+++ b/client/src/gamedata/zh_cn/descriptions/levels/timevault.md
@@ -0,0 +1,7 @@
+下面的TimeVault合约实现了一个带有时间锁机制的安全存储。保险库设计为在特定时间段(1小时)内保持锁定状态,之后才能访问其内容。
+
+保险库包含一个秘密值,必须将其设置为特定数字才能完成此关卡。
+
+你的目标是绕过时间锁并将秘密值设置为42。
+
+在区块链世界中,时间只是一种幻觉。你能否操纵它为自己所用?
\ No newline at end of file
diff --git a/client/src/gamedata/zh_cn/descriptions/levels/timevault_complete.md b/client/src/gamedata/zh_cn/descriptions/levels/timevault_complete.md
new file mode 100644
index 000000000..607011f91
--- /dev/null
+++ b/client/src/gamedata/zh_cn/descriptions/levels/timevault_complete.md
@@ -0,0 +1,13 @@
+此关卡演示了在智能合约中使用`block.timestamp`进行基于时间的访问控制的漏洞。
+
+解决方案涉及理解矿工对区块时间戳有一定的控制权。虽然他们不能设置任意时间戳,但可以在一定范围内操纵它们(通常为实际时间的±15秒)。
+
+在Foundry或Hardhat等测试环境中,你可以使用时间操纵函数(`vm.warp()`或`evm_increaseTime()`)来快进时间并立即绕过时间锁。
+
+对于安全的时间锁实现,请考虑:
+- 使用区块号而不是时间戳来获得更可预测的时间
+- 在基于时间的限制之外实施额外的访问控制
+- 使用已建立的时间锁模式,如OpenZeppelin的TimelockController
+- 意识到所有链上数据都是公开的,包括"私有"变量
+
+有关时间戳依赖漏洞的更多信息,请参阅[Consensys智能合约最佳实践](https://consensys.github.io/smart-contract-best-practices/development-recommendations/general/timestamp-dependence/)。
\ No newline at end of file
diff --git a/client/src/gamedata/zh_tw/descriptions/levels/timevault.md b/client/src/gamedata/zh_tw/descriptions/levels/timevault.md
new file mode 100644
index 000000000..941250152
--- /dev/null
+++ b/client/src/gamedata/zh_tw/descriptions/levels/timevault.md
@@ -0,0 +1,7 @@
+下方的 TimeVault 合約實現了一個具有時間鎖機制的安全儲存庫。該儲存庫被設計為在特定時間段(1小時)內保持鎖定狀態,之後任何人才能存取其內容。
+
+儲存庫包含一個秘密值,必須將其設定為特定數字才能完成此關卡。
+
+您的目標是繞過時間鎖並將秘密值設定為 42。
+
+在區塊鏈世界中,時間是一種幻覺。您能否操縱它來為自己謀利?
\ No newline at end of file
diff --git a/client/src/gamedata/zh_tw/descriptions/levels/timevault_complete.md b/client/src/gamedata/zh_tw/descriptions/levels/timevault_complete.md
new file mode 100644
index 000000000..f83ac3816
--- /dev/null
+++ b/client/src/gamedata/zh_tw/descriptions/levels/timevault_complete.md
@@ -0,0 +1,13 @@
+此關卡展示了在智能合約中使用 `block.timestamp` 進行基於時間的存取控制的漏洞。
+
+解決方案涉及理解礦工對區塊時間戳具有一定程度的控制權。雖然他們無法設定任意時間戳,但可以在一定範圍內(通常為實際時間的 ±15 秒)操縱它們。
+
+在 Foundry 或 Hardhat 等測試環境中,您可以使用時間操縱函數(`vm.warp()` 或 `evm_increaseTime()`)來快進時間並立即繞過時間鎖。
+
+對於安全的時間鎖實現,請考慮:
+- 使用區塊號而非時間戳來獲得更可預測的時間
+- 除了時間限制外,還要實施額外的存取控制
+- 使用既定的時間鎖模式,如 OpenZeppelin 的 TimelockController
+- 認識到區塊鏈上的所有資料都是公開的,包括「私有」變數
+
+請參閱 [Consensys 智能合約最佳實踐](https://consensys.github.io/smart-contract-best-practices/development-recommendations/general/timestamp-dependence/) 以獲取有關時間戳依賴漏洞的更多資訊。
\ No newline at end of file
diff --git a/contracts/out/Level.sol/Level.json b/contracts/out/Level.sol/Level.json
index 61c947e34..937963e45 100644
--- a/contracts/out/Level.sol/Level.json
+++ b/contracts/out/Level.sol/Level.json
@@ -1 +1 @@
-{"abi":[{"type":"function","name":"createInstance","inputs":[{"name":"_player","type":"address","internalType":"address"}],"outputs":[{"name":"","type":"address","internalType":"address"}],"stateMutability":"payable"},{"type":"function","name":"owner","inputs":[],"outputs":[{"name":"","type":"address","internalType":"address"}],"stateMutability":"view"},{"type":"function","name":"renounceOwnership","inputs":[],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"transferOwnership","inputs":[{"name":"newOwner","type":"address","internalType":"address"}],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"validateInstance","inputs":[{"name":"_instance","type":"address","internalType":"address payable"},{"name":"_player","type":"address","internalType":"address"}],"outputs":[{"name":"","type":"bool","internalType":"bool"}],"stateMutability":"nonpayable"},{"type":"event","name":"OwnershipTransferred","inputs":[{"name":"previousOwner","type":"address","indexed":true,"internalType":"address"},{"name":"newOwner","type":"address","indexed":true,"internalType":"address"}],"anonymous":false}],"bytecode":{"object":"0x","sourceMap":"","linkReferences":{}},"deployedBytecode":{"object":"0x","sourceMap":"","linkReferences":{}},"methodIdentifiers":{"createInstance(address)":"7726f776","owner()":"8da5cb5b","renounceOwnership()":"715018a6","transferOwnership(address)":"f2fde38b","validateInstance(address,address)":"d38def5b"},"rawMetadata":"{\"compiler\":{\"version\":\"0.8.25+commit.b61c2a91\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"previousOwner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_player\",\"type\":\"address\"}],\"name\":\"createInstance\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"renounceOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address payable\",\"name\":\"_instance\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_player\",\"type\":\"address\"}],\"name\":\"validateInstance\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{\"owner()\":{\"details\":\"Returns the address of the current owner.\"},\"renounceOwnership()\":{\"details\":\"Leaves the contract without owner. It will not be possible to call `onlyOwner` functions anymore. Can only be called by the current owner. NOTE: Renouncing ownership will leave the contract without an owner, thereby removing any functionality that is only available to the owner.\"},\"transferOwnership(address)\":{\"details\":\"Transfers ownership of the contract to a new account (`newOwner`). Can only be called by the current owner.\"}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"src/levels/base/Level.sol\":\"Level\"},\"evmVersion\":\"shanghai\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":1000},\"remappings\":[\":ds-test/=lib/openzeppelin-contracts-upgradeable/lib/forge-std/lib/ds-test/src/\",\":erc4626-tests/=lib/openzeppelin-contracts-upgradeable/lib/erc4626-tests/\",\":forge-std/=lib/forge-std/src/\",\":openzeppelin-contracts-06/=lib/openzeppelin-contracts-06/contracts/\",\":openzeppelin-contracts-08/=lib/openzeppelin-contracts-08/contracts/\",\":openzeppelin-contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/\",\":openzeppelin-upgradeable/=lib/openzeppelin-contracts-upgradeable/contracts/\",\":openzeppelin/=lib/openzeppelin-contracts-upgradeable/contracts/\"]},\"sources\":{\"lib/openzeppelin-contracts-08/contracts/access/Ownable.sol\":{\"keccak256\":\"0xa94b34880e3c1b0b931662cb1c09e5dfa6662f31cba80e07c5ee71cd135c9673\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://40fb1b5102468f783961d0af743f91b9980cf66b50d1d12009f6bb1869cea4d2\",\"dweb:/ipfs/QmYqEbJML4jB1GHbzD4cUZDtJg5wVwNm3vDJq1GbyDus8y\"]},\"lib/openzeppelin-contracts-08/contracts/utils/Context.sol\":{\"keccak256\":\"0xe2e337e6dde9ef6b680e07338c493ebea1b5fd09b43424112868e9cc1706bca7\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://6df0ddf21ce9f58271bdfaa85cde98b200ef242a05a3f85c2bc10a8294800a92\",\"dweb:/ipfs/QmRK2Y5Yc6BK7tGKkgsgn3aJEQGi5aakeSPZvS65PV8Xp3\"]},\"src/levels/base/Level.sol\":{\"keccak256\":\"0x23e8a2c9454707c888fc4dc4cc44d89e5928e8d58a1f9c8f5c16c36697aadfdf\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://693402ec163e362b086874db09be2d1d11111276f70100bf9192a0fb3f5d9ccd\",\"dweb:/ipfs/QmSsygUUkJHRh13rGUQ4BrMTnzmPQKrRsBABS4Yk11kfAA\"]}},\"version\":1}","metadata":{"compiler":{"version":"0.8.25+commit.b61c2a91"},"language":"Solidity","output":{"abi":[{"inputs":[{"internalType":"address","name":"previousOwner","type":"address","indexed":true},{"internalType":"address","name":"newOwner","type":"address","indexed":true}],"type":"event","name":"OwnershipTransferred","anonymous":false},{"inputs":[{"internalType":"address","name":"_player","type":"address"}],"stateMutability":"payable","type":"function","name":"createInstance","outputs":[{"internalType":"address","name":"","type":"address"}]},{"inputs":[],"stateMutability":"view","type":"function","name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}]},{"inputs":[],"stateMutability":"nonpayable","type":"function","name":"renounceOwnership"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"stateMutability":"nonpayable","type":"function","name":"transferOwnership"},{"inputs":[{"internalType":"address payable","name":"_instance","type":"address"},{"internalType":"address","name":"_player","type":"address"}],"stateMutability":"nonpayable","type":"function","name":"validateInstance","outputs":[{"internalType":"bool","name":"","type":"bool"}]}],"devdoc":{"kind":"dev","methods":{"owner()":{"details":"Returns the address of the current owner."},"renounceOwnership()":{"details":"Leaves the contract without owner. It will not be possible to call `onlyOwner` functions anymore. Can only be called by the current owner. NOTE: Renouncing ownership will leave the contract without an owner, thereby removing any functionality that is only available to the owner."},"transferOwnership(address)":{"details":"Transfers ownership of the contract to a new account (`newOwner`). Can only be called by the current owner."}},"version":1},"userdoc":{"kind":"user","methods":{},"version":1}},"settings":{"remappings":["ds-test/=lib/openzeppelin-contracts-upgradeable/lib/forge-std/lib/ds-test/src/","erc4626-tests/=lib/openzeppelin-contracts-upgradeable/lib/erc4626-tests/","forge-std/=lib/forge-std/src/","openzeppelin-contracts-06/=lib/openzeppelin-contracts-06/contracts/","openzeppelin-contracts-08/=lib/openzeppelin-contracts-08/contracts/","openzeppelin-contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/","openzeppelin-upgradeable/=lib/openzeppelin-contracts-upgradeable/contracts/","openzeppelin/=lib/openzeppelin-contracts-upgradeable/contracts/"],"optimizer":{"enabled":true,"runs":1000},"metadata":{"bytecodeHash":"ipfs"},"compilationTarget":{"src/levels/base/Level.sol":"Level"},"evmVersion":"shanghai","libraries":{}},"sources":{"lib/openzeppelin-contracts-08/contracts/access/Ownable.sol":{"keccak256":"0xa94b34880e3c1b0b931662cb1c09e5dfa6662f31cba80e07c5ee71cd135c9673","urls":["bzz-raw://40fb1b5102468f783961d0af743f91b9980cf66b50d1d12009f6bb1869cea4d2","dweb:/ipfs/QmYqEbJML4jB1GHbzD4cUZDtJg5wVwNm3vDJq1GbyDus8y"],"license":"MIT"},"lib/openzeppelin-contracts-08/contracts/utils/Context.sol":{"keccak256":"0xe2e337e6dde9ef6b680e07338c493ebea1b5fd09b43424112868e9cc1706bca7","urls":["bzz-raw://6df0ddf21ce9f58271bdfaa85cde98b200ef242a05a3f85c2bc10a8294800a92","dweb:/ipfs/QmRK2Y5Yc6BK7tGKkgsgn3aJEQGi5aakeSPZvS65PV8Xp3"],"license":"MIT"},"src/levels/base/Level.sol":{"keccak256":"0x23e8a2c9454707c888fc4dc4cc44d89e5928e8d58a1f9c8f5c16c36697aadfdf","urls":["bzz-raw://693402ec163e362b086874db09be2d1d11111276f70100bf9192a0fb3f5d9ccd","dweb:/ipfs/QmSsygUUkJHRh13rGUQ4BrMTnzmPQKrRsBABS4Yk11kfAA"],"license":"MIT"}},"version":1},"id":38}
\ No newline at end of file
+{"abi":[{"type":"function","name":"createInstance","inputs":[{"name":"_player","type":"address","internalType":"address"}],"outputs":[{"name":"","type":"address","internalType":"address"}],"stateMutability":"payable"},{"type":"function","name":"owner","inputs":[],"outputs":[{"name":"","type":"address","internalType":"address"}],"stateMutability":"view"},{"type":"function","name":"renounceOwnership","inputs":[],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"transferOwnership","inputs":[{"name":"newOwner","type":"address","internalType":"address"}],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"validateInstance","inputs":[{"name":"_instance","type":"address","internalType":"address payable"},{"name":"_player","type":"address","internalType":"address"}],"outputs":[{"name":"","type":"bool","internalType":"bool"}],"stateMutability":"nonpayable"},{"type":"event","name":"OwnershipTransferred","inputs":[{"name":"previousOwner","type":"address","indexed":true,"internalType":"address"},{"name":"newOwner","type":"address","indexed":true,"internalType":"address"}],"anonymous":false}],"bytecode":{"object":"0x","sourceMap":"","linkReferences":{}},"deployedBytecode":{"object":"0x","sourceMap":"","linkReferences":{}},"methodIdentifiers":{"createInstance(address)":"7726f776","owner()":"8da5cb5b","renounceOwnership()":"715018a6","transferOwnership(address)":"f2fde38b","validateInstance(address,address)":"d38def5b"},"rawMetadata":"{\"compiler\":{\"version\":\"0.8.19+commit.7dd6d404\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"previousOwner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_player\",\"type\":\"address\"}],\"name\":\"createInstance\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"renounceOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address payable\",\"name\":\"_instance\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_player\",\"type\":\"address\"}],\"name\":\"validateInstance\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{\"owner()\":{\"details\":\"Returns the address of the current owner.\"},\"renounceOwnership()\":{\"details\":\"Leaves the contract without owner. It will not be possible to call `onlyOwner` functions anymore. Can only be called by the current owner. NOTE: Renouncing ownership will leave the contract without an owner, thereby removing any functionality that is only available to the owner.\"},\"transferOwnership(address)\":{\"details\":\"Transfers ownership of the contract to a new account (`newOwner`). Can only be called by the current owner.\"}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"src/levels/base/Level.sol\":\"Level\"},\"evmVersion\":\"paris\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":1000},\"remappings\":[\":ds-test/=lib/openzeppelin-contracts-upgradeable/lib/forge-std/lib/ds-test/src/\",\":erc4626-tests/=lib/openzeppelin-contracts-upgradeable/lib/erc4626-tests/\",\":forge-std/=lib/forge-std/src/\",\":openzeppelin-contracts-06/=lib/openzeppelin-contracts-06/contracts/\",\":openzeppelin-contracts-08/=lib/openzeppelin-contracts-08/contracts/\",\":openzeppelin-contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/\",\":openzeppelin-upgradeable/=lib/openzeppelin-contracts-upgradeable/contracts/\",\":openzeppelin/=lib/openzeppelin-contracts-upgradeable/contracts/\"]},\"sources\":{\"lib/openzeppelin-contracts-08/contracts/access/Ownable.sol\":{\"keccak256\":\"0xa94b34880e3c1b0b931662cb1c09e5dfa6662f31cba80e07c5ee71cd135c9673\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://40fb1b5102468f783961d0af743f91b9980cf66b50d1d12009f6bb1869cea4d2\",\"dweb:/ipfs/QmYqEbJML4jB1GHbzD4cUZDtJg5wVwNm3vDJq1GbyDus8y\"]},\"lib/openzeppelin-contracts-08/contracts/utils/Context.sol\":{\"keccak256\":\"0xe2e337e6dde9ef6b680e07338c493ebea1b5fd09b43424112868e9cc1706bca7\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://6df0ddf21ce9f58271bdfaa85cde98b200ef242a05a3f85c2bc10a8294800a92\",\"dweb:/ipfs/QmRK2Y5Yc6BK7tGKkgsgn3aJEQGi5aakeSPZvS65PV8Xp3\"]},\"src/levels/base/Level.sol\":{\"keccak256\":\"0x23e8a2c9454707c888fc4dc4cc44d89e5928e8d58a1f9c8f5c16c36697aadfdf\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://693402ec163e362b086874db09be2d1d11111276f70100bf9192a0fb3f5d9ccd\",\"dweb:/ipfs/QmSsygUUkJHRh13rGUQ4BrMTnzmPQKrRsBABS4Yk11kfAA\"]}},\"version\":1}","metadata":{"compiler":{"version":"0.8.19+commit.7dd6d404"},"language":"Solidity","output":{"abi":[{"inputs":[{"internalType":"address","name":"previousOwner","type":"address","indexed":true},{"internalType":"address","name":"newOwner","type":"address","indexed":true}],"type":"event","name":"OwnershipTransferred","anonymous":false},{"inputs":[{"internalType":"address","name":"_player","type":"address"}],"stateMutability":"payable","type":"function","name":"createInstance","outputs":[{"internalType":"address","name":"","type":"address"}]},{"inputs":[],"stateMutability":"view","type":"function","name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}]},{"inputs":[],"stateMutability":"nonpayable","type":"function","name":"renounceOwnership"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"stateMutability":"nonpayable","type":"function","name":"transferOwnership"},{"inputs":[{"internalType":"address payable","name":"_instance","type":"address"},{"internalType":"address","name":"_player","type":"address"}],"stateMutability":"nonpayable","type":"function","name":"validateInstance","outputs":[{"internalType":"bool","name":"","type":"bool"}]}],"devdoc":{"kind":"dev","methods":{"owner()":{"details":"Returns the address of the current owner."},"renounceOwnership()":{"details":"Leaves the contract without owner. It will not be possible to call `onlyOwner` functions anymore. Can only be called by the current owner. NOTE: Renouncing ownership will leave the contract without an owner, thereby removing any functionality that is only available to the owner."},"transferOwnership(address)":{"details":"Transfers ownership of the contract to a new account (`newOwner`). Can only be called by the current owner."}},"version":1},"userdoc":{"kind":"user","methods":{},"version":1}},"settings":{"remappings":["ds-test/=lib/openzeppelin-contracts-upgradeable/lib/forge-std/lib/ds-test/src/","erc4626-tests/=lib/openzeppelin-contracts-upgradeable/lib/erc4626-tests/","forge-std/=lib/forge-std/src/","openzeppelin-contracts-06/=lib/openzeppelin-contracts-06/contracts/","openzeppelin-contracts-08/=lib/openzeppelin-contracts-08/contracts/","openzeppelin-contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/","openzeppelin-upgradeable/=lib/openzeppelin-contracts-upgradeable/contracts/","openzeppelin/=lib/openzeppelin-contracts-upgradeable/contracts/"],"optimizer":{"enabled":true,"runs":1000},"metadata":{"bytecodeHash":"ipfs"},"compilationTarget":{"src/levels/base/Level.sol":"Level"},"evmVersion":"paris","libraries":{}},"sources":{"lib/openzeppelin-contracts-08/contracts/access/Ownable.sol":{"keccak256":"0xa94b34880e3c1b0b931662cb1c09e5dfa6662f31cba80e07c5ee71cd135c9673","urls":["bzz-raw://40fb1b5102468f783961d0af743f91b9980cf66b50d1d12009f6bb1869cea4d2","dweb:/ipfs/QmYqEbJML4jB1GHbzD4cUZDtJg5wVwNm3vDJq1GbyDus8y"],"license":"MIT"},"lib/openzeppelin-contracts-08/contracts/utils/Context.sol":{"keccak256":"0xe2e337e6dde9ef6b680e07338c493ebea1b5fd09b43424112868e9cc1706bca7","urls":["bzz-raw://6df0ddf21ce9f58271bdfaa85cde98b200ef242a05a3f85c2bc10a8294800a92","dweb:/ipfs/QmRK2Y5Yc6BK7tGKkgsgn3aJEQGi5aakeSPZvS65PV8Xp3"],"license":"MIT"},"src/levels/base/Level.sol":{"keccak256":"0x23e8a2c9454707c888fc4dc4cc44d89e5928e8d58a1f9c8f5c16c36697aadfdf","urls":["bzz-raw://693402ec163e362b086874db09be2d1d11111276f70100bf9192a0fb3f5d9ccd","dweb:/ipfs/QmSsygUUkJHRh13rGUQ4BrMTnzmPQKrRsBABS4Yk11kfAA"],"license":"MIT"}},"version":1},"id":4}
\ No newline at end of file
diff --git a/contracts/out/TimeVault.sol/TimeVault.json b/contracts/out/TimeVault.sol/TimeVault.json
new file mode 100644
index 000000000..816a90920
--- /dev/null
+++ b/contracts/out/TimeVault.sol/TimeVault.json
@@ -0,0 +1 @@
+{"abi":[{"type":"constructor","inputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"getCurrentTime","inputs":[],"outputs":[{"name":"","type":"uint256","internalType":"uint256"}],"stateMutability":"view"},{"type":"function","name":"getTimeRemaining","inputs":[],"outputs":[{"name":"","type":"uint256","internalType":"uint256"}],"stateMutability":"view"},{"type":"function","name":"isCompleted","inputs":[],"outputs":[{"name":"","type":"bool","internalType":"bool"}],"stateMutability":"view"},{"type":"function","name":"isUnlocked","inputs":[],"outputs":[{"name":"","type":"bool","internalType":"bool"}],"stateMutability":"view"},{"type":"function","name":"owner","inputs":[],"outputs":[{"name":"","type":"address","internalType":"address"}],"stateMutability":"view"},{"type":"function","name":"secretValue","inputs":[],"outputs":[{"name":"","type":"uint256","internalType":"uint256"}],"stateMutability":"view"},{"type":"function","name":"setSecret","inputs":[{"name":"_secret","type":"uint256","internalType":"uint256"}],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"unlock","inputs":[],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"unlockTime","inputs":[],"outputs":[{"name":"","type":"uint256","internalType":"uint256"}],"stateMutability":"view"},{"type":"event","name":"SecretSet","inputs":[{"name":"setter","type":"address","indexed":true,"internalType":"address"},{"name":"value","type":"uint256","indexed":false,"internalType":"uint256"}],"anonymous":false},{"type":"event","name":"VaultUnlocked","inputs":[{"name":"unlocker","type":"address","indexed":true,"internalType":"address"},{"name":"timestamp","type":"uint256","indexed":false,"internalType":"uint256"}],"anonymous":false}],"bytecode":{"object":"0x608060405234801561001057600080fd5b5060028054610100600160a81b031916336101000217905561003442610e1061004b565b60009081556002805460ff19169055600155610072565b8082018082111561006c57634e487b7160e01b600052601160045260246000fd5b92915050565b61034d806100816000396000f3fe608060405234801561001057600080fd5b50600436106100a35760003560e01c80638da5cb5b11610076578063ccaa02481161005b578063ccaa02481461014e578063dac6270d14610157578063fa391c641461015f57600080fd5b80638da5cb5b146100fc578063a69df4b51461014657600080fd5b8063251c1aa3146100a857806329cb924d146100c45780633b4dbf8b146100ca5780638380edb7146100df575b600080fd5b6100b160005481565b6040519081526020015b60405180910390f35b426100b1565b6100dd6100d83660046102be565b61016a565b005b6002546100ec9060ff1681565b60405190151581526020016100bb565b60025461012190610100900473ffffffffffffffffffffffffffffffffffffffff1681565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016100bb565b6100dd6101fe565b6100b160015481565b6100b161029b565b600154602a146100ec565b60025460ff166101c15760405162461bcd60e51b815260206004820152601c60248201527f5661756c74206d75737420626520756e6c6f636b65642066697273740000000060448201526064015b60405180910390fd5b600181905560405181815233907fd07fa57b9c72461d5676947bbfbf63a9d3091f9ef047e999a34b39dd5f6df93a9060200160405180910390a250565b6000544210156102505760405162461bcd60e51b815260206004820152601560248201527f5661756c74206973207374696c6c206c6f636b6564000000000000000000000060448201526064016101b8565b6002805460ff1916600117905560405133907f58f708cb331f8b003aab2818910d14f42d171878a3e31abb65877606ac28b2d9906102919042815260200190565b60405180910390a2565b6000805442106102ab5750600090565b426000546102b991906102d7565b905090565b6000602082840312156102d057600080fd5b5035919050565b81810381811115610311577f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b9291505056fea26469706673582212203f804dd5a2e500892d1e532207b8490fa04dc611b5cd18ec6da7806eff82f4fe64736f6c63430008130033","sourceMap":"57:1840:2:-:0;;;339:203;;;;;;;;;-1:-1:-1;363:5:2;:18;;-1:-1:-1;;;;;;363:18:2;371:10;363:18;;;;;457:25;:15;475:7;457:25;:::i;:::-;444:10;:38;;;492:10;:18;;-1:-1:-1;;492:18:2;;;;520:15;57:1840;;14:222:5;79:9;;;100:10;;;97:133;;;152:10;147:3;143:20;140:1;133:31;187:4;184:1;177:15;215:4;212:1;205:15;97:133;14:222;;;;:::o;:::-;57:1840:2;;;;;;","linkReferences":{}},"deployedBytecode":{"object":"0x608060405234801561001057600080fd5b50600436106100a35760003560e01c80638da5cb5b11610076578063ccaa02481161005b578063ccaa02481461014e578063dac6270d14610157578063fa391c641461015f57600080fd5b80638da5cb5b146100fc578063a69df4b51461014657600080fd5b8063251c1aa3146100a857806329cb924d146100c45780633b4dbf8b146100ca5780638380edb7146100df575b600080fd5b6100b160005481565b6040519081526020015b60405180910390f35b426100b1565b6100dd6100d83660046102be565b61016a565b005b6002546100ec9060ff1681565b60405190151581526020016100bb565b60025461012190610100900473ffffffffffffffffffffffffffffffffffffffff1681565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016100bb565b6100dd6101fe565b6100b160015481565b6100b161029b565b600154602a146100ec565b60025460ff166101c15760405162461bcd60e51b815260206004820152601c60248201527f5661756c74206d75737420626520756e6c6f636b65642066697273740000000060448201526064015b60405180910390fd5b600181905560405181815233907fd07fa57b9c72461d5676947bbfbf63a9d3091f9ef047e999a34b39dd5f6df93a9060200160405180910390a250565b6000544210156102505760405162461bcd60e51b815260206004820152601560248201527f5661756c74206973207374696c6c206c6f636b6564000000000000000000000060448201526064016101b8565b6002805460ff1916600117905560405133907f58f708cb331f8b003aab2818910d14f42d171878a3e31abb65877606ac28b2d9906102919042815260200190565b60405180910390a2565b6000805442106102ab5750600090565b426000546102b991906102d7565b905090565b6000602082840312156102d057600080fd5b5035919050565b81810381811115610311577f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b9291505056fea26469706673582212203f804dd5a2e500892d1e532207b8490fa04dc611b5cd18ec6da7806eff82f4fe64736f6c63430008130033","sourceMap":"57:1840:2:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;82:25;;;;;;;;;160::5;;;148:2;133:18;82:25:2;;;;;;;;1541:97;1616:15;1541:97;;1104:141;;;;;;:::i;:::-;;:::i;:::-;;145:22;;;;;;;;;;;;546:14:5;;539:22;521:41;;509:2;494:18;145:22:2;381:187:5;173:20:2;;;;;;;;;;;;;;;749:42:5;737:55;;;719:74;;707:2;692:18;173:20:2;573:226:5;872:138:2;;;:::i;113:26::-;;;;;;1706:189;;;:::i;1306:154::-;1436:11;;1451:2;1436:17;1306:154;;1104:141;726:10;;;;718:51;;;;-1:-1:-1;;;718:51:2;;1006:2:5;718:51:2;;;988:21:5;1045:2;1025:18;;;1018:30;1084;1064:18;;;1057:58;1132:18;;718:51:2;;;;;;;;;1172:11:::1;:21:::0;;;1208:30:::1;::::0;160:25:5;;;1218:10:2::1;::::0;1208:30:::1;::::0;148:2:5;133:18;1208:30:2::1;;;;;;;1104:141:::0;:::o;872:138::-;620:10;;601:15;:29;;593:63;;;;-1:-1:-1;;;593:63:2;;1363:2:5;593:63:2;;;1345:21:5;1402:2;1382:18;;;1375:30;1441:23;1421:18;;;1414:51;1482:18;;593:63:2;1161:345:5;593:63:2;929:10:::1;:17:::0;;-1:-1:-1;;929:17:2::1;942:4;929:17;::::0;;961:42:::1;::::0;975:10:::1;::::0;961:42:::1;::::0;::::1;::::0;987:15:::1;160:25:5::0;;148:2;133:18;;14:177;961:42:2::1;;;;;;;;872:138::o:0;1706:189::-;1757:7;1799:10;;1780:15;:29;1776:68;;-1:-1:-1;1832:1:2;;1706:189::o;1776:68::-;1873:15;1860:10;;:28;;;;:::i;:::-;1853:35;;1706:189;:::o;196:180:5:-;255:6;308:2;296:9;287:7;283:23;279:32;276:52;;;324:1;321;314:12;276:52;-1:-1:-1;347:23:5;;196:180;-1:-1:-1;196:180:5:o;1511:282::-;1578:9;;;1599:11;;;1596:191;;;1643:77;1640:1;1633:88;1744:4;1741:1;1734:15;1772:4;1769:1;1762:15;1596:191;1511:282;;;;:::o","linkReferences":{}},"methodIdentifiers":{"getCurrentTime()":"29cb924d","getTimeRemaining()":"dac6270d","isCompleted()":"fa391c64","isUnlocked()":"8380edb7","owner()":"8da5cb5b","secretValue()":"ccaa0248","setSecret(uint256)":"3b4dbf8b","unlock()":"a69df4b5","unlockTime()":"251c1aa3"},"rawMetadata":"{\"compiler\":{\"version\":\"0.8.19+commit.7dd6d404\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"setter\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"SecretSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"unlocker\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"timestamp\",\"type\":\"uint256\"}],\"name\":\"VaultUnlocked\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"getCurrentTime\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getTimeRemaining\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"isCompleted\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"isUnlocked\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"secretValue\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_secret\",\"type\":\"uint256\"}],\"name\":\"setSecret\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"unlock\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"unlockTime\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"src/levels/TimeVault.sol\":\"TimeVault\"},\"evmVersion\":\"paris\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":1000},\"remappings\":[\":ds-test/=lib/openzeppelin-contracts-upgradeable/lib/forge-std/lib/ds-test/src/\",\":erc4626-tests/=lib/openzeppelin-contracts-upgradeable/lib/erc4626-tests/\",\":forge-std/=lib/forge-std/src/\",\":openzeppelin-contracts-06/=lib/openzeppelin-contracts-06/contracts/\",\":openzeppelin-contracts-08/=lib/openzeppelin-contracts-08/contracts/\",\":openzeppelin-contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/\",\":openzeppelin-upgradeable/=lib/openzeppelin-contracts-upgradeable/contracts/\",\":openzeppelin/=lib/openzeppelin-contracts-upgradeable/contracts/\"]},\"sources\":{\"src/levels/TimeVault.sol\":{\"keccak256\":\"0x1f6e8e0a2781cbae5a675edef10a334150660a860b04c88cccc15272c9a53976\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://61f1a8153400a2f4b3193e03deb67824f3f2e5d7c5685827f3e36ee69e238aca\",\"dweb:/ipfs/QmXvr1pDtpmWBnY47a8Sy5S1ADUPgpujd26tZSoVfeETdJ\"]}},\"version\":1}","metadata":{"compiler":{"version":"0.8.19+commit.7dd6d404"},"language":"Solidity","output":{"abi":[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"address","name":"setter","type":"address","indexed":true},{"internalType":"uint256","name":"value","type":"uint256","indexed":false}],"type":"event","name":"SecretSet","anonymous":false},{"inputs":[{"internalType":"address","name":"unlocker","type":"address","indexed":true},{"internalType":"uint256","name":"timestamp","type":"uint256","indexed":false}],"type":"event","name":"VaultUnlocked","anonymous":false},{"inputs":[],"stateMutability":"view","type":"function","name":"getCurrentTime","outputs":[{"internalType":"uint256","name":"","type":"uint256"}]},{"inputs":[],"stateMutability":"view","type":"function","name":"getTimeRemaining","outputs":[{"internalType":"uint256","name":"","type":"uint256"}]},{"inputs":[],"stateMutability":"view","type":"function","name":"isCompleted","outputs":[{"internalType":"bool","name":"","type":"bool"}]},{"inputs":[],"stateMutability":"view","type":"function","name":"isUnlocked","outputs":[{"internalType":"bool","name":"","type":"bool"}]},{"inputs":[],"stateMutability":"view","type":"function","name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}]},{"inputs":[],"stateMutability":"view","type":"function","name":"secretValue","outputs":[{"internalType":"uint256","name":"","type":"uint256"}]},{"inputs":[{"internalType":"uint256","name":"_secret","type":"uint256"}],"stateMutability":"nonpayable","type":"function","name":"setSecret"},{"inputs":[],"stateMutability":"nonpayable","type":"function","name":"unlock"},{"inputs":[],"stateMutability":"view","type":"function","name":"unlockTime","outputs":[{"internalType":"uint256","name":"","type":"uint256"}]}],"devdoc":{"kind":"dev","methods":{},"version":1},"userdoc":{"kind":"user","methods":{},"version":1}},"settings":{"remappings":["ds-test/=lib/openzeppelin-contracts-upgradeable/lib/forge-std/lib/ds-test/src/","erc4626-tests/=lib/openzeppelin-contracts-upgradeable/lib/erc4626-tests/","forge-std/=lib/forge-std/src/","openzeppelin-contracts-06/=lib/openzeppelin-contracts-06/contracts/","openzeppelin-contracts-08/=lib/openzeppelin-contracts-08/contracts/","openzeppelin-contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/","openzeppelin-upgradeable/=lib/openzeppelin-contracts-upgradeable/contracts/","openzeppelin/=lib/openzeppelin-contracts-upgradeable/contracts/"],"optimizer":{"enabled":true,"runs":1000},"metadata":{"bytecodeHash":"ipfs"},"compilationTarget":{"src/levels/TimeVault.sol":"TimeVault"},"evmVersion":"paris","libraries":{}},"sources":{"src/levels/TimeVault.sol":{"keccak256":"0x1f6e8e0a2781cbae5a675edef10a334150660a860b04c88cccc15272c9a53976","urls":["bzz-raw://61f1a8153400a2f4b3193e03deb67824f3f2e5d7c5685827f3e36ee69e238aca","dweb:/ipfs/QmXvr1pDtpmWBnY47a8Sy5S1ADUPgpujd26tZSoVfeETdJ"],"license":"MIT"}},"version":1},"id":2}
\ No newline at end of file
diff --git a/contracts/out/TimeVaultFactory.sol/TimeVaultFactory.json b/contracts/out/TimeVaultFactory.sol/TimeVaultFactory.json
new file mode 100644
index 000000000..0f8d3906f
--- /dev/null
+++ b/contracts/out/TimeVaultFactory.sol/TimeVaultFactory.json
@@ -0,0 +1 @@
+{"abi":[{"type":"function","name":"createInstance","inputs":[{"name":"_player","type":"address","internalType":"address"}],"outputs":[{"name":"","type":"address","internalType":"address"}],"stateMutability":"payable"},{"type":"function","name":"owner","inputs":[],"outputs":[{"name":"","type":"address","internalType":"address"}],"stateMutability":"view"},{"type":"function","name":"renounceOwnership","inputs":[],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"transferOwnership","inputs":[{"name":"newOwner","type":"address","internalType":"address"}],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"validateInstance","inputs":[{"name":"_instance","type":"address","internalType":"address payable"},{"name":"","type":"address","internalType":"address"}],"outputs":[{"name":"","type":"bool","internalType":"bool"}],"stateMutability":"view"},{"type":"event","name":"OwnershipTransferred","inputs":[{"name":"previousOwner","type":"address","indexed":true,"internalType":"address"},{"name":"newOwner","type":"address","indexed":true,"internalType":"address"}],"anonymous":false}],"bytecode":{"object":"0x608060405234801561001057600080fd5b5061001a3361001f565b61006f565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b6107c78061007e6000396000f3fe60806040526004361061005a5760003560e01c80638da5cb5b116100435780638da5cb5b146100a6578063d38def5b146100c4578063f2fde38b146100f457600080fd5b8063715018a61461005f5780637726f77614610076575b600080fd5b34801561006b57600080fd5b50610074610114565b005b610089610084366004610344565b610128565b6040516001600160a01b0390911681526020015b60405180910390f35b3480156100b257600080fd5b506000546001600160a01b0316610089565b3480156100d057600080fd5b506100e46100df366004610368565b61015b565b604051901515815260200161009d565b34801561010057600080fd5b5061007461010f366004610344565b6101cb565b61011c610260565b61012660006102ba565b565b60008060405161013790610322565b604051809103906000f080158015610153573d6000803e3d6000fd5b509392505050565b600080839050806001600160a01b031663fa391c646040518163ffffffff1660e01b8152600401602060405180830381865afa15801561019f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906101c391906103a1565b949350505050565b6101d3610260565b6001600160a01b0381166102545760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f646472657373000000000000000000000000000000000000000000000000000060648201526084015b60405180910390fd5b61025d816102ba565b50565b6000546001600160a01b031633146101265760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015260640161024b565b600080546001600160a01b038381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b6103ce806103c483390190565b6001600160a01b038116811461025d57600080fd5b60006020828403121561035657600080fd5b81356103618161032f565b9392505050565b6000806040838503121561037b57600080fd5b82356103868161032f565b915060208301356103968161032f565b809150509250929050565b6000602082840312156103b357600080fd5b8151801515811461036157600080fdfe608060405234801561001057600080fd5b5060028054610100600160a81b031916336101000217905561003442610e1061004b565b60009081556002805460ff19169055600155610072565b8082018082111561006c57634e487b7160e01b600052601160045260246000fd5b92915050565b61034d806100816000396000f3fe608060405234801561001057600080fd5b50600436106100a35760003560e01c80638da5cb5b11610076578063ccaa02481161005b578063ccaa02481461014e578063dac6270d14610157578063fa391c641461015f57600080fd5b80638da5cb5b146100fc578063a69df4b51461014657600080fd5b8063251c1aa3146100a857806329cb924d146100c45780633b4dbf8b146100ca5780638380edb7146100df575b600080fd5b6100b160005481565b6040519081526020015b60405180910390f35b426100b1565b6100dd6100d83660046102be565b61016a565b005b6002546100ec9060ff1681565b60405190151581526020016100bb565b60025461012190610100900473ffffffffffffffffffffffffffffffffffffffff1681565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016100bb565b6100dd6101fe565b6100b160015481565b6100b161029b565b600154602a146100ec565b60025460ff166101c15760405162461bcd60e51b815260206004820152601c60248201527f5661756c74206d75737420626520756e6c6f636b65642066697273740000000060448201526064015b60405180910390fd5b600181905560405181815233907fd07fa57b9c72461d5676947bbfbf63a9d3091f9ef047e999a34b39dd5f6df93a9060200160405180910390a250565b6000544210156102505760405162461bcd60e51b815260206004820152601560248201527f5661756c74206973207374696c6c206c6f636b6564000000000000000000000060448201526064016101b8565b6002805460ff1916600117905560405133907f58f708cb331f8b003aab2818910d14f42d171878a3e31abb65877606ac28b2d9906102919042815260200190565b60405180910390a2565b6000805442106102ab5750600090565b426000546102b991906102d7565b905090565b6000602082840312156102d057600080fd5b5035919050565b81810381811115610311577f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b9291505056fea26469706673582212203f804dd5a2e500892d1e532207b8490fa04dc611b5cd18ec6da7806eff82f4fe64736f6c63430008130033a2646970667358221220c775f4ea65fef31ff53ca65831bda3407ad65896a1239b486e6a20fb9b3b1b2a64736f6c63430008130033","sourceMap":"111:748:3:-:0;;;;;;;;;;;;-1:-1:-1;936:32:0;719:10:1;936:18:0;:32::i;:::-;111:748:3;;2433:187:0;2506:16;2525:6;;-1:-1:-1;;;;;2541:17:0;;;-1:-1:-1;;;;;;2541:17:0;;;;;;2573:40;;2525:6;;;;;;;2573:40;;2506:16;2573:40;2496:124;2433:187;:::o;111:748:3:-;;;;;;;","linkReferences":{}},"deployedBytecode":{"object":"0x60806040526004361061005a5760003560e01c80638da5cb5b116100435780638da5cb5b146100a6578063d38def5b146100c4578063f2fde38b146100f457600080fd5b8063715018a61461005f5780637726f77614610076575b600080fd5b34801561006b57600080fd5b50610074610114565b005b610089610084366004610344565b610128565b6040516001600160a01b0390911681526020015b60405180910390f35b3480156100b257600080fd5b506000546001600160a01b0316610089565b3480156100d057600080fd5b506100e46100df366004610368565b61015b565b604051901515815260200161009d565b34801561010057600080fd5b5061007461010f366004610344565b6101cb565b61011c610260565b61012660006102ba565b565b60008060405161013790610322565b604051809103906000f080158015610153573d6000803e3d6000fd5b509392505050565b600080839050806001600160a01b031663fa391c646040518163ffffffff1660e01b8152600401602060405180830381865afa15801561019f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906101c391906103a1565b949350505050565b6101d3610260565b6001600160a01b0381166102545760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f646472657373000000000000000000000000000000000000000000000000000060648201526084015b60405180910390fd5b61025d816102ba565b50565b6000546001600160a01b031633146101265760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015260640161024b565b600080546001600160a01b038381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b6103ce806103c483390190565b6001600160a01b038116811461025d57600080fd5b60006020828403121561035657600080fd5b81356103618161032f565b9392505050565b6000806040838503121561037b57600080fd5b82356103868161032f565b915060208301356103968161032f565b809150509250929050565b6000602082840312156103b357600080fd5b8151801515811461036157600080fdfe608060405234801561001057600080fd5b5060028054610100600160a81b031916336101000217905561003442610e1061004b565b60009081556002805460ff19169055600155610072565b8082018082111561006c57634e487b7160e01b600052601160045260246000fd5b92915050565b61034d806100816000396000f3fe608060405234801561001057600080fd5b50600436106100a35760003560e01c80638da5cb5b11610076578063ccaa02481161005b578063ccaa02481461014e578063dac6270d14610157578063fa391c641461015f57600080fd5b80638da5cb5b146100fc578063a69df4b51461014657600080fd5b8063251c1aa3146100a857806329cb924d146100c45780633b4dbf8b146100ca5780638380edb7146100df575b600080fd5b6100b160005481565b6040519081526020015b60405180910390f35b426100b1565b6100dd6100d83660046102be565b61016a565b005b6002546100ec9060ff1681565b60405190151581526020016100bb565b60025461012190610100900473ffffffffffffffffffffffffffffffffffffffff1681565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016100bb565b6100dd6101fe565b6100b160015481565b6100b161029b565b600154602a146100ec565b60025460ff166101c15760405162461bcd60e51b815260206004820152601c60248201527f5661756c74206d75737420626520756e6c6f636b65642066697273740000000060448201526064015b60405180910390fd5b600181905560405181815233907fd07fa57b9c72461d5676947bbfbf63a9d3091f9ef047e999a34b39dd5f6df93a9060200160405180910390a250565b6000544210156102505760405162461bcd60e51b815260206004820152601560248201527f5661756c74206973207374696c6c206c6f636b6564000000000000000000000060448201526064016101b8565b6002805460ff1916600117905560405133907f58f708cb331f8b003aab2818910d14f42d171878a3e31abb65877606ac28b2d9906102919042815260200190565b60405180910390a2565b6000805442106102ab5750600090565b426000546102b991906102d7565b905090565b6000602082840312156102d057600080fd5b5035919050565b81810381811115610311577f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b9291505056fea26469706673582212203f804dd5a2e500892d1e532207b8490fa04dc611b5cd18ec6da7806eff82f4fe64736f6c63430008130033a2646970667358221220c775f4ea65fef31ff53ca65831bda3407ad65896a1239b486e6a20fb9b3b1b2a64736f6c63430008130033","sourceMap":"111:748:3:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;1831:101:0;;;;;;;;;;;;;:::i;:::-;;152:294:3;;;;;;:::i;:::-;;:::i;:::-;;;-1:-1:-1;;;;;589:55:5;;;571:74;;559:2;544:18;152:294:3;;;;;;;;1201:85:0;;;;;;;;;;-1:-1:-1;1247:7:0;1273:6;-1:-1:-1;;;;;1273:6:0;1201:85;;452:405:3;;;;;;;;;;-1:-1:-1;452:405:3;;;;;:::i;:::-;;:::i;:::-;;;1222:14:5;;1215:22;1197:41;;1185:2;1170:18;452:405:3;1057:187:5;2081:198:0;;;;;;;;;;-1:-1:-1;2081:198:0;;;;;:::i;:::-;;:::i;1831:101::-;1094:13;:11;:13::i;:::-;1895:30:::1;1922:1;1895:18;:30::i;:::-;1831:101::o:0;152:294:3:-;226:7;360:18;381:15;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;360:36:3;152:294;-1:-1:-1;;;152:294:3:o;452:405::-;558:4;637:18;668:9;637:41;;828:8;-1:-1:-1;;;;;828:20:3;;:22;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;821:29;452:405;-1:-1:-1;;;;452:405:3:o;2081:198:0:-;1094:13;:11;:13::i;:::-;-1:-1:-1;;;;;2169:22:0;::::1;2161:73;;;::::0;-1:-1:-1;;;2161:73:0;;1733:2:5;2161:73:0::1;::::0;::::1;1715:21:5::0;1772:2;1752:18;;;1745:30;1811:34;1791:18;;;1784:62;1882:8;1862:18;;;1855:36;1908:19;;2161:73:0::1;;;;;;;;;2244:28;2263:8;2244:18;:28::i;:::-;2081:198:::0;:::o;1359:130::-;1247:7;1273:6;-1:-1:-1;;;;;1273:6:0;719:10:1;1422:23:0;1414:68;;;;-1:-1:-1;;;1414:68:0;;2140:2:5;1414:68:0;;;2122:21:5;;;2159:18;;;2152:30;2218:34;2198:18;;;2191:62;2270:18;;1414:68:0;1938:356:5;2433:187:0;2506:16;2525:6;;-1:-1:-1;;;;;2541:17:0;;;;;;;;;;2573:40;;2525:6;;;;;;;2573:40;;2506:16;2573:40;2496:124;2433:187;:::o;-1:-1:-1:-;;;;;;;;:::o;14:154:5:-;-1:-1:-1;;;;;93:5:5;89:54;82:5;79:65;69:93;;158:1;155;148:12;173:247;232:6;285:2;273:9;264:7;260:23;256:32;253:52;;;301:1;298;291:12;253:52;340:9;327:23;359:31;384:5;359:31;:::i;:::-;409:5;173:247;-1:-1:-1;;;173:247:5:o;656:396::-;732:6;740;793:2;781:9;772:7;768:23;764:32;761:52;;;809:1;806;799:12;761:52;848:9;835:23;867:31;892:5;867:31;:::i;:::-;917:5;-1:-1:-1;974:2:5;959:18;;946:32;987:33;946:32;987:33;:::i;:::-;1039:7;1029:17;;;656:396;;;;;:::o;1249:277::-;1316:6;1369:2;1357:9;1348:7;1344:23;1340:32;1337:52;;;1385:1;1382;1375:12;1337:52;1417:9;1411:16;1470:5;1463:13;1456:21;1449:5;1446:32;1436:60;;1492:1;1489;1482:12","linkReferences":{}},"methodIdentifiers":{"createInstance(address)":"7726f776","owner()":"8da5cb5b","renounceOwnership()":"715018a6","transferOwnership(address)":"f2fde38b","validateInstance(address,address)":"d38def5b"},"rawMetadata":"{\"compiler\":{\"version\":\"0.8.19+commit.7dd6d404\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"previousOwner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_player\",\"type\":\"address\"}],\"name\":\"createInstance\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"renounceOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address payable\",\"name\":\"_instance\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"validateInstance\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{\"owner()\":{\"details\":\"Returns the address of the current owner.\"},\"renounceOwnership()\":{\"details\":\"Leaves the contract without owner. It will not be possible to call `onlyOwner` functions anymore. Can only be called by the current owner. NOTE: Renouncing ownership will leave the contract without an owner, thereby removing any functionality that is only available to the owner.\"},\"transferOwnership(address)\":{\"details\":\"Transfers ownership of the contract to a new account (`newOwner`). Can only be called by the current owner.\"}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"src/levels/TimeVaultFactory.sol\":\"TimeVaultFactory\"},\"evmVersion\":\"paris\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":1000},\"remappings\":[\":ds-test/=lib/openzeppelin-contracts-upgradeable/lib/forge-std/lib/ds-test/src/\",\":erc4626-tests/=lib/openzeppelin-contracts-upgradeable/lib/erc4626-tests/\",\":forge-std/=lib/forge-std/src/\",\":openzeppelin-contracts-06/=lib/openzeppelin-contracts-06/contracts/\",\":openzeppelin-contracts-08/=lib/openzeppelin-contracts-08/contracts/\",\":openzeppelin-contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/\",\":openzeppelin-upgradeable/=lib/openzeppelin-contracts-upgradeable/contracts/\",\":openzeppelin/=lib/openzeppelin-contracts-upgradeable/contracts/\"]},\"sources\":{\"lib/openzeppelin-contracts-08/contracts/access/Ownable.sol\":{\"keccak256\":\"0xa94b34880e3c1b0b931662cb1c09e5dfa6662f31cba80e07c5ee71cd135c9673\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://40fb1b5102468f783961d0af743f91b9980cf66b50d1d12009f6bb1869cea4d2\",\"dweb:/ipfs/QmYqEbJML4jB1GHbzD4cUZDtJg5wVwNm3vDJq1GbyDus8y\"]},\"lib/openzeppelin-contracts-08/contracts/utils/Context.sol\":{\"keccak256\":\"0xe2e337e6dde9ef6b680e07338c493ebea1b5fd09b43424112868e9cc1706bca7\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://6df0ddf21ce9f58271bdfaa85cde98b200ef242a05a3f85c2bc10a8294800a92\",\"dweb:/ipfs/QmRK2Y5Yc6BK7tGKkgsgn3aJEQGi5aakeSPZvS65PV8Xp3\"]},\"src/levels/TimeVault.sol\":{\"keccak256\":\"0x1f6e8e0a2781cbae5a675edef10a334150660a860b04c88cccc15272c9a53976\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://61f1a8153400a2f4b3193e03deb67824f3f2e5d7c5685827f3e36ee69e238aca\",\"dweb:/ipfs/QmXvr1pDtpmWBnY47a8Sy5S1ADUPgpujd26tZSoVfeETdJ\"]},\"src/levels/TimeVaultFactory.sol\":{\"keccak256\":\"0xce4f8d06d48181d48812ee6050194b5bf42c10eae2c8459bd213bee8fcf7b97d\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://7b714a63b3c6a6ee5bedb623878f97f25de1f5af22f68db4febb5ca108d58d1b\",\"dweb:/ipfs/QmQTgmf3vZkpwQt5snKByYhRUp6zsTwYUcVtHpSr5RvKne\"]},\"src/levels/base/Level.sol\":{\"keccak256\":\"0x23e8a2c9454707c888fc4dc4cc44d89e5928e8d58a1f9c8f5c16c36697aadfdf\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://693402ec163e362b086874db09be2d1d11111276f70100bf9192a0fb3f5d9ccd\",\"dweb:/ipfs/QmSsygUUkJHRh13rGUQ4BrMTnzmPQKrRsBABS4Yk11kfAA\"]}},\"version\":1}","metadata":{"compiler":{"version":"0.8.19+commit.7dd6d404"},"language":"Solidity","output":{"abi":[{"inputs":[{"internalType":"address","name":"previousOwner","type":"address","indexed":true},{"internalType":"address","name":"newOwner","type":"address","indexed":true}],"type":"event","name":"OwnershipTransferred","anonymous":false},{"inputs":[{"internalType":"address","name":"_player","type":"address"}],"stateMutability":"payable","type":"function","name":"createInstance","outputs":[{"internalType":"address","name":"","type":"address"}]},{"inputs":[],"stateMutability":"view","type":"function","name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}]},{"inputs":[],"stateMutability":"nonpayable","type":"function","name":"renounceOwnership"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"stateMutability":"nonpayable","type":"function","name":"transferOwnership"},{"inputs":[{"internalType":"address payable","name":"_instance","type":"address"},{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function","name":"validateInstance","outputs":[{"internalType":"bool","name":"","type":"bool"}]}],"devdoc":{"kind":"dev","methods":{"owner()":{"details":"Returns the address of the current owner."},"renounceOwnership()":{"details":"Leaves the contract without owner. It will not be possible to call `onlyOwner` functions anymore. Can only be called by the current owner. NOTE: Renouncing ownership will leave the contract without an owner, thereby removing any functionality that is only available to the owner."},"transferOwnership(address)":{"details":"Transfers ownership of the contract to a new account (`newOwner`). Can only be called by the current owner."}},"version":1},"userdoc":{"kind":"user","methods":{},"version":1}},"settings":{"remappings":["ds-test/=lib/openzeppelin-contracts-upgradeable/lib/forge-std/lib/ds-test/src/","erc4626-tests/=lib/openzeppelin-contracts-upgradeable/lib/erc4626-tests/","forge-std/=lib/forge-std/src/","openzeppelin-contracts-06/=lib/openzeppelin-contracts-06/contracts/","openzeppelin-contracts-08/=lib/openzeppelin-contracts-08/contracts/","openzeppelin-contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/","openzeppelin-upgradeable/=lib/openzeppelin-contracts-upgradeable/contracts/","openzeppelin/=lib/openzeppelin-contracts-upgradeable/contracts/"],"optimizer":{"enabled":true,"runs":1000},"metadata":{"bytecodeHash":"ipfs"},"compilationTarget":{"src/levels/TimeVaultFactory.sol":"TimeVaultFactory"},"evmVersion":"paris","libraries":{}},"sources":{"lib/openzeppelin-contracts-08/contracts/access/Ownable.sol":{"keccak256":"0xa94b34880e3c1b0b931662cb1c09e5dfa6662f31cba80e07c5ee71cd135c9673","urls":["bzz-raw://40fb1b5102468f783961d0af743f91b9980cf66b50d1d12009f6bb1869cea4d2","dweb:/ipfs/QmYqEbJML4jB1GHbzD4cUZDtJg5wVwNm3vDJq1GbyDus8y"],"license":"MIT"},"lib/openzeppelin-contracts-08/contracts/utils/Context.sol":{"keccak256":"0xe2e337e6dde9ef6b680e07338c493ebea1b5fd09b43424112868e9cc1706bca7","urls":["bzz-raw://6df0ddf21ce9f58271bdfaa85cde98b200ef242a05a3f85c2bc10a8294800a92","dweb:/ipfs/QmRK2Y5Yc6BK7tGKkgsgn3aJEQGi5aakeSPZvS65PV8Xp3"],"license":"MIT"},"src/levels/TimeVault.sol":{"keccak256":"0x1f6e8e0a2781cbae5a675edef10a334150660a860b04c88cccc15272c9a53976","urls":["bzz-raw://61f1a8153400a2f4b3193e03deb67824f3f2e5d7c5685827f3e36ee69e238aca","dweb:/ipfs/QmXvr1pDtpmWBnY47a8Sy5S1ADUPgpujd26tZSoVfeETdJ"],"license":"MIT"},"src/levels/TimeVaultFactory.sol":{"keccak256":"0xce4f8d06d48181d48812ee6050194b5bf42c10eae2c8459bd213bee8fcf7b97d","urls":["bzz-raw://7b714a63b3c6a6ee5bedb623878f97f25de1f5af22f68db4febb5ca108d58d1b","dweb:/ipfs/QmQTgmf3vZkpwQt5snKByYhRUp6zsTwYUcVtHpSr5RvKne"],"license":"MIT"},"src/levels/base/Level.sol":{"keccak256":"0x23e8a2c9454707c888fc4dc4cc44d89e5928e8d58a1f9c8f5c16c36697aadfdf","urls":["bzz-raw://693402ec163e362b086874db09be2d1d11111276f70100bf9192a0fb3f5d9ccd","dweb:/ipfs/QmSsygUUkJHRh13rGUQ4BrMTnzmPQKrRsBABS4Yk11kfAA"],"license":"MIT"}},"version":1},"id":3}
\ No newline at end of file
diff --git a/contracts/out/test_timevault.sol/TimeVaultTestRunner.json b/contracts/out/test_timevault.sol/TimeVaultTestRunner.json
new file mode 100644
index 000000000..af4827404
--- /dev/null
+++ b/contracts/out/test_timevault.sol/TimeVaultTestRunner.json
@@ -0,0 +1 @@
+{"abi":[{"type":"constructor","inputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"testCreateInstance","inputs":[],"outputs":[{"name":"","type":"bool","internalType":"bool"}],"stateMutability":"nonpayable"},{"type":"function","name":"testSolveLevel","inputs":[],"outputs":[{"name":"","type":"bool","internalType":"bool"}],"stateMutability":"nonpayable"},{"type":"function","name":"testValidation","inputs":[],"outputs":[{"name":"","type":"bool","internalType":"bool"}],"stateMutability":"nonpayable"}],"bytecode":{"object":"0x608060405234801561001057600080fd5b5060405161001d9061005f565b604051809103906000f080158015610039573d6000803e3d6000fd5b50600080546001600160a01b0319166001600160a01b039290921691909117905561006c565b610845806108b183390190565b6108368061007b6000396000f3fe608060405234801561001057600080fd5b50600436106100415760003560e01c80634151c179146100465780638a66255914610062578063cbe8047e1461006a575b600080fd5b61004e610072565b604051901515815260200160405180910390f35b61004e610470565b61004e61064a565b60008054604051633b937bbb60e11b815230600482015282916001600160a01b031690637726f776906024016020604051808303816000875af11580156100bd573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906100e19190610795565b600180547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b038316908117909155604080517f8380edb700000000000000000000000000000000000000000000000000000000815290519293509091638380edb7916004808201926020929091908290030181865afa158015610170573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061019491906107c5565b156101e65760405162461bcd60e51b815260206004820181905260248201527f5661756c742073686f756c64206265206c6f636b656420696e697469616c6c7960448201526064015b60405180910390fd5b600160009054906101000a90046001600160a01b03166001600160a01b031663ccaa02486040518163ffffffff1660e01b8152600401602060405180830381865afa158015610239573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061025d91906107e7565b156102aa5760405162461bcd60e51b815260206004820152601c60248201527f5365637265742073686f756c64206265203020696e697469616c6c790000000060448201526064016101dd565b600160009054906101000a90046001600160a01b03166001600160a01b031663fa391c646040518163ffffffff1660e01b8152600401602060405180830381865afa1580156102fd573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061032191906107c5565b156103945760405162461bcd60e51b815260206004820152602760248201527f4c6576656c2073686f756c64206e6f7420626520636f6d706c6574656420696e60448201527f697469616c6c790000000000000000000000000000000000000000000000000060648201526084016101dd565b600154604080517fdac6270d00000000000000000000000000000000000000000000000000000000815290516000926001600160a01b03169163dac6270d9160048083019260209291908290030181865afa1580156103f7573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061041b91906107e7565b116104685760405162461bcd60e51b815260206004820152601a60248201527f53686f756c6420686176652072656d61696e696e672074696d6500000000000060448201526064016101dd565b600191505090565b6001546000906001600160a01b031661048d5761048b610072565b505b600160009054906101000a90046001600160a01b03166001600160a01b031663a69df4b56040518163ffffffff1660e01b8152600401600060405180830381600087803b1580156104dd57600080fd5b505af19250505080156104ee575060015b156105615760405162461bcd60e51b815260206004820152602860248201527f53686f756c64206e6f742062652061626c6520746f20756e6c6f636b2062656660448201527f6f72652074696d6500000000000000000000000000000000000000000000000060648201526084016101dd565b6001546040517f3b4dbf8b000000000000000000000000000000000000000000000000000000008152602a60048201526001600160a01b0390911690633b4dbf8b90602401600060405180830381600087803b1580156105c057600080fd5b505af19250505080156105d1575060015b156106445760405162461bcd60e51b815260206004820152602d60248201527f53686f756c64206e6f742062652061626c6520746f207365742073656372657460448201527f207768696c65206c6f636b65640000000000000000000000000000000000000060648201526084016101dd565b50600190565b60008054604051633b937bbb60e11b815230600482015282916001600160a01b031690637726f776906024016020604051808303816000875af1158015610695573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106b99190610795565b6000546040517fd38def5b0000000000000000000000000000000000000000000000000000000081526001600160a01b03808416600483015230602483015292935091169063d38def5b90604401602060405180830381865afa158015610724573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061074891906107c5565b156104685760405162461bcd60e51b815260206004820152601d60248201527f53686f756c64206e6f742076616c696461746520696e697469616c6c7900000060448201526064016101dd565b6000602082840312156107a757600080fd5b81516001600160a01b03811681146107be57600080fd5b9392505050565b6000602082840312156107d757600080fd5b815180151581146107be57600080fd5b6000602082840312156107f957600080fd5b505191905056fea2646970667358221220b4be5edb8bf8894c6395033daaa298534d2074302d047e9fce989a54e80699ea64736f6c63430008130033608060405234801561001057600080fd5b5061001a3361001f565b61006f565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b6107c78061007e6000396000f3fe60806040526004361061005a5760003560e01c80638da5cb5b116100435780638da5cb5b146100a6578063d38def5b146100c4578063f2fde38b146100f457600080fd5b8063715018a61461005f5780637726f77614610076575b600080fd5b34801561006b57600080fd5b50610074610114565b005b610089610084366004610344565b610128565b6040516001600160a01b0390911681526020015b60405180910390f35b3480156100b257600080fd5b506000546001600160a01b0316610089565b3480156100d057600080fd5b506100e46100df366004610368565b61015b565b604051901515815260200161009d565b34801561010057600080fd5b5061007461010f366004610344565b6101cb565b61011c610260565b61012660006102ba565b565b60008060405161013790610322565b604051809103906000f080158015610153573d6000803e3d6000fd5b509392505050565b600080839050806001600160a01b031663fa391c646040518163ffffffff1660e01b8152600401602060405180830381865afa15801561019f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906101c391906103a1565b949350505050565b6101d3610260565b6001600160a01b0381166102545760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f646472657373000000000000000000000000000000000000000000000000000060648201526084015b60405180910390fd5b61025d816102ba565b50565b6000546001600160a01b031633146101265760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015260640161024b565b600080546001600160a01b038381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b6103ce806103c483390190565b6001600160a01b038116811461025d57600080fd5b60006020828403121561035657600080fd5b81356103618161032f565b9392505050565b6000806040838503121561037b57600080fd5b82356103868161032f565b915060208301356103968161032f565b809150509250929050565b6000602082840312156103b357600080fd5b8151801515811461036157600080fdfe608060405234801561001057600080fd5b5060028054610100600160a81b031916336101000217905561003442610e1061004b565b60009081556002805460ff19169055600155610072565b8082018082111561006c57634e487b7160e01b600052601160045260246000fd5b92915050565b61034d806100816000396000f3fe608060405234801561001057600080fd5b50600436106100a35760003560e01c80638da5cb5b11610076578063ccaa02481161005b578063ccaa02481461014e578063dac6270d14610157578063fa391c641461015f57600080fd5b80638da5cb5b146100fc578063a69df4b51461014657600080fd5b8063251c1aa3146100a857806329cb924d146100c45780633b4dbf8b146100ca5780638380edb7146100df575b600080fd5b6100b160005481565b6040519081526020015b60405180910390f35b426100b1565b6100dd6100d83660046102be565b61016a565b005b6002546100ec9060ff1681565b60405190151581526020016100bb565b60025461012190610100900473ffffffffffffffffffffffffffffffffffffffff1681565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016100bb565b6100dd6101fe565b6100b160015481565b6100b161029b565b600154602a146100ec565b60025460ff166101c15760405162461bcd60e51b815260206004820152601c60248201527f5661756c74206d75737420626520756e6c6f636b65642066697273740000000060448201526064015b60405180910390fd5b600181905560405181815233907fd07fa57b9c72461d5676947bbfbf63a9d3091f9ef047e999a34b39dd5f6df93a9060200160405180910390a250565b6000544210156102505760405162461bcd60e51b815260206004820152601560248201527f5661756c74206973207374696c6c206c6f636b6564000000000000000000000060448201526064016101b8565b6002805460ff1916600117905560405133907f58f708cb331f8b003aab2818910d14f42d171878a3e31abb65877606ac28b2d9906102919042815260200190565b60405180910390a2565b6000805442106102ab5750600090565b426000546102b991906102d7565b905090565b6000602082840312156102d057600080fd5b5035919050565b81810381811115610311577f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b9291505056fea26469706673582212203f804dd5a2e500892d1e532207b8490fa04dc611b5cd18ec6da7806eff82f4fe64736f6c63430008130033a2646970667358221220c775f4ea65fef31ff53ca65831bda3407ad65896a1239b486e6a20fb9b3b1b2a64736f6c63430008130033","sourceMap":"197:1862:5:-:0;;;288:63;;;;;;;;;;322:22;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;312:7:5;:32;;-1:-1:-1;;;;;;312:32:5;-1:-1:-1;;;;;312:32:5;;;;;;;;;;197:1862;;;;;;;;;;:::o;:::-;;;;;;;","linkReferences":{}},"deployedBytecode":{"object":"0x608060405234801561001057600080fd5b50600436106100415760003560e01c80634151c179146100465780638a66255914610062578063cbe8047e1461006a575b600080fd5b61004e610072565b604051901515815260200160405180910390f35b61004e610470565b61004e61064a565b60008054604051633b937bbb60e11b815230600482015282916001600160a01b031690637726f776906024016020604051808303816000875af11580156100bd573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906100e19190610795565b600180547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b038316908117909155604080517f8380edb700000000000000000000000000000000000000000000000000000000815290519293509091638380edb7916004808201926020929091908290030181865afa158015610170573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061019491906107c5565b156101e65760405162461bcd60e51b815260206004820181905260248201527f5661756c742073686f756c64206265206c6f636b656420696e697469616c6c7960448201526064015b60405180910390fd5b600160009054906101000a90046001600160a01b03166001600160a01b031663ccaa02486040518163ffffffff1660e01b8152600401602060405180830381865afa158015610239573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061025d91906107e7565b156102aa5760405162461bcd60e51b815260206004820152601c60248201527f5365637265742073686f756c64206265203020696e697469616c6c790000000060448201526064016101dd565b600160009054906101000a90046001600160a01b03166001600160a01b031663fa391c646040518163ffffffff1660e01b8152600401602060405180830381865afa1580156102fd573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061032191906107c5565b156103945760405162461bcd60e51b815260206004820152602760248201527f4c6576656c2073686f756c64206e6f7420626520636f6d706c6574656420696e60448201527f697469616c6c790000000000000000000000000000000000000000000000000060648201526084016101dd565b600154604080517fdac6270d00000000000000000000000000000000000000000000000000000000815290516000926001600160a01b03169163dac6270d9160048083019260209291908290030181865afa1580156103f7573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061041b91906107e7565b116104685760405162461bcd60e51b815260206004820152601a60248201527f53686f756c6420686176652072656d61696e696e672074696d6500000000000060448201526064016101dd565b600191505090565b6001546000906001600160a01b031661048d5761048b610072565b505b600160009054906101000a90046001600160a01b03166001600160a01b031663a69df4b56040518163ffffffff1660e01b8152600401600060405180830381600087803b1580156104dd57600080fd5b505af19250505080156104ee575060015b156105615760405162461bcd60e51b815260206004820152602860248201527f53686f756c64206e6f742062652061626c6520746f20756e6c6f636b2062656660448201527f6f72652074696d6500000000000000000000000000000000000000000000000060648201526084016101dd565b6001546040517f3b4dbf8b000000000000000000000000000000000000000000000000000000008152602a60048201526001600160a01b0390911690633b4dbf8b90602401600060405180830381600087803b1580156105c057600080fd5b505af19250505080156105d1575060015b156106445760405162461bcd60e51b815260206004820152602d60248201527f53686f756c64206e6f742062652061626c6520746f207365742073656372657460448201527f207768696c65206c6f636b65640000000000000000000000000000000000000060648201526084016101dd565b50600190565b60008054604051633b937bbb60e11b815230600482015282916001600160a01b031690637726f776906024016020604051808303816000875af1158015610695573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106b99190610795565b6000546040517fd38def5b0000000000000000000000000000000000000000000000000000000081526001600160a01b03808416600483015230602483015292935091169063d38def5b90604401602060405180830381865afa158015610724573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061074891906107c5565b156104685760405162461bcd60e51b815260206004820152601d60248201527f53686f756c64206e6f742076616c696461746520696e697469616c6c7900000060448201526064016101dd565b6000602082840312156107a757600080fd5b81516001600160a01b03811681146107be57600080fd5b9392505050565b6000602082840312156107d757600080fd5b815180151581146107be57600080fd5b6000602082840312156107f957600080fd5b505191905056fea2646970667358221220b4be5edb8bf8894c6395033daaa298534d2074302d047e9fce989a54e80699ea64736f6c63430008130033","sourceMap":"197:1862:5:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;361:540;;;:::i;:::-;;;179:14:6;;172:22;154:41;;142:2;127:18;361:540:5;;;;;;;911:789;;;:::i;1710:347::-;;;:::i;361:540::-;407:4;442:7;;:37;;-1:-1:-1;;;442:37:5;;473:4;442:37;;;352:74:6;407:4:5;;-1:-1:-1;;;;;442:7:5;;:22;;325:18:6;;442:37:5;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;489:5;:27;;;;-1:-1:-1;;;;;489:27:5;;;;;;;;575:18;;;;;;;;489:27;;-1:-1:-1;489:27:5;;575:16;;:18;;;;;;;;;;;;;;;489:27;575:18;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;574:19;566:64;;;;-1:-1:-1;;;566:64:5;;1239:2:6;566:64:5;;;1221:21:6;;;1258:18;;;1251:30;1317:34;1297:18;;;1290:62;1369:18;;566:64:5;;;;;;;;;648:5;;;;;;;;;-1:-1:-1;;;;;648:5:5;-1:-1:-1;;;;;648:17:5;;:19;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;:24;640:65;;;;-1:-1:-1;;;640:65:5;;1789:2:6;640:65:5;;;1771:21:6;1828:2;1808:18;;;1801:30;1867;1847:18;;;1840:58;1915:18;;640:65:5;1587:352:6;640:65:5;724:5;;;;;;;;;-1:-1:-1;;;;;724:5:5;-1:-1:-1;;;;;724:17:5;;:19;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;723:20;715:72;;;;-1:-1:-1;;;715:72:5;;2146:2:6;715:72:5;;;2128:21:6;2185:2;2165:18;;;2158:30;2224:34;2204:18;;;2197:62;2295:9;2275:18;;;2268:37;2322:19;;715:72:5;1944:403:6;715:72:5;805:5;;:24;;;;;;;;832:1;;-1:-1:-1;;;;;805:5:5;;:22;;:24;;;;;;;;;;;;;;:5;:24;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;:28;797:67;;;;-1:-1:-1;;;797:67:5;;2554:2:6;797:67:5;;;2536:21:6;2593:2;2573:18;;;2566:30;2632:28;2612:18;;;2605:56;2678:18;;797:67:5;2352:350:6;797:67:5;890:4;883:11;;;361:540;:::o;911:789::-;1037:5;;953:4;;-1:-1:-1;;;;;1037:5:5;1025:79;;1073:20;:18;:20::i;:::-;;1025:79;1177:5;;;;;;;;;-1:-1:-1;;;;;1177:5:5;-1:-1:-1;;;;;1177:12:5;;:14;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;1173:144;;;1206:50;;-1:-1:-1;;;1206:50:5;;2909:2:6;1206:50:5;;;2891:21:6;2948:2;2928:18;;;2921:30;2987:34;2967:18;;;2960:62;3058:10;3038:18;;;3031:38;3086:19;;1206:50:5;2707:404:6;1173:144:5;1514:5;;:19;;;;;1530:2;1514:19;;;3271:25:6;-1:-1:-1;;;;;1514:5:5;;;;:15;;3244:18:6;;1514:19:5;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;1510:154;;;1548:55;;-1:-1:-1;;;1548:55:5;;3509:2:6;1548:55:5;;;3491:21:6;3548:2;3528:18;;;3521:30;3587:34;3567:18;;;3560:62;3658:15;3638:18;;;3631:43;3691:19;;1548:55:5;3307:409:6;1510:154:5;-1:-1:-1;1689:4:5;;911:789::o;1710:347::-;1752:4;1822:7;;:37;;-1:-1:-1;;;1822:37:5;;1853:4;1822:37;;;352:74:6;1752:4:5;;-1:-1:-1;;;;;1822:7:5;;:22;;325:18:6;;1822:37:5;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;1928:7;;:58;;;;;-1:-1:-1;;;;;3990:15:6;;;1928:58:5;;;3972:34:6;1980:4:5;4022:18:6;;;4015:43;1803:56:5;;-1:-1:-1;1928:7:5;;;:24;;3884:18:6;;1928:58:5;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;1927:59;1919:101;;;;-1:-1:-1;;;1919:101:5;;4271:2:6;1919:101:5;;;4253:21:6;4310:2;4290:18;;;4283:30;4349:31;4329:18;;;4322:59;4398:18;;1919:101:5;4069:353:6;437:313;507:6;560:2;548:9;539:7;535:23;531:32;528:52;;;576:1;573;566:12;528:52;608:9;602:16;-1:-1:-1;;;;;651:5:6;647:54;640:5;637:65;627:93;;716:1;713;706:12;627:93;739:5;437:313;-1:-1:-1;;;437:313:6:o;755:277::-;822:6;875:2;863:9;854:7;850:23;846:32;843:52;;;891:1;888;881:12;843:52;923:9;917:16;976:5;969:13;962:21;955:5;952:32;942:60;;998:1;995;988:12;1398:184;1468:6;1521:2;1509:9;1500:7;1496:23;1492:32;1489:52;;;1537:1;1534;1527:12;1489:52;-1:-1:-1;1560:16:6;;1398:184;-1:-1:-1;1398:184:6:o","linkReferences":{}},"methodIdentifiers":{"testCreateInstance()":"4151c179","testSolveLevel()":"8a662559","testValidation()":"cbe8047e"},"rawMetadata":"{\"compiler\":{\"version\":\"0.8.19+commit.7dd6d404\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"testCreateInstance\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"testSolveLevel\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"testValidation\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"test_timevault.sol\":\"TimeVaultTestRunner\"},\"evmVersion\":\"paris\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":1000},\"remappings\":[\":ds-test/=lib/openzeppelin-contracts-upgradeable/lib/forge-std/lib/ds-test/src/\",\":erc4626-tests/=lib/openzeppelin-contracts-upgradeable/lib/erc4626-tests/\",\":forge-std/=lib/forge-std/src/\",\":openzeppelin-contracts-06/=lib/openzeppelin-contracts-06/contracts/\",\":openzeppelin-contracts-08/=lib/openzeppelin-contracts-08/contracts/\",\":openzeppelin-contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/\",\":openzeppelin-upgradeable/=lib/openzeppelin-contracts-upgradeable/contracts/\",\":openzeppelin/=lib/openzeppelin-contracts-upgradeable/contracts/\"]},\"sources\":{\"lib/openzeppelin-contracts-08/contracts/access/Ownable.sol\":{\"keccak256\":\"0xa94b34880e3c1b0b931662cb1c09e5dfa6662f31cba80e07c5ee71cd135c9673\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://40fb1b5102468f783961d0af743f91b9980cf66b50d1d12009f6bb1869cea4d2\",\"dweb:/ipfs/QmYqEbJML4jB1GHbzD4cUZDtJg5wVwNm3vDJq1GbyDus8y\"]},\"lib/openzeppelin-contracts-08/contracts/utils/Context.sol\":{\"keccak256\":\"0xe2e337e6dde9ef6b680e07338c493ebea1b5fd09b43424112868e9cc1706bca7\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://6df0ddf21ce9f58271bdfaa85cde98b200ef242a05a3f85c2bc10a8294800a92\",\"dweb:/ipfs/QmRK2Y5Yc6BK7tGKkgsgn3aJEQGi5aakeSPZvS65PV8Xp3\"]},\"src/levels/TimeVault.sol\":{\"keccak256\":\"0x1f6e8e0a2781cbae5a675edef10a334150660a860b04c88cccc15272c9a53976\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://61f1a8153400a2f4b3193e03deb67824f3f2e5d7c5685827f3e36ee69e238aca\",\"dweb:/ipfs/QmXvr1pDtpmWBnY47a8Sy5S1ADUPgpujd26tZSoVfeETdJ\"]},\"src/levels/TimeVaultFactory.sol\":{\"keccak256\":\"0xce4f8d06d48181d48812ee6050194b5bf42c10eae2c8459bd213bee8fcf7b97d\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://7b714a63b3c6a6ee5bedb623878f97f25de1f5af22f68db4febb5ca108d58d1b\",\"dweb:/ipfs/QmQTgmf3vZkpwQt5snKByYhRUp6zsTwYUcVtHpSr5RvKne\"]},\"src/levels/base/Level.sol\":{\"keccak256\":\"0x23e8a2c9454707c888fc4dc4cc44d89e5928e8d58a1f9c8f5c16c36697aadfdf\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://693402ec163e362b086874db09be2d1d11111276f70100bf9192a0fb3f5d9ccd\",\"dweb:/ipfs/QmSsygUUkJHRh13rGUQ4BrMTnzmPQKrRsBABS4Yk11kfAA\"]},\"test_timevault.sol\":{\"keccak256\":\"0xca7bbb24a183f97a8571bfae5fbf7aa2e222a44c44ac4160071cdabf35e7c55f\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://f86b48d6fa258717c7637ffe9568529a90691ae4aaba6e200a76e4d8f2538cbc\",\"dweb:/ipfs/QmQumS3Zzv9aq5Ucwc4a4J659g1LQwHuGXAFKCjYYvd1Xn\"]}},\"version\":1}","metadata":{"compiler":{"version":"0.8.19+commit.7dd6d404"},"language":"Solidity","output":{"abi":[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"stateMutability":"nonpayable","type":"function","name":"testCreateInstance","outputs":[{"internalType":"bool","name":"","type":"bool"}]},{"inputs":[],"stateMutability":"nonpayable","type":"function","name":"testSolveLevel","outputs":[{"internalType":"bool","name":"","type":"bool"}]},{"inputs":[],"stateMutability":"nonpayable","type":"function","name":"testValidation","outputs":[{"internalType":"bool","name":"","type":"bool"}]}],"devdoc":{"kind":"dev","methods":{},"version":1},"userdoc":{"kind":"user","methods":{},"version":1}},"settings":{"remappings":["ds-test/=lib/openzeppelin-contracts-upgradeable/lib/forge-std/lib/ds-test/src/","erc4626-tests/=lib/openzeppelin-contracts-upgradeable/lib/erc4626-tests/","forge-std/=lib/forge-std/src/","openzeppelin-contracts-06/=lib/openzeppelin-contracts-06/contracts/","openzeppelin-contracts-08/=lib/openzeppelin-contracts-08/contracts/","openzeppelin-contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/","openzeppelin-upgradeable/=lib/openzeppelin-contracts-upgradeable/contracts/","openzeppelin/=lib/openzeppelin-contracts-upgradeable/contracts/"],"optimizer":{"enabled":true,"runs":1000},"metadata":{"bytecodeHash":"ipfs"},"compilationTarget":{"test_timevault.sol":"TimeVaultTestRunner"},"evmVersion":"paris","libraries":{}},"sources":{"lib/openzeppelin-contracts-08/contracts/access/Ownable.sol":{"keccak256":"0xa94b34880e3c1b0b931662cb1c09e5dfa6662f31cba80e07c5ee71cd135c9673","urls":["bzz-raw://40fb1b5102468f783961d0af743f91b9980cf66b50d1d12009f6bb1869cea4d2","dweb:/ipfs/QmYqEbJML4jB1GHbzD4cUZDtJg5wVwNm3vDJq1GbyDus8y"],"license":"MIT"},"lib/openzeppelin-contracts-08/contracts/utils/Context.sol":{"keccak256":"0xe2e337e6dde9ef6b680e07338c493ebea1b5fd09b43424112868e9cc1706bca7","urls":["bzz-raw://6df0ddf21ce9f58271bdfaa85cde98b200ef242a05a3f85c2bc10a8294800a92","dweb:/ipfs/QmRK2Y5Yc6BK7tGKkgsgn3aJEQGi5aakeSPZvS65PV8Xp3"],"license":"MIT"},"src/levels/TimeVault.sol":{"keccak256":"0x1f6e8e0a2781cbae5a675edef10a334150660a860b04c88cccc15272c9a53976","urls":["bzz-raw://61f1a8153400a2f4b3193e03deb67824f3f2e5d7c5685827f3e36ee69e238aca","dweb:/ipfs/QmXvr1pDtpmWBnY47a8Sy5S1ADUPgpujd26tZSoVfeETdJ"],"license":"MIT"},"src/levels/TimeVaultFactory.sol":{"keccak256":"0xce4f8d06d48181d48812ee6050194b5bf42c10eae2c8459bd213bee8fcf7b97d","urls":["bzz-raw://7b714a63b3c6a6ee5bedb623878f97f25de1f5af22f68db4febb5ca108d58d1b","dweb:/ipfs/QmQTgmf3vZkpwQt5snKByYhRUp6zsTwYUcVtHpSr5RvKne"],"license":"MIT"},"src/levels/base/Level.sol":{"keccak256":"0x23e8a2c9454707c888fc4dc4cc44d89e5928e8d58a1f9c8f5c16c36697aadfdf","urls":["bzz-raw://693402ec163e362b086874db09be2d1d11111276f70100bf9192a0fb3f5d9ccd","dweb:/ipfs/QmSsygUUkJHRh13rGUQ4BrMTnzmPQKrRsBABS4Yk11kfAA"],"license":"MIT"},"test_timevault.sol":{"keccak256":"0xca7bbb24a183f97a8571bfae5fbf7aa2e222a44c44ac4160071cdabf35e7c55f","urls":["bzz-raw://f86b48d6fa258717c7637ffe9568529a90691ae4aaba6e200a76e4d8f2538cbc","dweb:/ipfs/QmQumS3Zzv9aq5Ucwc4a4J659g1LQwHuGXAFKCjYYvd1Xn"],"license":"MIT"}},"version":1},"id":5}
\ No newline at end of file
diff --git a/contracts/src/levels/TimeVault.sol b/contracts/src/levels/TimeVault.sol
new file mode 100644
index 000000000..401370957
--- /dev/null
+++ b/contracts/src/levels/TimeVault.sol
@@ -0,0 +1,61 @@
+// SPDX-License-Identifier: MIT
+pragma solidity ^0.8.0;
+
+contract TimeVault {
+ uint256 public unlockTime;
+ uint256 public secretValue;
+ bool public isUnlocked;
+ address public owner;
+
+ event VaultUnlocked(address indexed unlocker, uint256 timestamp);
+ event SecretSet(address indexed setter, uint256 value);
+
+ constructor() {
+ owner = msg.sender;
+ // Set unlock time to 1 hour from deployment
+ unlockTime = block.timestamp + 1 hours;
+ isUnlocked = false;
+ secretValue = 0;
+ }
+
+ modifier onlyAfterUnlockTime() {
+ require(block.timestamp >= unlockTime, "Vault is still locked");
+ _;
+ }
+
+ modifier onlyUnlocked() {
+ require(isUnlocked, "Vault must be unlocked first");
+ _;
+ }
+
+ // Function to unlock the vault - can only be called after unlock time
+ function unlock() external onlyAfterUnlockTime {
+ isUnlocked = true;
+ emit VaultUnlocked(msg.sender, block.timestamp);
+ }
+
+ // Function to set the secret value - can only be called when vault is unlocked
+ function setSecret(uint256 _secret) external onlyUnlocked {
+ secretValue = _secret;
+ emit SecretSet(msg.sender, _secret);
+ }
+
+ // Function to check if the level is completed
+ function isCompleted() external view returns (bool) {
+ // Level is completed when secret value is set to 42
+ return secretValue == 42;
+ }
+
+ // Helper function to get current timestamp (for testing purposes)
+ function getCurrentTime() external view returns (uint256) {
+ return block.timestamp;
+ }
+
+ // Helper function to get time remaining until unlock
+ function getTimeRemaining() external view returns (uint256) {
+ if (block.timestamp >= unlockTime) {
+ return 0;
+ }
+ return unlockTime - block.timestamp;
+ }
+}
\ No newline at end of file
diff --git a/contracts/src/levels/TimeVaultFactory.sol b/contracts/src/levels/TimeVaultFactory.sol
new file mode 100644
index 000000000..262f37a13
--- /dev/null
+++ b/contracts/src/levels/TimeVaultFactory.sol
@@ -0,0 +1,25 @@
+// SPDX-License-Identifier: MIT
+pragma solidity ^0.8.0;
+
+import "./base/Level.sol";
+import "./TimeVault.sol";
+
+contract TimeVaultFactory is Level {
+ function createInstance(address _player) public payable override returns (address) {
+ _player; // Unused parameter, silence compiler warning
+
+ // Create a new TimeVault instance
+ TimeVault instance = new TimeVault();
+
+ return address(instance);
+ }
+
+ function validateInstance(address payable _instance, address /* _player */) public view override returns (bool) {
+ // Cast the instance address to the TimeVault contract
+ TimeVault instance = TimeVault(_instance);
+
+ // Check if the player has completed the level
+ // The level is completed when the secret value is set to 42
+ return instance.isCompleted();
+ }
+}
\ No newline at end of file
diff --git a/contracts/test/levels/TimeVault.t.sol b/contracts/test/levels/TimeVault.t.sol
new file mode 100644
index 000000000..84e8802e2
--- /dev/null
+++ b/contracts/test/levels/TimeVault.t.sol
@@ -0,0 +1,85 @@
+// SPDX-License-Identifier: MIT
+pragma solidity ^0.8.0;
+
+import "forge-std/Test.sol";
+import {Utils} from "../utils/Utils.sol";
+
+import {TimeVault} from "../../src/levels/TimeVault.sol";
+import {TimeVaultFactory} from "../../src/levels/TimeVaultFactory.sol";
+import {Level} from "../../src/levels/base/Level.sol";
+import {Ethernaut} from "../../src/Ethernaut.sol";
+
+contract TestTimeVault is Test, Utils {
+ Ethernaut ethernaut;
+ TimeVault instance;
+
+ address payable owner;
+ address payable player;
+
+ /*//////////////////////////////////////////////////////////////
+ HELPERS
+ //////////////////////////////////////////////////////////////*/
+
+ function setUp() public {
+ address payable[] memory users = createUsers(2);
+
+ owner = users[0];
+ vm.label(owner, "Owner");
+
+ player = users[1];
+ vm.label(player, "Player");
+
+ vm.startPrank(owner);
+ ethernaut = getEthernautWithStatsProxy(owner);
+ TimeVaultFactory factory = new TimeVaultFactory();
+ ethernaut.registerLevel(Level(address(factory)));
+ vm.stopPrank();
+
+ vm.startPrank(player);
+ instance = TimeVault(payable(createLevelInstance(ethernaut, Level(address(factory)), 0 ether)));
+ vm.stopPrank();
+ }
+
+ /*//////////////////////////////////////////////////////////////
+ TESTS
+ //////////////////////////////////////////////////////////////*/
+
+ /// @notice Check the initial state of the level and environment.
+ function testInit() public {
+ vm.startPrank(player);
+
+ // Check initial state
+ assertFalse(instance.isUnlocked());
+ assertEq(instance.secretValue(), 0);
+ assertTrue(instance.unlockTime() > block.timestamp);
+
+ // Verify level is not completed yet
+ assertFalse(submitLevelInstance(ethernaut, address(instance)));
+
+ vm.stopPrank();
+ }
+
+ /// @notice Test the solution for the level.
+ function testSolve() public {
+ vm.startPrank(player);
+
+ // Get the current unlock time
+ uint256 currentUnlockTime = instance.unlockTime();
+
+ // Warp time to after unlock time
+ vm.warp(currentUnlockTime + 1);
+
+ // Unlock the vault
+ instance.unlock();
+ assertTrue(instance.isUnlocked());
+
+ // Set the secret value to 42
+ instance.setSecret(42);
+ assertEq(instance.secretValue(), 42);
+
+ // Verify level is completed
+ assertTrue(submitLevelInstance(ethernaut, address(instance)));
+
+ vm.stopPrank();
+ }
+}
\ No newline at end of file