diff --git a/README.md b/README.md index ccd9b5f6..92a9ab77 100644 --- a/README.md +++ b/README.md @@ -62,8 +62,7 @@ If a bug turns up after mainnet, the alternative to a pause is asking every integrator to stop calling the contract. Since issue #35 there is a narrow on-chain lever instead: one `pause_admin` address, fixed at deployment by the contract's constructor, can flip a flag that makes every deposit path -fail with `Paused` (provisional error code 3500; the maintainer fold -renumbers it). +fail with `Paused` (error code 38). Nothing else changes. `release`, `refund`, the timeout refund, and both `settle_many` ops (release and refund) never read the flag, so **a pause can never lock funds that are already escrowed** — diff --git a/ROADMAP.md b/ROADMAP.md index 94cdaf19..5b0781be 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -267,8 +267,8 @@ An opt-in creation method can require the payee to authorize `accept` before rel Alternatives rejected in the ADR: permissionless pause (trivial griefing), auto-expiring pause (silently lapses mid-incident), token allowlist (a different problem), and doing nothing. New error codes - `Paused`, `AlreadyPaused` and `NotPaused`, added with the provisional - codes 3500–3502 (`contract-changes.d/35-emergency-pause.md`); + `Paused`, `AlreadyPaused` and `NotPaused`, with codes + 38–40 (contract 2.5.0); `Paused`/`Unpaused` events carry the custodian. 20 tests in `contracts/escrow/tests/pause.rs`, including release, releaser refund, stranger timeout refund, and release-after-deadline while paused, plus a @@ -1049,3 +1049,18 @@ An opt-in creation method can require the payee to authorize `accept` before rel - Issue #40: allow the stored payee to authorize a voluntary full refund of a funded single-payee escrow to its stored payer destination, and emit a distinct `payee_refunded` event. - Issue #45 (Phase E5): new `transfer_payee(escrow_id, current_payee, new_payee)` entry point — only the current payee may authorize it, only while the escrow is `Funded`, and `new_payee` may be neither the contract address nor the payer. Emits a `pay_xfer` event and adds `Error::InvalidNewPayee` (code 37). Rotation tool, not key-loss recovery; covered by `contracts/escrow/tests/transfer_payee.rs`. Final error codes: Error::InvalidNewPayee 4500 -> 37. +- 2026-10-31 — Issue #35 (Phase E5): deposit-only emergency pause. The contract's + `__constructor` now also takes a `pause_admin` address; only that custodian + can call `pause`/`unpause`, and while paused every deposit path fails with + `Paused` before any funds move — including pooled `create_pooled_escrow` + and `contribute` (`Paused`, plus `AlreadyPaused`/`NotPaused` for the + transition guards — codes 38–40). `release`, `refund`, the timeout refund and pooled + `claim_refund` never read the flag, so a + pause can stop new exposure but never lock escrowed funds (invariant I8, + threat model T12, `docs/adr/0011`). The SDK gains `pause`/`unpause`/ + `isPaused`/`getPauseAdmin` (minor changeset) and regenerated bindings. This + is a deployment change: the live testnet contract predates the constructor + and cannot pause until it is redeployed. +- 2026-10-31 — Contract 2.5.0 (was 2.4.0), folded from 1 change(s): + - Issue #35 (Phase E5): deposit-only emergency pause (ADR 0011). The constructor gains a second argument (`pause_admin`) and the contract gains `pause`/`unpause`/`is_paused`/`get_pause_admin` entry points plus the `Paused`/`Unpaused` events and the `Paused`, `AlreadyPaused`, `NotPaused` errors (codes 38–40). Every deposit path is gated — `create_escrow` and its variants, `top_up`, and pooled `create_pooled_escrow`/`contribute` — while `release`, `refund`, the timeout refund, pooled `claim_refund` and both `settle_many` ops never read the flag, so a pause can never lock funds already escrowed. + Final error codes: Error::Paused 3500 -> 38, Error::AlreadyPaused 3501 -> 39, Error::NotPaused 3502 -> 40. diff --git a/changelog.d/35-emergency-pause.md b/changelog.d/35-emergency-pause.md deleted file mode 100644 index 97e48bd2..00000000 --- a/changelog.d/35-emergency-pause.md +++ /dev/null @@ -1,13 +0,0 @@ -Issue #35 (Phase E5): deposit-only emergency pause. The contract's -`__constructor` now also takes a `pause_admin` address; only that custodian -can call `pause`/`unpause`, and while paused every deposit path fails with -`Paused` before any funds move — including pooled `create_pooled_escrow` -and `contribute` (`Paused`, plus `AlreadyPaused`/`NotPaused` for the -transition guards — provisional codes 3500–3502, renumbered by the -maintainer fold). `release`, `refund`, the timeout refund and pooled -`claim_refund` never read the flag, so a -pause can stop new exposure but never lock escrowed funds (invariant I8, -threat model T12, `docs/adr/0011`). The SDK gains `pause`/`unpause`/ -`isPaused`/`getPauseAdmin` (minor changeset) and regenerated bindings. This -is a deployment change: the live testnet contract predates the constructor -and cannot pause until it is redeployed. diff --git a/contract-changes.d/35-emergency-pause.md b/contract-changes.d/35-emergency-pause.md deleted file mode 100644 index f1e077cf..00000000 --- a/contract-changes.d/35-emergency-pause.md +++ /dev/null @@ -1,11 +0,0 @@ -bump: minor ---- -Issue #35 (Phase E5): deposit-only emergency pause (ADR 0011). The -constructor gains a second argument (`pause_admin`) and the contract gains -`pause`/`unpause`/`is_paused`/`get_pause_admin` entry points plus the -`Paused`/`Unpaused` events and the `Paused`, `AlreadyPaused`, `NotPaused` -errors (provisional codes 3500–3502, renumbered by the maintainer fold). -Every deposit path is gated — `create_escrow` and its variants, `top_up`, -and pooled `create_pooled_escrow`/`contribute` — while `release`, `refund`, -the timeout refund, pooled `claim_refund` and both `settle_many` ops never -read the flag, so a pause can never lock funds already escrowed. diff --git a/contracts/escrow/src/lib.rs b/contracts/escrow/src/lib.rs index b8db6351..0eb044bf 100644 --- a/contracts/escrow/src/lib.rs +++ b/contracts/escrow/src/lib.rs @@ -57,7 +57,7 @@ use soroban_sdk::{ // Bump this value whenever a contract interface or behavior change is made. // CI checks this constant against the base branch when this file changes. -pub const CONTRACT_VERSION: &str = "2.4.0"; +pub const CONTRACT_VERSION: &str = "2.5.0"; include!(concat!(env!("OUT_DIR"), "/contract_metadata.rs")); @@ -366,16 +366,14 @@ pub enum Error { /// retryable and may still use its refund path. Undeliverable = 36, /// A deposit path was called while the emergency pause is on — see - /// docs/adr/0011. `main` already spent 35 (`InvalidFee`) and 36 - /// (`Undeliverable`), so this uses a provisional code (issue #35 × 100); - /// the maintainer fold renumbers it — see contract-changes.d/README.md. - Paused = 3500, + /// docs/adr/0011. + Paused = 38, /// `pause` on an already-paused contract. The transition did not /// happen, so no event is emitted. - AlreadyPaused = 3501, + AlreadyPaused = 39, /// `unpause` on a running contract. The transition did not happen, so /// no event is emitted. - NotPaused = 3502, + NotPaused = 40, } #[contract] diff --git a/docs/adr/0011-emergency-pause-for-new-deposits-only.md b/docs/adr/0011-emergency-pause-for-new-deposits-only.md index 092f8d15..202cb32c 100644 --- a/docs/adr/0011-emergency-pause-for-new-deposits-only.md +++ b/docs/adr/0011-emergency-pause-for-new-deposits-only.md @@ -125,7 +125,7 @@ Option 1. an event never claims a transition that didn't happen. 3. **Scope: new deposits only.** Every creation entry point funnels through `create_escrow_inner`, which checks the flag first and returns the new - `Error::Paused` (provisional code 3500) without pulling funds, without + `Error::Paused` (code 38) without pulling funds, without consuming an escrow id, and without writing an escrow. `top_up` — a deposit path added after this ADR was first written — applies the same check before its transfer, exactly as the ADR originally required of any future deposit path. @@ -178,10 +178,9 @@ the deadline. keys (`PauseAdmin`, `Paused`) are added. Existing escrow entries are unaffected — and there is no migration to worry about, because a redeploy is a new contract id by definition. -- **New error codes**: `Paused`, `AlreadyPaused`, `NotPaused`, added with - the provisional codes 3500–3502 (issue #35 × 100 + n) described in - `contract-changes.d/README.md`; the maintainer fold assigns the final - numbers. Every existing code keeps its number, because consumers map +- **New error codes**: `Paused`, `AlreadyPaused`, `NotPaused`, codes 38–40, + assigned by the contract 2.5.0 maintainer fold from the provisional codes + 3500–3502 (issue #35 × 100 + n) described in `contract-changes.d/README.md`. Every existing code keeps its number, because consumers map codes, not names. They were originally reserved as 26–28, but batch settlement (`BatchTooLarge = 25`), pooled escrows (`NotPooled` through `InvalidFundingDeadline`, 26–34) and the protocol fee / outbound-transfer diff --git a/sdk/src/generated/contract-client.ts b/sdk/src/generated/contract-client.ts index 6c04ab75..30caa02b 100644 --- a/sdk/src/generated/contract-client.ts +++ b/sdk/src/generated/contract-client.ts @@ -185,21 +185,19 @@ export const Errors = { 36: {message:"Undeliverable"}, /** * A deposit path was called while the emergency pause is on — see - * docs/adr/0011. `main` already spent 35 (`InvalidFee`) and 36 - * (`Undeliverable`), so this uses a provisional code (issue #35 × 100); - * the maintainer fold renumbers it — see contract-changes.d/README.md. + * docs/adr/0011. */ - 3500: {message:"Paused"}, + 38: {message:"Paused"}, /** * `pause` on an already-paused contract. The transition did not * happen, so no event is emitted. */ - 3501: {message:"AlreadyPaused"}, + 39: {message:"AlreadyPaused"}, /** * `unpause` on a running contract. The transition did not happen, so * no event is emitted. */ - 3502: {message:"NotPaused"} + 40: {message:"NotPaused"} } @@ -748,7 +746,7 @@ export class Client extends ContractClient { } constructor(public readonly options: ContractClientOptions) { super( - new ContractSpec([ "AAAABAAAAAAAAAAAAAAABUVycm9yAAAAAAAAJgAAAAAAAAAITm90Rm91bmQAAAABAAAAAAAAAA1JbnZhbGlkQW1vdW50AAAAAAAAAgAAAAAAAAAMVW5hdXRob3JpemVkAAAAAwAAAAAAAAAJTm90RnVuZGVkAAAAAAAABAAAALpgcmVmdW5kX2FmdGVyYCB3YXMgbm90IHN0cmljdGx5IGluIHRoZSBmdXR1cmUgYXQgY3JlYXRpb24g4oCUIHNlZQpkb2NzL2Fkci8wMDA0OiBhIGRlYWRsaW5lIHRoYXQgaGFzIGFscmVhZHkgcGFzc2VkIHdvdWxkIGxldAphbnlvbmUgcmVmdW5kIHRoZSBlc2Nyb3cgYmVmb3JlIHRoZSByZWxlYXNlciBjb3VsZCBldmVyIGFjdC4AAAAAABJJbnZhbGlkUmVmdW5kQWZ0ZXIAAAAAAAUAAACjVGhlIGNvbnRyYWN0J3MgdG9rZW4gYmFsYW5jZSBkaWRuJ3QgcmlzZSBieSBleGFjdGx5IGBhbW91bnRgCmFjcm9zcyBgY3JlYXRlX2VzY3Jvd2AncyB0cmFuc2ZlciAoYSBseWluZyBvciBzaG9ydC1kZWxpdmVyaW5nCnRva2VuKSDigJQgc2VlIGRvY3MvdGhyZWF0LW1vZGVsLm1kIFQ1LgAAAAAPQmFsYW5jZU1pc21hdGNoAAAAAAYAAAEAYGNvbmRpdGlvbl9yZWZgIGV4Y2VlZGVkIHRoZSBtYXhpbXVtIGFsbG93ZWQgbGVuZ3RoIChjdXJyZW50bHkKNjQgYnl0ZXMpIOKAlCBzZWUgZG9jcy90aHJlYXQtbW9kZWwubWQgVDEwIGFuZCBST0FETUFQLm1kIFBoYXNlIEU1LgpCb3VuZGVkIHRvIGtlZXAgc3RvcmFnZSBhbmQgZXZlbnQgY29zdHMgcHJlZGljdGFibGU7IHJlamVjdCBhdApjcmVhdGlvbiBzbyBubyBvbi1jaGFpbiBzdG9yYWdlIGlzIHdhc3RlZCBvbiBhbiBvdmVyc2l6ZWQgcmVmLgAAABNDb25kaXRpb25SZWZUb29Mb25nAAAAAAcAAAA2YHRva2VuYCBpcyBub3QgaW4gdGhlIGltbXV0YWJsZSBkZXBsb3ktdGltZSBhbGxvd2xpc3QuAAAAAAAPRGlzYWxsb3dlZFRva2VuAAAAAAgAAACDVGhlIG9wdGVkLWluIHBheWVlIGNhbGxiYWNrIHJldHVybmVkIGFuIGVycm9yIG9yIGNvdWxkIG5vdCBiZQppbnZva2VkLiBUaGUgcmVsZWFzZSB0cmFuc2FjdGlvbiAoaW5jbHVkaW5nIGl0cyB0cmFuc2Zlcikgcm9sbHMgYmFjay4AAAAADkNhbGxiYWNrRmFpbGVkAAAAAAAJAAAA/WBuZXdfcGF5ZWVgIGlzIGludmFsaWQ6IGl0IGlzIGVpdGhlciB0aGUgY29udHJhY3QncyBvd24gYWRkcmVzcwpvciB0aGUgcGF5ZXIncyBhZGRyZXNzLiBUaGUgY29udHJhY3QgYWRkcmVzcyBjYW4gbmV2ZXIgc2lnbiB0bwphY2NlcHQgYSBwYXlvdXQ7IHRoZSBwYXllciBpcyBleGNsdWRlZCBzbyBhIHBheWVyIGNhbm5vdCByZWRpcmVjdAp0aGUgcmVsZWFzZSBkZXN0aW5hdGlvbiB0byB0aGVtc2VsdmVzIHZpYSBhIGNvbGx1ZGluZyBwYXllZS4AAAAAAAAPSW52YWxpZE5ld1BheWVlAAAAACUAAAAAAAAACE92ZXJmbG93AAAADAAAAGxUaGUgcmVsZWFzZXIgc2V0IGlzIGVtcHR5LCBvciBgdGhyZXNob2xkYCBpcyAwIG9yIGxhcmdlciB0aGFuIHRoZQpudW1iZXIgb2YgcmVsZWFzZXJzIOKAlCBzZWUgZG9jcy9hZHIvMDAwNy4AAAAQSW52YWxpZFRocmVzaG9sZAAAAA0AAABDTW9yZSB0aGFuIGBNQVhfUkVMRUFTRVJTYCAoMTApIGFkZHJlc3NlcyB3ZXJlIHN1cHBsaWVkIGF0IGNyZWF0aW9uLgAAAAAQVG9vTWFueVJlbGVhc2VycwAAAA4AAACfRmV3ZXIgZGlzdGluY3QgYXBwcm92YWxzIHdlcmUgc3VwcGxpZWQgdGhhbiB0aGUgZXNjcm93J3MgdGhyZXNob2xkLApvciBhIHNpbmdsZSByZWxlYXNlciB0cmllZCB0byBzZXR0bGUgYSBxdW9ydW0gZXNjcm93IHRocm91Z2ggdGhlCnNpbmdsZS1jYWxsZXIgZW50cnkgcG9pbnQuAAAAAA9UaHJlc2hvbGROb3RNZXQAAAAADwAAAGhUaGUgc2FtZSBhZGRyZXNzIGFwcGVhcmVkIHR3aWNlIGluIG9uZSBhcHByb3ZhbCBsaXN0LiBEdXBsaWNhdGVzCm5ldmVyIGNvdW50IHR3aWNlIHRvd2FyZCB0aGUgdGhyZXNob2xkLgAAABFEdXBsaWNhdGVBcHByb3ZlcgAAAAAAABAAAABAVGhlIHNhbWUgYWRkcmVzcyBhcHBlYXJlZCB0d2ljZSBpbiB0aGUgcmVsZWFzZXIgc2V0IGF0IGNyZWF0aW9uLgAAABFEdXBsaWNhdGVSZWxlYXNlcgAAAAAAABEAAAAAAAAAEkFjY2VwdGFuY2VSZXF1aXJlZAAAAAAAEgAAAAAAAAAXQWNjZXB0YW5jZU5vdENvbmZpZ3VyZWQAAAAAEwAAAAAAAAAPQWxyZWFkeUFjY2VwdGVkAAAAABQAAAA4VGhlIG5ldyByZWxlYXNlciBjYW5ub3QgYmUgdGhlIGVzY3JvdyBjb250cmFjdCBvciBwYXllZS4AAAAPSW52YWxpZFJlbGVhc2VyAAAAABgAAAB8YHJlZnVuZF90b2Agd2FzIHRoZSBlc2Nyb3cgY29udHJhY3QncyBvd24gYWRkcmVzcyDigJQgZnVuZHMgc2VudAp0aGVyZSBvbiByZWZ1bmQgY291bGQgbmV2ZXIgYmUgbW92ZWQgYWdhaW4gKGRvY3MvYWRyLzAwMDkpLgAAAA9JbnZhbGlkUmVmdW5kVG8AAAAAFQAAAERUaGUgY29uZmlndXJlZCByZWxlYXNlIHRpbWUgaXMgaW4gdGhlIHBhc3Qgb3IgYWZ0ZXIgdGhlIHJlZnVuZCB0aW1lLgAAABdJbnZhbGlkUmVsZWFzZU5vdEJlZm9yZQAAAAAWAAAAMVJlbGVhc2Ugd2FzIGF0dGVtcHRlZCBiZWZvcmUgdGhlIGNvbmZpZ3VyZWQgdGltZS4AAAAAAAAPUmVsZWFzZVRvb0Vhcmx5AAAAABcAAACtQSBiYXRjaCBjYWxsIHdhcyBwYXNzZWQgbW9yZSB0aGFuIGBNQVhfQkFUQ0hfU0laRWAgaXRlbXMg4oCUIHNlZQpkb2NzL2Fkci8wMDA1LiBDYWxsZXJzIG11c3QgY2h1bmsuIEFwcGVuZGVkIGF0IHRoZSBlbmQgc28gZXhpc3RpbmcKZGlzY3JpbWluYW50cyBrZWVwIHRoZWlyIG9uLWNoYWluIHZhbHVlcy4AAAAAAAANQmF0Y2hUb29MYXJnZQAAAAAAABkAAACIYGNvbnRyaWJ1dGVgL2BjbGFpbV9yZWZ1bmRgL2BnZXRfY29udHJpYnV0aW9uYCBvbiBhIG5vbi1wb29sZWQKZXNjcm93LCBvciBgZ2V0X3Bvb2xlZGAgb24gYSBub24tcG9vbGVkL3Vua25vd24gaWQg4oCUIHNlZQpkb2NzL2Fkci8wMDExLgAAAAlOb3RQb29sZWQAAAAAAAAaAAAAv0EgY29udHJpYnV0aW9uIGFycml2ZWQgYWZ0ZXIgdGhlIHBvb2xlZCBlc2Nyb3cncyBmdW5kaW5nIGRlYWRsaW5lLgpMYXRlIGNvbnRyaWJ1dGlvbnMgY2FuIG5ldmVyIGJlIGFjY2VwdGVkOiB0aGUgcm91bmQncyBvdXRjb21lCihyZWxlYXNlIHZzIHBlci1jb250cmlidXRvciByZWZ1bmRzKSBpcyBmaXhlZCBhdCB0aGUgZGVhZGxpbmUuAAAAABVGdW5kaW5nRGVhZGxpbmVQYXNzZWQAAAAAAAAbAAAAv0EgY29udHJpYnV0aW9uIHdvdWxkIHB1c2ggdGhlIHBvb2xlZCB0b3RhbCBwYXN0IHRoZSBmdW5kaW5nIHRhcmdldAoob3ZlcmZ1bmRpbmcgaXMgcmVqZWN0ZWQsIG5vdCBhY2NlcHRlZCksIHRoZSB0YXJnZXQgaXMgYWxyZWFkeSBtZXQsCm9yIGEgcmVmdW5kIHdhcyBjbGFpbWVkIG9uIGEgZnVsbHkgZnVuZGVkIHBvb2xlZCBlc2Nyb3cuAAAAABRGdW5kaW5nVGFyZ2V0UmVhY2hlZAAAABwAAAB0YHJlbGVhc2VgIG9uIGEgcG9vbGVkIGVzY3JvdyB3aG9zZSBmdW5kZWQgdG90YWwgaXMgYmVsb3cgdGhlCmZ1bmRpbmcgdGFyZ2V0IOKAlCBwYXJ0aWFsIGZ1bmRpbmcgaXMgbmV2ZXIgcmVsZWFzYWJsZS4AAAARRnVuZGluZ0luY29tcGxldGUAAAAAAAAdAAAAhmBjbGFpbV9yZWZ1bmRgIGJlZm9yZSB0aGUgZnVuZGluZyBkZWFkbGluZSBwYXNzZWQgb24gYSByb3VuZCB0aGF0CmlzIHN0aWxsIChvciBub3cgZnVsbHkpIGZ1bmRlZC4gQ2xhaW1zIG9wZW4gb25seSBmb3IgYSBmYWlsZWQgcm91bmQuAAAAAAANUmVmdW5kTm90T3BlbgAAAAAAAB4AAAAzVGhlIHNhbWUgY29udHJpYnV0b3IgdHJpZWQgdG8gY2xhaW0gYSByZWZ1bmQgdHdpY2UuAAAAAA9BbHJlYWR5UmVmdW5kZWQAAAAAHwAAADtgY2xhaW1fcmVmdW5kYCBieSBhbiBhZGRyZXNzIHdpdGggbm8gcmVjb3JkZWQgY29udHJpYnV0aW9uLgAAAAAOTm9Db250cmlidXRpb24AAAAAACAAAADzYHJlZnVuZGAvYHJlZnVuZF93aXRoX2FwcHJvdmFsc2AvYGNhbmNlbGAvYHRvcF91cGAgb24gYSBwb29sZWQKZXNjcm93OiBwdXNoaW5nIHRoZSB3aG9sZSBwb29sZWQgdG90YWwgdG8gb25lIGFkZHJlc3Mgd291bGQgdmlvbGF0ZQpwZXItY29udHJpYnV0b3IgYWNjb3VudGluZy4gUG9vbGVkIHJlZnVuZHMgYXJlIHB1bGwtYmFzZWQKKGBjbGFpbV9yZWZ1bmRgKTsgcG9vbGVkIGZ1bmRpbmcgaXMgYGNvbnRyaWJ1dGVgLW9ubHkuAAAAABVOb3RTdXBwb3J0ZWRGb3JQb29sZWQAAAAAAAAhAAAAQFRoZSBmdW5kaW5nIGRlYWRsaW5lIHdhcyBub3Qgc3RyaWN0bHkgaW4gdGhlIGZ1dHVyZSBhdCBjcmVhdGlvbi4AAAAWSW52YWxpZEZ1bmRpbmdEZWFkbGluZQAAAAAAIgAAANJUaGUgb3B0aW9uYWwgcHJvdG9jb2wgZmVlIHdhcyBtaXNjb25maWd1cmVkIGF0IGNyZWF0aW9uOiBgYnBzYAphYm92ZSBbYE1BWF9GRUVfQlBTYF0gKDEwICUpLCBhIHJlY2lwaWVudCBlcXVhbCB0byB0aGUgZXNjcm93CmNvbnRyYWN0IGl0c2VsZiwgb3IgYW4gYW1vdW50IHRoYXQgd291bGQgb3ZlcmZsb3cgdGhlIGZlZSBtYXRoIOKAlApzZWUgZG9jcy9hZHIvMDAxMC4AAAAAAApJbnZhbGlkRmVlAAAAAAAjAAAAa0FuIG91dGJvdW5kIHJlbGVhc2UgdHJhbnNmZXIgZmFpbGVkOyB0aGUgZnVuZGVkIGVzY3JvdyByZW1haW5zCnJldHJ5YWJsZSBhbmQgbWF5IHN0aWxsIHVzZSBpdHMgcmVmdW5kIHBhdGguAAAAAA1VbmRlbGl2ZXJhYmxlAAAAAAAAJAAAAQxBIGRlcG9zaXQgcGF0aCB3YXMgY2FsbGVkIHdoaWxlIHRoZSBlbWVyZ2VuY3kgcGF1c2UgaXMgb24g4oCUIHNlZQpkb2NzL2Fkci8wMDExLiBgbWFpbmAgYWxyZWFkeSBzcGVudCAzNSAoYEludmFsaWRGZWVgKSBhbmQgMzYKKGBVbmRlbGl2ZXJhYmxlYCksIHNvIHRoaXMgdXNlcyBhIHByb3Zpc2lvbmFsIGNvZGUgKGlzc3VlICMzNSDDlyAxMDApOwp0aGUgbWFpbnRhaW5lciBmb2xkIHJlbnVtYmVycyBpdCDigJQgc2VlIGNvbnRyYWN0LWNoYW5nZXMuZC9SRUFETUUubWQuAAAABlBhdXNlZAAAAAANrAAAAF1gcGF1c2VgIG9uIGFuIGFscmVhZHktcGF1c2VkIGNvbnRyYWN0LiBUaGUgdHJhbnNpdGlvbiBkaWQgbm90CmhhcHBlbiwgc28gbm8gZXZlbnQgaXMgZW1pdHRlZC4AAAAAAAANQWxyZWFkeVBhdXNlZAAAAAAADa0AAABXYHVucGF1c2VgIG9uIGEgcnVubmluZyBjb250cmFjdC4gVGhlIHRyYW5zaXRpb24gZGlkIG5vdCBoYXBwZW4sIHNvCm5vIGV2ZW50IGlzIGVtaXR0ZWQuAAAAAAlOb3RQYXVzZWQAAAAAAA2u", + new ContractSpec([ "AAAABAAAAAAAAAAAAAAABUVycm9yAAAAAAAAJgAAAAAAAAAITm90Rm91bmQAAAABAAAAAAAAAA1JbnZhbGlkQW1vdW50AAAAAAAAAgAAAAAAAAAMVW5hdXRob3JpemVkAAAAAwAAAAAAAAAJTm90RnVuZGVkAAAAAAAABAAAALpgcmVmdW5kX2FmdGVyYCB3YXMgbm90IHN0cmljdGx5IGluIHRoZSBmdXR1cmUgYXQgY3JlYXRpb24g4oCUIHNlZQpkb2NzL2Fkci8wMDA0OiBhIGRlYWRsaW5lIHRoYXQgaGFzIGFscmVhZHkgcGFzc2VkIHdvdWxkIGxldAphbnlvbmUgcmVmdW5kIHRoZSBlc2Nyb3cgYmVmb3JlIHRoZSByZWxlYXNlciBjb3VsZCBldmVyIGFjdC4AAAAAABJJbnZhbGlkUmVmdW5kQWZ0ZXIAAAAAAAUAAACjVGhlIGNvbnRyYWN0J3MgdG9rZW4gYmFsYW5jZSBkaWRuJ3QgcmlzZSBieSBleGFjdGx5IGBhbW91bnRgCmFjcm9zcyBgY3JlYXRlX2VzY3Jvd2AncyB0cmFuc2ZlciAoYSBseWluZyBvciBzaG9ydC1kZWxpdmVyaW5nCnRva2VuKSDigJQgc2VlIGRvY3MvdGhyZWF0LW1vZGVsLm1kIFQ1LgAAAAAPQmFsYW5jZU1pc21hdGNoAAAAAAYAAAEAYGNvbmRpdGlvbl9yZWZgIGV4Y2VlZGVkIHRoZSBtYXhpbXVtIGFsbG93ZWQgbGVuZ3RoIChjdXJyZW50bHkKNjQgYnl0ZXMpIOKAlCBzZWUgZG9jcy90aHJlYXQtbW9kZWwubWQgVDEwIGFuZCBST0FETUFQLm1kIFBoYXNlIEU1LgpCb3VuZGVkIHRvIGtlZXAgc3RvcmFnZSBhbmQgZXZlbnQgY29zdHMgcHJlZGljdGFibGU7IHJlamVjdCBhdApjcmVhdGlvbiBzbyBubyBvbi1jaGFpbiBzdG9yYWdlIGlzIHdhc3RlZCBvbiBhbiBvdmVyc2l6ZWQgcmVmLgAAABNDb25kaXRpb25SZWZUb29Mb25nAAAAAAcAAAA2YHRva2VuYCBpcyBub3QgaW4gdGhlIGltbXV0YWJsZSBkZXBsb3ktdGltZSBhbGxvd2xpc3QuAAAAAAAPRGlzYWxsb3dlZFRva2VuAAAAAAgAAACDVGhlIG9wdGVkLWluIHBheWVlIGNhbGxiYWNrIHJldHVybmVkIGFuIGVycm9yIG9yIGNvdWxkIG5vdCBiZQppbnZva2VkLiBUaGUgcmVsZWFzZSB0cmFuc2FjdGlvbiAoaW5jbHVkaW5nIGl0cyB0cmFuc2Zlcikgcm9sbHMgYmFjay4AAAAADkNhbGxiYWNrRmFpbGVkAAAAAAAJAAAA/WBuZXdfcGF5ZWVgIGlzIGludmFsaWQ6IGl0IGlzIGVpdGhlciB0aGUgY29udHJhY3QncyBvd24gYWRkcmVzcwpvciB0aGUgcGF5ZXIncyBhZGRyZXNzLiBUaGUgY29udHJhY3QgYWRkcmVzcyBjYW4gbmV2ZXIgc2lnbiB0bwphY2NlcHQgYSBwYXlvdXQ7IHRoZSBwYXllciBpcyBleGNsdWRlZCBzbyBhIHBheWVyIGNhbm5vdCByZWRpcmVjdAp0aGUgcmVsZWFzZSBkZXN0aW5hdGlvbiB0byB0aGVtc2VsdmVzIHZpYSBhIGNvbGx1ZGluZyBwYXllZS4AAAAAAAAPSW52YWxpZE5ld1BheWVlAAAAACUAAAAAAAAACE92ZXJmbG93AAAADAAAAGxUaGUgcmVsZWFzZXIgc2V0IGlzIGVtcHR5LCBvciBgdGhyZXNob2xkYCBpcyAwIG9yIGxhcmdlciB0aGFuIHRoZQpudW1iZXIgb2YgcmVsZWFzZXJzIOKAlCBzZWUgZG9jcy9hZHIvMDAwNy4AAAAQSW52YWxpZFRocmVzaG9sZAAAAA0AAABDTW9yZSB0aGFuIGBNQVhfUkVMRUFTRVJTYCAoMTApIGFkZHJlc3NlcyB3ZXJlIHN1cHBsaWVkIGF0IGNyZWF0aW9uLgAAAAAQVG9vTWFueVJlbGVhc2VycwAAAA4AAACfRmV3ZXIgZGlzdGluY3QgYXBwcm92YWxzIHdlcmUgc3VwcGxpZWQgdGhhbiB0aGUgZXNjcm93J3MgdGhyZXNob2xkLApvciBhIHNpbmdsZSByZWxlYXNlciB0cmllZCB0byBzZXR0bGUgYSBxdW9ydW0gZXNjcm93IHRocm91Z2ggdGhlCnNpbmdsZS1jYWxsZXIgZW50cnkgcG9pbnQuAAAAAA9UaHJlc2hvbGROb3RNZXQAAAAADwAAAGhUaGUgc2FtZSBhZGRyZXNzIGFwcGVhcmVkIHR3aWNlIGluIG9uZSBhcHByb3ZhbCBsaXN0LiBEdXBsaWNhdGVzCm5ldmVyIGNvdW50IHR3aWNlIHRvd2FyZCB0aGUgdGhyZXNob2xkLgAAABFEdXBsaWNhdGVBcHByb3ZlcgAAAAAAABAAAABAVGhlIHNhbWUgYWRkcmVzcyBhcHBlYXJlZCB0d2ljZSBpbiB0aGUgcmVsZWFzZXIgc2V0IGF0IGNyZWF0aW9uLgAAABFEdXBsaWNhdGVSZWxlYXNlcgAAAAAAABEAAAAAAAAAEkFjY2VwdGFuY2VSZXF1aXJlZAAAAAAAEgAAAAAAAAAXQWNjZXB0YW5jZU5vdENvbmZpZ3VyZWQAAAAAEwAAAAAAAAAPQWxyZWFkeUFjY2VwdGVkAAAAABQAAAA4VGhlIG5ldyByZWxlYXNlciBjYW5ub3QgYmUgdGhlIGVzY3JvdyBjb250cmFjdCBvciBwYXllZS4AAAAPSW52YWxpZFJlbGVhc2VyAAAAABgAAAB8YHJlZnVuZF90b2Agd2FzIHRoZSBlc2Nyb3cgY29udHJhY3QncyBvd24gYWRkcmVzcyDigJQgZnVuZHMgc2VudAp0aGVyZSBvbiByZWZ1bmQgY291bGQgbmV2ZXIgYmUgbW92ZWQgYWdhaW4gKGRvY3MvYWRyLzAwMDkpLgAAAA9JbnZhbGlkUmVmdW5kVG8AAAAAFQAAAERUaGUgY29uZmlndXJlZCByZWxlYXNlIHRpbWUgaXMgaW4gdGhlIHBhc3Qgb3IgYWZ0ZXIgdGhlIHJlZnVuZCB0aW1lLgAAABdJbnZhbGlkUmVsZWFzZU5vdEJlZm9yZQAAAAAWAAAAMVJlbGVhc2Ugd2FzIGF0dGVtcHRlZCBiZWZvcmUgdGhlIGNvbmZpZ3VyZWQgdGltZS4AAAAAAAAPUmVsZWFzZVRvb0Vhcmx5AAAAABcAAACtQSBiYXRjaCBjYWxsIHdhcyBwYXNzZWQgbW9yZSB0aGFuIGBNQVhfQkFUQ0hfU0laRWAgaXRlbXMg4oCUIHNlZQpkb2NzL2Fkci8wMDA1LiBDYWxsZXJzIG11c3QgY2h1bmsuIEFwcGVuZGVkIGF0IHRoZSBlbmQgc28gZXhpc3RpbmcKZGlzY3JpbWluYW50cyBrZWVwIHRoZWlyIG9uLWNoYWluIHZhbHVlcy4AAAAAAAANQmF0Y2hUb29MYXJnZQAAAAAAABkAAACIYGNvbnRyaWJ1dGVgL2BjbGFpbV9yZWZ1bmRgL2BnZXRfY29udHJpYnV0aW9uYCBvbiBhIG5vbi1wb29sZWQKZXNjcm93LCBvciBgZ2V0X3Bvb2xlZGAgb24gYSBub24tcG9vbGVkL3Vua25vd24gaWQg4oCUIHNlZQpkb2NzL2Fkci8wMDExLgAAAAlOb3RQb29sZWQAAAAAAAAaAAAAv0EgY29udHJpYnV0aW9uIGFycml2ZWQgYWZ0ZXIgdGhlIHBvb2xlZCBlc2Nyb3cncyBmdW5kaW5nIGRlYWRsaW5lLgpMYXRlIGNvbnRyaWJ1dGlvbnMgY2FuIG5ldmVyIGJlIGFjY2VwdGVkOiB0aGUgcm91bmQncyBvdXRjb21lCihyZWxlYXNlIHZzIHBlci1jb250cmlidXRvciByZWZ1bmRzKSBpcyBmaXhlZCBhdCB0aGUgZGVhZGxpbmUuAAAAABVGdW5kaW5nRGVhZGxpbmVQYXNzZWQAAAAAAAAbAAAAv0EgY29udHJpYnV0aW9uIHdvdWxkIHB1c2ggdGhlIHBvb2xlZCB0b3RhbCBwYXN0IHRoZSBmdW5kaW5nIHRhcmdldAoob3ZlcmZ1bmRpbmcgaXMgcmVqZWN0ZWQsIG5vdCBhY2NlcHRlZCksIHRoZSB0YXJnZXQgaXMgYWxyZWFkeSBtZXQsCm9yIGEgcmVmdW5kIHdhcyBjbGFpbWVkIG9uIGEgZnVsbHkgZnVuZGVkIHBvb2xlZCBlc2Nyb3cuAAAAABRGdW5kaW5nVGFyZ2V0UmVhY2hlZAAAABwAAAB0YHJlbGVhc2VgIG9uIGEgcG9vbGVkIGVzY3JvdyB3aG9zZSBmdW5kZWQgdG90YWwgaXMgYmVsb3cgdGhlCmZ1bmRpbmcgdGFyZ2V0IOKAlCBwYXJ0aWFsIGZ1bmRpbmcgaXMgbmV2ZXIgcmVsZWFzYWJsZS4AAAARRnVuZGluZ0luY29tcGxldGUAAAAAAAAdAAAAhmBjbGFpbV9yZWZ1bmRgIGJlZm9yZSB0aGUgZnVuZGluZyBkZWFkbGluZSBwYXNzZWQgb24gYSByb3VuZCB0aGF0CmlzIHN0aWxsIChvciBub3cgZnVsbHkpIGZ1bmRlZC4gQ2xhaW1zIG9wZW4gb25seSBmb3IgYSBmYWlsZWQgcm91bmQuAAAAAAANUmVmdW5kTm90T3BlbgAAAAAAAB4AAAAzVGhlIHNhbWUgY29udHJpYnV0b3IgdHJpZWQgdG8gY2xhaW0gYSByZWZ1bmQgdHdpY2UuAAAAAA9BbHJlYWR5UmVmdW5kZWQAAAAAHwAAADtgY2xhaW1fcmVmdW5kYCBieSBhbiBhZGRyZXNzIHdpdGggbm8gcmVjb3JkZWQgY29udHJpYnV0aW9uLgAAAAAOTm9Db250cmlidXRpb24AAAAAACAAAADzYHJlZnVuZGAvYHJlZnVuZF93aXRoX2FwcHJvdmFsc2AvYGNhbmNlbGAvYHRvcF91cGAgb24gYSBwb29sZWQKZXNjcm93OiBwdXNoaW5nIHRoZSB3aG9sZSBwb29sZWQgdG90YWwgdG8gb25lIGFkZHJlc3Mgd291bGQgdmlvbGF0ZQpwZXItY29udHJpYnV0b3IgYWNjb3VudGluZy4gUG9vbGVkIHJlZnVuZHMgYXJlIHB1bGwtYmFzZWQKKGBjbGFpbV9yZWZ1bmRgKTsgcG9vbGVkIGZ1bmRpbmcgaXMgYGNvbnRyaWJ1dGVgLW9ubHkuAAAAABVOb3RTdXBwb3J0ZWRGb3JQb29sZWQAAAAAAAAhAAAAQFRoZSBmdW5kaW5nIGRlYWRsaW5lIHdhcyBub3Qgc3RyaWN0bHkgaW4gdGhlIGZ1dHVyZSBhdCBjcmVhdGlvbi4AAAAWSW52YWxpZEZ1bmRpbmdEZWFkbGluZQAAAAAAIgAAANJUaGUgb3B0aW9uYWwgcHJvdG9jb2wgZmVlIHdhcyBtaXNjb25maWd1cmVkIGF0IGNyZWF0aW9uOiBgYnBzYAphYm92ZSBbYE1BWF9GRUVfQlBTYF0gKDEwICUpLCBhIHJlY2lwaWVudCBlcXVhbCB0byB0aGUgZXNjcm93CmNvbnRyYWN0IGl0c2VsZiwgb3IgYW4gYW1vdW50IHRoYXQgd291bGQgb3ZlcmZsb3cgdGhlIGZlZSBtYXRoIOKAlApzZWUgZG9jcy9hZHIvMDAxMC4AAAAAAApJbnZhbGlkRmVlAAAAAAAjAAAAa0FuIG91dGJvdW5kIHJlbGVhc2UgdHJhbnNmZXIgZmFpbGVkOyB0aGUgZnVuZGVkIGVzY3JvdyByZW1haW5zCnJldHJ5YWJsZSBhbmQgbWF5IHN0aWxsIHVzZSBpdHMgcmVmdW5kIHBhdGguAAAAAA1VbmRlbGl2ZXJhYmxlAAAAAAAAJAAAAFBBIGRlcG9zaXQgcGF0aCB3YXMgY2FsbGVkIHdoaWxlIHRoZSBlbWVyZ2VuY3kgcGF1c2UgaXMgb24g4oCUIHNlZQpkb2NzL2Fkci8wMDExLgAAAAZQYXVzZWQAAAAAACYAAABdYHBhdXNlYCBvbiBhbiBhbHJlYWR5LXBhdXNlZCBjb250cmFjdC4gVGhlIHRyYW5zaXRpb24gZGlkIG5vdApoYXBwZW4sIHNvIG5vIGV2ZW50IGlzIGVtaXR0ZWQuAAAAAAAADUFscmVhZHlQYXVzZWQAAAAAAAAnAAAAV2B1bnBhdXNlYCBvbiBhIHJ1bm5pbmcgY29udHJhY3QuIFRoZSB0cmFuc2l0aW9uIGRpZCBub3QgaGFwcGVuLCBzbwpubyBldmVudCBpcyBlbWl0dGVkLgAAAAAJTm90UGF1c2VkAAAAAAAAKA==", "AAAABQAAAIhFbWl0dGVkIGJ5IGBwYXVzZWAgKGRvY3MvYWRyLzAwMTEpLiBDYXJyaWVzIHRoZSBjdXN0b2RpYW4gdGhhdCBmbGlwcGVkCnRoZSBmbGFnIHNvIGludGVncmF0b3JzIGFuZCBtb25pdG9yaW5nIGNhbiByZWFjdCB3aXRob3V0IHBvbGxpbmcuAAAAAAAAAAZQYXVzZWQAAAAAAAEAAAAGcGF1c2VkAAAAAAABAAAAAAAAAAVhZG1pbgAAAAAAABMAAAABAAAAAg==", "AAAABQAAACVFbWl0dGVkIGJ5IGB1bnBhdXNlYCAoZG9jcy9hZHIvMDAxMSkuAAAAAAAAAAAAAAhVbnBhdXNlZAAAAAEAAAAIdW5wYXVzZWQAAAABAAAAAAAAAAVhZG1pbgAAAAAAABMAAAABAAAAAg==", "AAAAAQAAAHJPbmUgZW50cnkgb2YgYSBgY3JlYXRlX2VzY3Jvd3NgIGJhdGNoLiBNaXJyb3JzIHRoZSBzaW5nbGUtZXNjcm93CmNyZWF0aW9uIHBhcmFtZXRlcnMgbWludXMgdGhlIGJhdGNoLXdpZGUgYHBheWVyYC4AAAAAAAAAAAAKQ3JlYXRlSXRlbQAAAAAABgAAAAAAAAAGYW1vdW50AAAAAAALAAAAAAAAAA1jb25kaXRpb25fcmVmAAAAAAAAEAAAAAAAAAAFcGF5ZWUAAAAAAAATAAAAAAAAAAxyZWZ1bmRfYWZ0ZXIAAAPoAAAABgAAAAAAAAAIcmVsZWFzZXIAAAATAAAAAAAAAAV0b2tlbgAAAAAAABM=",