Description:
Smart contract deployed on Ethereum.
Blockchain: Ethereum
Source Code: View Code On The Blockchain
Solidity Source Code:
// ░█░█░█▀█░█▀▀░█▀█░█▀█░█░█░█▀▀░█▀█
// ░█░█░█░█░▀▀█░█▀▀░█░█░█▀▄░█▀▀░█░█
// ░▀▀▀░▀░▀░▀▀▀░▀░░░▀▀▀░▀░▀░▀▀▀░▀░▀
//
// SPDX-License-Identifier: MIT
// Copyright Han, 2025
pragma solidity ^0.8.25;
contract Unspoken {
event ArtpieceCreated(address indexed creator);
event ArtpieceTransferred(address indexed oldOwner, address indexed newOwner);
event BidAccepted(uint256 value, address indexed fromAddress, address indexed toAddress);
event BidPlaced(uint256 value, address indexed fromAddress);
event BidWithdrawn(uint256 value, address indexed fromAddress);
event ListedForSale(uint256 value, address indexed fromAddress, address indexed toAddress);
event SaleCanceled(uint256 value, address indexed fromAddress, address indexed toAddress);
event SaleCompleted(uint256 value, address indexed fromAddress, address indexed toAddress);
error FundsTransfer();
error InsufficientFunds();
error ListedForSaleToSpecificAddress();
error NoBid();
error NotForSale();
error NotOwner();
error NotRoyaltyRecipient();
error NotYourBid();
error NullAddress();
error RoyaltyTooHigh();
string public constant MANIFEST = (
'Between words.' '
'
);
string public constant CORE = (
'"use strict";const credits="wwwtyro sphere intersect",pr=Math.min(window.devicePixelRatio,1.5);let s={signature:"data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjE2IiBoZWlnaHQ9IjIxNiIgdmlld0JveD0iMCAwIDIxNiAyMTYiIGZpbGw9Im5vbmUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CjxwYXRoIGQ9Ik0xMjQuOTUyIDEwNy4wMzJDMTI0Ljk1MiAxMTYuMzkzIDExNy4zNjMgMTIzLjk4MiAxMDguMDAxIDEyMy45ODJDOTguNjM5OSAxMjMuOTgyIDkxLjA1MDggMTE2LjM5MyA5MS4wNTA4IDEwNy4wMzJDOTEuMDUwOCA5Ny42NzAxIDk4LjYzOTkgOTAuMDgxMSAxMDguMDAxIDkwLjA4MTFDMTE3LjM2MyA5MC4wODExIDEyNC45NTIgOTcuNjcwMSAxMjQuOTUyIDEwNy4wMzJaIiBmaWxsPSJ3aGl0ZSIvPgo8cGF0aCBkPSJNMTIxLjA3NCAyMDIuOTI0QzEyMS4wNzQgMjEwLjE0NiAxMTUuMjIgMjE2IDEwNy45OTggMjE2QzEwMC43NzYgMjE2IDk0LjkyMTkgMjEwLjE0NiA5NC45MjE5IDIwMi45MjRDOTQuOTIxOSAxOTUuNzAyIDEwMC43NzYgMTg5Ljg0OCAxMDcuOTk4IDE4OS44NDhDMTE1LjIyIDE4OS44NDggMTIxLjA3NCAxOTUuNzAyIDEyMS4wNzQgMjAyLjkyNFoiIGZpbGw9IndoaXRlIi8+CjxwYXRoIGQ9Ik0xMjEuMDc0IDEzLjA3NjJDMTIxLjA3NCAyMC4yOTggMTE1LjIyIDI2LjE1MjUgMTA3Ljk5OCAyNi4xNTI1QzEwMC43NzYgMjYuMTUyNSA5NC45MjE5IDIwLjI5OCA5NC45MjE5IDEzLjA3NjJDOTQuOTIxOSA1Ljg1NDQzIDEwMC43NzYgMCAxMDcuOTk4IDBDMTE1LjIyIDAgMTIxLjA3NCA1Ljg1NDQzIDEyMS4wNzQgMTMuMDc2MloiIGZpbGw9IndoaXRlIi8+CjxwYXRoIGQ9Ik0yMTYgMTA4QzIxNiAxMTUuMjIyIDIxMC4xNDYgMTIxLjA3NiAyMDIuOTI0IDEyMS4wNzZDMTk1LjcwMiAxMjEuMDc2IDE4OS44NDggMTE1LjIyMiAxODkuODQ4IDEwOEMxODkuODQ4IDEwMC43NzggMTk1LjcwMiA5NC45MjM4IDIwMi45MjQgOTQuOTIzOEMyMTAuMTQ2IDk0LjkyMzggMjE2IDEwMC43NzggMjE2IDEwOFoiIGZpbGw9IndoaXRlIi8+CjxwYXRoIGQ9Ik0yNi4xNTI1IDEwOEMyNi4xNTI1IDExNS4yMjIgMjAuMjk4IDEyMS4wNzYgMTMuMDc2MiAxMjEuMDc2QzUuODU0NDMgMTIxLjA3NiAwIDExNS4yMjIgMCAxMDhDMCAxMDAuNzc4IDUuODU0NDMgOTQuOTIzOCAxMy4wNzYyIDk0LjkyMzhDMjAuMjk4IDk0LjkyMzggMjYuMTUyNSAxMDAuNzc4IDI2LjE1MjUgMTA4WiIgZmlsbD0id2hpdGUiLz4KPC9zdmc+Cg==",mouse_sensitivity:1,mouse_limit:0,color_offset_frames:60,frame:0,res:[0,0],save_frames:0},h={newline:String.fromCharCode(10),parser:new URL(window.location)};const mobile=/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent);let w=window,d=document,b=d.body;d.body.style.touchAction="none",d.body.style.userSelect="none";let c=d.createElement("canvas");c.style.display="block",b.appendChild(c);const image=d.createElement("img");image.src=s.signature.trim(),image.style.cssText="width:40px;z-index:50;position:fixed;bottom:20px;right:20px;",b.appendChild(image);const glOptions={powerPreference:"high-performance"};mobile&&delete glOptions.powerPreference,w.gl=c.getContext("webgl2",glOptions),h.uniform1i=(e,t)=>h.uniform(e,t,"uniform1i"),h.uniform=(e,t,r)=>{s.uniforms||={};(s.uniforms[e]||=(()=>{const i=gl.getUniformLocation(s.current_program,e),o=r||(Array.isArray(t)?"uniform2fv":"uniform1f");return{update:e=>gl[o](i,e)}})()).update(t)},h.resize=()=>{let e,t,r,i=h.ix.mouse.x/s.res[0],o=h.ix.mouse.y/s.res[1];const a=h.parser.searchParams.get("res",t);a?(e=t=a,r=1):(e=w.innerWidth,t=w.innerHeight,s.aspect&&(e>t*s.aspect?e=t*s.aspect:t=e/s.aspect),r=pr),s.res[0]=c.width=e*r,s.res[1]=c.height=t*r,c.style.width=e+"px",c.style.height=t+"px",h.ix.set(c.width*i,c.height*o)},h.ix={start:{x:0,y:0},mouse:{x:0,y:0}},h.ix.set=(e,t)=>{h.ix.mouse={x:e,y:t}},h.ix.start=e=>{h.ix.start.x=e.clientX,h.ix.start.y=e.clientY,d.addEventListener("pointermove",h.ix.move)},h.clamp=(e,t,r)=>Math.max(t,Math.min(r,e)),h.ix.move=e=>{h.ix.mouse.x+=(e.clientX-h.ix.start.x)*pr*s.mouse_sensitivity,h.ix.mouse.y-=(e.clientY-h.ix.start.y)*pr*s.mouse_sensitivity,h.ix.start.x=e.clientX,h.ix.start.y=e.clientY,h.ix.mouse.x=h.clamp(h.ix.mouse.x,s.res[0]*s.mouse_limit,s.res[0]*(1-s.mouse_limit)),h.ix.mouse.y=h.clamp(h.ix.mouse.y,s.res[1]*s.mouse_limit,s.res[1]*(1-s.mouse_limit))},h.ix.stop=e=>{d.removeEventListener("pointermove",h.ix.move)},h.save={},h.save.toImage=()=>{const e=new Date;let t=String(e.getFullYear()).slice(2,4)+"-"+e.getMonth()+"-"+e.getDate()+" ("+s.frame+").png",r=document.createElement("a");r.setAttribute("download",t);let i=c.toDataURL("image/png").replace("data:image/png","data:application/octet-stream");r.setAttribute("href",i),r.click(),r.remove()},h.buildShader=(e,t)=>{let r=gl.createShader(e);return gl.shaderSource(r,t),gl.compileShader(r),r},h.initProgram=(e,t,r)=>{const i=gl.createProgram(),o=h.buildShader(gl.VERTEX_SHADER,t),a=h.buildShader(gl.FRAGMENT_SHADER,e);gl.attachShader(i,o),gl.attachShader(i,a),gl.linkProgram(i),gl.getShaderParameter(o,gl.COMPILE_STATUS)||console.error("V: "+gl.getShaderInfoLog(o)),gl.getShaderParameter(a,gl.COMPILE_STATUS)||console.error("F: "+gl.getShaderInfoLog(a)),gl.getProgramParameter(i,gl.LINK_STATUS)||console.error("P: "+gl.getProgramInfoLog(i));let s=gl.createBuffer(),n=gl.getAttribLocation(i,"p");return gl.bindBuffer(gl.ARRAY_BUFFER,s),gl.bufferData(gl.ARRAY_BUFFER,r,gl.STATIC_DRAW),gl.enableVertexAttribArray(n),gl.vertexAttribPointer(n,2,gl.FLOAT,!1,0,0),i},s.pixel=new Uint8Array(4),h.render=()=>{gl.viewport(0,0,c.width,c.height),gl.useProgram(s.program),s.current_program=s.program,h.uniform("u_time",.001*performance.now()),h.uniform("u_resolution",s.res),h.uniform("u_mouse",[h.ix.mouse.x,h.ix.mouse.y]),gl.drawArrays(gl.TRIANGLE_STRIP,0,4),(h.save.queued||s.frame<s.save_frames&&s.frame>3)&&(h.save.queued=!1,h.save.toImage()),s.frame++,requestAnimationFrame(h.render)};const init=async()=>{if(gl){h.resize(),h.ix.set(c.width/2,c.height/2),d.addEventListener("pointerdown",h.ix.start),d.addEventListener("pointerup",h.ix.stop),w.addEventListener("resize",h.resize),s.save_frames=h.parser.searchParams.get("frames")||0,d.addEventListener("keyup",e=>{if(!(e.ctrlKey||e.altKey||e.shiftKey||e.metaKey))switch(e.key){case"f":const e=prompt("Frames to render",s.save_frames);h.parser.searchParams.set("frames",e),window.location=h.parser.href;break;case"r":const t=prompt("Canvas size in pixels (max 8192)",c.height);t>=8&&t<=8192&&(h.parser.searchParams.set("res",t),window.location=h.parser.href);break;case"s":h.save.queued=!0}});let e=Float32Array.of(-1,1,-1,-1,1,1,1,-1);const t="#version 300 es"+h.newline+"precision highp float; in vec2 p; void main(){ gl_Position =vec4(p,1.0,1.0); }";let r="#version 300 es"+h.newline+"#ifdef GL_ES"+h.newline+"precision highp float;"+h.newline+"#endif"+h.newline+"const int AA=2;uniform vec2 u_resolution;uniform float u_time;uniform vec2 u_mouse;const vec3 v=vec3(.901960784313726),f=vec3(.749019607843137),m=vec3(.941176470588235),x=vec3(0,0,-10);"+h.newline+"#define R(a)mat2(cos(a),sin(a),-sin(a),cos(a))"+h.newline+"#define TAU 6.283185307"+h.newline+"#define PI 3.14159"+h.newline+"vec3 u=vec3(0);float A=1.,s=0.;out vec4 fragColor;vec3 n(){vec3 v=gl_FragCoord.xyy,f;v=vec3(dot(v,vec3(127.1,311.7,74.7)),dot(v,vec3(269.5,183.3,246.1)),dot(v,vec3(113.5,271.9,124.6)));f=-1.+2.*fract(sin(v)*43758.5453123);return fract(555.*sin(777.*f))/256.;}float n(float v,float f,float x){return min(-x,max(v,f))+length(max(vec2(v,f)+x,vec2(0)));}float n(float v,float f){return n(v,-v,f);}vec3 n(vec3 v,float f){return vec3(n(v.x,f),n(v.y,f),n(v.z,f));}vec2 n(vec3 v){float f=mix(1.5,3.,sin(u.z*TAU)*.5+.5),x;vec3 A=v;A.xz*=R(TAU*u.z*ceil(6.));A.xz*=R(TAU*(u_mouse/u_resolution).x);A.x=n(A.x,1.25)-f;x=length(A)-1.;return vec2(x,1);}vec3 t(vec3 v){vec2 f=vec2(.002,0);float A=n(v).x;return normalize(vec3(A-n(v-f.xyy).x,A-n(v-f.yxy).x,A-n(v-f.yyx).x));}vec2 t(vec3 v,vec3 f){float A=0.;vec2 u;vec3 x;for(int r=0;r<128;r++){x=v+f*A;u=n(x);if(A>1e2||abs(u.x)<.01)break;A+=u.x;}A=min(A,1e2);return vec2(A,u.y);}float t(vec3 v,vec3 f,vec3 A){float a=u.y*6.*TAU,y,r,s;vec3 i=x,m;i+=vec3(cos(a),-sin(a),0)*10.;m=normalize(i-v);y=pow(1.-dot(f,-A),2.);y*=1.2;y=max(0.,y);r=max(dot(f,m),0.);r*=1.;s=max(dot(reflect(-m,f),-A),0.);s=pow(s,.001)*0.;return r+y+s;}vec4 p(vec2 u,float x){float y;vec3 r=m,a=vec3(0,0,-38.5+0.*s*A),d=normalize(vec3(0)-a),T=normalize(vec3(d.z,0,-d.x)),i;vec2 n=u_mouse/u_resolution,c;n.y=clamp(n.y,0.,1.)*2.-1.;y=n.y;i=normalize(u.x*T+u.y*cross(d,T)+1./tan((.582913588955734+y)*.5)*d);c=t(a,i);if(c.x<1e2){vec3 U=a+i*c.x,z=t(U);r=mix(f,v,t(U,z,i));}return vec4(r,1);}void p(float v,float f,float x){float a=v+11.22,m=smoothstep(0.,1.,sin(v/20.*TAU));u=vec3((a-.1*m*f)/20.,(a-.2*m*f)/20.,a/20.);s=f;A=m;}void main(){vec4 v=vec4(0,0,0,1);vec2 f=gl_FragCoord.xy;float A=.5+.5*sin(f.x*147.)*sin(f.y*131.),s=u_time;for(int a=0;a<AA;a++)for(int x=0;x<AA;x++){vec2 u=vec2(x,a)/float(AA)-.5,r=(gl_FragCoord.xy+u-.5*u_resolution.xy)/min(u_resolution.x,u_resolution.y),d=vec2(floor(1.)),y=mod(d,2.),i=vec2(0);float c=0.,z,T;r*=1.;z=step(abs(r.x),.5)*step(abs(r.y),.5);T=step(1.,.9999);if(z>0.||T>0.){vec2 U=(r+.5*y)*d;r=mix(fract(U)-.5,r,T);r.y*=d.x/d.y;i=floor(U)+1.;c=fract(sin(dot(i,vec2(12.9898,78.233)))*43758.5453);float G=.1*(float(a*AA+x)+A)/float(AA*AA),g=s-G-c;p(g,-1.,c);v.x+=p(r,c).x;p(g,0.,c);v.yw+=p(r,c).yw;p(g,1.,c);v.z+=p(r,c).z;}else v+=vec4(m,1);}v/=float(AA*AA);v.xyz+=n();fragColor=v;}";if(mobile){const e="const int AA = 2";r=r.replace(e,"const int AA=1")}window.program=s.program=h.initProgram(r,t,e),h.render()}else{const e=d.createElement("div");e.style.cssText="align-items:center;background:#969696;color:#fff;display:flex;font-family:monospace;font-size:20px;height:100vh;justify-content:center;left:0;position:fixed;top:0;width:100vw;",e.innerHTML="Your browser does not support WebGL.",b.append(e)}};init();'
);
modifier onlyOwner() {
if (owner != msg.sender) {
revert NotOwner();
}
_;
}
modifier onlyRoyaltyRecipient() {
if (royaltyRecipient != msg.sender) {
revert NotRoyaltyRecipient();
}
_;
}
struct Offer {
bool active;
uint256 value;
address toAddress;
}
struct Bid {
bool active;
uint256 value;
address fromAddress;
}
address public owner;
Offer public currentOffer;
Bid public currentBid;
address public royaltyRecipient;
uint256 public royaltyPercentage;
mapping (address => uint256) public pendingWithdrawals;
constructor(uint256 _royaltyPercentage) {
if (_royaltyPercentage >= 100) {
revert RoyaltyTooHigh();
}
owner = msg.sender;
royaltyRecipient = msg.sender;
royaltyPercentage = _royaltyPercentage;
emit ArtpieceCreated(msg.sender);
}
function name() public view virtual returns (string memory) {
return 'Unspoken';
}
function symbol() public view virtual returns (string memory) {
return 'U';
}
function artpiece() public view virtual returns (string memory) {
return string.concat(
'<!DOCTYPE html>'
'<html>'
'<head>'
'<title>', 'Unspoken', '</title>'
'<meta name="viewport" content="width=device-width, initial-scale=1" />'
'<style>html,body{background:#969696;margin:0;padding:0;overflow:hidden;}</style>'
'</head>'
'<body>'
'<script type="text/javascript">',
CORE,
'</script>'
'</body>'
'</html>'
);
}
function withdraw() public {
uint256 amount = pendingWithdrawals[msg.sender];
pendingWithdrawals[msg.sender] = 0;
_sendFunds(amount);
}
function transferOwnership(address newOwner) public onlyOwner {
if (newOwner == address(0)) {
revert NullAddress();
}
_transferOwnership(newOwner);
if (currentBid.fromAddress == newOwner) {
uint256 amount = currentBid.value;
currentBid = Bid({ active: false, value: 0, fromAddress: address(0) });
pendingWithdrawals[newOwner] += amount;
}
if (currentOffer.active) {
currentOffer = Offer({ active: false, value: 0, toAddress: address(0) });
}
}
function listForSale(uint256 salePriceInWei) public onlyOwner {
currentOffer = Offer({ active: true, value: salePriceInWei, toAddress: address(0) });
emit ListedForSale(salePriceInWei, msg.sender, address(0));
}
function listForSaleToAddress(uint256 salePriceInWei, address toAddress) public onlyOwner {
currentOffer = Offer({ active: true, value: salePriceInWei, toAddress: toAddress });
emit ListedForSale(salePriceInWei, msg.sender, toAddress);
}
function cancelFromSale() public onlyOwner {
Offer memory oldOffer = currentOffer;
currentOffer = Offer({ active: false, value: 0, toAddress: address(0) });
emit SaleCanceled(oldOffer.value, msg.sender, oldOffer.toAddress);
}
function buyNow() public payable {
if (!currentOffer.active) {
revert NotForSale();
}
if (currentOffer.toAddress != address(0) && currentOffer.toAddress != msg.sender) {
revert ListedForSaleToSpecificAddress();
}
if (msg.value != currentOffer.value) {
revert InsufficientFunds();
}
currentOffer = Offer({ active: false, value: 0, toAddress: address(0) });
uint256 royaltyAmount = _calcRoyalty(msg.value);
pendingWithdrawals[owner] += msg.value - royaltyAmount;
pendingWithdrawals[royaltyRecipient] += royaltyAmount;
emit SaleCompleted(msg.value, owner, msg.sender);
_transferOwnership(msg.sender);
}
function placeBid() public payable {
if (msg.value <= currentBid.value) {
revert InsufficientFunds();
}
if (currentBid.value > 0) {
pendingWithdrawals[currentBid.fromAddress] += currentBid.value;
}
currentBid = Bid({ active: true, value: msg.value, fromAddress: msg.sender });
emit BidPlaced(msg.value, msg.sender);
}
function acceptBid() public onlyOwner {
if (!currentBid.active) {
revert NoBid();
}
uint256 amount = currentBid.value;
address bidder = currentBid.fromAddress;
currentOffer = Offer({ active: false, value: 0, toAddress: address(0) });
currentBid = Bid({ active: false, value: 0, fromAddress: address(0) });
uint256 royaltyAmount = _calcRoyalty(amount);
pendingWithdrawals[owner] += amount - royaltyAmount;
pendingWithdrawals[royaltyRecipient] += royaltyAmount;
emit BidAccepted(amount, owner, bidder);
_transferOwnership(bidder);
}
function withdrawBid() public {
if (msg.sender != currentBid.fromAddress) {
revert NotYourBid();
}
uint256 amount = currentBid.value;
currentBid = Bid({ active: false, value: 0, fromAddress: address(0) });
_sendFunds(amount);
emit BidWithdrawn(amount, msg.sender);
}
function setRoyaltyRecipient(address newRoyaltyRecipient) public onlyRoyaltyRecipient {
if (newRoyaltyRecipient == address(0)) {
revert NullAddress();
}
royaltyRecipient = newRoyaltyRecipient;
}
function _transferOwnership(address newOwner) internal virtual {
address oldOwner = owner;
owner = newOwner;
emit ArtpieceTransferred(oldOwner, newOwner);
}
function _sendFunds(uint256 amount) internal virtual {
(bool success, ) = msg.sender.call{value: amount}('');
if (!success) {
revert FundsTransfer();
}
}
function _calcRoyalty(uint256 amount) internal virtual returns (uint256) {
return (amount * royaltyPercentage) / 100;
}
}
Submitted on: 2025-10-18 10:42:09
Comments
Log in to comment.
No comments yet.