Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 19 additions & 8 deletions Browser~/blockmaker-txnlab-wallet.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -75882,17 +75882,20 @@ function E6(e) {
icon: t.metadata.icon,
providerId: r,
networkGenesisId: o6
}), o = null, s = !1, c = null, l = async (e) => {
}), o = null, s = null, c = null, l = async (e) => {
if (C6(t), s) throw Error(`A signing request is already waiting in ${n}.`);
if (r === l6 && !t.web3auth?.connected) {
let e = /* @__PURE__ */ Error("Your email wallet session expired. Sign out and sign in again before reviewing another transaction.");
throw Object.assign(e, { code: "SESSION_EXPIRED" }), e;
}
s = !0;
let i, a = new Promise((e, t) => {
i = t;
}), o = { cancel: () => i(Object.assign(/* @__PURE__ */ Error("The player cancelled the wallet request."), { code: "PLAYER_CANCELLED" })) };
s = o;
try {
return await e();
return await Promise.race([e(), a]);
} finally {
s = !1;
s === o && (s = null);
}
};
return Object.freeze({
Expand All @@ -75902,8 +75905,10 @@ function E6(e) {
networkGenesisId: o6,
...r === u6 || r === l6 ? { beginUnityPresentation: (e) => {
if (c) throw Error("A Unity wallet presentation is already active.");
let n = r === u6 ? m(t, e) : p(t, e), i = n.dispose;
return n.dispose = () => {
let n = r === u6 ? m(t, e) : p(t, e), i = n.dispose, a = n.cancel;
return n.cancel = async () => {
s?.cancel(), await a();
}, n.dispose = () => {
i(), c === n && (c = null);
}, c = n, n;
} } : {},
Expand All @@ -75917,7 +75922,9 @@ function E6(e) {
o = null;
}), o)),
resumeSession: async () => (C6(t), await t.resumeSession(), C6(t), S6(t)),
disconnect: () => t.disconnect(),
disconnect: async () => {
s?.cancel(), await t.disconnect();
},
signTransactions: (e, n) => l(() => t.signTransactions(T6(e, i), n?.slice())),
transactionSigner: (e, n) => l(async () => (await t.signTransactions(T6(e, i), n.slice())).reduce((e, t) => (t !== null && e.push(t), e), [])),
canSignData: t.canSignData,
Expand Down Expand Up @@ -76004,7 +76011,11 @@ async function O6(e) {
algorandWallets: m,
algosdk: i,
resumeError: u,
disconnectAll: () => e.exposeExternalWallets ? o.disconnect() : s.disconnect()
disconnectAll: async () => {
let t = (await Promise.allSettled(m.filter((e) => (e.wallet.accounts?.length ?? 0) > 0).map((e) => e.wallet.disconnect()))).find((e) => e.status === "rejected");
if (t?.status === "rejected") throw t.reason;
e.exposeExternalWallets && await o.disconnect();
}
});
}
async function k6(e) {
Expand Down
25 changes: 15 additions & 10 deletions Browser~/blockmaker.js
Original file line number Diff line number Diff line change
Expand Up @@ -2611,7 +2611,7 @@ export function createBlockmaker(options = {}) {
}

const completePreparedAlgorandWalletLogin = prepared => {
if (!preparedAlgorandWalletLogins.has(prepared)) {
if (!preparedAlgorandWalletLogins.has(prepared) || prepared.attemptId !== loginAttemptSequence) {
return Promise.reject(new BlockmakerError('This wallet sign-in approval is no longer current.', {
code: 'AUTH_SUPERSEDED',
}))
Expand All @@ -2629,6 +2629,8 @@ export function createBlockmaker(options = {}) {
return Promise.reject(error)
}
return Promise.resolve(signing).then(async signed => {
if (prepared.attemptId !== loginAttemptSequence)
throw new BlockmakerError('This wallet sign-in was cancelled.', { code: 'AUTH_SUPERSEDED' })
const signedTxn = Array.isArray(signed)
? signed.find(value => value instanceof Uint8Array && value.byteLength > 0)
: null
Expand Down Expand Up @@ -8387,34 +8389,37 @@ export function createBlockmaker(options = {}) {

const logoutUnitySession = async value => {
requireUnityWalletCleanupIdle()
const target = packageSession(value)
const target = value == null ? null : packageSession(value)
if (!target && (activeOpen || pendingHandoff || session || acknowledgedUnitySigner || preparedTransactionGroup))
throw new BlockmakerError('Finish cancelling the current request before disconnecting.', { code: 'REQUEST_ALREADY_PENDING' })
beginUnityWalletCleanup()
try {
await rawRequest('/v1/auth/logout', {
if (target) await rawRequest('/v1/auth/logout', {
method: 'POST', auth: false, keepalive: true,
body: { refreshToken: target.refreshToken, gameId },
})
await walletSetup.disconnectAll()
} catch (error) {
if (session?.refreshToken === target.refreshToken) storeSession(null)
if (pendingHandoff?.refreshToken === target.refreshToken) {
if (session?.refreshToken === target?.refreshToken) storeSession(null)
if (pendingHandoff?.refreshToken === target?.refreshToken) {
pendingHandoff = null
clearPendingHandoffPageHide()
}
if (rememberedAlgorandSigner?.walletAddress === target.walletAddress)
if (rememberedAlgorandSigner?.walletAddress === target?.walletAddress)
rememberedAlgorandSigner = null
latchUnityWalletPackageCleanup()
throw error
}
confirmUnityWalletCleanup()
if (session?.refreshToken === target.refreshToken) storeSession(null)
if (pendingHandoff?.refreshToken === target.refreshToken) {
invalidateLoginAttempts()
if (session?.refreshToken === target?.refreshToken) storeSession(null)
if (pendingHandoff?.refreshToken === target?.refreshToken) {
pendingHandoff = null
clearPendingHandoffPageHide()
}
if (rememberedAlgorandSigner?.walletAddress === target.walletAddress)
if (rememberedAlgorandSigner?.walletAddress === target?.walletAddress)
rememberedAlgorandSigner = null
if (acknowledgedUnitySigner?.walletAddress === target.walletAddress)
if (acknowledgedUnitySigner?.walletAddress === target?.walletAddress)
acknowledgedUnitySigner = null
if (preparedTransactionGroup) {
if (preparedTransactionGroup.state === 'signing') preparedTransactionGroup.state = 'abandoned'
Expand Down
9 changes: 9 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,14 @@
# Changelog

## [2.0.1] - 2026-09-17

- Email-first sign-in, a Wallet submenu, and Pera with its original reusable logo.
- Configurable labels and logo; browsing/back/cancel keeps the existing wallet manager.
- Cancel incomplete sign-in and disconnect remembered connections with Use another account.
- Retain exact session revocation and discard late cancelled approvals.
- Keep Cancel and account switching visible on short screens. Size the demo
using the canvas's visible dimensions, including high-DPI and phone screens.

## [2.0.0] - 2026-09-16

- Make the current WebGL Pera/optional email SDK the root Unity Package Manager
Expand Down
21 changes: 20 additions & 1 deletion Documentation~/integration.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ These are integration fragments; the complete working component is
keep the receiving GameObject's name unique, and dispose the view at teardown.
`RuntimeSupported` lets the game show a friendly message in Editor/native builds.
A blank public email client ID selects `pera_lute`; a configured ID selects
`pera_lute_txnlab_web3auth`. The Unity presentation shows Pera and optional email;
`pera_lute_txnlab_web3auth`. The Unity presentation shows Email first when enabled, then Wallet → Pera;
`OpenAccount` is available for the broader account UI. The older
`web3auth_avm_email` authentication-only broker is separate and remains restricted.

Expand Down Expand Up @@ -105,3 +105,22 @@ this package locally without claiming provider or game qualification.
Commit scene/template changes and Unity metadata. Use complete tagged releases,
not individual vendor-file patches. Required setup and attended acceptance remain
in [email setup](email-setup.md) and [validation](validation.md).

The original Pera logo is bundled in the shared presentation. Set `PeraLogo` in
`BlockmakerUnityWalletAppearance` to provide your own texture, or call
`BlockmakerUnityWalletIcons.CreatePeraLogo()` for a caller-owned copy. Destroy
that texture when finished. Pera branding remains its owner's mark.

Use **Use another account** in the chooser to cancel sign-in and disconnect a
remembered connection, then choose Email or Wallet again. `Logout` also handles
remembered connections when no game session has been acknowledged. Wait for its
confirmed result; retain your game's economic recovery records when changing accounts.

## Phone and high-DPI layout

The demo clones its panel settings at runtime and sizes the UI in visible canvas
pixels. Your authored settings remain intact. In a custom integration, supply a
full-screen UI Toolkit root with the same visible-pixel sizing; a gameplay panel
scaled from a 1920×1080 design can make wallet controls too small on phones.
The wallet view keeps Cancel and account switching outside its scrolling area.
Use a short landscape phone viewport when checking your integration.
7 changes: 4 additions & 3 deletions Documentation~/upgrading.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,16 +14,17 @@ current installation route.
the client, wallet facade and presentation shown in the [integration guide](integration.md).
Remove obsolete scene objects after wiring their replacements. Existing API
callers will need changes; the package does not rewrite gameplay code.
3. Install `https://github.com/blockmaker-ai/blockmaker-unity.git#v2.0.0` through
3. Follow the [current installation instructions](../README.md) in
Package Manager. Keep one wallet manager. Old Reown/Nethereum dependencies can
be removed through Package Manager only if no other project code uses them.
4. Confirm the same owner wallet/profile, cancellation and pending-operation
recovery before resuming live game actions.

## From the September Assets/ZIP package

The nine wallet runtime files are unchanged. The new package manages their paths
and WebGL build inclusion. Close Unity and back up the complete existing SDK
The version 2 package manages the nine wallet runtime files and their WebGL
build inclusion. The local 2.0.1 candidate changes only the presentation file;
the other eight runtime files retain their 2.0.0 contents. Close Unity and back up the complete existing SDK
files and their `.meta` files outside Assets before removing their old copies
from compilation. Preserve your own game UI, configuration and recovery data.

Expand Down
94 changes: 39 additions & 55 deletions Documentation~/validation.md
Original file line number Diff line number Diff line change
@@ -1,58 +1,42 @@
# Validation — Unity Package Manager SDK 2.0.0

The package contains canonical wallet runtime
`unity-webgl-package-sha256-cicBnjQf1cPzH5Sz3Gt7wX8seHXG9Cj1VTf6eRIAFlQ`, from
runtime revision `226bd9136b268cd1c7005efdb3bccf23be50e607`. All nine runtime files
are unchanged from the package used by NFTURBO build `20260915-6f70eb687b39`.
Version 2.0.0 describes the public UPM distribution and setup tools; the canonical
runtime manifest retains backend release version `0.2.5`.

## Checked for this distribution

- The root package resolves from its public Git revision in Unity 6000.3.15f1
using Unity Package Manager. It compiles without Reown or separately installed
wallet dependencies. The imported sample scene retains its document, panel,
theme and camera references, with no game ID or email client ID prefilled.
- The setup menu creates a scene with a UI document, panel, camera and wallet
demo. Repeating setup does not create a second demo. The `.jslib` plugin is
enabled for WebGL and disabled for Editor.
- A small actual WebGL build succeeded with zero errors. Its five browser files
match the canonical hashes, and no vendor copies were written into the
project's Assets/StreamingAssets folder. The full NFTURBO game was not rebuilt.
- A headless browser loaded the demo and all three executable wallet modules
from the built StreamingAssets with HTTP 200. The fullscreen template entered
document-root fullscreen; Pera's in-game QR and cancellation were checked.
- Five focused checks cover package/dependency layout, the full canonical
runtime hashes, Unity metadata/plugin settings, removal of the old active
runtime, documentation links and sample/template presence.

The same unchanged core previously completed NFTURBO's desktop, ASTC and ETC2
builds and focused authentication/session/recovery-boundary tests. Its email
form opening/focus, close/retry and fullscreen behavior were checked in that
integration. These earlier checks do not prove every game or device works.

## Still requires attended player testing

Actual email/OTP and Pera wallet approval, C# acknowledgment after a real login,
returning login/recovery and stable identity across two actual game origins
remain player acceptance checks. The packaging test did not enter an email or
create a wallet. Opening a provider form is not proof of a completed login.

No live transaction was signed or submitted for this release. Shop delivery,
ASA opt-ins, Garage groups, Loadout ownership and Marketplace operations need
their own game-specific acceptance under existing backend policy. The sample
makes no economic requests. Preserve ambiguous-operation recovery and never
retry a submission automatically.

Physical mobile devices, provider popups and the complete verification/recovery
screens still need checks. The package supports Unity WebGL only; native exports
and unrelated email-provider configurations have not been implemented here.
# Validation — Unity Package Manager SDK 2.0.1

Canonical runtime: `unity-webgl-package-sha256-ABEU4Xw6yrr_x5QxD0RBoncEqP2IStnSSnbbfQhI-5k`.
Source revision: `4e56ec769561f54b561cea28a181995883e3983d`.
The UPM distribution is version 2.0.1; the canonical manifest retains backend
release version 0.2.5. The complete nine-file runtime is included unchanged.

## Checks

- Thirty-four existing canonical package/manifest checks passed.
- Nineteen Unity UI checks passed: email-first choices, Pera logo, Back,
cancellation once, Pera-only configuration and duplicate-open protection.
- The dialogs were rendered at desktop, tablet, phone landscape and phone
portrait sizes. Cancel and account switching remain outside scrolling content.
- The package distribution checks verify runtime hashes, Unity GUIDs, plugin
platforms, dependencies, installer, sample, template and documentation links.

- A minimal Unity 6000.3.15f1 WebGL consumer built with zero errors and warnings.
- The actual demo loaded all three wallet modules with HTTP 200. At a desktop
size and an 844×390 phone viewport with a 1688×780 render target, its controls
stayed readable. Pera QR, Cancel, reopening and Use another account worked;
document-root fullscreen remained active throughout those wallet actions.

These checks cover the shared component and demo. They do not establish a
completed wallet login or transaction in a consuming game.

## Player checks still needed

The NFTURBO owner reported successful email login on 16 September 2026 using the
previous presentation. Automated checks did not enter an email, OTP or recovery
material and did not sign or submit a live transaction.

Returning login/recovery, identity across actual game origins, physical mobile
browsers and each game's economic operations require attended checks. The demo
reads profiles and makes no economic requests. Native exports are unsupported.

## Recheck locally

Use **Blockmaker → Verify Installed Package** in Unity to check the nine runtime
hashes. Build with the included template and inspect its StreamingAssets output.
For contributors, `node --test 'Tools~/package.test.mjs'` runs the lightweight
packaging checks; Node.js is not required to install or use the SDK in Unity.
Installation and file verification do not activate a provider, qualify a game or
prove completed wallet/economic flows.
Use **Blockmaker → Verify Installed Package** for the nine runtime hashes.
Build using the included WebGL template. For contributors, run
`node --test 'Tools~/package.test.mjs'`; Node.js is not needed to install or use
the SDK through Unity Package Manager.
2 changes: 1 addition & 1 deletion Editor/BlockmakerWebGLBuild.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ namespace Blockmaker.Editor
/// <summary>Adds the package's exact browser payload without modifying Assets.</summary>
public sealed class BlockmakerWebGLBuild : BuildPlayerProcessor
{
public const string CanonicalPackageId = "unity-webgl-package-sha256-cicBnjQf1cPzH5Sz3Gt7wX8seHXG9Cj1VTf6eRIAFlQ";
public const string CanonicalPackageId = "unity-webgl-package-sha256-ABEU4Xw6yrr_x5QxD0RBoncEqP2IStnSSnbbfQhI-5k";
public override int callbackOrder => 0;
private static readonly Dictionary<string, string> Paths = new Dictionary<string, string> {
{ "BlockmakerClient.cs", "Runtime/BlockmakerClient.cs" },
Expand Down
2 changes: 1 addition & 1 deletion Installer~/BlockmakerInstaller.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
[InitializeOnLoad]
public static class BlockmakerInstaller
{
private const string PackageUrl = "https://github.com/blockmaker-ai/blockmaker-unity.git#v2.0.0";
private const string PackageUrl = "https://github.com/blockmaker-ai/blockmaker-unity.git#v2.0.1";
private static AddRequest request;
static BlockmakerInstaller()
{
Expand Down
11 changes: 11 additions & 0 deletions Plugins/WebGL/BlockmakerDemoViewport.jslib
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
// Demo layout only. No wallet state or private material crosses this boundary.
mergeInto(LibraryManager.library, {
BlockmakerDemoViewportWidth: function () {
var box = Module.canvas && Module.canvas.getBoundingClientRect();
return Math.max(1, Math.round(box && box.width || window.innerWidth));
},
BlockmakerDemoViewportHeight: function () {
var box = Module.canvas && Module.canvas.getBoundingClientRect();
return Math.max(1, Math.round(box && box.height || window.innerHeight));
}
});
32 changes: 32 additions & 0 deletions Plugins/WebGL/BlockmakerDemoViewport.jslib.meta

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading
Loading